Merge changes I69b33b0c,If904c85e,I28444df4,I3bfa4580,I88d9667d, ... into rvc-dev
* changes:
Decrease avatar and sender name sizes in MessagingStyle
Fixed various conversation layout appearences
Implemented FacePile if no group icon is present
Fixed the behavior of headers in conversation groups
Ensured correct coloring of badge in dark mode
Fixed an issue where the bubble badge was visible independent of the icon
Improved transitions for expanding messaging notifications
Adjusted single line representation to include a colon
Made the expand button positioning conditional on expanded state
Ensured that the sender of the first message is hidden
Baseline for the new ConversationLayout
diff --git a/Android.bp b/Android.bp
index 78d38c5..53417e8 100644
--- a/Android.bp
+++ b/Android.bp
@@ -281,17 +281,33 @@
filegroup {
name: "framework-updatable-sources",
srcs: [
- ":framework-sdkextensions-sources",
- ":framework-statsd-sources",
- ":framework-tethering-srcs",
- ":updatable-media-srcs",
":framework-mediaprovider-sources",
":framework-permission-sources",
- ":framework-wifi-updatable-sources",
+ ":framework-sdkextensions-sources",
+ ":framework-statsd-sources",
":framework-telephony-sources",
+ ":framework-tethering-srcs",
+ ":framework-wifi-updatable-sources",
+ ":updatable-media-srcs",
]
}
+java_library {
+ name: "framework-updatable-stubs-module_libs_api",
+ static_libs: [
+ "framework-media-stubs-module_libs_api",
+ "framework-mediaprovider-stubs-module_libs_api",
+ "framework-permission-stubs-module_libs_api",
+ "framework-sdkextensions-stubs-module_libs_api",
+ "framework-statsd-stubs-module_libs_api",
+ "framework-telephony-stubs", // TODO: Update to module_libs_api when there is one.
+ "framework-tethering-stubs-module_libs_api",
+ "framework-wifi-stubs-module_libs_api",
+ ],
+ sdk_version: "module_current",
+ visibility: [":__pkg__"],
+}
+
filegroup {
name: "framework-all-sources",
srcs: [
@@ -307,7 +323,6 @@
name: "framework-aidl-export-defaults",
aidl: {
export_include_dirs: [
- "apex/media/framework/java",
"core/java",
"drm/java",
"graphics/java",
@@ -324,6 +339,12 @@
"rs/java",
"sax/java",
"telecomm/java",
+
+ // TODO(b/148660295): remove this
+ "apex/media/framework/java",
+
+ // TODO(b/147699819): remove this
+ "telephony/java",
],
},
}
@@ -397,9 +418,7 @@
"app-compat-annotations",
"ext",
"unsupportedappusage",
- "framework-media-stubs-systemapi",
- "framework-mediaprovider-stubs-systemapi",
- "framework-telephony-stubs",
+ "framework-updatable-stubs-module_libs_api",
],
jarjar_rules: ":framework-jarjar-rules",
@@ -465,13 +484,6 @@
name: "framework-minus-apex",
defaults: ["framework-defaults"],
srcs: [":framework-non-updatable-sources"],
- libs: [
- "framework-sdkextensions-stubs-systemapi",
- "framework-statsd-stubs-module_libs_api",
- "framework-permission-stubs-systemapi",
- "framework-wifi-stubs-systemapi",
- "framework-tethering-stubs",
- ],
installable: true,
javac_shard_size: 150,
required: [
@@ -512,16 +524,9 @@
installable: false, // this lib is a build-only library
static_libs: [
"framework-minus-apex",
- "framework-media-stubs-systemapi",
- "framework-mediaprovider-stubs-systemapi",
- "framework-permission-stubs-systemapi",
- "framework-sdkextensions-stubs-systemapi",
- "framework-statsd-stubs-module_libs_api",
- "framework-wifi-stubs-systemapi",
- "framework-tethering-stubs",
- // TODO (b/147688669) should be framework-telephony-stubs
+ // TODO (b/147688669) should be removed
"framework-telephony",
- // TODO(jiyong): add stubs for APEXes here
+ "framework-updatable-stubs-module_libs_api",
],
sdk_version: "core_platform",
apex_available: ["//apex_available:platform"],
@@ -540,9 +545,7 @@
visibility: [
// DO NOT ADD ANY MORE ENTRIES TO THIS LIST
"//external/robolectric-shadows:__subpackages__",
- "//frameworks/base/packages/Tethering/common/TetheringLib:__subpackages__",
"//frameworks/layoutlib:__subpackages__",
- "//frameworks/opt/net/ike:__subpackages__",
],
}
diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
index c458d11..e042782 100644
--- a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
+++ b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
@@ -670,7 +670,7 @@
private void startApp(int userId, String packageName) throws RemoteException {
final Context context = InstrumentationRegistry.getContext();
final WaitResult result = ActivityTaskManager.getService().startActivityAndWait(null,
- context.getPackageName(), context.getFeatureId(),
+ context.getPackageName(), context.getAttributionTag(),
context.getPackageManager().getLaunchIntentForPackage(packageName), null, null,
null, 0, 0, null, null, userId);
attestTrue("User " + userId + " failed to start " + packageName,
diff --git a/apex/Android.bp b/apex/Android.bp
index 051986e..1510911 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -43,6 +43,7 @@
name: "framework-module-stubs-defaults-publicapi",
args: mainline_stubs_args,
installable: false,
+ sdk_version: "current",
}
stubs_defaults {
@@ -50,6 +51,7 @@
args: mainline_stubs_args + priv_apps,
srcs: [":framework-annotations"],
installable: false,
+ sdk_version: "system_current",
}
// The defaults for module_libs comes in two parts - defaults for API checks
@@ -62,6 +64,7 @@
args: mainline_stubs_args + module_libs,
srcs: [":framework-annotations"],
installable: false,
+ sdk_version: "module_current",
}
stubs_defaults {
@@ -69,4 +72,5 @@
args: mainline_stubs_args + module_libs + priv_apps,
srcs: [":framework-annotations"],
installable: false,
+ sdk_version: "module_current",
}
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
index b905273..ae8976a 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
@@ -53,9 +53,8 @@
* Container of data passed to the {@link android.app.job.JobScheduler} fully encapsulating the
* parameters required to schedule work against the calling application. These are constructed
* using the {@link JobInfo.Builder}.
- * You must specify at least one sort of constraint on the JobInfo object that you are creating.
* The goal here is to provide the scheduler with high-level semantics about the work you want to
- * accomplish. Doing otherwise with throw an exception in your app.
+ * accomplish.
*/
public class JobInfo implements Parcelable {
private static String TAG = "JobInfo";
@@ -147,7 +146,7 @@
/**
* Query the minimum interval allowed for periodic scheduled jobs. Attempting
- * to declare a smaller period that this when scheduling a job will result in a
+ * to declare a smaller period than this when scheduling a job will result in a
* job that is still periodic, but will run with this effective period.
*
* @return The minimum available interval for scheduling periodic jobs, in milliseconds.
diff --git a/apex/media/framework/java/android/media/MediaParser.java b/apex/media/framework/java/android/media/MediaParser.java
index b219fd41..29c48ad 100644
--- a/apex/media/framework/java/android/media/MediaParser.java
+++ b/apex/media/framework/java/android/media/MediaParser.java
@@ -139,7 +139,7 @@
* @Override
* public void onSampleCompleted(
* int trackIndex,
- * long timeUs,
+ * long timeMicros,
* int flags,
* int size,
* int offset,
@@ -163,7 +163,7 @@
* /* destPos= */ 0,
* /* size= */ offset);
* bytesWrittenCount = bytesWrittenCount - offset;
- * publishSample(sampleData, timeUs, flags);
+ * publishSample(sampleData, timeMicros, flags);
* }
*
* private void ensureSpaceInBuffer(int numberOfBytesToRead) {
@@ -187,7 +187,7 @@
*/
public static final class SeekMap {
- /** Returned by {@link #getDurationUs()} when the duration is unknown. */
+ /** Returned by {@link #getDurationMicros()} when the duration is unknown. */
public static final int UNKNOWN_DURATION = Integer.MIN_VALUE;
private final com.google.android.exoplayer2.extractor.SeekMap mExoPlayerSeekMap;
@@ -205,26 +205,26 @@
* Returns the duration of the stream in microseconds or {@link #UNKNOWN_DURATION} if the
* duration is unknown.
*/
- public long getDurationUs() {
+ public long getDurationMicros() {
return mExoPlayerSeekMap.getDurationUs();
}
/**
* Obtains {@link SeekPoint SeekPoints} for the specified seek time in microseconds.
*
- * <p>{@code getSeekPoints(timeUs).first} contains the latest seek point for samples with
- * timestamp equal to or smaller than {@code timeUs}.
+ * <p>{@code getSeekPoints(timeMicros).first} contains the latest seek point for samples
+ * with timestamp equal to or smaller than {@code timeMicros}.
*
- * <p>{@code getSeekPoints(timeUs).second} contains the earliest seek point for samples with
- * timestamp equal to or greater than {@code timeUs}. If a seek point exists for {@code
- * timeUs}, the returned pair will contain the same {@link SeekPoint} twice.
+ * <p>{@code getSeekPoints(timeMicros).second} contains the earliest seek point for samples
+ * with timestamp equal to or greater than {@code timeMicros}. If a seek point exists for
+ * {@code timeMicros}, the returned pair will contain the same {@link SeekPoint} twice.
*
- * @param timeUs A seek time in microseconds.
+ * @param timeMicros A seek time in microseconds.
* @return The corresponding {@link SeekPoint SeekPoints}.
*/
@NonNull
- public Pair<SeekPoint, SeekPoint> getSeekPoints(long timeUs) {
- SeekPoints seekPoints = mExoPlayerSeekMap.getSeekPoints(timeUs);
+ public Pair<SeekPoint, SeekPoint> getSeekPoints(long timeMicros) {
+ SeekPoints seekPoints = mExoPlayerSeekMap.getSeekPoints(timeMicros);
return new Pair<>(toSeekPoint(seekPoints.first), toSeekPoint(seekPoints.second));
}
}
@@ -254,24 +254,24 @@
@NonNull public static final SeekPoint START = new SeekPoint(0, 0);
/** The time of the seek point, in microseconds. */
- public final long timeUs;
+ public final long timeMicros;
/** The byte offset of the seek point. */
public final long position;
/**
- * @param timeUs The time of the seek point, in microseconds.
+ * @param timeMicros The time of the seek point, in microseconds.
* @param position The byte offset of the seek point.
*/
- private SeekPoint(long timeUs, long position) {
- this.timeUs = timeUs;
+ private SeekPoint(long timeMicros, long position) {
+ this.timeMicros = timeMicros;
this.position = position;
}
@Override
@NonNull
public String toString() {
- return "[timeUs=" + timeUs + ", position=" + position + "]";
+ return "[timeMicros=" + timeMicros + ", position=" + position + "]";
}
@Override
@@ -283,12 +283,12 @@
return false;
}
SeekPoint other = (SeekPoint) obj;
- return timeUs == other.timeUs && position == other.position;
+ return timeMicros == other.timeMicros && position == other.position;
}
@Override
public int hashCode() {
- int result = (int) timeUs;
+ int result = (int) timeMicros;
result = 31 * result + (int) position;
return result;
}
@@ -345,25 +345,25 @@
*
* @param seekMap The extracted {@link SeekMap}.
*/
- void onSeekMap(@NonNull SeekMap seekMap);
+ void onSeekMapFound(@NonNull SeekMap seekMap);
/**
* Called when the number of tracks is found.
*
* @param numberOfTracks The number of tracks in the stream.
*/
- void onTracksFound(int numberOfTracks);
+ void onTrackCountFound(int numberOfTracks);
/**
- * Called when new {@link TrackData} is extracted from the stream.
+ * Called when new {@link TrackData} is found in the stream.
*
* @param trackIndex The index of the track for which the {@link TrackData} was extracted.
* @param trackData The extracted {@link TrackData}.
*/
- void onTrackData(int trackIndex, @NonNull TrackData trackData);
+ void onTrackDataFound(int trackIndex, @NonNull TrackData trackData);
/**
- * Called to write sample data to the output.
+ * Called when sample data is found in the stream.
*
* <p>If the invocation of this method returns before the entire {@code inputReader} {@link
* InputReader#getLength() length} is consumed, the method will be called again for the
@@ -374,15 +374,15 @@
* @param inputReader The {@link InputReader} from which to read the data.
* @throws IOException If an exception occurs while reading from {@code inputReader}.
*/
- void onSampleData(int trackIndex, @NonNull InputReader inputReader) throws IOException;
+ void onSampleDataFound(int trackIndex, @NonNull InputReader inputReader) throws IOException;
/**
- * Called once all the data of a sample has been passed to {@link #onSampleData}.
+ * Called once all the data of a sample has been passed to {@link #onSampleDataFound}.
*
* <p>Also includes sample metadata, like presentation timestamp and flags.
*
* @param trackIndex The index of the track to which the sample corresponds.
- * @param timeUs The media timestamp associated with the sample, in microseconds.
+ * @param timeMicros The media timestamp associated with the sample, in microseconds.
* @param flags Flags associated with the sample. See {@link MediaCodec
* MediaCodec.BUFFER_FLAG_*}.
* @param size The size of the sample data, in bytes.
@@ -394,7 +394,7 @@
*/
void onSampleCompleted(
int trackIndex,
- long timeUs,
+ long timeMicros,
int flags,
int size,
int offset,
@@ -632,7 +632,7 @@
private Extractor mExtractor;
private ExtractorInput mExtractorInput;
private long mPendingSeekPosition;
- private long mPendingSeekTimeUs;
+ private long mPendingSeekTimeMicros;
// Public methods.
@@ -760,7 +760,7 @@
}
if (isPendingSeek()) {
- mExtractor.seek(mPendingSeekPosition, mPendingSeekTimeUs);
+ mExtractor.seek(mPendingSeekPosition, mPendingSeekTimeMicros);
removePendingSeek();
}
@@ -786,7 +786,7 @@
* Seeks within the media container being extracted.
*
* <p>{@link SeekPoint SeekPoints} can be obtained from the {@link SeekMap} passed to {@link
- * OutputConsumer#onSeekMap(SeekMap)}.
+ * OutputConsumer#onSeekMapFound(SeekMap)}.
*
* <p>Following a call to this method, the {@link InputReader} passed to the next invocation of
* {@link #advance} must provide data starting from {@link SeekPoint#position} in the stream.
@@ -796,9 +796,9 @@
public void seek(@NonNull SeekPoint seekPoint) {
if (mExtractor == null) {
mPendingSeekPosition = seekPoint.position;
- mPendingSeekTimeUs = seekPoint.timeUs;
+ mPendingSeekTimeMicros = seekPoint.timeMicros;
} else {
- mExtractor.seek(seekPoint.position, seekPoint.timeUs);
+ mExtractor.seek(seekPoint.position, seekPoint.timeMicros);
}
}
@@ -836,7 +836,7 @@
private void removePendingSeek() {
mPendingSeekPosition = -1;
- mPendingSeekTimeUs = -1;
+ mPendingSeekTimeMicros = -1;
}
// Private classes.
@@ -897,12 +897,12 @@
@Override
public void endTracks() {
- mOutputConsumer.onTracksFound(mTrackOutputAdapters.size());
+ mOutputConsumer.onTrackCountFound(mTrackOutputAdapters.size());
}
@Override
public void seekMap(com.google.android.exoplayer2.extractor.SeekMap exoplayerSeekMap) {
- mOutputConsumer.onSeekMap(new SeekMap(exoplayerSeekMap));
+ mOutputConsumer.onSeekMapFound(new SeekMap(exoplayerSeekMap));
}
}
@@ -916,7 +916,7 @@
@Override
public void format(Format format) {
- mOutputConsumer.onTrackData(
+ mOutputConsumer.onTrackDataFound(
mTrackIndex,
new TrackData(
toMediaFormat(format), toFrameworkDrmInitData(format.drmInitData)));
@@ -927,7 +927,7 @@
throws IOException {
mScratchExtractorInputAdapter.setExtractorInput(input, length);
long positionBeforeReading = mScratchExtractorInputAdapter.getPosition();
- mOutputConsumer.onSampleData(mTrackIndex, mScratchExtractorInputAdapter);
+ mOutputConsumer.onSampleDataFound(mTrackIndex, mScratchExtractorInputAdapter);
return (int) (mScratchExtractorInputAdapter.getPosition() - positionBeforeReading);
}
@@ -935,7 +935,7 @@
public void sampleData(ParsableByteArray data, int length) {
mScratchParsableByteArrayAdapter.resetWithByteArray(data, length);
try {
- mOutputConsumer.onSampleData(mTrackIndex, mScratchParsableByteArrayAdapter);
+ mOutputConsumer.onSampleDataFound(mTrackIndex, mScratchParsableByteArrayAdapter);
} catch (IOException e) {
// Unexpected.
throw new RuntimeException(e);
diff --git a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java
index 0d163cf..aedba29 100644
--- a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java
+++ b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistence.java
@@ -40,7 +40,7 @@
* @return the runtime permissions read
*/
@Nullable
- RuntimePermissionsState readAsUser(@NonNull UserHandle user);
+ RuntimePermissionsState readForUser(@NonNull UserHandle user);
/**
* Write the runtime permissions to persistence.
@@ -50,7 +50,8 @@
* @param runtimePermissions the runtime permissions to write
* @param user the user to write for
*/
- void writeAsUser(@NonNull RuntimePermissionsState runtimePermissions, @NonNull UserHandle user);
+ void writeForUser(@NonNull RuntimePermissionsState runtimePermissions,
+ @NonNull UserHandle user);
/**
* Delete the runtime permissions from persistence.
@@ -59,7 +60,7 @@
*
* @param user the user to delete for
*/
- void deleteAsUser(@NonNull UserHandle user);
+ void deleteForUser(@NonNull UserHandle user);
/**
* Create a new instance of {@link RuntimePermissionsPersistence} implementation.
diff --git a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java
index 0ac0c73..e43f59a 100644
--- a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java
+++ b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsPersistenceImpl.java
@@ -67,7 +67,7 @@
@Nullable
@Override
- public RuntimePermissionsState readAsUser(@NonNull UserHandle user) {
+ public RuntimePermissionsState readForUser(@NonNull UserHandle user) {
File file = getFile(user);
try (FileInputStream inputStream = new AtomicFile(file).openRead()) {
XmlPullParser parser = Xml.newPullParser();
@@ -172,7 +172,7 @@
}
@Override
- public void writeAsUser(@NonNull RuntimePermissionsState runtimePermissions,
+ public void writeForUser(@NonNull RuntimePermissionsState runtimePermissions,
@NonNull UserHandle user) {
File file = getFile(user);
AtomicFile atomicFile = new AtomicFile(file);
@@ -252,7 +252,7 @@
}
@Override
- public void deleteAsUser(@NonNull UserHandle user) {
+ public void deleteForUser(@NonNull UserHandle user) {
getFile(user).delete();
}
diff --git a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsState.java b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsState.java
index cd2750a..c6bfc6d 100644
--- a/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsState.java
+++ b/apex/permission/service/java/com/android/permission/persistence/RuntimePermissionsState.java
@@ -23,6 +23,7 @@
import java.util.List;
import java.util.Map;
+import java.util.Objects;
/**
* State of all runtime permissions.
@@ -61,6 +62,14 @@
@NonNull
private final Map<String, List<PermissionState>> mSharedUserPermissions;
+ /**
+ * Create a new instance of this class.
+ *
+ * @param version the version of the runtime permissions
+ * @param fingerprint the fingerprint of the runtime permissions
+ * @param packagePermissions the runtime permissions by packages
+ * @param sharedUserPermissions the runtime permissions by shared users
+ */
public RuntimePermissionsState(int version, @Nullable String fingerprint,
@NonNull Map<String, List<PermissionState>> packagePermissions,
@NonNull Map<String, List<PermissionState>> sharedUserPermissions) {
@@ -70,32 +79,72 @@
mSharedUserPermissions = sharedUserPermissions;
}
+ /**
+ * Get the version of the runtime permissions.
+ *
+ * @return the version of the runtime permissions
+ */
public int getVersion() {
return mVersion;
}
+ /**
+ * Get the fingerprint of the runtime permissions.
+ *
+ * @return the fingerprint of the runtime permissions
+ */
@Nullable
public String getFingerprint() {
return mFingerprint;
}
+ /**
+ * Get the runtime permissions by packages.
+ *
+ * @return the runtime permissions by packages
+ */
@NonNull
public Map<String, List<PermissionState>> getPackagePermissions() {
return mPackagePermissions;
}
+ /**
+ * Get the runtime permissions by shared users.
+ *
+ * @return the runtime permissions by shared users
+ */
@NonNull
public Map<String, List<PermissionState>> getSharedUserPermissions() {
return mSharedUserPermissions;
}
+ @Override
+ public boolean equals(Object object) {
+ if (this == object) {
+ return true;
+ }
+ if (object == null || getClass() != object.getClass()) {
+ return false;
+ }
+ RuntimePermissionsState that = (RuntimePermissionsState) object;
+ return mVersion == that.mVersion
+ && Objects.equals(mFingerprint, that.mFingerprint)
+ && Objects.equals(mPackagePermissions, that.mPackagePermissions)
+ && Objects.equals(mSharedUserPermissions, that.mSharedUserPermissions);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mVersion, mFingerprint, mPackagePermissions, mSharedUserPermissions);
+ }
+
/**
* State of a single permission.
*/
- public static class PermissionState {
+ public static final class PermissionState {
/**
- * Name of the permission.
+ * The name of the permission.
*/
@NonNull
private final String mName;
@@ -106,27 +155,68 @@
private final boolean mGranted;
/**
- * Flags of the permission.
+ * The flags of the permission.
*/
private final int mFlags;
+ /**
+ * Create a new instance of this class.
+ *
+ * @param name the name of the permission
+ * @param granted whether the permission is granted
+ * @param flags the flags of the permission
+ */
public PermissionState(@NonNull String name, boolean granted, int flags) {
mName = name;
mGranted = granted;
mFlags = flags;
}
+ /**
+ * Get the name of the permission.
+ *
+ * @return the name of the permission
+ */
@NonNull
public String getName() {
return mName;
}
+ /**
+ * Get whether the permission is granted.
+ *
+ * @return whether the permission is granted
+ */
public boolean isGranted() {
return mGranted;
}
+ /**
+ * Get the flags of the permission.
+ *
+ * @return the flags of the permission
+ */
public int getFlags() {
return mFlags;
}
+
+ @Override
+ public boolean equals(Object object) {
+ if (this == object) {
+ return true;
+ }
+ if (object == null || getClass() != object.getClass()) {
+ return false;
+ }
+ PermissionState that = (PermissionState) object;
+ return mGranted == that.mGranted
+ && mFlags == that.mFlags
+ && Objects.equals(mName, that.mName);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mName, mGranted, mFlags);
+ }
}
}
diff --git a/apex/permission/service/java/com/android/role/persistence/RolesPersistence.java b/apex/permission/service/java/com/android/role/persistence/RolesPersistence.java
index 64d6545..2e5a28a 100644
--- a/apex/permission/service/java/com/android/role/persistence/RolesPersistence.java
+++ b/apex/permission/service/java/com/android/role/persistence/RolesPersistence.java
@@ -40,7 +40,7 @@
* @return the roles read
*/
@Nullable
- RolesState readAsUser(@NonNull UserHandle user);
+ RolesState readForUser(@NonNull UserHandle user);
/**
* Write the roles to persistence.
@@ -50,7 +50,7 @@
* @param roles the roles to write
* @param user the user to write for
*/
- void writeAsUser(@NonNull RolesState roles, @NonNull UserHandle user);
+ void writeForUser(@NonNull RolesState roles, @NonNull UserHandle user);
/**
* Delete the roles from persistence.
@@ -59,7 +59,7 @@
*
* @param user the user to delete for
*/
- void deleteAsUser(@NonNull UserHandle user);
+ void deleteForUser(@NonNull UserHandle user);
/**
* Create a new instance of {@link RolesPersistence} implementation.
diff --git a/apex/permission/service/java/com/android/role/persistence/RolesPersistenceImpl.java b/apex/permission/service/java/com/android/role/persistence/RolesPersistenceImpl.java
index 2346c11..f66257f 100644
--- a/apex/permission/service/java/com/android/role/persistence/RolesPersistenceImpl.java
+++ b/apex/permission/service/java/com/android/role/persistence/RolesPersistenceImpl.java
@@ -65,7 +65,7 @@
@Nullable
@Override
- public RolesState readAsUser(@NonNull UserHandle user) {
+ public RolesState readForUser(@NonNull UserHandle user) {
File file = getFile(user);
try (FileInputStream inputStream = new AtomicFile(file).openRead()) {
XmlPullParser parser = Xml.newPullParser();
@@ -146,7 +146,7 @@
}
@Override
- public void writeAsUser(@NonNull RolesState roles, @NonNull UserHandle user) {
+ public void writeForUser(@NonNull RolesState roles, @NonNull UserHandle user) {
File file = getFile(user);
AtomicFile atomicFile = new AtomicFile(file);
FileOutputStream outputStream = null;
@@ -205,7 +205,7 @@
}
@Override
- public void deleteAsUser(@NonNull UserHandle user) {
+ public void deleteForUser(@NonNull UserHandle user) {
getFile(user).delete();
}
diff --git a/apex/permission/service/java/com/android/role/persistence/RolesState.java b/apex/permission/service/java/com/android/role/persistence/RolesState.java
index 7da9d11..f61efa0 100644
--- a/apex/permission/service/java/com/android/role/persistence/RolesState.java
+++ b/apex/permission/service/java/com/android/role/persistence/RolesState.java
@@ -22,6 +22,7 @@
import android.annotation.SystemApi.Client;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
/**
@@ -50,6 +51,13 @@
@NonNull
private final Map<String, Set<String>> mRoles;
+ /**
+ * Create a new instance of this class.
+ *
+ * @param version the version of the roles
+ * @param packagesHash the hash of all packages in the system
+ * @param roles the roles
+ */
public RolesState(int version, @Nullable String packagesHash,
@NonNull Map<String, Set<String>> roles) {
mVersion = version;
@@ -57,17 +65,51 @@
mRoles = roles;
}
+ /**
+ * Get the version of the roles.
+ *
+ * @return the version of the roles
+ */
public int getVersion() {
return mVersion;
}
+ /**
+ * Get the hash of all packages in the system.
+ *
+ * @return the hash of all packages in the system
+ */
@Nullable
public String getPackagesHash() {
return mPackagesHash;
}
+ /**
+ * Get the roles.
+ *
+ * @return the roles
+ */
@NonNull
public Map<String, Set<String>> getRoles() {
return mRoles;
}
+
+ @Override
+ public boolean equals(Object object) {
+ if (this == object) {
+ return true;
+ }
+ if (object == null || getClass() != object.getClass()) {
+ return false;
+ }
+ RolesState that = (RolesState) object;
+ return mVersion == that.mVersion
+ && Objects.equals(mPackagesHash, that.mPackagesHash)
+ && Objects.equals(mRoles, that.mRoles);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mVersion, mPackagesHash, mRoles);
+ }
}
diff --git a/api/current.txt b/api/current.txt
index 2efb305..7256461 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -572,6 +572,7 @@
field public static final int elevation = 16843840; // 0x1010440
field public static final int ellipsize = 16842923; // 0x10100ab
field public static final int ems = 16843096; // 0x1010158
+ field public static final int enableGwpAsan = 16844310; // 0x1010616
field public static final int enableVrMode = 16844069; // 0x1010525
field public static final int enabled = 16842766; // 0x101000e
field public static final int end = 16843996; // 0x10104dc
@@ -620,7 +621,6 @@
field public static final int fastScrollTextColor = 16843609; // 0x1010359
field public static final int fastScrollThumbDrawable = 16843574; // 0x1010336
field public static final int fastScrollTrackDrawable = 16843577; // 0x1010339
- field public static final int featureId = 16844301; // 0x101060d
field public static final int fillAfter = 16843197; // 0x10101bd
field public static final int fillAlpha = 16843980; // 0x10104cc
field public static final int fillBefore = 16843196; // 0x10101bc
@@ -4586,7 +4586,7 @@
public final class AsyncNotedAppOp implements android.os.Parcelable {
method public int describeContents();
- method @Nullable public String getFeatureId();
+ method @Nullable public String getAttributionTag();
method @NonNull public String getMessage();
method @IntRange(from=0) public int getNotingUid();
method @NonNull public String getOp();
@@ -6430,7 +6430,7 @@
public final class SyncNotedAppOp implements android.os.Parcelable {
ctor public SyncNotedAppOp(@IntRange(from=0L) int, @Nullable String);
method public int describeContents();
- method @Nullable public String getFeatureId();
+ method @Nullable public String getAttributionTag();
method @NonNull public String getOp();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.SyncNotedAppOp> CREATOR;
@@ -6856,9 +6856,9 @@
method @Nullable public String getAlwaysOnVpnPackage(@NonNull android.content.ComponentName);
method @NonNull @WorkerThread public android.os.Bundle getApplicationRestrictions(@Nullable android.content.ComponentName, String);
method @Deprecated @Nullable public String getApplicationRestrictionsManagingPackage(@NonNull android.content.ComponentName);
- method public boolean getAutoTime(@NonNull android.content.ComponentName);
+ method public boolean getAutoTimeEnabled(@NonNull android.content.ComponentName);
method @Deprecated public boolean getAutoTimeRequired();
- method public boolean getAutoTimeZone(@NonNull android.content.ComponentName);
+ method public boolean getAutoTimeZoneEnabled(@NonNull android.content.ComponentName);
method @NonNull public java.util.List<android.os.UserHandle> getBindDeviceAdminTargetUsers(@NonNull android.content.ComponentName);
method public boolean getBluetoothContactSharingDisabled(@NonNull android.content.ComponentName);
method public boolean getCameraDisabled(@Nullable android.content.ComponentName);
@@ -6982,9 +6982,9 @@
method public boolean setApplicationHidden(@NonNull android.content.ComponentName, String, boolean);
method @WorkerThread public void setApplicationRestrictions(@Nullable android.content.ComponentName, String, android.os.Bundle);
method @Deprecated public void setApplicationRestrictionsManagingPackage(@NonNull android.content.ComponentName, @Nullable String) throws android.content.pm.PackageManager.NameNotFoundException;
- method public void setAutoTime(@NonNull android.content.ComponentName, boolean);
+ method public void setAutoTimeEnabled(@NonNull android.content.ComponentName, boolean);
method @Deprecated public void setAutoTimeRequired(@NonNull android.content.ComponentName, boolean);
- method public void setAutoTimeZone(@NonNull android.content.ComponentName, boolean);
+ method public void setAutoTimeZoneEnabled(@NonNull android.content.ComponentName, boolean);
method public void setBackupServiceEnabled(@NonNull android.content.ComponentName, boolean);
method public void setBluetoothContactSharingDisabled(@NonNull android.content.ComponentName, boolean);
method public void setCameraDisabled(@NonNull android.content.ComponentName, boolean);
@@ -9696,7 +9696,7 @@
method public abstract int delete(@NonNull android.net.Uri, @Nullable String, @Nullable String[]);
method public int delete(@NonNull android.net.Uri, @Nullable android.os.Bundle);
method public void dump(java.io.FileDescriptor, java.io.PrintWriter, String[]);
- method @Nullable public final String getCallingFeatureId();
+ method @Nullable public final String getCallingAttributionTag();
method @Nullable public final String getCallingPackage();
method @Nullable public final String getCallingPackageUnchecked();
method @Nullable public final android.content.Context getContext();
@@ -10030,11 +10030,11 @@
method @CheckResult(suggest="#enforceUriPermission(Uri,int,int,String)") public abstract int checkUriPermission(android.net.Uri, int, int, int);
method @CheckResult(suggest="#enforceUriPermission(Uri,String,String,int,int,int,String)") public abstract int checkUriPermission(@Nullable android.net.Uri, @Nullable String, @Nullable String, int, int, int);
method @Deprecated public abstract void clearWallpaper() throws java.io.IOException;
+ method @NonNull public android.content.Context createAttributionContext(@Nullable String);
method public abstract android.content.Context createConfigurationContext(@NonNull android.content.res.Configuration);
method public abstract android.content.Context createContextForSplit(String) throws android.content.pm.PackageManager.NameNotFoundException;
method public abstract android.content.Context createDeviceProtectedStorageContext();
method public abstract android.content.Context createDisplayContext(@NonNull android.view.Display);
- method @NonNull public android.content.Context createFeatureContext(@Nullable String);
method public abstract android.content.Context createPackageContext(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
method @NonNull public android.content.Context createWindowContext(int, @Nullable android.os.Bundle);
method public abstract String[] databaseList();
@@ -10052,6 +10052,7 @@
method public abstract android.content.Context getApplicationContext();
method public abstract android.content.pm.ApplicationInfo getApplicationInfo();
method public abstract android.content.res.AssetManager getAssets();
+ method @Nullable public String getAttributionTag();
method public abstract java.io.File getCacheDir();
method public abstract ClassLoader getClassLoader();
method public abstract java.io.File getCodeCacheDir();
@@ -10068,7 +10069,6 @@
method @Nullable public abstract java.io.File getExternalFilesDir(@Nullable String);
method public abstract java.io.File[] getExternalFilesDirs(String);
method @Deprecated public abstract java.io.File[] getExternalMediaDirs();
- method @Nullable public String getFeatureId();
method public abstract java.io.File getFileStreamPath(String);
method public abstract java.io.File getFilesDir();
method public java.util.concurrent.Executor getMainExecutor();
@@ -10806,6 +10806,7 @@
field public static final String EXTRA_TEMPLATE = "android.intent.extra.TEMPLATE";
field public static final String EXTRA_TEXT = "android.intent.extra.TEXT";
field public static final String EXTRA_TIME = "android.intent.extra.TIME";
+ field public static final String EXTRA_TIMEZONE = "time-zone";
field public static final String EXTRA_TITLE = "android.intent.extra.TITLE";
field public static final String EXTRA_UID = "android.intent.extra.UID";
field public static final String EXTRA_USER = "android.intent.extra.USER";
@@ -11438,6 +11439,7 @@
method public int describeContents();
method public void dump(android.util.Printer, String);
method public static CharSequence getCategoryTitle(android.content.Context, int);
+ method @Nullable public Boolean isGwpAsanEnabled();
method public boolean isProfileableByShell();
method public boolean isResourceOverlay();
method public boolean isVirtualPreload();
@@ -11571,6 +11573,7 @@
method @NonNull public CharSequence getProfileSwitchingLabel(@NonNull android.os.UserHandle);
method @NonNull public java.util.List<android.os.UserHandle> getTargetUserProfiles();
method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_PROFILES, "android.permission.INTERACT_ACROSS_USERS"}) public void startActivity(@NonNull android.content.Intent, @NonNull android.os.UserHandle, @Nullable android.app.Activity);
+ method @RequiresPermission(anyOf={android.Manifest.permission.INTERACT_ACROSS_PROFILES, "android.permission.INTERACT_ACROSS_USERS"}) public void startActivity(@NonNull android.content.Intent, @NonNull android.os.UserHandle, @Nullable android.app.Activity, @Nullable android.os.Bundle);
method public void startMainActivity(@NonNull android.content.ComponentName, @NonNull android.os.UserHandle);
field public static final String ACTION_CAN_INTERACT_ACROSS_PROFILES_CHANGED = "android.content.pm.action.CAN_INTERACT_ACROSS_PROFILES_CHANGED";
}
@@ -26448,14 +26451,14 @@
public static interface MediaParser.OutputConsumer {
method public void onSampleCompleted(int, long, int, int, int, @Nullable android.media.MediaCodec.CryptoInfo);
- method public void onSampleData(int, @NonNull android.media.MediaParser.InputReader) throws java.io.IOException;
- method public void onSeekMap(@NonNull android.media.MediaParser.SeekMap);
- method public void onTrackData(int, @NonNull android.media.MediaParser.TrackData);
- method public void onTracksFound(int);
+ method public void onSampleDataFound(int, @NonNull android.media.MediaParser.InputReader) throws java.io.IOException;
+ method public void onSeekMapFound(@NonNull android.media.MediaParser.SeekMap);
+ method public void onTrackCountFound(int);
+ method public void onTrackDataFound(int, @NonNull android.media.MediaParser.TrackData);
}
public static final class MediaParser.SeekMap {
- method public long getDurationUs();
+ method public long getDurationMicros();
method @NonNull public android.util.Pair<android.media.MediaParser.SeekPoint,android.media.MediaParser.SeekPoint> getSeekPoints(long);
method public boolean isSeekable();
field public static final int UNKNOWN_DURATION = -2147483648; // 0x80000000
@@ -26464,7 +26467,7 @@
public static final class MediaParser.SeekPoint {
field @NonNull public static final android.media.MediaParser.SeekPoint START;
field public final long position;
- field public final long timeUs;
+ field public final long timeMicros;
}
public static interface MediaParser.SeekableInputReader extends android.media.MediaParser.InputReader {
@@ -40714,6 +40717,7 @@
field public static final String PARENTAL_CONTROL_LAST_UPDATE = "parental_control_last_update";
field public static final String PARENTAL_CONTROL_REDIRECT_URL = "parental_control_redirect_url";
field public static final String RTT_CALLING_MODE = "rtt_calling_mode";
+ field public static final String SECURE_FRP_MODE = "secure_frp_mode";
field public static final String SELECTED_INPUT_METHOD_SUBTYPE = "selected_input_method_subtype";
field public static final String SETTINGS_CLASSNAME = "settings_classname";
field public static final String SKIP_FIRST_USE_HINTS = "skip_first_use_hints";
@@ -43012,12 +43016,12 @@
}
public static final class Dataset.Builder {
- ctor public Dataset.Builder(@NonNull android.widget.RemoteViews, @NonNull android.service.autofill.InlinePresentation);
ctor public Dataset.Builder(@NonNull android.widget.RemoteViews);
ctor public Dataset.Builder();
method @NonNull public android.service.autofill.Dataset build();
method @NonNull public android.service.autofill.Dataset.Builder setAuthentication(@Nullable android.content.IntentSender);
method @NonNull public android.service.autofill.Dataset.Builder setId(@Nullable String);
+ method @NonNull public android.service.autofill.Dataset.Builder setInlinePresentation(@NonNull android.service.autofill.InlinePresentation);
method @NonNull public android.service.autofill.Dataset.Builder setValue(@NonNull android.view.autofill.AutofillId, @Nullable android.view.autofill.AutofillValue);
method @NonNull public android.service.autofill.Dataset.Builder setValue(@NonNull android.view.autofill.AutofillId, @Nullable android.view.autofill.AutofillValue, @NonNull android.widget.RemoteViews);
method @NonNull public android.service.autofill.Dataset.Builder setValue(@NonNull android.view.autofill.AutofillId, @Nullable android.view.autofill.AutofillValue, @Nullable java.util.regex.Pattern);
@@ -45973,9 +45977,6 @@
field public static final int MISSED = 5; // 0x5
field public static final int OTHER = 9; // 0x9
field public static final String REASON_EMERGENCY_CALL_PLACED = "REASON_EMERGENCY_CALL_PLACED";
- field public static final String REASON_EMULATING_SINGLE_CALL = "EMULATING_SINGLE_CALL";
- field public static final String REASON_IMS_ACCESS_BLOCKED = "REASON_IMS_ACCESS_BLOCKED";
- field public static final String REASON_WIFI_ON_BUT_WFC_OFF = "REASON_WIFI_ON_BUT_WFC_OFF";
field public static final int REJECTED = 6; // 0x6
field public static final int REMOTE = 3; // 0x3
field public static final int RESTRICTED = 8; // 0x8
@@ -46302,7 +46303,6 @@
field public static final int DURATION_SHORT = 1; // 0x1
field public static final int DURATION_VERY_SHORT = 0; // 0x0
field public static final String EXTRA_CALL_BACK_NUMBER = "android.telecom.extra.CALL_BACK_NUMBER";
- field public static final String EXTRA_CALL_CREATED_TIME_MILLIS = "android.telecom.extra.CALL_CREATED_TIME_MILLIS";
field public static final String EXTRA_CALL_DISCONNECT_CAUSE = "android.telecom.extra.CALL_DISCONNECT_CAUSE";
field public static final String EXTRA_CALL_DISCONNECT_MESSAGE = "android.telecom.extra.CALL_DISCONNECT_MESSAGE";
field public static final String EXTRA_CALL_DURATION = "android.telecom.extra.CALL_DURATION";
@@ -48044,13 +48044,13 @@
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.os.ParcelUuid createSubscriptionGroup(@NonNull java.util.List<java.lang.Integer>);
method @Deprecated public static android.telephony.SubscriptionManager from(android.content.Context);
method public java.util.List<android.telephony.SubscriptionInfo> getAccessibleSubscriptionInfoList();
- method @Nullable public java.util.List<android.telephony.SubscriptionInfo> getActiveAndHiddenSubscriptionInfoList();
method public static int getActiveDataSubscriptionId();
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public android.telephony.SubscriptionInfo getActiveSubscriptionInfo(int);
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getActiveSubscriptionInfoCount();
method public int getActiveSubscriptionInfoCountMax();
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public android.telephony.SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int);
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.List<android.telephony.SubscriptionInfo> getActiveSubscriptionInfoList();
+ method @NonNull public java.util.List<android.telephony.SubscriptionInfo> getCompleteActiveSubscriptionInfoList();
method public static int getDefaultDataSubscriptionId();
method public static int getDefaultSmsSubscriptionId();
method public static int getDefaultSubscriptionId();
@@ -48213,6 +48213,7 @@
method public boolean isEmergencyNumber(@NonNull String);
method public boolean isHearingAidCompatibilitySupported();
method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, "android.permission.READ_PRIVILEGED_PHONE_STATE"}) public boolean isManualNetworkSelectionAllowed();
+ method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isModemEnabledForSlot(int);
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int isMultiSimSupported();
method public boolean isNetworkRoaming();
method public boolean isRttSupported();
@@ -48326,7 +48327,6 @@
field public static final int NETWORK_TYPE_UNKNOWN = 0; // 0x0
field public static final int PHONE_TYPE_CDMA = 2; // 0x2
field public static final int PHONE_TYPE_GSM = 1; // 0x1
- field public static final int PHONE_TYPE_IMS = 5; // 0x5
field public static final int PHONE_TYPE_NONE = 0; // 0x0
field public static final int PHONE_TYPE_SIP = 3; // 0x3
field public static final int SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION = 2; // 0x2
@@ -55582,10 +55582,12 @@
}
public interface WindowInsetsController {
+ method public void addOnControllableInsetsChangedListener(@NonNull android.view.WindowInsetsController.OnControllableInsetsChangedListener);
method @NonNull public android.os.CancellationSignal controlWindowInsetsAnimation(int, long, @Nullable android.view.animation.Interpolator, @NonNull android.view.WindowInsetsAnimationControlListener);
method public int getSystemBarsAppearance();
method public int getSystemBarsBehavior();
method public void hide(int);
+ method public void removeOnControllableInsetsChangedListener(@NonNull android.view.WindowInsetsController.OnControllableInsetsChangedListener);
method public void setSystemBarsAppearance(int, int);
method public void setSystemBarsBehavior(int);
method public void show(int);
@@ -55596,6 +55598,10 @@
field public static final int BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE = 2; // 0x2
}
+ public static interface WindowInsetsController.OnControllableInsetsChangedListener {
+ method public void onControllableInsetsChanged(@NonNull android.view.WindowInsetsController, int);
+ }
+
public interface WindowManager extends android.view.ViewManager {
method @NonNull public default android.view.WindowMetrics getCurrentWindowMetrics();
method @Deprecated public android.view.Display getDefaultDisplay();
@@ -82227,3 +82233,4 @@
}
}
+
diff --git a/api/lint-baseline.txt b/api/lint-baseline.txt
index 569e838..83c78fe 100644
--- a/api/lint-baseline.txt
+++ b/api/lint-baseline.txt
@@ -15,6 +15,16 @@
ArrayReturn: android.content.ContentProviderOperation#resolveExtrasBackReferences(android.content.ContentProviderResult[], int) parameter #0:
+ArrayReturn: android.location.GnssAntennaInfo.SphericalCorrections#SphericalCorrections(double[][], double[][]) parameter #0:
+ Method parameter should be Collection<> (or subclass) instead of raw array; was `double[][]`
+ArrayReturn: android.location.GnssAntennaInfo.SphericalCorrections#SphericalCorrections(double[][], double[][]) parameter #1:
+ Method parameter should be Collection<> (or subclass) instead of raw array; was `double[][]`
+ArrayReturn: android.location.GnssAntennaInfo.SphericalCorrections#getCorrectionUncertaintiesArray():
+ Method should return Collection<> (or subclass) instead of raw array; was `double[][]`
+ArrayReturn: android.location.GnssAntennaInfo.SphericalCorrections#getCorrectionsArray():
+ Method should return Collection<> (or subclass) instead of raw array; was `double[][]`
+ArrayReturn: android.service.autofill.FillResponse.Builder#setAuthentication(android.view.autofill.AutofillId[], android.content.IntentSender, android.widget.RemoteViews, android.service.autofill.InlinePresentation) parameter #0:
+ Method parameter should be Collection<AutofillId> (or subclass) instead of raw array; was `android.view.autofill.AutofillId[]`
BroadcastBehavior: android.app.AlarmManager#ACTION_NEXT_ALARM_CLOCK_CHANGED:
@@ -453,8 +463,12 @@
+ExecutorRegistration: android.media.MediaRouter2#setOnGetControllerHintsListener(android.media.MediaRouter2.OnGetControllerHintsListener):
+ Registration methods should have overload that accepts delivery Executor: `setOnGetControllerHintsListener`
+
+
GenericException: android.content.res.loader.ResourcesProvider#finalize():
- Methods must not throw generic exceptions (`java.lang.Throwable`)
+
HiddenSuperclass: android.content.res.ColorStateList:
@@ -499,6 +513,30 @@
+IntentBuilderName: android.net.VpnManager#provisionVpnProfile(android.net.PlatformVpnProfile):
+ Methods creating an Intent should be named `create<Foo>Intent()`, was `provisionVpnProfile`
+
+
+KotlinOperator: android.media.AudioMetadata.Map#set(android.media.AudioMetadata.Key<T>, T):
+ Method can be invoked with an indexing operator from Kotlin: `set` (this is usually desirable; just make sure it makes sense for this type of object)
+KotlinOperator: android.media.AudioMetadata.ReadMap#get(android.media.AudioMetadata.Key<T>):
+ Method can be invoked with an indexing operator from Kotlin: `get` (this is usually desirable; just make sure it makes sense for this type of object)
+
+
+MethodNameUnits: android.media.MediaParser.SeekMap#getDurationMicros():
+ Returned time values are strongly encouraged to be in milliseconds unless you need the extra precision, was `getDurationMicros`
+
+
+MinMaxConstant: android.telephony.DataFailCause#MAX_ACCESS_PROBE:
+ If min/max could change in future, make them dynamic methods: android.telephony.DataFailCause#MAX_ACCESS_PROBE
+MinMaxConstant: android.telephony.DataFailCause#MAX_IPV4_CONNECTIONS:
+ If min/max could change in future, make them dynamic methods: android.telephony.DataFailCause#MAX_IPV4_CONNECTIONS
+MinMaxConstant: android.telephony.DataFailCause#MAX_IPV6_CONNECTIONS:
+ If min/max could change in future, make them dynamic methods: android.telephony.DataFailCause#MAX_IPV6_CONNECTIONS
+MinMaxConstant: android.telephony.DataFailCause#MAX_PPP_INACTIVITY_TIMER_EXPIRED:
+ If min/max could change in future, make them dynamic methods: android.telephony.DataFailCause#MAX_PPP_INACTIVITY_TIMER_EXPIRED
+
+
MissingNullability: android.app.AsyncNotedAppOp#equals(Object) parameter #0:
MissingNullability: android.app.AsyncNotedAppOp#writeToParcel(android.os.Parcel, int) parameter #0:
@@ -506,11 +544,11 @@
MissingNullability: android.app.SyncNotedAppOp#equals(Object) parameter #0:
MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#CHORASMIAN:
- Missing nullability on field `CHORASMIAN` in class `class android.icu.lang.UCharacter.UnicodeBlock`
+
MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#CJK_UNIFIED_IDEOGRAPHS_EXTENSION_G:
- Missing nullability on field `CJK_UNIFIED_IDEOGRAPHS_EXTENSION_G` in class `class android.icu.lang.UCharacter.UnicodeBlock`
+
MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#DIVES_AKURU:
- Missing nullability on field `DIVES_AKURU` in class `class android.icu.lang.UCharacter.UnicodeBlock`
+
MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#EGYPTIAN_HIEROGLYPH_FORMAT_CONTROLS:
MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#ELYMAIC:
@@ -556,14 +594,39 @@
MissingNullability: android.icu.util.VersionInfo#UNICODE_12_1:
MissingNullability: android.icu.util.VersionInfo#UNICODE_13_0:
- Missing nullability on field `UNICODE_13_0` in class `class android.icu.util.VersionInfo`
+
MissingNullability: android.media.MediaMetadataRetriever#getFrameAtTime(long, int, android.media.MediaMetadataRetriever.BitmapParams):
MissingNullability: android.media.MediaMetadataRetriever#getScaledFrameAtTime(long, int, int, int, android.media.MediaMetadataRetriever.BitmapParams):
-
MissingNullability: java.time.chrono.JapaneseEra#REIWA:
- Missing nullability on field `REIWA` in class `class java.time.chrono.JapaneseEra`
+
+
+
+NotCloseable: android.media.MediaCodec.GraphicBlock:
+ Classes that release resources (finalize()) should implement AutoClosable and CloseGuard: class android.media.MediaCodec.GraphicBlock
+NotCloseable: android.media.MediaCodec.LinearBlock:
+ Classes that release resources (finalize()) should implement AutoClosable and CloseGuard: class android.media.MediaCodec.LinearBlock
+NotCloseable: android.media.MediaParser:
+ Classes that release resources (release()) should implement AutoClosable and CloseGuard: class android.media.MediaParser
+NotCloseable: android.media.MediaRouter2.RoutingController:
+ Classes that release resources (release()) should implement AutoClosable and CloseGuard: class android.media.MediaRouter2.RoutingController
+NotCloseable: android.util.CloseGuard:
+ Classes that release resources (close()) should implement AutoClosable and CloseGuard: class android.util.CloseGuard
+NotCloseable: android.view.SurfaceControlViewHost:
+ Classes that release resources (release()) should implement AutoClosable and CloseGuard: class android.view.SurfaceControlViewHost
+
+
+OnNameExpected: android.app.admin.DevicePolicyKeyguardService#dismiss():
+ If implemented by developer, should follow the on<Something> style; otherwise consider marking final
+OnNameExpected: android.service.controls.ControlsProviderService#createPublisherFor(java.util.List<java.lang.String>):
+ Methods implemented by developers should follow the on<Something> style, was `createPublisherFor`
+OnNameExpected: android.service.controls.ControlsProviderService#createPublisherForAllAvailable():
+ Methods implemented by developers should follow the on<Something> style, was `createPublisherForAllAvailable`
+OnNameExpected: android.service.controls.ControlsProviderService#createPublisherForSuggested():
+ If implemented by developer, should follow the on<Something> style; otherwise consider marking final
+OnNameExpected: android.service.controls.ControlsProviderService#performControlAction(String, android.service.controls.actions.ControlAction, java.util.function.Consumer<java.lang.Integer>):
+ Methods implemented by developers should follow the on<Something> style, was `performControlAction`
RequiresPermission: android.accounts.AccountManager#getAccountsByTypeAndFeatures(String, String[], android.accounts.AccountManagerCallback<android.accounts.Account[]>, android.os.Handler):
@@ -1189,11 +1252,13 @@
SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(String, long, float, java.util.concurrent.Executor, android.location.LocationListener):
SamShouldBeLast: android.location.LocationManager#requestLocationUpdates(long, float, android.location.Criteria, java.util.concurrent.Executor, android.location.LocationListener):
+
-
+StreamFiles: android.content.res.loader.DirectoryAssetsProvider#DirectoryAssetsProvider(java.io.File):
+ Methods accepting `File` should also accept `FileDescriptor` or streams: constructor android.content.res.loader.DirectoryAssetsProvider(java.io.File)
StreamFiles: android.content.res.loader.DirectoryResourceLoader#DirectoryResourceLoader(java.io.File):
- Methods accepting `File` should also accept `FileDescriptor` or streams: constructor android.content.res.loader.DirectoryResourceLoader(java.io.File)
+
Todo: android.hardware.camera2.params.StreamConfigurationMap:
diff --git a/api/removed.txt b/api/removed.txt
index 8537b21..077c915 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -1,4 +1,12 @@
// Signature format: 2.0
+package android {
+
+ public static final class R.attr {
+ field public static final int featureId = 16844301; // 0x101060d
+ }
+
+}
+
package android.app {
public class ActivityManager {
@@ -69,11 +77,17 @@
package android.content {
+ public abstract class ContentProvider implements android.content.ComponentCallbacks2 {
+ method @Deprecated @Nullable public final String getCallingFeatureId();
+ }
+
public abstract class ContentResolver {
method @Deprecated public void notifyChange(@NonNull Iterable<android.net.Uri>, @Nullable android.database.ContentObserver, int);
}
public abstract class Context {
+ method @Deprecated @NonNull public android.content.Context createFeatureContext(@Nullable String);
+ method @Deprecated @Nullable public String getFeatureId();
method public abstract android.content.SharedPreferences getSharedPreferences(java.io.File, int);
method public abstract java.io.File getSharedPreferencesPath(String);
}
diff --git a/api/system-current.txt b/api/system-current.txt
index 979d6e6..82a3ffa 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -79,6 +79,7 @@
field public static final String DEVICE_POWER = "android.permission.DEVICE_POWER";
field public static final String DISPATCH_PROVISIONING_MESSAGE = "android.permission.DISPATCH_PROVISIONING_MESSAGE";
field public static final String ENTER_CAR_MODE_PRIORITIZED = "android.permission.ENTER_CAR_MODE_PRIORITIZED";
+ field public static final String EXEMPT_FROM_AUDIO_RECORD_RESTRICTIONS = "android.permission.EXEMPT_FROM_AUDIO_RECORD_RESTRICTIONS";
field public static final String FORCE_BACK = "android.permission.FORCE_BACK";
field public static final String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES";
field public static final String GET_APP_OPS_STATS = "android.permission.GET_APP_OPS_STATS";
@@ -231,6 +232,7 @@
field public static final String UPDATE_APP_OPS_STATS = "android.permission.UPDATE_APP_OPS_STATS";
field public static final String UPDATE_LOCK = "android.permission.UPDATE_LOCK";
field public static final String UPDATE_TIME_ZONE_RULES = "android.permission.UPDATE_TIME_ZONE_RULES";
+ field public static final String UPGRADE_RUNTIME_PERMISSIONS = "android.permission.UPGRADE_RUNTIME_PERMISSIONS";
field public static final String USER_ACTIVITY = "android.permission.USER_ACTIVITY";
field public static final String USE_RESERVED_DISK = "android.permission.USE_RESERVED_DISK";
field public static final String WHITELIST_RESTRICTED_PERMISSIONS = "android.permission.WHITELIST_RESTRICTED_PERMISSIONS";
@@ -446,14 +448,37 @@
field public static final int UID_STATE_TOP = 200; // 0xc8
}
- public static final class AppOpsManager.HistoricalFeatureOps implements android.os.Parcelable {
+ public static final class AppOpsManager.AttributedHistoricalOps implements android.os.Parcelable {
method public int describeContents();
- method @Nullable public String getFeatureId();
method @Nullable public android.app.AppOpsManager.HistoricalOp getOp(@NonNull String);
method @NonNull public android.app.AppOpsManager.HistoricalOp getOpAt(@IntRange(from=0) int);
method @IntRange(from=0) public int getOpCount();
+ method @Nullable public String getTag();
method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalFeatureOps> CREATOR;
+ field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.AttributedHistoricalOps> CREATOR;
+ }
+
+ public static final class AppOpsManager.AttributedOpEntry implements android.os.Parcelable {
+ method public int describeContents();
+ method public long getLastAccessBackgroundTime(int);
+ method public long getLastAccessForegroundTime(int);
+ method public long getLastAccessTime(int);
+ method public long getLastAccessTime(int, int, int);
+ method public long getLastBackgroundDuration(int);
+ method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastBackgroundProxyInfo(int);
+ method public long getLastDuration(int);
+ method public long getLastDuration(int, int, int);
+ method public long getLastForegroundDuration(int);
+ method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastForegroundProxyInfo(int);
+ method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastProxyInfo(int);
+ method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastProxyInfo(int, int, int);
+ method public long getLastRejectBackgroundTime(int);
+ method public long getLastRejectForegroundTime(int);
+ method public long getLastRejectTime(int);
+ method public long getLastRejectTime(int, int, int);
+ method public boolean isRunning();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.AttributedOpEntry> CREATOR;
}
public static final class AppOpsManager.HistoricalOp implements android.os.Parcelable {
@@ -489,7 +514,7 @@
public static final class AppOpsManager.HistoricalOpsRequest.Builder {
ctor public AppOpsManager.HistoricalOpsRequest.Builder(long, long);
method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest build();
- method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setFeatureId(@Nullable String);
+ method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setAttributionTag(@Nullable String);
method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setFlags(int);
method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setOpNames(@Nullable java.util.List<java.lang.String>);
method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setPackageName(@Nullable String);
@@ -498,9 +523,9 @@
public static final class AppOpsManager.HistoricalPackageOps implements android.os.Parcelable {
method public int describeContents();
- method @IntRange(from=0) public int getFeatureCount();
- method @Nullable public android.app.AppOpsManager.HistoricalFeatureOps getFeatureOps(@NonNull String);
- method @NonNull public android.app.AppOpsManager.HistoricalFeatureOps getFeatureOpsAt(@IntRange(from=0) int);
+ method @Nullable public android.app.AppOpsManager.AttributedHistoricalOps getAttributedOps(@NonNull String);
+ method @NonNull public android.app.AppOpsManager.AttributedHistoricalOps getAttributedOpsAt(@IntRange(from=0) int);
+ method @IntRange(from=0) public int getAttributedOpsCount();
method @Nullable public android.app.AppOpsManager.HistoricalOp getOp(@NonNull String);
method @NonNull public android.app.AppOpsManager.HistoricalOp getOpAt(@IntRange(from=0) int);
method @IntRange(from=0) public int getOpCount();
@@ -521,8 +546,8 @@
public static final class AppOpsManager.OpEntry implements android.os.Parcelable {
method public int describeContents();
+ method @NonNull public java.util.Map<java.lang.String,android.app.AppOpsManager.AttributedOpEntry> getAttributedOpEntries();
method @Deprecated public long getDuration();
- method @NonNull public java.util.Map<java.lang.String,android.app.AppOpsManager.OpFeatureEntry> getFeatures();
method public long getLastAccessBackgroundTime(int);
method public long getLastAccessForegroundTime(int);
method public long getLastAccessTime(int);
@@ -552,36 +577,13 @@
public static final class AppOpsManager.OpEventProxyInfo implements android.os.Parcelable {
method public int describeContents();
- method @Nullable public String getFeatureId();
+ method @Nullable public String getAttributionTag();
method @Nullable public String getPackageName();
method @IntRange(from=0) public int getUid();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.OpEventProxyInfo> CREATOR;
}
- public static final class AppOpsManager.OpFeatureEntry implements android.os.Parcelable {
- method public int describeContents();
- method public long getLastAccessBackgroundTime(int);
- method public long getLastAccessForegroundTime(int);
- method public long getLastAccessTime(int);
- method public long getLastAccessTime(int, int, int);
- method public long getLastBackgroundDuration(int);
- method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastBackgroundProxyInfo(int);
- method public long getLastDuration(int);
- method public long getLastDuration(int, int, int);
- method public long getLastForegroundDuration(int);
- method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastForegroundProxyInfo(int);
- method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastProxyInfo(int);
- method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastProxyInfo(int, int, int);
- method public long getLastRejectBackgroundTime(int);
- method public long getLastRejectForegroundTime(int);
- method public long getLastRejectTime(int);
- method public long getLastRejectTime(int, int, int);
- method public boolean isRunning();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.OpFeatureEntry> CREATOR;
- }
-
public static final class AppOpsManager.PackageOps implements android.os.Parcelable {
method public int describeContents();
method @NonNull public java.util.List<android.app.AppOpsManager.OpEntry> getOps();
@@ -686,7 +688,7 @@
public final class RuntimeAppOpAccessMessage implements android.os.Parcelable {
ctor public RuntimeAppOpAccessMessage(@IntRange(from=0L) int, @IntRange(from=0L) int, @NonNull String, @Nullable String, @NonNull String, int);
method public int describeContents();
- method @Nullable public String getFeatureId();
+ method @Nullable public String getAttributionTag();
method @NonNull public String getMessage();
method @NonNull public String getOp();
method @NonNull public String getPackageName();
@@ -1369,7 +1371,6 @@
method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void addRoleHolderAsUser(@NonNull String, @NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public boolean addRoleHolderFromController(@NonNull String, @NonNull String);
method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void clearRoleHoldersAsUser(@NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
- method @Nullable public String getDefaultSmsPackage(int);
method @NonNull @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public java.util.List<java.lang.String> getHeldRolesFromController(@NonNull String);
method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public java.util.List<java.lang.String> getRoleHolders(@NonNull String);
method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public java.util.List<java.lang.String> getRoleHoldersAsUser(@NonNull String, @NonNull android.os.UserHandle);
@@ -2214,7 +2215,7 @@
field public static final String FEATURE_INCREMENTAL_DELIVERY = "android.software.incremental_delivery";
field public static final String FEATURE_REBOOT_ESCROW = "android.hardware.reboot_escrow";
field public static final String FEATURE_TELEPHONY_CARRIERLOCK = "android.hardware.telephony.carrierlock";
- field public static final int FLAGS_PERMISSION_RESERVED_PERMISSIONCONTROLLER = -268435456; // 0xf0000000
+ field public static final int FLAGS_PERMISSION_RESERVED_PERMISSION_CONTROLLER = -268435456; // 0xf0000000
field public static final int FLAG_PERMISSION_APPLY_RESTRICTION = 16384; // 0x4000
field public static final int FLAG_PERMISSION_AUTO_REVOKED = 131072; // 0x20000
field public static final int FLAG_PERMISSION_GRANTED_BY_DEFAULT = 32; // 0x20
@@ -2938,7 +2939,7 @@
public final class LightsManager.LightsSession implements java.lang.AutoCloseable {
method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_LIGHTS) public void close();
- method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_LIGHTS) public void setLights(@NonNull android.hardware.lights.LightsRequest);
+ method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_LIGHTS) public void requestLights(@NonNull android.hardware.lights.LightsRequest);
}
public final class LightsRequest {
@@ -5618,8 +5619,8 @@
method public int getConstellation();
method public int getGuardInterval();
method public int getHierarchy();
- method public int getHpCodeRate();
- method public int getLpCodeRate();
+ method public int getHighPriorityCodeRate();
+ method public int getLowPriorityCodeRate();
method public int getPlpGroupId();
method public int getPlpId();
method public int getPlpMode();
@@ -5647,20 +5648,20 @@
field public static final int CODERATE_8_9 = 512; // 0x200
field public static final int CODERATE_AUTO = 1; // 0x1
field public static final int CODERATE_UNDEFINED = 0; // 0x0
+ field public static final int CONSTELLATION_16QAM = 4; // 0x4
+ field public static final int CONSTELLATION_256QAM = 16; // 0x10
+ field public static final int CONSTELLATION_64QAM = 8; // 0x8
field public static final int CONSTELLATION_AUTO = 1; // 0x1
- field public static final int CONSTELLATION_CONSTELLATION_16QAM = 4; // 0x4
- field public static final int CONSTELLATION_CONSTELLATION_256QAM = 16; // 0x10
- field public static final int CONSTELLATION_CONSTELLATION_64QAM = 8; // 0x8
- field public static final int CONSTELLATION_CONSTELLATION_QPSK = 2; // 0x2
+ field public static final int CONSTELLATION_QPSK = 2; // 0x2
field public static final int CONSTELLATION_UNDEFINED = 0; // 0x0
+ field public static final int GUARD_INTERVAL_19_128 = 64; // 0x40
+ field public static final int GUARD_INTERVAL_19_256 = 128; // 0x80
+ field public static final int GUARD_INTERVAL_1_128 = 32; // 0x20
+ field public static final int GUARD_INTERVAL_1_16 = 4; // 0x4
+ field public static final int GUARD_INTERVAL_1_32 = 2; // 0x2
+ field public static final int GUARD_INTERVAL_1_4 = 16; // 0x10
+ field public static final int GUARD_INTERVAL_1_8 = 8; // 0x8
field public static final int GUARD_INTERVAL_AUTO = 1; // 0x1
- field public static final int GUARD_INTERVAL_INTERVAL_19_128 = 64; // 0x40
- field public static final int GUARD_INTERVAL_INTERVAL_19_256 = 128; // 0x80
- field public static final int GUARD_INTERVAL_INTERVAL_1_128 = 32; // 0x20
- field public static final int GUARD_INTERVAL_INTERVAL_1_16 = 4; // 0x4
- field public static final int GUARD_INTERVAL_INTERVAL_1_32 = 2; // 0x2
- field public static final int GUARD_INTERVAL_INTERVAL_1_4 = 16; // 0x10
- field public static final int GUARD_INTERVAL_INTERVAL_1_8 = 8; // 0x8
field public static final int GUARD_INTERVAL_UNDEFINED = 0; // 0x0
field public static final int HIERARCHY_1_INDEPTH = 64; // 0x40
field public static final int HIERARCHY_1_NATIVE = 4; // 0x4
@@ -5695,8 +5696,8 @@
method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setGuardInterval(int);
method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setHierarchy(int);
method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setHighPriority(boolean);
- method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setHpCodeRate(int);
- method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setLpCodeRate(int);
+ method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setHighPriorityCodeRate(int);
+ method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setLowPriorityCodeRate(int);
method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setMiso(boolean);
method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setPlpGroupId(int);
method @NonNull public android.media.tv.tuner.frontend.DvbtFrontendSettings.Builder setPlpId(int);
@@ -7156,7 +7157,7 @@
method @NonNull public java.util.List<android.net.MacAddress> getBlockedClientList();
method public int getChannel();
method public int getMaxNumberOfClients();
- method public int getShutdownTimeoutMillis();
+ method public long getShutdownTimeoutMillis();
method public boolean isAutoShutdownEnabled();
method public boolean isClientControlByUserEnabled();
method @Nullable public android.net.wifi.WifiConfiguration toWifiConfiguration();
@@ -7170,16 +7171,17 @@
ctor public SoftApConfiguration.Builder();
ctor public SoftApConfiguration.Builder(@NonNull android.net.wifi.SoftApConfiguration);
method @NonNull public android.net.wifi.SoftApConfiguration build();
- method @NonNull public android.net.wifi.SoftApConfiguration.Builder enableClientControlByUser(boolean);
+ method @NonNull public android.net.wifi.SoftApConfiguration.Builder setAllowedClientList(@NonNull java.util.List<android.net.MacAddress>);
method @NonNull public android.net.wifi.SoftApConfiguration.Builder setAutoShutdownEnabled(boolean);
method @NonNull public android.net.wifi.SoftApConfiguration.Builder setBand(int);
+ method @NonNull public android.net.wifi.SoftApConfiguration.Builder setBlockedClientList(@NonNull java.util.List<android.net.MacAddress>);
method @NonNull public android.net.wifi.SoftApConfiguration.Builder setBssid(@Nullable android.net.MacAddress);
method @NonNull public android.net.wifi.SoftApConfiguration.Builder setChannel(int, int);
- method @NonNull public android.net.wifi.SoftApConfiguration.Builder setClientList(@NonNull java.util.List<android.net.MacAddress>, @NonNull java.util.List<android.net.MacAddress>);
+ method @NonNull public android.net.wifi.SoftApConfiguration.Builder setClientControlByUserEnabled(boolean);
method @NonNull public android.net.wifi.SoftApConfiguration.Builder setHiddenSsid(boolean);
method @NonNull public android.net.wifi.SoftApConfiguration.Builder setMaxNumberOfClients(@IntRange(from=0) int);
method @NonNull public android.net.wifi.SoftApConfiguration.Builder setPassphrase(@Nullable String, int);
- method @NonNull public android.net.wifi.SoftApConfiguration.Builder setShutdownTimeoutMillis(@IntRange(from=0) int);
+ method @NonNull public android.net.wifi.SoftApConfiguration.Builder setShutdownTimeoutMillis(@IntRange(from=0) long);
method @NonNull public android.net.wifi.SoftApConfiguration.Builder setSsid(@Nullable String);
}
@@ -7240,7 +7242,6 @@
field @Deprecated public int numScorerOverride;
field @Deprecated public int numScorerOverrideAndSwitchedNetwork;
field @Deprecated public boolean requirePmf;
- field @Deprecated @Nullable public String saePasswordId;
field @Deprecated public boolean shared;
field @Deprecated public boolean useExternalScores;
}
@@ -7338,7 +7339,7 @@
method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.Map<android.net.wifi.hotspot2.OsuProvider,android.net.wifi.hotspot2.PasspointConfiguration> getMatchingPasspointConfigsForOsuProviders(@NonNull java.util.Set<android.net.wifi.hotspot2.OsuProvider>);
method @NonNull @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_WIFI_STATE}) public java.util.Map<android.net.wifi.WifiNetworkSuggestion,java.util.List<android.net.wifi.ScanResult>> getMatchingScanResults(@NonNull java.util.List<android.net.wifi.WifiNetworkSuggestion>, @Nullable java.util.List<android.net.wifi.ScanResult>);
method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_FINE_LOCATION, android.Manifest.permission.ACCESS_WIFI_STATE, android.Manifest.permission.READ_WIFI_CREDENTIAL}) public java.util.List<android.net.wifi.WifiConfiguration> getPrivilegedConfiguredNetworks();
- method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public android.net.wifi.SoftApConfiguration getSoftApConfiguration();
+ method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public android.net.wifi.SoftApConfiguration getSoftApConfiguration();
method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public void getWifiActivityEnergyInfoAsync(@NonNull java.util.concurrent.Executor, @NonNull android.net.wifi.WifiManager.OnWifiActivityEnergyInfoListener);
method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public android.net.wifi.WifiConfiguration getWifiApConfiguration();
method @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE) public int getWifiApState();
@@ -8223,13 +8224,15 @@
field public static final String ACTION_UPDATE_CARRIER_PROVISIONING_URLS = "android.intent.action.UPDATE_CARRIER_PROVISIONING_URLS";
field public static final String ACTION_UPDATE_CONVERSATION_ACTIONS = "android.intent.action.UPDATE_CONVERSATION_ACTIONS";
field public static final String ACTION_UPDATE_CT_LOGS = "android.intent.action.UPDATE_CT_LOGS";
- field public static final String ACTION_UPDATE_EMERGENCY_NUMBER_DB = "android.os.action.UPDATE_EMERGENCY_NUMBER_DB";
+ field @RequiresPermission("android.permission.UPDATE_CONFIG") public static final String ACTION_UPDATE_EMERGENCY_NUMBER_DB = "android.os.action.UPDATE_EMERGENCY_NUMBER_DB";
field public static final String ACTION_UPDATE_INTENT_FIREWALL = "android.intent.action.UPDATE_INTENT_FIREWALL";
field public static final String ACTION_UPDATE_LANG_ID = "android.intent.action.UPDATE_LANG_ID";
field public static final String ACTION_UPDATE_NETWORK_WATCHLIST = "android.intent.action.UPDATE_NETWORK_WATCHLIST";
field public static final String ACTION_UPDATE_PINS = "android.intent.action.UPDATE_PINS";
field public static final String ACTION_UPDATE_SMART_SELECTION = "android.intent.action.UPDATE_SMART_SELECTION";
field public static final String ACTION_UPDATE_SMS_SHORT_CODES = "android.intent.action.UPDATE_SMS_SHORT_CODES";
+ field public static final String EXTRA_REQUIRED_HASH = "android.os.extra.REQUIRED_HASH";
+ field public static final String EXTRA_VERSION = "android.os.extra.VERSION";
}
public class Environment {
@@ -8939,12 +8942,12 @@
method @BinderThread public abstract void onRevokeRuntimePermissions(@NonNull java.util.Map<java.lang.String,java.util.List<java.lang.String>>, boolean, int, @NonNull String, @NonNull java.util.function.Consumer<java.util.Map<java.lang.String,java.util.List<java.lang.String>>>);
method @BinderThread public abstract void onSetRuntimePermissionGrantStateByDeviceAdmin(@NonNull String, @NonNull String, @NonNull String, int, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @BinderThread public void onStageAndApplyRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.InputStream, @NonNull Runnable);
- method @BinderThread public void onUpdateUserSensitivePermissionFlags();
+ method @BinderThread public void onUpdateUserSensitivePermissionFlags(int, @NonNull Runnable);
field public static final String SERVICE_INTERFACE = "android.permission.PermissionControllerService";
}
public final class PermissionManager {
- method @IntRange(from=0) @RequiresPermission(anyOf={android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, "android.permission.UPGRADE_RUNTIME_PERMISSIONS"}) public int getRuntimePermissionsVersion();
+ method @IntRange(from=0) @RequiresPermission(anyOf={android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, android.Manifest.permission.UPGRADE_RUNTIME_PERMISSIONS}) public int getRuntimePermissionsVersion();
method @NonNull public java.util.List<android.permission.PermissionManager.SplitPermissionInfo> getSplitPermissions();
method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) public void grantDefaultPermissionsToEnabledCarrierApps(@NonNull String[], @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) public void grantDefaultPermissionsToEnabledImsServices(@NonNull String[], @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
@@ -8952,7 +8955,7 @@
method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) public void grantDefaultPermissionsToLuiApp(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) public void revokeDefaultPermissionsFromDisabledTelephonyDataServices(@NonNull String[], @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS_TO_TELEPHONY_DEFAULTS) public void revokeDefaultPermissionsFromLuiApps(@NonNull String[], @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
- method @RequiresPermission(anyOf={android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, "android.permission.UPGRADE_RUNTIME_PERMISSIONS"}) public void setRuntimePermissionsVersion(@IntRange(from=0) int);
+ method @RequiresPermission(anyOf={android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, android.Manifest.permission.UPGRADE_RUNTIME_PERMISSIONS}) public void setRuntimePermissionsVersion(@IntRange(from=0) int);
method @RequiresPermission(android.Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS) public void startOneTimePermissionSession(@NonNull String, long, int, int);
method @RequiresPermission(android.Manifest.permission.MANAGE_ONE_TIME_PERMISSION_SESSIONS) public void stopOneTimePermissionSession(@NonNull String);
}
@@ -9066,18 +9069,6 @@
package android.provider {
- public class BlockedNumberContract {
- field public static final String METHOD_NOTIFY_EMERGENCY_CONTACT = "notify_emergency_contact";
- field public static final String METHOD_SHOULD_SYSTEM_BLOCK_NUMBER = "should_system_block_number";
- field public static final String RES_BLOCK_STATUS = "block_status";
- field public static final int STATUS_BLOCKED_IN_LIST = 1; // 0x1
- field public static final int STATUS_BLOCKED_NOT_IN_CONTACTS = 5; // 0x5
- field public static final int STATUS_BLOCKED_PAYPHONE = 4; // 0x4
- field public static final int STATUS_BLOCKED_RESTRICTED = 2; // 0x2
- field public static final int STATUS_BLOCKED_UNKNOWN_NUMBER = 3; // 0x3
- field public static final int STATUS_NOT_BLOCKED = 0; // 0x0
- }
-
@Deprecated public static final class ContactsContract.MetadataSync implements android.provider.BaseColumns android.provider.ContactsContract.MetadataSyncColumns {
field @Deprecated public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact_metadata";
field @Deprecated public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contact_metadata";
@@ -9389,7 +9380,6 @@
field public static final String LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS = "lock_screen_allow_private_notifications";
field public static final String LOCK_SCREEN_SHOW_NOTIFICATIONS = "lock_screen_show_notifications";
field public static final String ODI_CAPTIONS_ENABLED = "odi_captions_enabled";
- field public static final String SECURE_FRP_MODE = "secure_frp_mode";
field public static final String THEME_CUSTOMIZATION_OVERLAY_PACKAGES = "theme_customization_overlay_packages";
field public static final String USER_SETUP_COMPLETE = "user_setup_complete";
field public static final int USER_SETUP_PERSONALIZATION_COMPLETE = 10; // 0xa
@@ -9435,20 +9425,12 @@
public static final class Telephony.Carriers implements android.provider.BaseColumns {
field public static final String APN_SET_ID = "apn_set_id";
- field @Deprecated public static final String BEARER_BITMASK = "bearer_bitmask";
field public static final int CARRIER_EDITED = 4; // 0x4
- field @NonNull public static final android.net.Uri DPC_URI;
field public static final String EDITED_STATUS = "edited";
- field public static final int INVALID_APN_ID = -1; // 0xffffffff
field public static final String MAX_CONNECTIONS = "max_conns";
field public static final String MODEM_PERSIST = "modem_cognitive";
field public static final String MTU = "mtu";
field public static final int NO_APN_SET_ID = 0; // 0x0
- field public static final String PROFILE_ID = "profile_id";
- field public static final String SKIP_464XLAT = "skip_464xlat";
- field public static final int SKIP_464XLAT_DEFAULT = -1; // 0xffffffff
- field public static final int SKIP_464XLAT_DISABLE = 0; // 0x0
- field public static final int SKIP_464XLAT_ENABLE = 1; // 0x1
field public static final String TIME_LIMIT_FOR_MAX_CONNECTIONS = "max_conns_time";
field public static final int UNEDITED = 0; // 0x0
field public static final int USER_DELETED = 2; // 0x2
@@ -9813,7 +9795,7 @@
public static final class Dataset.Builder {
ctor public Dataset.Builder(@NonNull android.service.autofill.InlinePresentation);
- method @NonNull public android.service.autofill.Dataset.Builder setInlinePresentation(@NonNull android.view.autofill.AutofillId, @Nullable android.view.autofill.AutofillValue, @Nullable java.util.regex.Pattern, @NonNull android.service.autofill.InlinePresentation);
+ method @NonNull public android.service.autofill.Dataset.Builder setFieldInlinePresentation(@NonNull android.view.autofill.AutofillId, @Nullable android.view.autofill.AutofillValue, @Nullable java.util.regex.Pattern, @NonNull android.service.autofill.InlinePresentation);
}
public abstract class InlineSuggestionRenderService extends android.app.Service {
@@ -9974,7 +9956,7 @@
}
public static final class DataLoaderService.FileSystemConnector {
- method public void writeData(@NonNull String, long, long, @NonNull android.os.ParcelFileDescriptor) throws java.io.IOException;
+ method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void writeData(@NonNull String, long, long, @NonNull android.os.ParcelFileDescriptor) throws java.io.IOException;
}
}
@@ -10652,14 +10634,7 @@
}
public final class PhoneAccount implements android.os.Parcelable {
- field public static final int CAPABILITY_EMERGENCY_CALLS_ONLY = 128; // 0x80
- field public static final int CAPABILITY_EMERGENCY_PREFERRED = 8192; // 0x2000
- field public static final int CAPABILITY_EMERGENCY_VIDEO_CALLING = 512; // 0x200
field public static final int CAPABILITY_MULTI_USER = 32; // 0x20
- field public static final String EXTRA_ALWAYS_USE_VOIP_AUDIO_MODE = "android.telecom.extra.ALWAYS_USE_VOIP_AUDIO_MODE";
- field public static final String EXTRA_PLAY_CALL_RECORDING_TONE = "android.telecom.extra.PLAY_CALL_RECORDING_TONE";
- field public static final String EXTRA_SORT_ORDER = "android.telecom.extra.SORT_ORDER";
- field public static final String EXTRA_SUPPORTS_VIDEO_CALLING_FALLBACK = "android.telecom.extra.SUPPORTS_VIDEO_CALLING_FALLBACK";
}
public static class PhoneAccount.Builder {
@@ -10745,20 +10720,13 @@
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean isInEmergencyCall();
method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRinging();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUserSelectedOutgoingPhoneAccount(@Nullable android.telecom.PhoneAccountHandle);
- field public static final String ACTION_CURRENT_TTY_MODE_CHANGED = "android.telecom.action.CURRENT_TTY_MODE_CHANGED";
- field public static final String ACTION_TTY_PREFERRED_MODE_CHANGED = "android.telecom.action.TTY_PREFERRED_MODE_CHANGED";
field public static final int CALL_SOURCE_EMERGENCY_DIALPAD = 1; // 0x1
field public static final int CALL_SOURCE_EMERGENCY_SHORTCUT = 2; // 0x2
field public static final int CALL_SOURCE_UNSPECIFIED = 0; // 0x0
field public static final String EXTRA_CALL_BACK_INTENT = "android.telecom.extra.CALL_BACK_INTENT";
- field public static final String EXTRA_CALL_SOURCE = "android.telecom.extra.CALL_SOURCE";
- field public static final String EXTRA_CALL_TECHNOLOGY_TYPE = "android.telecom.extra.CALL_TECHNOLOGY_TYPE";
field public static final String EXTRA_CLEAR_MISSED_CALLS_INTENT = "android.telecom.extra.CLEAR_MISSED_CALLS_INTENT";
field public static final String EXTRA_CONNECTION_SERVICE = "android.telecom.extra.CONNECTION_SERVICE";
- field public static final String EXTRA_CURRENT_TTY_MODE = "android.telecom.extra.CURRENT_TTY_MODE";
field public static final String EXTRA_IS_USER_INTENT_EMERGENCY_CALL = "android.telecom.extra.IS_USER_INTENT_EMERGENCY_CALL";
- field public static final String EXTRA_TTY_PREFERRED_MODE = "android.telecom.extra.TTY_PREFERRED_MODE";
- field public static final String EXTRA_UNKNOWN_CALL_HANDLE = "android.telecom.extra.UNKNOWN_CALL_HANDLE";
field public static final int TTY_MODE_FULL = 1; // 0x1
field public static final int TTY_MODE_HCO = 2; // 0x2
field public static final int TTY_MODE_OFF = 0; // 0x0
@@ -11206,19 +11174,6 @@
field @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public static final int LISTEN_VOICE_ACTIVATION_STATE = 131072; // 0x20000
}
- public final class PinResult implements android.os.Parcelable {
- ctor public PinResult(int, int);
- method public int describeContents();
- method public int getAttemptsRemaining();
- method @NonNull public static android.telephony.PinResult getDefaultFailedResult();
- method public int getType();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.PinResult> CREATOR;
- field public static final int PIN_RESULT_TYPE_FAILURE = 2; // 0x2
- field public static final int PIN_RESULT_TYPE_INCORRECT = 1; // 0x1
- field public static final int PIN_RESULT_TYPE_SUCCESS = 0; // 0x0
- }
-
public final class PreciseCallState implements android.os.Parcelable {
ctor public PreciseCallState(int, int, int, int, int);
method public int describeContents();
@@ -11349,7 +11304,6 @@
public class ServiceState implements android.os.Parcelable {
method public void fillInNotifierBundle(@NonNull android.os.Bundle);
method public int getDataNetworkType();
- method public int getDataRegistrationState();
method @Nullable public android.telephony.NetworkRegistrationInfo getNetworkRegistrationInfo(int, int);
method @NonNull public java.util.List<android.telephony.NetworkRegistrationInfo> getNetworkRegistrationInfoListForDomain(int);
method @NonNull public java.util.List<android.telephony.NetworkRegistrationInfo> getNetworkRegistrationInfoListForTransportType(int);
@@ -11583,7 +11537,6 @@
}
public class TelephonyManager {
- method public int addDevicePolicyOverrideApn(@NonNull android.content.Context, @NonNull android.telephony.data.ApnSetting);
method @Deprecated @RequiresPermission(android.Manifest.permission.CALL_PHONE) public void call(String, String);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int changeIccLockPassword(@NonNull String, @NonNull String);
method public int checkCarrierPrivilegesForPackage(String);
@@ -11616,11 +11569,9 @@
method @Deprecated public boolean getDataEnabled();
method @Deprecated public boolean getDataEnabled(int);
method @Nullable public static android.content.ComponentName getDefaultRespondViaMessageApplication(@NonNull android.content.Context, boolean);
- method @NonNull public static String getDefaultSimCountryIso();
- method @NonNull public java.util.List<android.telephony.data.ApnSetting> getDevicePolicyOverrideApns(@NonNull android.content.Context);
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getDeviceSoftwareVersion(int);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean getEmergencyCallbackMode();
- method public int getEmergencyNumberDbVersion();
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getEmergencyNumberDbVersion();
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimDomain();
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String[] getIsimImpu();
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimIst();
@@ -11650,7 +11601,7 @@
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isApnMetered(int);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isApplicationOnUicc(int);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isDataAllowedInVoiceCall();
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isDataConnectionEnabled();
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isDataConnectionAllowed();
method public boolean isDataConnectivityPossible();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isDataEnabledForApn(int);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isEmergencyAssistanceEnabled();
@@ -11658,7 +11609,6 @@
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isIdle();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isInEmergencySmsMode();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isLteCdmaEvdoGsmWcdmaEnabled();
- method public boolean isModemEnabledForSlot(int);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isOffhook();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isOpportunisticNetworkEnabled();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isPotentialEmergencyNumber(@NonNull String);
@@ -11668,7 +11618,6 @@
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isVideoCallingEnabled();
method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isVisualVoicemailEnabled(android.telecom.PhoneAccountHandle);
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean matchesCurrentSimOperator(@NonNull String, int, @Nullable String);
- method public boolean modifyDevicePolicyOverrideApn(@NonNull android.content.Context, int, @NonNull android.telephony.data.ApnSetting);
method public boolean needsOtaServiceProvisioning();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyOtaEmergencyNumberDbInstalled();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyUserActivity();
@@ -11711,10 +11660,8 @@
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoiceActivationState(int);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void shutdownAllRadios();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean supplyPin(String);
- method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telephony.PinResult supplyPinReportPinResult(@NonNull String);
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int[] supplyPinReportResult(String);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean supplyPuk(String, String);
- method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.telephony.PinResult supplyPukReportPinResult(@NonNull String, @NonNull String);
method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int[] supplyPukReportResult(String, String);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean switchSlots(int[]);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void toggleRadioOnOff();
@@ -11807,7 +11754,6 @@
field public static final long NETWORK_TYPE_BITMASK_TD_SCDMA = 65536L; // 0x10000L
field public static final long NETWORK_TYPE_BITMASK_UMTS = 4L; // 0x4L
field public static final long NETWORK_TYPE_BITMASK_UNKNOWN = 0L; // 0x0L
- field public static final int PHONE_TYPE_THIRD_PARTY = 4; // 0x4
field public static final int RADIO_POWER_OFF = 0; // 0x0
field public static final int RADIO_POWER_ON = 1; // 0x1
field public static final int RADIO_POWER_UNAVAILABLE = 2; // 0x2
@@ -11887,23 +11833,6 @@
package android.telephony.data {
- public class ApnSetting implements android.os.Parcelable {
- method @NonNull public static String getApnTypesStringFromBitmask(int);
- field public static final String TYPE_ALL_STRING = "*";
- field public static final String TYPE_CBS_STRING = "cbs";
- field public static final String TYPE_DEFAULT_STRING = "default";
- field public static final String TYPE_DUN_STRING = "dun";
- field public static final String TYPE_EMERGENCY_STRING = "emergency";
- field public static final String TYPE_FOTA_STRING = "fota";
- field public static final String TYPE_HIPRI_STRING = "hipri";
- field public static final String TYPE_IA_STRING = "ia";
- field public static final String TYPE_IMS_STRING = "ims";
- field public static final String TYPE_MCX_STRING = "mcx";
- field public static final String TYPE_MMS_STRING = "mms";
- field public static final String TYPE_SUPL_STRING = "supl";
- field public static final String TYPE_XCAP_STRING = "xcap";
- }
-
public final class DataCallResponse implements android.os.Parcelable {
method public int describeContents();
method @NonNull public java.util.List<android.net.LinkAddress> getAddresses();
diff --git a/api/test-current.txt b/api/test-current.txt
index 9d284b5..6353edc 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -21,6 +21,7 @@
field public static final String REMOVE_TASKS = "android.permission.REMOVE_TASKS";
field public static final String SUSPEND_APPS = "android.permission.SUSPEND_APPS";
field public static final String TEST_MANAGE_ROLLBACKS = "android.permission.TEST_MANAGE_ROLLBACKS";
+ field public static final String UPGRADE_RUNTIME_PERMISSIONS = "android.permission.UPGRADE_RUNTIME_PERMISSIONS";
field public static final String WRITE_DEVICE_CONFIG = "android.permission.WRITE_DEVICE_CONFIG";
field @Deprecated public static final String WRITE_MEDIA_STORAGE = "android.permission.WRITE_MEDIA_STORAGE";
field public static final String WRITE_OBB = "android.permission.WRITE_OBB";
@@ -82,6 +83,7 @@
method public static void resumeAppSwitches() throws android.os.RemoteException;
method @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public void scheduleApplicationInfoChanged(java.util.List<java.lang.String>, int);
method @RequiresPermission("android.permission.MANAGE_USERS") public boolean switchUser(@NonNull android.os.UserHandle);
+ method @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public boolean updateMccMncConfiguration(@NonNull String, @NonNull String);
field public static final int PROCESS_CAPABILITY_ALL = 7; // 0x7
field public static final int PROCESS_CAPABILITY_ALL_EXPLICIT = 1; // 0x1
field public static final int PROCESS_CAPABILITY_ALL_IMPLICIT = 6; // 0x6
@@ -262,14 +264,37 @@
field public static final int UID_STATE_TOP = 200; // 0xc8
}
- public static final class AppOpsManager.HistoricalFeatureOps implements android.os.Parcelable {
+ public static final class AppOpsManager.AttributedHistoricalOps implements android.os.Parcelable {
method public int describeContents();
- method @Nullable public String getFeatureId();
method @Nullable public android.app.AppOpsManager.HistoricalOp getOp(@NonNull String);
method @NonNull public android.app.AppOpsManager.HistoricalOp getOpAt(@IntRange(from=0) int);
method @IntRange(from=0) public int getOpCount();
+ method @Nullable public String getTag();
method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.HistoricalFeatureOps> CREATOR;
+ field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.AttributedHistoricalOps> CREATOR;
+ }
+
+ public static final class AppOpsManager.AttributedOpEntry implements android.os.Parcelable {
+ method public int describeContents();
+ method public long getLastAccessBackgroundTime(int);
+ method public long getLastAccessForegroundTime(int);
+ method public long getLastAccessTime(int);
+ method public long getLastAccessTime(int, int, int);
+ method public long getLastBackgroundDuration(int);
+ method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastBackgroundProxyInfo(int);
+ method public long getLastDuration(int);
+ method public long getLastDuration(int, int, int);
+ method public long getLastForegroundDuration(int);
+ method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastForegroundProxyInfo(int);
+ method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastProxyInfo(int);
+ method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastProxyInfo(int, int, int);
+ method public long getLastRejectBackgroundTime(int);
+ method public long getLastRejectForegroundTime(int);
+ method public long getLastRejectTime(int);
+ method public long getLastRejectTime(int, int, int);
+ method public boolean isRunning();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.AttributedOpEntry> CREATOR;
}
public static final class AppOpsManager.HistoricalOp implements android.os.Parcelable {
@@ -310,7 +335,7 @@
public static final class AppOpsManager.HistoricalOpsRequest.Builder {
ctor public AppOpsManager.HistoricalOpsRequest.Builder(long, long);
method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest build();
- method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setFeatureId(@Nullable String);
+ method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setAttributionTag(@Nullable String);
method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setFlags(int);
method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setOpNames(@Nullable java.util.List<java.lang.String>);
method @NonNull public android.app.AppOpsManager.HistoricalOpsRequest.Builder setPackageName(@Nullable String);
@@ -319,9 +344,9 @@
public static final class AppOpsManager.HistoricalPackageOps implements android.os.Parcelable {
method public int describeContents();
- method @IntRange(from=0) public int getFeatureCount();
- method @Nullable public android.app.AppOpsManager.HistoricalFeatureOps getFeatureOps(@NonNull String);
- method @NonNull public android.app.AppOpsManager.HistoricalFeatureOps getFeatureOpsAt(@IntRange(from=0) int);
+ method @Nullable public android.app.AppOpsManager.AttributedHistoricalOps getAttributedOps(@NonNull String);
+ method @NonNull public android.app.AppOpsManager.AttributedHistoricalOps getAttributedOpsAt(@IntRange(from=0) int);
+ method @IntRange(from=0) public int getAttributedOpsCount();
method @Nullable public android.app.AppOpsManager.HistoricalOp getOp(@NonNull String);
method @NonNull public android.app.AppOpsManager.HistoricalOp getOpAt(@IntRange(from=0) int);
method @IntRange(from=0) public int getOpCount();
@@ -342,8 +367,8 @@
public static final class AppOpsManager.OpEntry implements android.os.Parcelable {
method public int describeContents();
+ method @NonNull public java.util.Map<java.lang.String,android.app.AppOpsManager.AttributedOpEntry> getAttributedOpEntries();
method @Deprecated public long getDuration();
- method @NonNull public java.util.Map<java.lang.String,android.app.AppOpsManager.OpFeatureEntry> getFeatures();
method public long getLastAccessBackgroundTime(int);
method public long getLastAccessForegroundTime(int);
method public long getLastAccessTime(int);
@@ -373,36 +398,13 @@
public static final class AppOpsManager.OpEventProxyInfo implements android.os.Parcelable {
method public int describeContents();
- method @Nullable public String getFeatureId();
+ method @Nullable public String getAttributionTag();
method @Nullable public String getPackageName();
method @IntRange(from=0) public int getUid();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.OpEventProxyInfo> CREATOR;
}
- public static final class AppOpsManager.OpFeatureEntry implements android.os.Parcelable {
- method public int describeContents();
- method public long getLastAccessBackgroundTime(int);
- method public long getLastAccessForegroundTime(int);
- method public long getLastAccessTime(int);
- method public long getLastAccessTime(int, int, int);
- method public long getLastBackgroundDuration(int);
- method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastBackgroundProxyInfo(int);
- method public long getLastDuration(int);
- method public long getLastDuration(int, int, int);
- method public long getLastForegroundDuration(int);
- method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastForegroundProxyInfo(int);
- method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastProxyInfo(int);
- method @Nullable public android.app.AppOpsManager.OpEventProxyInfo getLastProxyInfo(int, int, int);
- method public long getLastRejectBackgroundTime(int);
- method public long getLastRejectForegroundTime(int);
- method public long getLastRejectTime(int);
- method public long getLastRejectTime(int, int, int);
- method public boolean isRunning();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.OpFeatureEntry> CREATOR;
- }
-
public static final class AppOpsManager.PackageOps implements android.os.Parcelable {
method public int describeContents();
method @NonNull public java.util.List<android.app.AppOpsManager.OpEntry> getOps();
@@ -427,6 +429,7 @@
method public boolean isBlockableSystem();
method public boolean isImportanceLockedByCriticalDeviceFunction();
method public boolean isImportanceLockedByOEM();
+ method public void lockFields(int);
method public void setBlockableSystem(boolean);
method public void setDeleted(boolean);
method public void setFgServiceShown(boolean);
@@ -434,6 +437,7 @@
method public void setImportanceLockedByOEM(boolean);
method public void setImportantConversation(boolean);
method public void setOriginalImportance(int);
+ field public static final int USER_LOCKED_SOUND = 32; // 0x20
}
public final class NotificationChannelGroup implements android.os.Parcelable {
@@ -462,7 +466,7 @@
public final class RuntimeAppOpAccessMessage implements android.os.Parcelable {
ctor public RuntimeAppOpAccessMessage(@IntRange(from=0L) int, @IntRange(from=0L) int, @NonNull String, @Nullable String, @NonNull String, int);
method public int describeContents();
- method @Nullable public String getFeatureId();
+ method @Nullable public String getAttributionTag();
method @NonNull public String getMessage();
method @NonNull public String getOp();
method @NonNull public String getPackageName();
@@ -1278,7 +1282,7 @@
public final class LightsManager.LightsSession implements java.lang.AutoCloseable {
method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_LIGHTS) public void close();
- method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_LIGHTS) public void setLights(@NonNull android.hardware.lights.LightsRequest);
+ method @RequiresPermission(android.Manifest.permission.CONTROL_DEVICE_LIGHTS) public void requestLights(@NonNull android.hardware.lights.LightsRequest);
}
public final class LightsRequest {
@@ -2811,9 +2815,9 @@
}
public final class PermissionManager {
- method @IntRange(from=0) @RequiresPermission(anyOf={"android.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY", "android.permission.UPGRADE_RUNTIME_PERMISSIONS"}) public int getRuntimePermissionsVersion();
+ method @IntRange(from=0) @RequiresPermission(anyOf={"android.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY", android.Manifest.permission.UPGRADE_RUNTIME_PERMISSIONS}) public int getRuntimePermissionsVersion();
method @NonNull public java.util.List<android.permission.PermissionManager.SplitPermissionInfo> getSplitPermissions();
- method @RequiresPermission(anyOf={"android.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY", "android.permission.UPGRADE_RUNTIME_PERMISSIONS"}) public void setRuntimePermissionsVersion(@IntRange(from=0) int);
+ method @RequiresPermission(anyOf={"android.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY", android.Manifest.permission.UPGRADE_RUNTIME_PERMISSIONS}) public void setRuntimePermissionsVersion(@IntRange(from=0) int);
}
public static final class PermissionManager.SplitPermissionInfo {
@@ -3131,7 +3135,7 @@
public static final class Dataset.Builder {
ctor public Dataset.Builder(@NonNull android.service.autofill.InlinePresentation);
- method @NonNull public android.service.autofill.Dataset.Builder setInlinePresentation(@NonNull android.view.autofill.AutofillId, @Nullable android.view.autofill.AutofillValue, @Nullable java.util.regex.Pattern, @NonNull android.service.autofill.InlinePresentation);
+ method @NonNull public android.service.autofill.Dataset.Builder setFieldInlinePresentation(@NonNull android.view.autofill.AutofillId, @Nullable android.view.autofill.AutofillValue, @Nullable java.util.regex.Pattern, @NonNull android.service.autofill.InlinePresentation);
}
public final class DateTransformation extends android.service.autofill.InternalTransformation implements android.os.Parcelable android.service.autofill.Transformation {
@@ -3742,7 +3746,7 @@
method public java.util.List<java.lang.String> getCarrierPackageNamesForIntent(android.content.Intent);
method @Nullable public static android.content.ComponentName getDefaultRespondViaMessageApplication(@NonNull android.content.Context, boolean);
method @NonNull public java.util.List<android.telephony.data.ApnSetting> getDevicePolicyOverrideApns(@NonNull android.content.Context);
- method public int getEmergencyNumberDbVersion();
+ method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public int getEmergencyNumberDbVersion();
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getLine1AlphaTag();
method public android.util.Pair<java.lang.Integer,java.lang.Integer> getRadioHalVersion();
method public boolean modifyDevicePolicyOverrideApn(@NonNull android.content.Context, int, @NonNull android.telephony.data.ApnSetting);
@@ -4967,7 +4971,7 @@
method public void resetRtlProperties();
method public boolean restoreFocusInCluster(int);
method public boolean restoreFocusNotInCluster();
- method public void setAutofilled(boolean);
+ method public void setAutofilled(boolean, boolean);
method public final void setFocusedInCluster();
method public void setIsRootNamespace(boolean);
method public final void setShowingLayoutBounds(boolean);
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp
index f84e4b5..8f5e49d 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.cpp
+++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp
@@ -113,7 +113,7 @@
Status Idmap2Service::createIdmap(const std::string& target_apk_path,
const std::string& overlay_apk_path, int32_t fulfilled_policies,
bool enforce_overlayable, int32_t user_id ATTRIBUTE_UNUSED,
- std::unique_ptr<std::string>* _aidl_return) {
+ aidl::nullable<std::string>* _aidl_return) {
assert(_aidl_return);
SYSTRACE << "Idmap2Service::createIdmap " << target_apk_path << " " << overlay_apk_path;
_aidl_return->reset(nullptr);
@@ -155,7 +155,7 @@
return error("failed to write to idmap path " + idmap_path);
}
- *_aidl_return = std::make_unique<std::string>(idmap_path);
+ *_aidl_return = aidl::make_nullable<std::string>(idmap_path);
return ok();
}
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.h b/cmds/idmap2/idmap2d/Idmap2Service.h
index 94d2af4..b6f5136 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.h
+++ b/cmds/idmap2/idmap2d/Idmap2Service.h
@@ -19,9 +19,7 @@
#include <android-base/unique_fd.h>
#include <binder/BinderService.h>
-
-#include <memory>
-#include <string>
+#include <binder/Nullable.h>
#include "android/os/BnIdmap2.h"
@@ -46,7 +44,7 @@
binder::Status createIdmap(const std::string& target_apk_path,
const std::string& overlay_apk_path, int32_t fulfilled_policies,
bool enforce_overlayable, int32_t user_id,
- std::unique_ptr<std::string>* _aidl_return) override;
+ aidl::nullable<std::string>* _aidl_return) override;
};
} // namespace android::os
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index bd6ca47..33bfe51 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -113,8 +113,8 @@
"libbase",
"libcutils",
"libprotoutil",
- "libstatslog",
"libstatsmetadata",
+ "libstatslog_statsd",
"libsysutils",
"libutils",
],
@@ -171,6 +171,37 @@
],
}
+genrule {
+ name: "statslog_statsd.h",
+ tools: ["stats-log-api-gen"],
+ cmd: "$(location stats-log-api-gen) --header $(genDir)/statslog_statsd.h --module statsd --namespace android,os,statsd,util",
+ out: [
+ "statslog_statsd.h",
+ ],
+}
+
+genrule {
+ name: "statslog_statsd.cpp",
+ tools: ["stats-log-api-gen"],
+ cmd: "$(location stats-log-api-gen) --cpp $(genDir)/statslog_statsd.cpp --module statsd --namespace android,os,statsd,util --importHeader statslog_statsd.h",
+ out: [
+ "statslog_statsd.cpp",
+ ],
+}
+
+cc_library_static {
+ name: "libstatslog_statsd",
+ generated_sources: ["statslog_statsd.cpp"],
+ generated_headers: ["statslog_statsd.h"],
+ export_generated_headers: ["statslog_statsd.h"],
+ apex_available: [
+ "com.android.os.statsd",
+ "test_com.android.os.statsd",
+ ],
+ shared_libs: [
+ "libstatssocket",
+ ]
+}
// =========
// statsd
@@ -300,6 +331,7 @@
static_libs: [
"libgmock",
"libplatformprotos",
+ "libstatslog", //TODO(b/150976524): remove this when the tests no longer hardcode atoms.
"libstatssocket_private",
],
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 649c004..69b9fc7 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -34,7 +34,7 @@
#include "state/StateManager.h"
#include "stats_log_util.h"
#include "stats_util.h"
-#include "statslog.h"
+#include "statslog_statsd.h"
#include "storage/StorageManager.h"
using namespace android;
@@ -287,17 +287,17 @@
int64_t firstId = trainInfo->experimentIds.at(0);
auto& ids = trainInfo->experimentIds;
switch (trainInfo->status) {
- case android::util::BINARY_PUSH_STATE_CHANGED__STATE__INSTALL_SUCCESS:
+ case android::os::statsd::util::BINARY_PUSH_STATE_CHANGED__STATE__INSTALL_SUCCESS:
if (find(ids.begin(), ids.end(), firstId + 1) == ids.end()) {
ids.push_back(firstId + 1);
}
break;
- case android::util::BINARY_PUSH_STATE_CHANGED__STATE__INSTALLER_ROLLBACK_INITIATED:
+ case android::os::statsd::util::BINARY_PUSH_STATE_CHANGED__STATE__INSTALLER_ROLLBACK_INITIATED:
if (find(ids.begin(), ids.end(), firstId + 2) == ids.end()) {
ids.push_back(firstId + 2);
}
break;
- case android::util::BINARY_PUSH_STATE_CHANGED__STATE__INSTALLER_ROLLBACK_SUCCESS:
+ case android::os::statsd::util::BINARY_PUSH_STATE_CHANGED__STATE__INSTALLER_ROLLBACK_SUCCESS:
if (find(ids.begin(), ids.end(), firstId + 3) == ids.end()) {
ids.push_back(firstId + 3);
}
@@ -366,13 +366,13 @@
int64_t firstId = trainInfoOnDisk.experimentIds[0];
auto& ids = trainInfoOnDisk.experimentIds;
switch (rollbackTypeIn) {
- case android::util::WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE:
+ case android::os::statsd::util::WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_INITIATE:
if (find(ids.begin(), ids.end(), firstId + 4) == ids.end()) {
ids.push_back(firstId + 4);
}
StorageManager::writeTrainInfo(trainInfoOnDisk);
break;
- case android::util::WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS:
+ case android::os::statsd::util::WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS:
if (find(ids.begin(), ids.end(), firstId + 5) == ids.end()) {
ids.push_back(firstId + 5);
}
@@ -405,13 +405,13 @@
// Hard-coded logic to update train info on disk and fill in any information
// this log event may be missing.
- if (event->GetTagId() == android::util::BINARY_PUSH_STATE_CHANGED) {
+ if (event->GetTagId() == android::os::statsd::util::BINARY_PUSH_STATE_CHANGED) {
onBinaryPushStateChangedEventLocked(event);
}
// Hard-coded logic to update experiment ids on disk for certain rollback
// types and fill the rollback atom with experiment ids
- if (event->GetTagId() == android::util::WATCHDOG_ROLLBACK_OCCURRED) {
+ if (event->GetTagId() == android::os::statsd::util::WATCHDOG_ROLLBACK_OCCURRED) {
onWatchdogRollbackOccurredLocked(event);
}
@@ -429,7 +429,7 @@
// Hard-coded logic to update the isolated uid's in the uid-map.
// The field numbers need to be currently updated by hand with atoms.proto
- if (event->GetTagId() == android::util::ISOLATED_UID_CHANGED) {
+ if (event->GetTagId() == android::os::statsd::util::ISOLATED_UID_CHANGED) {
onIsolatedUidChangedEventLocked(*event);
}
@@ -446,7 +446,7 @@
}
- if (event->GetTagId() != android::util::ISOLATED_UID_CHANGED) {
+ if (event->GetTagId() != android::os::statsd::util::ISOLATED_UID_CHANGED) {
// Map the isolated uid to host uid if necessary.
mapIsolatedUidToHostUidIfNecessaryLocked(event);
}
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index cd10457..07579bb 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -32,7 +32,7 @@
#include <frameworks/base/cmds/statsd/src/statsd_config.pb.h>
#include <frameworks/base/cmds/statsd/src/uid_data.pb.h>
#include <private/android_filesystem_config.h>
-#include <statslog.h>
+#include <statslog_statsd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/system_properties.h>
@@ -767,7 +767,8 @@
}
if (good) {
dprintf(out, "Logging AppBreadcrumbReported(%d, %d, %d) to statslog.\n", uid, label, state);
- android::util::stats_write(android::util::APP_BREADCRUMB_REPORTED, uid, label, state);
+ android::os::statsd::util::stats_write(
+ android::os::statsd::util::APP_BREADCRUMB_REPORTED, uid, label, state);
} else {
print_cmd_help(out);
return UNKNOWN_ERROR;
@@ -1188,7 +1189,7 @@
Status StatsService::sendAppBreadcrumbAtom(int32_t label, int32_t state) {
// Permission check not necessary as it's meant for applications to write to
// statsd.
- android::util::stats_write(util::APP_BREADCRUMB_REPORTED,
+ android::os::statsd::util::stats_write(android::os::statsd::util::APP_BREADCRUMB_REPORTED,
(int32_t) AIBinder_getCallingUid(), label,
state);
return Status::ok();
diff --git a/cmds/statsd/src/anomaly/AlarmTracker.cpp b/cmds/statsd/src/anomaly/AlarmTracker.cpp
index 019a9f7..5722f92 100644
--- a/cmds/statsd/src/anomaly/AlarmTracker.cpp
+++ b/cmds/statsd/src/anomaly/AlarmTracker.cpp
@@ -23,7 +23,6 @@
#include "stats_util.h"
#include "storage/StorageManager.h"
-#include <statslog.h>
#include <time.h>
namespace android {
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.cpp b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
index 7ace44e..a21abbf 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.cpp
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
@@ -25,7 +25,7 @@
#include "subscriber/SubscriberReporter.h"
#include <inttypes.h>
-#include <statslog.h>
+#include <statslog_statsd.h>
#include <time.h>
namespace android {
@@ -235,8 +235,8 @@
StatsdStats::getInstance().noteAnomalyDeclared(mConfigKey, mAlert.id());
// TODO(b/110564268): This should also take in the const MetricDimensionKey& key?
- android::util::stats_write(android::util::ANOMALY_DETECTED, mConfigKey.GetUid(),
- mConfigKey.GetId(), mAlert.id());
+ util::stats_write(util::ANOMALY_DETECTED, mConfigKey.GetUid(),
+ mConfigKey.GetId(), mAlert.id());
}
void AnomalyTracker::detectAndDeclareAnomaly(const int64_t& timestampNs,
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 80f9fea..bd5bdc6 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -122,10 +122,10 @@
SettingChanged setting_changed = 41 [(module) = "framework"];
ActivityForegroundStateChanged activity_foreground_state_changed =
42 [(module) = "framework"];
- IsolatedUidChanged isolated_uid_changed = 43 [(module) = "framework"];
+ IsolatedUidChanged isolated_uid_changed = 43 [(module) = "framework", (module) = "statsd"];
PacketWakeupOccurred packet_wakeup_occurred = 44 [(module) = "framework"];
WallClockTimeShifted wall_clock_time_shifted = 45 [(module) = "framework"];
- AnomalyDetected anomaly_detected = 46;
+ AnomalyDetected anomaly_detected = 46 [(module) = "statsd"];
AppBreadcrumbReported app_breadcrumb_reported =
47 [(allow_from_any_uid) = true, (module) = "statsd"];
AppStartOccurred app_start_occurred = 48 [(module) = "framework"];
@@ -138,7 +138,7 @@
AppStartMemoryStateCaptured app_start_memory_state_captured = 55 [(module) = "framework"];
ShutdownSequenceReported shutdown_sequence_reported = 56 [(module) = "framework"];
BootSequenceReported boot_sequence_reported = 57;
- DaveyOccurred davey_occurred = 58 [(allow_from_any_uid) = true];
+ DaveyOccurred davey_occurred = 58 [(allow_from_any_uid) = true, (module) = "statsd"];
OverlayStateChanged overlay_state_changed = 59 [(module) = "framework"];
ForegroundServiceStateChanged foreground_service_state_changed
= 60 [(module) = "framework"];
@@ -166,7 +166,7 @@
LowMemReported low_mem_reported = 81 [(module) = "framework"];
GenericAtom generic_atom = 82;
KeyValuePairsAtom key_value_pairs_atom =
- 83 [(allow_from_any_uid) = true, (module) = "framework"];
+ 83 [(allow_from_any_uid) = true, (module) = "framework", (module) = "statsd"];
VibratorStateChanged vibrator_state_changed = 84 [(module) = "framework"];
DeferredJobStatsReported deferred_job_stats_reported = 85 [(module) = "framework"];
ThermalThrottlingStateChanged thermal_throttling = 86 [deprecated=true];
@@ -242,7 +242,8 @@
AdbConnectionChanged adb_connection_changed = 144 [(module) = "framework"];
SpeechDspStatReported speech_dsp_stat_reported = 145;
UsbContaminantReported usb_contaminant_reported = 146 [(module) = "framework"];
- WatchdogRollbackOccurred watchdog_rollback_occurred = 147 [(module) = "framework"];
+ WatchdogRollbackOccurred watchdog_rollback_occurred =
+ 147 [(module) = "framework", (module) = "statsd"];
BiometricSystemHealthIssueDetected biometric_system_health_issue_detected =
148 [(module) = "framework"];
BubbleUIChanged bubble_ui_changed = 149 [(module) = "sysui"];
@@ -401,7 +402,7 @@
}
// Pulled events will start at field 10000.
- // Next: 10076
+ // Next: 10080
oneof pulled {
WifiBytesTransfer wifi_bytes_transfer = 10000 [(module) = "framework"];
WifiBytesTransferByFgBg wifi_bytes_transfer_by_fg_bg = 10001 [(module) = "framework"];
@@ -412,7 +413,8 @@
SubsystemSleepState subsystem_sleep_state = 10005;
CpuTimePerFreq cpu_time_per_freq = 10008 [(module) = "framework"];
CpuTimePerUid cpu_time_per_uid = 10009 [(module) = "framework"];
- CpuTimePerUidFreq cpu_time_per_uid_freq = 10010 [(module) = "framework"];
+ CpuTimePerUidFreq cpu_time_per_uid_freq =
+ 10010 [(module) = "framework", (module) = "statsd"];
WifiActivityInfo wifi_activity_info = 10011 [(module) = "framework"];
ModemActivityInfo modem_activity_info = 10012 [(module) = "framework"];
BluetoothActivityInfo bluetooth_activity_info = 10007 [(module) = "framework"];
@@ -425,9 +427,9 @@
RemainingBatteryCapacity remaining_battery_capacity = 10019 [(module) = "framework"];
FullBatteryCapacity full_battery_capacity = 10020 [(module) = "framework"];
Temperature temperature = 10021 [(module) = "framework"];
- BinderCalls binder_calls = 10022 [(module) = "framework"];
+ BinderCalls binder_calls = 10022 [(module) = "framework", (module) = "statsd"];
BinderCallsExceptions binder_calls_exceptions = 10023 [(module) = "framework"];
- LooperStats looper_stats = 10024 [(module) = "framework"];
+ LooperStats looper_stats = 10024 [(module) = "framework", (module) = "statsd"];
DiskStats disk_stats = 10025 [(module) = "framework"];
DirectoryUsage directory_usage = 10026 [(module) = "framework"];
AppSize app_size = 10027 [(module) = "framework"];
@@ -455,7 +457,7 @@
NumFacesEnrolled num_faces_enrolled = 10048 [(module) = "framework"];
RoleHolder role_holder = 10049 [(module) = "framework"];
DangerousPermissionState dangerous_permission_state = 10050 [(module) = "framework"];
- TrainInfo train_info = 10051;
+ TrainInfo train_info = 10051 [(module) = "statsd"];
TimeZoneDataInfo time_zone_data_info = 10052 [(module) = "framework"];
ExternalStorageInfo external_storage_info = 10053 [(module) = "framework"];
GpuStatsGlobalInfo gpu_stats_global_info = 10054;
@@ -483,7 +485,11 @@
PackageNotificationChannelGroupPreferences package_notification_channel_group_preferences =
10073 [(module) = "framework"];
GnssStats gnss_stats = 10074 [(module) = "framework"];
- AppFeaturesOps app_features_ops = 10075 [(module) = "framework"];
+ AttributedAppOps attributed_app_ops = 10075 [(module) = "framework"];
+ VoiceCallSession voice_call_session = 10076 [(module) = "telephony"];
+ VoiceCallRatUsage voice_call_rat_usage = 10077 [(module) = "telephony"];
+ SimSlotState sim_slot_state = 10078 [(module) = "telephony"];
+ SupportedRadioAccessFamily supported_radio_access_family = 10079 [(module) = "telephony"];
}
// DO NOT USE field numbers above 100,000 in AOSP.
@@ -4475,8 +4481,7 @@
* after an OTA.
*
* Logged from:
- * - system/core/fs_mgr/libsnapshot/snapshot.cpp
- * - system/core/fs_mgr/libsnapshot/snapshotctl.cpp
+ * - system/update_engine/cleanup_previous_update_action.cc
*/
message SnapshotMergeReported {
// Keep in sync with
@@ -7598,18 +7603,19 @@
}
/**
- * Historical app ops data per package and features.
+ * Historical app ops data per package and attribution tag.
*/
-message AppFeaturesOps {
+message AttributedAppOps {
// Uid of the package requesting the op
optional int32 uid = 1 [(is_uid) = true];
// Name of the package performing the op
optional string package_name = 2;
- // feature id; provided by developer when accessing related API, limited at 50 chars by API.
- // Features must be provided through manifest using <feature> tag available in R and above.
- optional string feature_id = 3;
+ // tag; provided by developer when accessing related API, limited at 50 chars by API.
+ // Attributions must be provided through manifest using <attribution> tag available in R and
+ // above.
+ optional string tag = 3;
// operation id; maps to the OPSTR_* constants in AppOpsManager.java
optional string op = 4;
@@ -8471,9 +8477,11 @@
// operation string id per OPSTR_ constants in AppOpsManager.java
optional string op = 3;
- // feature id; provided by developer when accessing related API, limited at 50 chars by API.
- // Features must be provided through manifest using <feature> tag available in R and above.
- optional string feature_id = 4;
+ // attribution_tag; provided by developer when accessing related API, limited at 50 chars by
+ // API.
+ // Attributions must be provided through manifest using <attribution> tag available in R and
+ // above.
+ optional string attribution_tag = 4;
// message related to app op access, limited to 600 chars by API
optional string message = 5;
@@ -8670,6 +8678,154 @@
}
/**
+ * Pulls information for a single voice call.
+ *
+ * Each pull creates multiple atoms, one for each call. The sequence is randomized when pulled.
+ *
+ * Pulled from:
+ * frameworks/opt/telephony/src/java/com/android/internal/telephony/metrics/PersistPullers.java
+ */
+message VoiceCallSession {
+ // Bearer (IMS or CS) when the call started.
+ optional android.telephony.CallBearerEnum bearer_at_start = 1;
+
+ // Bearer (IMS or CS) when the call ended.
+ // The bearer may change during the call, e.g. due to SRVCC.
+ optional android.telephony.CallBearerEnum bearer_at_end = 2;
+
+ // Direction of the call (incoming or outgoing).
+ optional android.telephony.CallDirectionEnum direction = 3;
+
+ // Time spent setting up the call.
+ optional android.telephony.CallSetupDurationEnum setup_duration = 4;
+
+ // Whether the call ended before the setup was completed.
+ optional bool setup_failed = 5;
+
+ // IMS reason code or CS disconnect cause.
+ // For IMS, see: frameworks/base/telephony/java/android/telephony/ims/ImsReasonInfo.java
+ // For CS, see: frameworks/base/telephony/java/android/telephony/DisconnectCause.java
+ optional int32 disconnect_reason_code = 6;
+
+ // IMS extra code or CS precise disconnect cause.
+ // For IMS, this code is vendor-specific
+ // For CS, see: frameworks/base/telephony/java/android/telephony/PreciseDisconnectCause.java
+ optional int32 disconnect_extra_code = 7;
+
+ // IMS extra message or CS vendor cause.
+ optional string disconnect_extra_message = 8;
+
+ // Radio access technology (RAT) used when call started.
+ optional android.telephony.NetworkTypeEnum rat_at_start = 9;
+
+ // Radio access technology (RAT) used when call terminated.
+ optional android.telephony.NetworkTypeEnum rat_at_end = 10;
+
+ // Number of times RAT changed during the call.
+ optional int64 rat_switch_count = 11;
+
+ // A bitmask of all codecs used during the call.
+ // See: frameworks/opt/telephony/src/java/com/android/internal/telephony/metrics/VoiceCallSessionStats.java
+ optional int64 codec_bitmask = 12;
+
+ // Number of other calls going on during call setup, for the same SIM slot.
+ optional int32 concurrent_call_count_at_start = 13;
+
+ // Number of other calls going on during call termination, for the same SIM slot.
+ optional int32 concurrent_call_count_at_end = 14;
+
+ // Index of the SIM is used, 0 for single-SIM devices.
+ optional int32 sim_slot_index = 15;
+
+ // Whether the device was in multi-SIM mode (with multiple active SIM profiles).
+ optional bool is_multi_sim = 16;
+
+ // Whether the call was made with an eSIM profile.
+ optional bool is_esim = 17;
+
+ // Carrier ID of the SIM card.
+ // See https://source.android.com/devices/tech/config/carrierid.
+ optional int32 carrier_id = 18;
+
+ // Whether an SRVCC has been completed successfully.
+ // SRVCC (CS fallback) should be recorded in the IMS call since there will be no more SRVCC
+ // events once the call is switched to CS.
+ optional bool srvcc_completed = 19;
+
+ // Number of SRVCC failures.
+ optional int64 srvcc_failure_count = 20;
+
+ // Number of SRVCC cancellations.
+ optional int64 srvcc_cancellation_count = 21;
+
+ // Whether the Real-Time Text (RTT) was ever used in the call.
+ optional bool rtt_enabled = 22;
+
+ // Whether this was an emergency call.
+ optional bool is_emergency = 23;
+
+ // Whether the call was performed while roaming.
+ optional bool is_roaming = 24;
+}
+
+/**
+ * Pulls voice call radio access technology (RAT) usage.
+ *
+ * Each pull creates multiple atoms, one for each carrier/RAT, the order of which is irrelevant to
+ * time. The atom will be skipped if not enough data is available.
+ *
+ * Pulled from:
+ * frameworks/opt/telephony/src/java/com/android/internal/telephony/metrics/PersistPullers.java
+ */
+message VoiceCallRatUsage {
+ // Carrier ID (https://source.android.com/devices/tech/config/carrierid).
+ optional int32 carrier_id = 1;
+
+ // Radio access technology.
+ optional android.telephony.NetworkTypeEnum rat = 2;
+
+ // Total duration that voice calls spent on this carrier and RAT.
+ optional int64 total_duration_seconds = 3;
+
+ // Total number of calls using this carrier and RAT.
+ // A call is counted once even if it used the RAT multiple times.
+ optional int64 call_count = 4;
+}
+
+/**
+ * Pulls the number of active SIM slots and SIMs/eSIM profiles.
+ *
+ * Pulled from:
+ * frameworks/opt/telephony/src/java/com/android/internal/telephony/metrics/NonPersistPullers.java
+ */
+message SimSlotState {
+ // Number of active SIM slots (both physical and eSIM profiles) in the device.
+ optional int32 active_slot_count = 1;
+
+ // Number of SIM cards (both physical and active eSIM profiles).
+ // This number is always equal to or less than the number of active SIM slots.
+ optional int32 sim_count = 2;
+
+ // Number of active eSIM profiles.
+ // This number is always equal to or less than the number of SIMs.
+ optional int32 esim_count = 3;
+}
+
+/**
+ * Pulls supported cellular radio access technologies.
+ *
+ * This atom reports the capabilities of the device, rather than the network it has access to.
+ *
+ * Pulled from:
+ * frameworks/opt/telephony/src/java/com/android/internal/telephony/metrics/NonPersistPullers.java
+ */
+message SupportedRadioAccessFamily {
+ // A bitmask of supported radio technologies.
+ // See android.telephony.TelephonyManager.NetworkTypeBitMask.
+ optional int64 network_type_bitmask = 1;
+}
+
+/**
* Logs gnss stats from location service provider
*
* Pulled from:
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index 0115ba2..8b6a5a1 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -32,7 +32,7 @@
#include "../statscompanion_util.h"
#include "StatsCallbackPuller.h"
#include "TrainInfoPuller.h"
-#include "statslog.h"
+#include "statslog_statsd.h"
using std::shared_ptr;
using std::vector;
@@ -47,7 +47,7 @@
StatsPullerManager::StatsPullerManager()
: kAllPullAtomInfo({
// TrainInfo.
- {{.atomTag = android::util::TRAIN_INFO}, new TrainInfoPuller()},
+ {{.atomTag = util::TRAIN_INFO}, new TrainInfoPuller()},
}),
mNextPullTimeNs(NO_ALARM_UPDATE) {
}
diff --git a/cmds/statsd/src/external/TrainInfoPuller.cpp b/cmds/statsd/src/external/TrainInfoPuller.cpp
index a7d8d4e..3837f4a 100644
--- a/cmds/statsd/src/external/TrainInfoPuller.cpp
+++ b/cmds/statsd/src/external/TrainInfoPuller.cpp
@@ -22,7 +22,7 @@
#include "TrainInfoPuller.h"
#include "logd/LogEvent.h"
#include "stats_log_util.h"
-#include "statslog.h"
+#include "statslog_statsd.h"
#include "storage/StorageManager.h"
using std::make_shared;
@@ -33,7 +33,7 @@
namespace statsd {
TrainInfoPuller::TrainInfoPuller() :
- StatsPuller(android::util::TRAIN_INFO) {
+ StatsPuller(util::TRAIN_INFO) {
}
bool TrainInfoPuller::PullInternal(vector<shared_ptr<LogEvent>>* data) {
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index 3054b6d..2bd13d7 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -20,7 +20,7 @@
#include <android/util/ProtoOutputStream.h>
#include "../stats_log_util.h"
-#include "statslog.h"
+#include "statslog_statsd.h"
#include "storage/StorageManager.h"
namespace android {
@@ -113,9 +113,9 @@
const int FIELD_ID_ACTIVATION_BROADCAST_GUARDRAIL_TIME = 2;
const std::map<int, std::pair<size_t, size_t>> StatsdStats::kAtomDimensionKeySizeLimitMap = {
- {android::util::BINDER_CALLS, {6000, 10000}},
- {android::util::LOOPER_STATS, {1500, 2500}},
- {android::util::CPU_TIME_PER_UID_FREQ, {6000, 10000}},
+ {util::BINDER_CALLS, {6000, 10000}},
+ {util::LOOPER_STATS, {1500, 2500}},
+ {util::CPU_TIME_PER_UID_FREQ, {6000, 10000}},
};
StatsdStats::StatsdStats() {
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index 974e203c..258f84d 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -18,7 +18,7 @@
#include "logd/LogEvent.h"
#include "stats_log_util.h"
-#include "statslog.h"
+#include "statslog_statsd.h"
#include <android/binder_ibinder.h>
#include <android-base/stringprintf.h>
@@ -100,7 +100,7 @@
const std::map<int32_t, float>& float_map) {
mLogdTimestampNs = wallClockTimestampNs;
mElapsedTimestampNs = elapsedTimestampNs;
- mTagId = android::util::KEY_VALUE_PAIRS_ATOM;
+ mTagId = util::KEY_VALUE_PAIRS_ATOM;
mLogUid = uid;
int pos[] = {1, 1, 1};
@@ -153,7 +153,7 @@
const std::vector<uint8_t>& experimentIds, int32_t userId) {
mLogdTimestampNs = getWallClockNs();
mElapsedTimestampNs = getElapsedRealtimeNs();
- mTagId = android::util::BINARY_PUSH_STATE_CHANGED;
+ mTagId = util::BINARY_PUSH_STATE_CHANGED;
mLogUid = AIBinder_getCallingUid();
mLogPid = AIBinder_getCallingPid();
@@ -172,7 +172,7 @@
const InstallTrainInfo& trainInfo) {
mLogdTimestampNs = wallClockTimestampNs;
mElapsedTimestampNs = elapsedTimestampNs;
- mTagId = android::util::TRAIN_INFO;
+ mTagId = util::TRAIN_INFO;
mValues.push_back(
FieldValue(Field(mTagId, getSimpleField(1)), Value(trainInfo.trainVersionCode)));
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h
index 3940aa8e..b68eeb8 100644
--- a/cmds/statsd/src/logd/LogEvent.h
+++ b/cmds/statsd/src/logd/LogEvent.h
@@ -328,4 +328,3 @@
} // namespace statsd
} // namespace os
} // namespace android
-
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 536700f..6f54ea7 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -31,7 +31,7 @@
#include "state/StateManager.h"
#include "stats_log_util.h"
#include "stats_util.h"
-#include "statslog.h"
+#include "statslog_statsd.h"
using android::util::FIELD_COUNT_REPEATED;
using android::util::FIELD_TYPE_INT32;
@@ -291,7 +291,7 @@
}
bool MetricsManager::eventSanityCheck(const LogEvent& event) {
- if (event.GetTagId() == android::util::APP_BREADCRUMB_REPORTED) {
+ if (event.GetTagId() == util::APP_BREADCRUMB_REPORTED) {
// Check that app breadcrumb reported fields are valid.
status_t err = NO_ERROR;
@@ -318,7 +318,7 @@
VLOG("APP_BREADCRUMB_REPORTED does not have valid state %ld", appHookState);
return false;
}
- } else if (event.GetTagId() == android::util::DAVEY_OCCURRED) {
+ } else if (event.GetTagId() == util::DAVEY_OCCURRED) {
// Daveys can be logged from any app since they are logged in libs/hwui/JankTracker.cpp.
// Check that the davey duration is reasonable. Max length check is for privacy.
status_t err = NO_ERROR;
diff --git a/cmds/statsd/src/packages/UidMap.h b/cmds/statsd/src/packages/UidMap.h
index 4e3c506..02fe7b1 100644
--- a/cmds/statsd/src/packages/UidMap.h
+++ b/cmds/statsd/src/packages/UidMap.h
@@ -139,7 +139,7 @@
// record is deleted.
void appendUidMap(const int64_t& timestamp, const ConfigKey& key, std::set<string>* str_set,
bool includeVersionStrings, bool includeInstaller,
- util::ProtoOutputStream* proto);
+ ProtoOutputStream* proto);
// Forces the output to be cleared. We still generate a snapshot based on the current state.
// This results in extra data uploaded but helps us reconstruct the uid mapping on the server
diff --git a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
index 4b78e30..7febb35 100644
--- a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
+++ b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
@@ -137,7 +137,9 @@
simplePredicate, trackerNameIndexMap);
EXPECT_FALSE(conditionTracker.isSliced());
- LogEvent event(1 /*tagId*/, 0 /*timestamp*/);
+ // This event is not accessed in this test besides dimensions which is why this is okay.
+ // This is technically an invalid LogEvent because we do not call parseBuffer.
+ LogEvent event(/*uid=*/0, /*pid=*/0);
vector<MatchingState> matcherState;
matcherState.push_back(MatchingState::kNotMatched);
@@ -222,7 +224,9 @@
trackerNameIndexMap);
EXPECT_FALSE(conditionTracker.isSliced());
- LogEvent event(1 /*tagId*/, 0 /*timestamp*/);
+ // This event is not accessed in this test besides dimensions which is why this is okay.
+ // This is technically an invalid LogEvent because we do not call parseBuffer.
+ LogEvent event(/*uid=*/0, /*pid=*/0);
// one matched start
vector<MatchingState> matcherState;
@@ -296,8 +300,8 @@
std::vector<int> uids = {111, 222, 333};
- LogEvent event(/*uid=*/-1, /*pid=*/-1);
- makeWakeLockEvent(&event, /*atomId=*/1, /*timestamp=*/0, uids, "wl1", /*acquire=*/1);
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ makeWakeLockEvent(&event1, /*atomId=*/1, /*timestamp=*/0, uids, "wl1", /*acquire=*/1);
// one matched start
vector<MatchingState> matcherState;
@@ -308,7 +312,7 @@
vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
vector<bool> changedCache(1, false);
- conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
+ conditionTracker.evaluateCondition(event1, matcherState, allPredicates, conditionCache,
changedCache);
if (position == Position::FIRST || position == Position::LAST) {
@@ -333,7 +337,7 @@
EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
// another wake lock acquired by this uid
- LogEvent event2(/*uid=*/-1, /*pid=*/-1);
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
makeWakeLockEvent(&event2, /*atomId=*/1, /*timestamp=*/0, uids, "wl2", /*acquire=*/1);
matcherState.clear();
matcherState.push_back(MatchingState::kMatched);
@@ -353,7 +357,7 @@
// wake lock 1 release
- LogEvent event3(/*uid=*/-1, /*pid=*/-1);
+ LogEvent event3(/*uid=*/0, /*pid=*/0);
makeWakeLockEvent(&event3, /*atomId=*/1, /*timestamp=*/0, uids, "wl1", /*acquire=*/0);
matcherState.clear();
matcherState.push_back(MatchingState::kNotMatched);
@@ -372,7 +376,7 @@
EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty());
EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
- LogEvent event4(/*uid=*/-1, /*pid=*/-1);
+ LogEvent event4(/*uid=*/0, /*pid=*/0);
makeWakeLockEvent(&event4, /*atomId=*/1, /*timestamp=*/0, uids, "wl2", /*acquire=*/0);
matcherState.clear();
matcherState.push_back(MatchingState::kNotMatched);
@@ -399,246 +403,235 @@
}
-//TEST(SimpleConditionTrackerTest, TestSlicedWithNoOutputDim) {
-// std::vector<sp<ConditionTracker>> allConditions;
-//
-// SimplePredicate simplePredicate = getWakeLockHeldCondition(
-// true /*nesting*/, true /*default to false*/, false /*slice output by uid*/,
-// Position::ANY /* position */);
-// string conditionName = "WL_HELD";
-//
-// unordered_map<int64_t, int> trackerNameIndexMap;
-// trackerNameIndexMap[StringToId("WAKE_LOCK_ACQUIRE")] = 0;
-// trackerNameIndexMap[StringToId("WAKE_LOCK_RELEASE")] = 1;
-// trackerNameIndexMap[StringToId("RELEASE_ALL")] = 2;
-//
-// SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName),
-// 0 /*condition tracker index*/, simplePredicate,
-// trackerNameIndexMap);
-//
-// EXPECT_FALSE(conditionTracker.isSliced());
-//
-// std::vector<int> uid_list1 = {111, 1111, 11111};
-// string uid1_wl1 = "wl1_1";
-// std::vector<int> uid_list2 = {222, 2222, 22222};
-// string uid2_wl1 = "wl2_1";
-//
-// LogEvent event(1 /*tagId*/, 0 /*timestamp*/);
-// makeWakeLockEvent(&event, uid_list1, uid1_wl1, 1);
-//
-// // one matched start for uid1
-// vector<MatchingState> matcherState;
-// matcherState.push_back(MatchingState::kMatched);
-// matcherState.push_back(MatchingState::kNotMatched);
-// matcherState.push_back(MatchingState::kNotMatched);
-// vector<sp<ConditionTracker>> allPredicates;
-// vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
-// vector<bool> changedCache(1, false);
-//
-// conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
-// changedCache);
-//
-// EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
-// EXPECT_TRUE(changedCache[0]);
-//
-// // Now test query
-// ConditionKey queryKey;
-// conditionCache[0] = ConditionState::kNotEvaluated;
-//
-// conditionTracker.isConditionMet(queryKey, allPredicates,
-// true,
-// conditionCache);
-// EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
-//
-// // another wake lock acquired by this uid
-// LogEvent event2(1 /*tagId*/, 0 /*timestamp*/);
-// makeWakeLockEvent(&event2, uid_list2, uid2_wl1, 1);
-// matcherState.clear();
-// matcherState.push_back(MatchingState::kMatched);
-// matcherState.push_back(MatchingState::kNotMatched);
-// conditionCache[0] = ConditionState::kNotEvaluated;
-// changedCache[0] = false;
-// conditionTracker.evaluateCondition(event2, matcherState, allPredicates, conditionCache,
-// changedCache);
-// EXPECT_FALSE(changedCache[0]);
-//
-// // uid1 wake lock 1 release
-// LogEvent event3(1 /*tagId*/, 0 /*timestamp*/);
-// makeWakeLockEvent(&event3, uid_list1, uid1_wl1, 0); // now release it.
-// matcherState.clear();
-// matcherState.push_back(MatchingState::kNotMatched);
-// matcherState.push_back(MatchingState::kMatched);
-// conditionCache[0] = ConditionState::kNotEvaluated;
-// changedCache[0] = false;
-// conditionTracker.evaluateCondition(event3, matcherState, allPredicates, conditionCache,
-// changedCache);
-// // nothing changes, because uid2 is still holding wl.
-// EXPECT_FALSE(changedCache[0]);
-//
-// LogEvent event4(1 /*tagId*/, 0 /*timestamp*/);
-// makeWakeLockEvent(&event4, uid_list2, uid2_wl1, 0); // now release it.
-// matcherState.clear();
-// matcherState.push_back(MatchingState::kNotMatched);
-// matcherState.push_back(MatchingState::kMatched);
-// conditionCache[0] = ConditionState::kNotEvaluated;
-// changedCache[0] = false;
-// conditionTracker.evaluateCondition(event4, matcherState, allPredicates, conditionCache,
-// changedCache);
-// EXPECT_EQ(0UL, conditionTracker.mSlicedConditionState.size());
-// EXPECT_TRUE(changedCache[0]);
-//
-// // query again
-// conditionCache[0] = ConditionState::kNotEvaluated;
-// conditionTracker.isConditionMet(queryKey, allPredicates,
-// true,
-// conditionCache);
-// EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
-//}
-//
-//TEST(SimpleConditionTrackerTest, TestStopAll) {
-// std::vector<sp<ConditionTracker>> allConditions;
-// for (Position position :
-// { Position::FIRST, Position::LAST }) {
-// SimplePredicate simplePredicate = getWakeLockHeldCondition(
-// true /*nesting*/, true /*default to false*/, true /*output slice by uid*/,
-// position);
-// string conditionName = "WL_HELD_BY_UID3";
-//
-// unordered_map<int64_t, int> trackerNameIndexMap;
-// trackerNameIndexMap[StringToId("WAKE_LOCK_ACQUIRE")] = 0;
-// trackerNameIndexMap[StringToId("WAKE_LOCK_RELEASE")] = 1;
-// trackerNameIndexMap[StringToId("RELEASE_ALL")] = 2;
-//
-// SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName),
-// 0 /*condition tracker index*/, simplePredicate,
-// trackerNameIndexMap);
-//
-// std::vector<int> uid_list1 = {111, 1111, 11111};
-// std::vector<int> uid_list2 = {222, 2222, 22222};
-//
-// LogEvent event(1 /*tagId*/, 0 /*timestamp*/);
-// makeWakeLockEvent(&event, uid_list1, "wl1", 1);
-//
-// // one matched start
-// vector<MatchingState> matcherState;
-// matcherState.push_back(MatchingState::kMatched);
-// matcherState.push_back(MatchingState::kNotMatched);
-// matcherState.push_back(MatchingState::kNotMatched);
-// vector<sp<ConditionTracker>> allPredicates;
-// vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
-// vector<bool> changedCache(1, false);
-//
-// conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
-// changedCache);
-// if (position == Position::FIRST ||
-// position == Position::LAST) {
-// EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
-// } else {
-// EXPECT_EQ(uid_list1.size(), conditionTracker.mSlicedConditionState.size());
-// }
-// EXPECT_TRUE(changedCache[0]);
-// {
-// if (position == Position::FIRST ||
-// position == Position::LAST) {
-// EXPECT_EQ(1UL, conditionTracker.getChangedToTrueDimensions(allConditions)->size());
-// EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
-// } else {
-// EXPECT_EQ(uid_list1.size(), conditionTracker.getChangedToTrueDimensions(allConditions)->size());
-// EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
-// }
-// }
-//
-// // Now test query
-// const auto queryKey = getWakeLockQueryKey(position, uid_list1, conditionName);
-// conditionCache[0] = ConditionState::kNotEvaluated;
-//
-// conditionTracker.isConditionMet(queryKey, allPredicates,
-// false,
-// conditionCache);
-// EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
-//
-// // another wake lock acquired by uid2
-// LogEvent event2(1 /*tagId*/, 0 /*timestamp*/);
-// makeWakeLockEvent(&event2, uid_list2, "wl2", 1);
-// matcherState.clear();
-// matcherState.push_back(MatchingState::kMatched);
-// matcherState.push_back(MatchingState::kNotMatched);
-// matcherState.push_back(MatchingState::kNotMatched);
-// conditionCache[0] = ConditionState::kNotEvaluated;
-// changedCache[0] = false;
-// conditionTracker.evaluateCondition(event2, matcherState, allPredicates, conditionCache,
-// changedCache);
-// if (position == Position::FIRST ||
-// position == Position::LAST) {
-// EXPECT_EQ(2UL, conditionTracker.mSlicedConditionState.size());
-// } else {
-// EXPECT_EQ(uid_list1.size() + uid_list2.size(),
-// conditionTracker.mSlicedConditionState.size());
-// }
-// EXPECT_TRUE(changedCache[0]);
-// {
-// if (position == Position::FIRST ||
-// position == Position::LAST) {
-// EXPECT_EQ(1UL, conditionTracker.getChangedToTrueDimensions(allConditions)->size());
-// EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
-// } else {
-// EXPECT_EQ(uid_list2.size(), conditionTracker.getChangedToTrueDimensions(allConditions)->size());
-// EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
-// }
-// }
-//
-//
-// // TEST QUERY
-// const auto queryKey2 = getWakeLockQueryKey(position, uid_list2, conditionName);
-// conditionCache[0] = ConditionState::kNotEvaluated;
-// conditionTracker.isConditionMet(queryKey, allPredicates,
-// false,
-// conditionCache);
-//
-// EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
-//
-//
-// // stop all event
-// LogEvent event3(2 /*tagId*/, 0 /*timestamp*/);
-// matcherState.clear();
-// matcherState.push_back(MatchingState::kNotMatched);
-// matcherState.push_back(MatchingState::kNotMatched);
-// matcherState.push_back(MatchingState::kMatched);
-//
-// conditionCache[0] = ConditionState::kNotEvaluated;
-// changedCache[0] = false;
-// conditionTracker.evaluateCondition(event3, matcherState, allPredicates, conditionCache,
-// changedCache);
-// EXPECT_TRUE(changedCache[0]);
-// EXPECT_EQ(0UL, conditionTracker.mSlicedConditionState.size());
-// {
-// if (position == Position::FIRST || position == Position::LAST) {
-// EXPECT_EQ(2UL, conditionTracker.getChangedToFalseDimensions(allConditions)->size());
-// EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty());
-// } else {
-// EXPECT_EQ(uid_list1.size() + uid_list2.size(),
-// conditionTracker.getChangedToFalseDimensions(allConditions)->size());
-// EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty());
-// }
-// }
-//
-// // TEST QUERY
-// const auto queryKey3 = getWakeLockQueryKey(position, uid_list1, conditionName);
-// conditionCache[0] = ConditionState::kNotEvaluated;
-// conditionTracker.isConditionMet(queryKey, allPredicates,
-// false,
-// conditionCache);
-// EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
-//
-// // TEST QUERY
-// const auto queryKey4 = getWakeLockQueryKey(position, uid_list2, conditionName);
-// conditionCache[0] = ConditionState::kNotEvaluated;
-// conditionTracker.isConditionMet(queryKey, allPredicates,
-// false,
-// conditionCache);
-// EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
-// }
-//}
+TEST(SimpleConditionTrackerTest, TestSlicedWithNoOutputDim) {
+ std::vector<sp<ConditionTracker>> allConditions;
+
+ SimplePredicate simplePredicate =
+ getWakeLockHeldCondition(true /*nesting*/, true /*default to false*/,
+ false /*slice output by uid*/, Position::ANY /* position */);
+ string conditionName = "WL_HELD";
+
+ unordered_map<int64_t, int> trackerNameIndexMap;
+ trackerNameIndexMap[StringToId("WAKE_LOCK_ACQUIRE")] = 0;
+ trackerNameIndexMap[StringToId("WAKE_LOCK_RELEASE")] = 1;
+ trackerNameIndexMap[StringToId("RELEASE_ALL")] = 2;
+
+ SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName),
+ 0 /*condition tracker index*/, simplePredicate,
+ trackerNameIndexMap);
+
+ EXPECT_FALSE(conditionTracker.isSliced());
+
+ std::vector<int> uids1 = {111, 1111, 11111};
+ string uid1_wl1 = "wl1_1";
+ std::vector<int> uids2 = {222, 2222, 22222};
+ string uid2_wl1 = "wl2_1";
+
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ makeWakeLockEvent(&event1, /*atomId=*/1, /*timestamp=*/0, uids1, uid1_wl1, /*acquire=*/1);
+
+ // one matched start for uid1
+ vector<MatchingState> matcherState;
+ matcherState.push_back(MatchingState::kMatched);
+ matcherState.push_back(MatchingState::kNotMatched);
+ matcherState.push_back(MatchingState::kNotMatched);
+ vector<sp<ConditionTracker>> allPredicates;
+ vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
+ vector<bool> changedCache(1, false);
+
+ conditionTracker.evaluateCondition(event1, matcherState, allPredicates, conditionCache,
+ changedCache);
+
+ EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
+ EXPECT_TRUE(changedCache[0]);
+
+ // Now test query
+ ConditionKey queryKey;
+ conditionCache[0] = ConditionState::kNotEvaluated;
+
+ conditionTracker.isConditionMet(queryKey, allPredicates, true, conditionCache);
+ EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
+
+ // another wake lock acquired by this uid
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ makeWakeLockEvent(&event2, /*atomId=*/1, /*timestamp=*/0, uids2, uid2_wl1, /*acquire=*/1);
+
+ matcherState.clear();
+ matcherState.push_back(MatchingState::kMatched);
+ matcherState.push_back(MatchingState::kNotMatched);
+ conditionCache[0] = ConditionState::kNotEvaluated;
+ changedCache[0] = false;
+ conditionTracker.evaluateCondition(event2, matcherState, allPredicates, conditionCache,
+ changedCache);
+ EXPECT_FALSE(changedCache[0]);
+
+ // uid1 wake lock 1 release
+ LogEvent event3(/*uid=*/0, /*pid=*/0);
+ makeWakeLockEvent(&event3, /*atomId=*/1, /*timestamp=*/0, uids1, uid1_wl1,
+ /*release=*/0); // now release it.
+
+ matcherState.clear();
+ matcherState.push_back(MatchingState::kNotMatched);
+ matcherState.push_back(MatchingState::kMatched);
+ conditionCache[0] = ConditionState::kNotEvaluated;
+ changedCache[0] = false;
+ conditionTracker.evaluateCondition(event3, matcherState, allPredicates, conditionCache,
+ changedCache);
+ // nothing changes, because uid2 is still holding wl.
+ EXPECT_FALSE(changedCache[0]);
+
+ LogEvent event4(/*uid=*/0, /*pid=*/0);
+ makeWakeLockEvent(&event4, /*atomId=*/1, /*timestamp=*/0, uids2, uid2_wl1,
+ /*acquire=*/0); // now release it.
+ matcherState.clear();
+ matcherState.push_back(MatchingState::kNotMatched);
+ matcherState.push_back(MatchingState::kMatched);
+ conditionCache[0] = ConditionState::kNotEvaluated;
+ changedCache[0] = false;
+ conditionTracker.evaluateCondition(event4, matcherState, allPredicates, conditionCache,
+ changedCache);
+ EXPECT_EQ(0UL, conditionTracker.mSlicedConditionState.size());
+ EXPECT_TRUE(changedCache[0]);
+
+ // query again
+ conditionCache[0] = ConditionState::kNotEvaluated;
+ conditionTracker.isConditionMet(queryKey, allPredicates, true, conditionCache);
+ EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
+}
+
+TEST(SimpleConditionTrackerTest, TestStopAll) {
+ std::vector<sp<ConditionTracker>> allConditions;
+ for (Position position : {Position::FIRST, Position::LAST}) {
+ SimplePredicate simplePredicate =
+ getWakeLockHeldCondition(true /*nesting*/, true /*default to false*/,
+ true /*output slice by uid*/, position);
+ string conditionName = "WL_HELD_BY_UID3";
+
+ unordered_map<int64_t, int> trackerNameIndexMap;
+ trackerNameIndexMap[StringToId("WAKE_LOCK_ACQUIRE")] = 0;
+ trackerNameIndexMap[StringToId("WAKE_LOCK_RELEASE")] = 1;
+ trackerNameIndexMap[StringToId("RELEASE_ALL")] = 2;
+
+ SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName),
+ 0 /*condition tracker index*/, simplePredicate,
+ trackerNameIndexMap);
+
+ std::vector<int> uids1 = {111, 1111, 11111};
+ std::vector<int> uids2 = {222, 2222, 22222};
+
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ makeWakeLockEvent(&event1, /*atomId=*/1, /*timestamp=*/0, uids1, "wl1", /*acquire=*/1);
+
+ // one matched start
+ vector<MatchingState> matcherState;
+ matcherState.push_back(MatchingState::kMatched);
+ matcherState.push_back(MatchingState::kNotMatched);
+ matcherState.push_back(MatchingState::kNotMatched);
+ vector<sp<ConditionTracker>> allPredicates;
+ vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
+ vector<bool> changedCache(1, false);
+
+ conditionTracker.evaluateCondition(event1, matcherState, allPredicates, conditionCache,
+ changedCache);
+ if (position == Position::FIRST || position == Position::LAST) {
+ EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
+ } else {
+ EXPECT_EQ(uids1.size(), conditionTracker.mSlicedConditionState.size());
+ }
+ EXPECT_TRUE(changedCache[0]);
+ {
+ if (position == Position::FIRST || position == Position::LAST) {
+ EXPECT_EQ(1UL, conditionTracker.getChangedToTrueDimensions(allConditions)->size());
+ EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
+ } else {
+ EXPECT_EQ(uids1.size(),
+ conditionTracker.getChangedToTrueDimensions(allConditions)->size());
+ EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
+ }
+ }
+
+ // Now test query
+ const auto queryKey = getWakeLockQueryKey(position, uids1, conditionName);
+ conditionCache[0] = ConditionState::kNotEvaluated;
+
+ conditionTracker.isConditionMet(queryKey, allPredicates, false, conditionCache);
+ EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
+
+ // another wake lock acquired by uid2
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ makeWakeLockEvent(&event2, /*atomId=*/1, /*timestamp=*/0, uids2, "wl2", /*acquire=*/1);
+
+ matcherState.clear();
+ matcherState.push_back(MatchingState::kMatched);
+ matcherState.push_back(MatchingState::kNotMatched);
+ matcherState.push_back(MatchingState::kNotMatched);
+ conditionCache[0] = ConditionState::kNotEvaluated;
+ changedCache[0] = false;
+ conditionTracker.evaluateCondition(event2, matcherState, allPredicates, conditionCache,
+ changedCache);
+ if (position == Position::FIRST || position == Position::LAST) {
+ EXPECT_EQ(2UL, conditionTracker.mSlicedConditionState.size());
+ } else {
+ EXPECT_EQ(uids1.size() + uids2.size(), conditionTracker.mSlicedConditionState.size());
+ }
+ EXPECT_TRUE(changedCache[0]);
+ {
+ if (position == Position::FIRST || position == Position::LAST) {
+ EXPECT_EQ(1UL, conditionTracker.getChangedToTrueDimensions(allConditions)->size());
+ EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
+ } else {
+ EXPECT_EQ(uids2.size(),
+ conditionTracker.getChangedToTrueDimensions(allConditions)->size());
+ EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
+ }
+ }
+
+ // TEST QUERY
+ const auto queryKey2 = getWakeLockQueryKey(position, uids2, conditionName);
+ conditionCache[0] = ConditionState::kNotEvaluated;
+ conditionTracker.isConditionMet(queryKey, allPredicates, false, conditionCache);
+
+ EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
+
+ // stop all event
+ LogEvent event3(/*uid=*/0, /*pid=*/0);
+ makeWakeLockEvent(&event3, /*atomId=*/1, /*timestamp=*/0, uids2, "wl2", /*acquire=*/1);
+
+ matcherState.clear();
+ matcherState.push_back(MatchingState::kNotMatched);
+ matcherState.push_back(MatchingState::kNotMatched);
+ matcherState.push_back(MatchingState::kMatched);
+
+ conditionCache[0] = ConditionState::kNotEvaluated;
+ changedCache[0] = false;
+ conditionTracker.evaluateCondition(event3, matcherState, allPredicates, conditionCache,
+ changedCache);
+ EXPECT_TRUE(changedCache[0]);
+ EXPECT_EQ(0UL, conditionTracker.mSlicedConditionState.size());
+ {
+ if (position == Position::FIRST || position == Position::LAST) {
+ EXPECT_EQ(2UL, conditionTracker.getChangedToFalseDimensions(allConditions)->size());
+ EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty());
+ } else {
+ EXPECT_EQ(uids1.size() + uids2.size(),
+ conditionTracker.getChangedToFalseDimensions(allConditions)->size());
+ EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty());
+ }
+ }
+
+ // TEST QUERY
+ const auto queryKey3 = getWakeLockQueryKey(position, uids1, conditionName);
+ conditionCache[0] = ConditionState::kNotEvaluated;
+ conditionTracker.isConditionMet(queryKey, allPredicates, false, conditionCache);
+ EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
+
+ // TEST QUERY
+ const auto queryKey4 = getWakeLockQueryKey(position, uids2, conditionName);
+ conditionCache[0] = ConditionState::kNotEvaluated;
+ conditionTracker.isConditionMet(queryKey, allPredicates, false, conditionCache);
+ EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
+ }
+}
} // namespace statsd
} // namespace os
diff --git a/cmds/statsd/tests/e2e/Anomaly_count_e2e_test.cpp b/cmds/statsd/tests/e2e/Anomaly_count_e2e_test.cpp
index 1eaaf08..e0eebef 100644
--- a/cmds/statsd/tests/e2e/Anomaly_count_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/Anomaly_count_e2e_test.cpp
@@ -53,185 +53,192 @@
} // namespace
-// TODO(b/149590301): Update these tests to use new socket schema.
-//TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_single_bucket) {
-// const int num_buckets = 1;
-// const int threshold = 3;
-// auto config = CreateStatsdConfig(num_buckets, threshold);
-// const uint64_t alert_id = config.alert(0).id();
-// const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
-//
-// int64_t bucketStartTimeNs = 10000000000;
-// int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
-//
-// ConfigKey cfgKey;
-// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-// EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
-//
-// sp<AnomalyTracker> anomalyTracker =
-// processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
-//
-// std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1")};
-// std::vector<AttributionNodeInternal> attributions2 = {
-// CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1")};
-// std::vector<AttributionNodeInternal> attributions3 = {
-// CreateAttribution(111, "App1"), CreateAttribution(333, "App3")};
-// std::vector<AttributionNodeInternal> attributions4 = {
-// CreateAttribution(222, "GMSCoreModule1"), CreateAttribution(333, "App3")};
-// std::vector<AttributionNodeInternal> attributions5 = {
-// CreateAttribution(222, "GMSCoreModule1") };
-//
-// FieldValue fieldValue1(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
-// Value((int32_t)111));
-// HashableDimensionKey whatKey1({fieldValue1});
-// MetricDimensionKey dimensionKey1(whatKey1, DEFAULT_DIMENSION_KEY);
-//
-// FieldValue fieldValue2(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
-// Value((int32_t)222));
-// HashableDimensionKey whatKey2({fieldValue2});
-// MetricDimensionKey dimensionKey2(whatKey2, DEFAULT_DIMENSION_KEY);
-//
-// auto event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 2);
-// processor->OnLogEvent(event.get());
-// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-//
-// event = CreateAcquireWakelockEvent(attributions4, "wl2", bucketStartTimeNs + 2);
-// processor->OnLogEvent(event.get());
-// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
-//
-// event = CreateAcquireWakelockEvent(attributions2, "wl1", bucketStartTimeNs + 3);
-// processor->OnLogEvent(event.get());
-// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-//
-// event = CreateAcquireWakelockEvent(attributions5, "wl2", bucketStartTimeNs + 3);
-// processor->OnLogEvent(event.get());
-// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
-//
-// event = CreateAcquireWakelockEvent(attributions3, "wl1", bucketStartTimeNs + 4);
-// processor->OnLogEvent(event.get());
-// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-//
-// event = CreateAcquireWakelockEvent(attributions5, "wl2", bucketStartTimeNs + 4);
-// processor->OnLogEvent(event.get());
-// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
-//
-// // Fired alarm and refractory period end timestamp updated.
-// event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 5);
-// processor->OnLogEvent(event.get());
-// EXPECT_EQ(refractory_period_sec + bucketStartTimeNs / NS_PER_SEC + 1,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-//
-// event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 100);
-// processor->OnLogEvent(event.get());
-// EXPECT_EQ(refractory_period_sec + bucketStartTimeNs / NS_PER_SEC + 1,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-//
-// event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + bucketSizeNs - 1);
-// processor->OnLogEvent(event.get());
-// EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs - 1) / NS_PER_SEC + 1,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-//
-// event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + bucketSizeNs + 1);
-// processor->OnLogEvent(event.get());
-// EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs - 1) / NS_PER_SEC + 1,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-//
-// event = CreateAcquireWakelockEvent(attributions4, "wl2", bucketStartTimeNs + bucketSizeNs + 1);
-// processor->OnLogEvent(event.get());
-// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
-//
-// event = CreateAcquireWakelockEvent(attributions5, "wl2", bucketStartTimeNs + bucketSizeNs + 2);
-// processor->OnLogEvent(event.get());
-// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
-//
-// event = CreateAcquireWakelockEvent(attributions5, "wl2", bucketStartTimeNs + bucketSizeNs + 3);
-// processor->OnLogEvent(event.get());
-// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
-//
-// event = CreateAcquireWakelockEvent(attributions5, "wl2", bucketStartTimeNs + bucketSizeNs + 4);
-// processor->OnLogEvent(event.get());
-// EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 4) / NS_PER_SEC + 1,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
-//}
-//
-//TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_multiple_buckets) {
-// const int num_buckets = 3;
-// const int threshold = 3;
-// auto config = CreateStatsdConfig(num_buckets, threshold);
-// const uint64_t alert_id = config.alert(0).id();
-// const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
-//
-// int64_t bucketStartTimeNs = 10000000000;
-// int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
-//
-// ConfigKey cfgKey;
-// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-// EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
-//
-// sp<AnomalyTracker> anomalyTracker =
-// processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
-//
-// std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1")};
-// std::vector<AttributionNodeInternal> attributions2 = {
-// CreateAttribution(111, "App1"), CreateAttribution(222, "GMSCoreModule1")};
-// std::vector<AttributionNodeInternal> attributions3 = {
-// CreateAttribution(111, "App1"), CreateAttribution(333, "App3")};
-// std::vector<AttributionNodeInternal> attributions4 = {
-// CreateAttribution(222, "GMSCoreModule1"), CreateAttribution(333, "App3")};
-// std::vector<AttributionNodeInternal> attributions5 = {
-// CreateAttribution(222, "GMSCoreModule1") };
-//
-// FieldValue fieldValue1(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
-// Value((int32_t)111));
-// HashableDimensionKey whatKey1({fieldValue1});
-// MetricDimensionKey dimensionKey1(whatKey1, DEFAULT_DIMENSION_KEY);
-//
-// FieldValue fieldValue2(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
-// Value((int32_t)222));
-// HashableDimensionKey whatKey2({fieldValue2});
-// MetricDimensionKey dimensionKey2(whatKey2, DEFAULT_DIMENSION_KEY);
-//
-// auto event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 2);
-// processor->OnLogEvent(event.get());
-// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-//
-// event = CreateAcquireWakelockEvent(attributions2, "wl1", bucketStartTimeNs + 3);
-// processor->OnLogEvent(event.get());
-// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-//
-// // Fired alarm and refractory period end timestamp updated.
-// event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 4);
-// processor->OnLogEvent(event.get());
-// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-//
-// event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + bucketSizeNs + 1);
-// processor->OnLogEvent(event.get());
-// EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 1) / NS_PER_SEC + 1,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-//
-// event = CreateAcquireWakelockEvent(attributions2, "wl1", bucketStartTimeNs + bucketSizeNs + 2);
-// processor->OnLogEvent(event.get());
-// EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 1) / NS_PER_SEC + 1,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-//
-// event = CreateAcquireWakelockEvent(
-// attributions2, "wl1", bucketStartTimeNs + 3 * bucketSizeNs + 1);
-// processor->OnLogEvent(event.get());
-// EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 1) / NS_PER_SEC + 1,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-//
-// event = CreateAcquireWakelockEvent(
-// attributions2, "wl1", bucketStartTimeNs + 3 * bucketSizeNs + 2);
-// processor->OnLogEvent(event.get());
-// EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + 3 * bucketSizeNs + 2) / NS_PER_SEC + 1,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
-//}
+TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_single_bucket) {
+ const int num_buckets = 1;
+ const int threshold = 3;
+ auto config = CreateStatsdConfig(num_buckets, threshold);
+ const uint64_t alert_id = config.alert(0).id();
+ const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
+
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
+
+ ConfigKey cfgKey;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
+
+ sp<AnomalyTracker> anomalyTracker =
+ processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
+
+ std::vector<int> attributionUids1 = {111};
+ std::vector<string> attributionTags1 = {"App1"};
+ std::vector<int> attributionUids2 = {111, 222};
+ std::vector<string> attributionTags2 = {"App1", "GMSCoreModule1"};
+ std::vector<int> attributionUids3 = {111, 333};
+ std::vector<string> attributionTags3 = {"App1", "App3"};
+ std::vector<int> attributionUids4 = {222, 333};
+ std::vector<string> attributionTags4 = {"GMSCoreModule1", "App3"};
+ std::vector<int> attributionUids5 = {222};
+ std::vector<string> attributionTags5 = {"GMSCoreModule1"};
+
+ FieldValue fieldValue1(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
+ Value((int32_t)111));
+ HashableDimensionKey whatKey1({fieldValue1});
+ MetricDimensionKey dimensionKey1(whatKey1, DEFAULT_DIMENSION_KEY);
+
+ FieldValue fieldValue2(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
+ Value((int32_t)222));
+ HashableDimensionKey whatKey2({fieldValue2});
+ MetricDimensionKey dimensionKey2(whatKey2, DEFAULT_DIMENSION_KEY);
+
+ auto event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2, attributionUids1,
+ attributionTags1, "wl1");
+ processor->OnLogEvent(event.get());
+ EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2, attributionUids4, attributionTags4,
+ "wl2");
+ processor->OnLogEvent(event.get());
+ EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
+
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + 3, attributionUids2, attributionTags2,
+ "wl1");
+ processor->OnLogEvent(event.get());
+ EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + 3, attributionUids5, attributionTags5,
+ "wl2");
+ processor->OnLogEvent(event.get());
+ EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
+
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + 4, attributionUids3, attributionTags3,
+ "wl1");
+ processor->OnLogEvent(event.get());
+ EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + 4, attributionUids5, attributionTags5,
+ "wl2");
+ processor->OnLogEvent(event.get());
+ EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
+
+ // Fired alarm and refractory period end timestamp updated.
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + 5, attributionUids1, attributionTags1,
+ "wl1");
+ processor->OnLogEvent(event.get());
+ EXPECT_EQ(refractory_period_sec + bucketStartTimeNs / NS_PER_SEC + 1,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + 100, attributionUids1, attributionTags1,
+ "wl1");
+ processor->OnLogEvent(event.get());
+ EXPECT_EQ(refractory_period_sec + bucketStartTimeNs / NS_PER_SEC + 1,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 1, attributionUids1,
+ attributionTags1, "wl1");
+ processor->OnLogEvent(event.get());
+ EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs - 1) / NS_PER_SEC + 1,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 1, attributionUids1,
+ attributionTags1, "wl1");
+ processor->OnLogEvent(event.get());
+ EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs - 1) / NS_PER_SEC + 1,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 1, attributionUids4,
+ attributionTags4, "wl2");
+ processor->OnLogEvent(event.get());
+ EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
+
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 2, attributionUids5,
+ attributionTags5, "wl2");
+ processor->OnLogEvent(event.get());
+ EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
+
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 3, attributionUids5,
+ attributionTags5, "wl2");
+ processor->OnLogEvent(event.get());
+ EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
+
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 4, attributionUids5,
+ attributionTags5, "wl2");
+ processor->OnLogEvent(event.get());
+ EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 4) / NS_PER_SEC + 1,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
+}
+
+TEST(AnomalyDetectionE2eTest, TestSlicedCountMetric_multiple_buckets) {
+ const int num_buckets = 3;
+ const int threshold = 3;
+ auto config = CreateStatsdConfig(num_buckets, threshold);
+ const uint64_t alert_id = config.alert(0).id();
+ const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
+
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
+
+ ConfigKey cfgKey;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
+
+ sp<AnomalyTracker> anomalyTracker =
+ processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
+
+ std::vector<int> attributionUids1 = {111};
+ std::vector<string> attributionTags1 = {"App1"};
+ std::vector<int> attributionUids2 = {111, 222};
+ std::vector<string> attributionTags2 = {"App1", "GMSCoreModule1"};
+
+ FieldValue fieldValue1(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
+ Value((int32_t)111));
+ HashableDimensionKey whatKey1({fieldValue1});
+ MetricDimensionKey dimensionKey1(whatKey1, DEFAULT_DIMENSION_KEY);
+
+ auto event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2, attributionUids1,
+ attributionTags1, "wl1");
+ processor->OnLogEvent(event.get());
+ EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + 3, attributionUids2, attributionTags2,
+ "wl1");
+ processor->OnLogEvent(event.get());
+ EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ // Fired alarm and refractory period end timestamp updated.
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + 4, attributionUids1, attributionTags1,
+ "wl1");
+ processor->OnLogEvent(event.get());
+ EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 1, attributionUids1,
+ attributionTags1, "wl1");
+ processor->OnLogEvent(event.get());
+ EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 1) / NS_PER_SEC + 1,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 2, attributionUids2,
+ attributionTags2, "wl1");
+ processor->OnLogEvent(event.get());
+ EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 1) / NS_PER_SEC + 1,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs + 1, attributionUids2,
+ attributionTags2, "wl1");
+ processor->OnLogEvent(event.get());
+ EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + 1) / NS_PER_SEC + 1,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs + 2, attributionUids2,
+ attributionTags2, "wl1");
+ processor->OnLogEvent(event.get());
+ EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + 3 * bucketSizeNs + 2) / NS_PER_SEC + 1,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+}
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
diff --git a/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp b/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp
index 03a209a..fe45b55 100644
--- a/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/Anomaly_duration_sum_e2e_test.cpp
@@ -69,414 +69,432 @@
return config;
}
-} // namespace
+std::vector<int> attributionUids1 = {111, 222};
+std::vector<string> attributionTags1 = {"App1", "GMSCoreModule1"};
-std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1"),
- CreateAttribution(222, "GMSCoreModule1")};
+std::vector<int> attributionUids2 = {111, 222};
+std::vector<string> attributionTags2 = {"App2", "GMSCoreModule1"};
-std::vector<AttributionNodeInternal> attributions2 = {CreateAttribution(111, "App2"),
- CreateAttribution(222, "GMSCoreModule1")};
+std::vector<int> attributionUids3 = {222};
+std::vector<string> attributionTags3 = {"GMSCoreModule1"};
-std::vector<AttributionNodeInternal> attributions3 = {CreateAttribution(222, "GMSCoreModule1")};
-
-MetricDimensionKey dimensionKey(
- HashableDimensionKey({FieldValue(Field(android::util::WAKELOCK_STATE_CHANGED,
- (int32_t)0x02010101), Value((int32_t)111))}),
- DEFAULT_DIMENSION_KEY);
+MetricDimensionKey dimensionKey1(
+ HashableDimensionKey({FieldValue(Field(android::util::WAKELOCK_STATE_CHANGED,
+ (int32_t)0x02010101),
+ Value((int32_t)111))}),
+ DEFAULT_DIMENSION_KEY);
MetricDimensionKey dimensionKey2(
HashableDimensionKey({FieldValue(Field(android::util::WAKELOCK_STATE_CHANGED,
(int32_t)0x02010101), Value((int32_t)222))}),
DEFAULT_DIMENSION_KEY);
-// TODO(b/149590301): Update these tests to use new socket schema.
-//TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket) {
-// const int num_buckets = 1;
-// const uint64_t threshold_ns = NS_PER_SEC;
-// auto config = CreateStatsdConfig(num_buckets, threshold_ns, DurationMetric::SUM, true);
-// const uint64_t alert_id = config.alert(0).id();
-// const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
-//
-// int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
-// int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000;
-//
-// ConfigKey cfgKey;
-// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-// EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
-//
-// sp<AnomalyTracker> anomalyTracker =
-// processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
-//
-// auto screen_on_event = CreateScreenStateChangedEvent(
-// android::view::DisplayStateEnum::DISPLAY_STATE_ON, bucketStartTimeNs + 1);
-// auto screen_off_event = CreateScreenStateChangedEvent(
-// android::view::DisplayStateEnum::DISPLAY_STATE_OFF, bucketStartTimeNs + 10);
-// processor->OnLogEvent(screen_on_event.get());
-// processor->OnLogEvent(screen_off_event.get());
-//
-// // Acquire wakelock wl1.
-// auto acquire_event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 11);
-// processor->OnLogEvent(acquire_event.get());
-// EXPECT_EQ((bucketStartTimeNs + 11 + threshold_ns) / NS_PER_SEC + 1,
-// anomalyTracker->getAlarmTimestampSec(dimensionKey));
-// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-// // Release wakelock wl1. No anomaly detected. Alarm cancelled at the "release" event.
-// auto release_event = CreateReleaseWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 101);
-// processor->OnLogEvent(release_event.get());
-// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-// // Acquire wakelock wl1 within bucket #0.
-// acquire_event = CreateAcquireWakelockEvent(attributions2, "wl1", bucketStartTimeNs + 110);
-// processor->OnLogEvent(acquire_event.get());
-// EXPECT_EQ((bucketStartTimeNs + 110 + threshold_ns - 90) / NS_PER_SEC + 1,
-// anomalyTracker->getAlarmTimestampSec(dimensionKey));
-// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-// // Release wakelock wl1. One anomaly detected.
-// release_event = CreateReleaseWakelockEvent(
-// attributions2, "wl1", bucketStartTimeNs + NS_PER_SEC + 109);
-// processor->OnLogEvent(release_event.get());
-// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-// EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + NS_PER_SEC + 109) / NS_PER_SEC + 1,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-// // Acquire wakelock wl1.
-// acquire_event = CreateAcquireWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + NS_PER_SEC + 112);
-// processor->OnLogEvent(acquire_event.get());
-// // Wakelock has been hold longer than the threshold in bucket #0. The alarm is set at the
-// // end of the refractory period.
-// const int64_t alarmFiredTimestampSec0 = anomalyTracker->getAlarmTimestampSec(dimensionKey);
-// EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + NS_PER_SEC + 109) / NS_PER_SEC + 1,
-// (uint32_t)alarmFiredTimestampSec0);
-//
-// // Anomaly alarm fired.
-// auto alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan(
-// static_cast<uint32_t>(alarmFiredTimestampSec0));
-// EXPECT_EQ(1u, alarmSet.size());
-// processor->onAnomalyAlarmFired(alarmFiredTimestampSec0 * NS_PER_SEC, alarmSet);
-// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-// EXPECT_EQ(refractory_period_sec + alarmFiredTimestampSec0,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-// // Release wakelock wl1.
-// release_event = CreateReleaseWakelockEvent(
-// attributions1, "wl1", alarmFiredTimestampSec0 * NS_PER_SEC + NS_PER_SEC + 1);
-// processor->OnLogEvent(release_event.get());
-// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-// // Within refractory period. No more anomaly detected.
-// EXPECT_EQ(refractory_period_sec + alarmFiredTimestampSec0,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-// // Acquire wakelock wl1.
-// acquire_event = CreateAcquireWakelockEvent(
-// attributions2, "wl1", bucketStartTimeNs + bucketSizeNs - 5 * NS_PER_SEC - 11);
-// processor->OnLogEvent(acquire_event.get());
-// const int64_t alarmFiredTimestampSec1 = anomalyTracker->getAlarmTimestampSec(dimensionKey);
-// EXPECT_EQ((bucketStartTimeNs + bucketSizeNs - 5 * NS_PER_SEC) / NS_PER_SEC,
-// (uint64_t)alarmFiredTimestampSec1);
-//
-// // Release wakelock wl1.
-// release_event = CreateReleaseWakelockEvent(
-// attributions2, "wl1", bucketStartTimeNs + bucketSizeNs - 4 * NS_PER_SEC - 10);
-// processor->OnLogEvent(release_event.get());
-// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-// EXPECT_EQ(refractory_period_sec +
-// (bucketStartTimeNs + bucketSizeNs - 4 * NS_PER_SEC - 10) / NS_PER_SEC + 1,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-// alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan(
-// static_cast<uint32_t>(alarmFiredTimestampSec1));
-// EXPECT_EQ(0u, alarmSet.size());
-//
-// // Acquire wakelock wl1 near the end of bucket #0.
-// acquire_event = CreateAcquireWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + bucketSizeNs - 2);
-// processor->OnLogEvent(acquire_event.get());
-// EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC,
-// anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//
-// // Release the event at early bucket #1.
-// release_event = CreateReleaseWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + bucketSizeNs + NS_PER_SEC - 1);
-// processor->OnLogEvent(release_event.get());
-// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-// // Anomaly detected when stopping the alarm. The refractory period does not change.
-// EXPECT_EQ(refractory_period_sec +
-// (bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-// // Condition changes to false.
-// screen_on_event = CreateScreenStateChangedEvent(
-// android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-// bucketStartTimeNs + 2 * bucketSizeNs + 20);
-// processor->OnLogEvent(screen_on_event.get());
-// EXPECT_EQ(refractory_period_sec +
-// (bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//
-// acquire_event = CreateAcquireWakelockEvent(
-// attributions2, "wl1", bucketStartTimeNs + 2 * bucketSizeNs + 30);
-// processor->OnLogEvent(acquire_event.get());
-// // The condition is false. Do not start the alarm.
-// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-// EXPECT_EQ(refractory_period_sec +
-// (bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-// // Condition turns true.
-// screen_off_event = CreateScreenStateChangedEvent(
-// android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
-// bucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC);
-// processor->OnLogEvent(screen_off_event.get());
-// EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC + threshold_ns) / NS_PER_SEC,
-// anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//
-// // Condition turns to false.
-// screen_on_event = CreateScreenStateChangedEvent(
-// android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-// bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 1);
-// processor->OnLogEvent(screen_on_event.get());
-// // Condition turns to false. Cancelled the alarm.
-// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-// // Detected one anomaly.
-// EXPECT_EQ(refractory_period_sec +
-// (bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 1) / NS_PER_SEC + 1,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-// // Condition turns to true again.
-// screen_off_event = CreateScreenStateChangedEvent(
-// android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
-// bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 2);
-// processor->OnLogEvent(screen_off_event.get());
-// EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2 + 2 + 1,
-// anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//
-// release_event = CreateReleaseWakelockEvent(
-// attributions2, "wl1", bucketStartTimeNs + 2 * bucketSizeNs + 5 * NS_PER_SEC);
-// processor->OnLogEvent(release_event.get());
-// EXPECT_EQ(refractory_period_sec +
-// (bucketStartTimeNs + 2 * bucketSizeNs + 5 * NS_PER_SEC) / NS_PER_SEC,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//}
-//
-//TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_multiple_buckets) {
-// const int num_buckets = 3;
-// const uint64_t threshold_ns = NS_PER_SEC;
-// auto config = CreateStatsdConfig(num_buckets, threshold_ns, DurationMetric::SUM, true);
-// const uint64_t alert_id = config.alert(0).id();
-// const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
-//
-// int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
-// int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000;
-//
-// ConfigKey cfgKey;
-// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-// EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
-//
-// sp<AnomalyTracker> anomalyTracker =
-// processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
-//
-// auto screen_off_event = CreateScreenStateChangedEvent(
-// android::view::DisplayStateEnum::DISPLAY_STATE_OFF, bucketStartTimeNs + 1);
-// processor->OnLogEvent(screen_off_event.get());
-//
-// // Acquire wakelock "wc1" in bucket #0.
-// auto acquire_event = CreateAcquireWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + bucketSizeNs - NS_PER_SEC / 2 - 1);
-// processor->OnLogEvent(acquire_event.get());
-// EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 1,
-// anomalyTracker->getAlarmTimestampSec(dimensionKey));
-// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-// // Release wakelock "wc1" in bucket #0.
-// auto release_event = CreateReleaseWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + bucketSizeNs - 1);
-// processor->OnLogEvent(release_event.get());
-// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-// // Acquire wakelock "wc1" in bucket #1.
-// acquire_event = CreateAcquireWakelockEvent(
-// attributions2, "wl1", bucketStartTimeNs + bucketSizeNs + 1);
-// processor->OnLogEvent(acquire_event.get());
-// EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 1,
-// anomalyTracker->getAlarmTimestampSec(dimensionKey));
-// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-// release_event = CreateReleaseWakelockEvent(
-// attributions2, "wl1", bucketStartTimeNs + bucketSizeNs + 100);
-// processor->OnLogEvent(release_event.get());
-// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-// // Acquire wakelock "wc2" in bucket #2.
-// acquire_event = CreateAcquireWakelockEvent(
-// attributions3, "wl2", bucketStartTimeNs + 2 * bucketSizeNs + 1);
-// processor->OnLogEvent(acquire_event.get());
-// EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2,
-// anomalyTracker->getAlarmTimestampSec(dimensionKey2));
-// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
-//
-// // Release wakelock "wc2" in bucket #2.
-// release_event = CreateReleaseWakelockEvent(
-// attributions3, "wl2", bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC);
-// processor->OnLogEvent(release_event.get());
-// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey2));
-// EXPECT_EQ(refractory_period_sec +
-// (bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC) / NS_PER_SEC,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
-//
-// // Acquire wakelock "wc1" in bucket #2.
-// acquire_event = CreateAcquireWakelockEvent(
-// attributions2, "wl1", bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC);
-// processor->OnLogEvent(acquire_event.get());
-// EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2 + 1,
-// anomalyTracker->getAlarmTimestampSec(dimensionKey));
-// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-// // Release wakelock "wc1" in bucket #2.
-// release_event = CreateReleaseWakelockEvent(
-// attributions2, "wl1", bucketStartTimeNs + 2 * bucketSizeNs + 2.5 * NS_PER_SEC);
-// processor->OnLogEvent(release_event.get());
-// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-// EXPECT_EQ(refractory_period_sec +
-// (int64_t)(bucketStartTimeNs + 2 * bucketSizeNs + 2.5 * NS_PER_SEC) / NS_PER_SEC + 1,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-// acquire_event = CreateAcquireWakelockEvent(
-// attributions3, "wl2", bucketStartTimeNs + 6 * bucketSizeNs - NS_PER_SEC + 4);
-// processor->OnLogEvent(acquire_event.get());
-// acquire_event = CreateAcquireWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + 6 * bucketSizeNs - NS_PER_SEC + 5);
-// processor->OnLogEvent(acquire_event.get());
-// EXPECT_EQ((bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 1,
-// anomalyTracker->getAlarmTimestampSec(dimensionKey));
-// EXPECT_EQ((bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 1,
-// anomalyTracker->getAlarmTimestampSec(dimensionKey2));
-//
-// release_event = CreateReleaseWakelockEvent(
-// attributions3, "wl2", bucketStartTimeNs + 6 * bucketSizeNs + 2);
-// processor->OnLogEvent(release_event.get());
-// release_event = CreateReleaseWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + 6 * bucketSizeNs + 6);
-// processor->OnLogEvent(release_event.get());
-// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey2));
-// // The buckets are not messed up across dimensions. Only one dimension has anomaly triggered.
-// EXPECT_EQ(refractory_period_sec +
-// (int64_t)(bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 1,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//}
-//
-//TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_long_refractory_period) {
-// const int num_buckets = 2;
-// const uint64_t threshold_ns = 3 * NS_PER_SEC;
-// auto config = CreateStatsdConfig(num_buckets, threshold_ns, DurationMetric::SUM, false);
-// int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
-// int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000;
-//
-// const uint64_t alert_id = config.alert(0).id();
-// const uint32_t refractory_period_sec = 3 * bucketSizeNs / NS_PER_SEC;
-// config.mutable_alert(0)->set_refractory_period_secs(refractory_period_sec);
-//
-// ConfigKey cfgKey;
-// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-// EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
-//
-// sp<AnomalyTracker> anomalyTracker =
-// processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
-//
-// auto screen_off_event = CreateScreenStateChangedEvent(
-// android::view::DisplayStateEnum::DISPLAY_STATE_OFF, bucketStartTimeNs + 1);
-// processor->OnLogEvent(screen_off_event.get());
-//
-// // Acquire wakelock "wc1" in bucket #0.
-// auto acquire_event = CreateAcquireWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + bucketSizeNs - 100);
-// processor->OnLogEvent(acquire_event.get());
-// EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3,
-// anomalyTracker->getAlarmTimestampSec(dimensionKey));
-// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-// // Acquire the wakelock "wc1" again.
-// acquire_event = CreateAcquireWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + bucketSizeNs + 2 * NS_PER_SEC + 1);
-// processor->OnLogEvent(acquire_event.get());
-// // The alarm does not change.
-// EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3,
-// anomalyTracker->getAlarmTimestampSec(dimensionKey));
-// EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-// // Anomaly alarm fired late.
-// const int64_t firedAlarmTimestampNs = bucketStartTimeNs + 2 * bucketSizeNs - NS_PER_SEC;
-// auto alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan(
-// static_cast<uint32_t>(firedAlarmTimestampNs / NS_PER_SEC));
-// EXPECT_EQ(1u, alarmSet.size());
-// processor->onAnomalyAlarmFired(firedAlarmTimestampNs, alarmSet);
-// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-// EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-// acquire_event = CreateAcquireWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + 2 * bucketSizeNs - 100);
-// processor->OnLogEvent(acquire_event.get());
-// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-// EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-// auto release_event = CreateReleaseWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + 2 * bucketSizeNs + 1);
-// processor->OnLogEvent(release_event.get());
-// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-// // Within the refractory period. No anomaly.
-// EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-// // A new wakelock, but still within refractory period.
-// acquire_event = CreateAcquireWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + 2 * bucketSizeNs + 10 * NS_PER_SEC);
-// processor->OnLogEvent(acquire_event.get());
-// EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
-// anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//
-// release_event = CreateReleaseWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + 3 * bucketSizeNs - NS_PER_SEC);
-// // Still in the refractory period. No anomaly.
-// processor->OnLogEvent(release_event.get());
-// EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
-// anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey));
-//
-// acquire_event = CreateAcquireWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 5);
-// processor->OnLogEvent(acquire_event.get());
-// EXPECT_EQ((bucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC,
-// anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//
-// release_event = CreateReleaseWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 4);
-// processor->OnLogEvent(release_event.get());
-// EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//
-// acquire_event = CreateAcquireWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 3);
-// processor->OnLogEvent(acquire_event.get());
-// EXPECT_EQ((bucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC,
-// anomalyTracker->getAlarmTimestampSec(dimensionKey));
-//}
+} // namespace
+
+TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_single_bucket) {
+ const int num_buckets = 1;
+ const uint64_t threshold_ns = NS_PER_SEC;
+ auto config = CreateStatsdConfig(num_buckets, threshold_ns, DurationMetric::SUM, true);
+ const uint64_t alert_id = config.alert(0).id();
+ const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
+
+ int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
+ int64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000;
+
+ ConfigKey cfgKey;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
+
+ sp<AnomalyTracker> anomalyTracker =
+ processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
+
+ auto screen_on_event = CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 1, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
+ auto screen_off_event = CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 10, android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
+ processor->OnLogEvent(screen_on_event.get());
+ processor->OnLogEvent(screen_off_event.get());
+
+ // Acquire wakelock wl1.
+ auto acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + 11, attributionUids1,
+ attributionTags1, "wl1");
+ processor->OnLogEvent(acquire_event.get());
+ EXPECT_EQ((bucketStartTimeNs + 11 + threshold_ns) / NS_PER_SEC + 1,
+ anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+ EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ // Release wakelock wl1. No anomaly detected. Alarm cancelled at the "release" event.
+ auto release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 101, attributionUids1,
+ attributionTags1, "wl1");
+ processor->OnLogEvent(release_event.get());
+ EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+ EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ // Acquire wakelock wl1 within bucket #0.
+ acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + 110, attributionUids2,
+ attributionTags2, "wl1");
+ processor->OnLogEvent(acquire_event.get());
+ EXPECT_EQ((bucketStartTimeNs + 110 + threshold_ns - 90) / NS_PER_SEC + 1,
+ anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+ EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ // Release wakelock wl1. One anomaly detected.
+ release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + NS_PER_SEC + 109,
+ attributionUids2, attributionTags2, "wl1");
+ processor->OnLogEvent(release_event.get());
+ EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+ EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + NS_PER_SEC + 109) / NS_PER_SEC + 1,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ // Acquire wakelock wl1.
+ acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + NS_PER_SEC + 112,
+ attributionUids1, attributionTags1, "wl1");
+ processor->OnLogEvent(acquire_event.get());
+ // Wakelock has been hold longer than the threshold in bucket #0. The alarm is set at the
+ // end of the refractory period.
+ const int64_t alarmFiredTimestampSec0 = anomalyTracker->getAlarmTimestampSec(dimensionKey1);
+ EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + NS_PER_SEC + 109) / NS_PER_SEC + 1,
+ (uint32_t)alarmFiredTimestampSec0);
+
+ // Anomaly alarm fired.
+ auto alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan(
+ static_cast<uint32_t>(alarmFiredTimestampSec0));
+ EXPECT_EQ(1u, alarmSet.size());
+ processor->onAnomalyAlarmFired(alarmFiredTimestampSec0 * NS_PER_SEC, alarmSet);
+ EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+ EXPECT_EQ(refractory_period_sec + alarmFiredTimestampSec0,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ // Release wakelock wl1.
+ release_event =
+ CreateReleaseWakelockEvent(alarmFiredTimestampSec0 * NS_PER_SEC + NS_PER_SEC + 1,
+ attributionUids1, attributionTags1, "wl1");
+ processor->OnLogEvent(release_event.get());
+ EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+ // Within refractory period. No more anomaly detected.
+ EXPECT_EQ(refractory_period_sec + alarmFiredTimestampSec0,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ // Acquire wakelock wl1.
+ acquire_event =
+ CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 5 * NS_PER_SEC - 11,
+ attributionUids2, attributionTags2, "wl1");
+ processor->OnLogEvent(acquire_event.get());
+ const int64_t alarmFiredTimestampSec1 = anomalyTracker->getAlarmTimestampSec(dimensionKey1);
+ EXPECT_EQ((bucketStartTimeNs + bucketSizeNs - 5 * NS_PER_SEC) / NS_PER_SEC,
+ (uint64_t)alarmFiredTimestampSec1);
+
+ // Release wakelock wl1.
+ release_event =
+ CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs - 4 * NS_PER_SEC - 10,
+ attributionUids2, attributionTags2, "wl1");
+ processor->OnLogEvent(release_event.get());
+ EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+ EXPECT_EQ(refractory_period_sec +
+ (bucketStartTimeNs + bucketSizeNs - 4 * NS_PER_SEC - 10) / NS_PER_SEC + 1,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan(
+ static_cast<uint32_t>(alarmFiredTimestampSec1));
+ EXPECT_EQ(0u, alarmSet.size());
+
+ // Acquire wakelock wl1 near the end of bucket #0.
+ acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 2,
+ attributionUids1, attributionTags1, "wl1");
+ processor->OnLogEvent(acquire_event.get());
+ EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC,
+ anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+
+ // Release the event at early bucket #1.
+ release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs + NS_PER_SEC - 1,
+ attributionUids1, attributionTags1, "wl1");
+ processor->OnLogEvent(release_event.get());
+ EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+ // Anomaly detected when stopping the alarm. The refractory period does not change.
+ EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ // Condition changes to false.
+ screen_on_event =
+ CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs + 20,
+ android::view::DisplayStateEnum::DISPLAY_STATE_ON);
+ processor->OnLogEvent(screen_on_event.get());
+ EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+ EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+
+ acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 30,
+ attributionUids2, attributionTags2, "wl1");
+ processor->OnLogEvent(acquire_event.get());
+ // The condition is false. Do not start the alarm.
+ EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+ EXPECT_EQ(refractory_period_sec + (bucketStartTimeNs + bucketSizeNs + NS_PER_SEC) / NS_PER_SEC,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ // Condition turns true.
+ screen_off_event =
+ CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC,
+ android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
+ processor->OnLogEvent(screen_off_event.get());
+ EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs + NS_PER_SEC + threshold_ns) / NS_PER_SEC,
+ anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+
+ // Condition turns to false.
+ screen_on_event =
+ CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 1,
+ android::view::DisplayStateEnum::DISPLAY_STATE_ON);
+ processor->OnLogEvent(screen_on_event.get());
+ // Condition turns to false. Cancelled the alarm.
+ EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+ // Detected one anomaly.
+ EXPECT_EQ(refractory_period_sec +
+ (bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 1) / NS_PER_SEC + 1,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ // Condition turns to true again.
+ screen_off_event =
+ CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC + 2,
+ android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
+ processor->OnLogEvent(screen_off_event.get());
+ EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2 + 2 + 1,
+ anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+
+ release_event =
+ CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 5 * NS_PER_SEC,
+ attributionUids2, attributionTags2, "wl1");
+ processor->OnLogEvent(release_event.get());
+ EXPECT_EQ(refractory_period_sec +
+ (bucketStartTimeNs + 2 * bucketSizeNs + 5 * NS_PER_SEC) / NS_PER_SEC,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+ EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+}
+
+TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_multiple_buckets) {
+ const int num_buckets = 3;
+ const uint64_t threshold_ns = NS_PER_SEC;
+ auto config = CreateStatsdConfig(num_buckets, threshold_ns, DurationMetric::SUM, true);
+ const uint64_t alert_id = config.alert(0).id();
+ const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
+
+ int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
+ int64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000;
+
+ ConfigKey cfgKey;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
+
+ sp<AnomalyTracker> anomalyTracker =
+ processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
+
+ auto screen_off_event = CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 1, android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
+ processor->OnLogEvent(screen_off_event.get());
+
+ // Acquire wakelock "wc1" in bucket #0.
+ auto acquire_event =
+ CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - NS_PER_SEC / 2 - 1,
+ attributionUids1, attributionTags1, "wl1");
+ processor->OnLogEvent(acquire_event.get());
+ EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 1,
+ anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+ EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ // Release wakelock "wc1" in bucket #0.
+ auto release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs - 1,
+ attributionUids1, attributionTags1, "wl1");
+ processor->OnLogEvent(release_event.get());
+ EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+ EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ // Acquire wakelock "wc1" in bucket #1.
+ acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 1,
+ attributionUids2, attributionTags2, "wl1");
+ processor->OnLogEvent(acquire_event.get());
+ EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 1,
+ anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+ EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs + 100,
+ attributionUids2, attributionTags2, "wl1");
+ processor->OnLogEvent(release_event.get());
+ EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+ EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ // Acquire wakelock "wc2" in bucket #2.
+ acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 1,
+ attributionUids3, attributionTags3, "wl2");
+ processor->OnLogEvent(acquire_event.get());
+ EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2,
+ anomalyTracker->getAlarmTimestampSec(dimensionKey2));
+ EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
+
+ // Release wakelock "wc2" in bucket #2.
+ release_event =
+ CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC,
+ attributionUids3, attributionTags3, "wl2");
+ processor->OnLogEvent(release_event.get());
+ EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey2));
+ EXPECT_EQ(refractory_period_sec +
+ (bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC) / NS_PER_SEC,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey2));
+
+ // Acquire wakelock "wc1" in bucket #2.
+ acquire_event =
+ CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2 * NS_PER_SEC,
+ attributionUids2, attributionTags2, "wl1");
+ processor->OnLogEvent(acquire_event.get());
+ EXPECT_EQ((bucketStartTimeNs + 2 * bucketSizeNs) / NS_PER_SEC + 2 + 1,
+ anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+ EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ // Release wakelock "wc1" in bucket #2.
+ release_event =
+ CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 2.5 * NS_PER_SEC,
+ attributionUids2, attributionTags2, "wl1");
+ processor->OnLogEvent(release_event.get());
+ EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+ EXPECT_EQ(refractory_period_sec +
+ (int64_t)(bucketStartTimeNs + 2 * bucketSizeNs + 2.5 * NS_PER_SEC) /
+ NS_PER_SEC +
+ 1,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ acquire_event =
+ CreateAcquireWakelockEvent(bucketStartTimeNs + 6 * bucketSizeNs - NS_PER_SEC + 4,
+ attributionUids3, attributionTags3, "wl2");
+ processor->OnLogEvent(acquire_event.get());
+ acquire_event =
+ CreateAcquireWakelockEvent(bucketStartTimeNs + 6 * bucketSizeNs - NS_PER_SEC + 5,
+ attributionUids1, attributionTags1, "wl1");
+ processor->OnLogEvent(acquire_event.get());
+ EXPECT_EQ((bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 1,
+ anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+ EXPECT_EQ((bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC + 1,
+ anomalyTracker->getAlarmTimestampSec(dimensionKey2));
+
+ release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 6 * bucketSizeNs + 2,
+ attributionUids3, attributionTags3, "wl2");
+ processor->OnLogEvent(release_event.get());
+ release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 6 * bucketSizeNs + 6,
+ attributionUids1, attributionTags1, "wl1");
+ processor->OnLogEvent(release_event.get());
+ EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+ EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey2));
+ // The buckets are not messed up across dimensions. Only one dimension has anomaly triggered.
+ EXPECT_EQ(refractory_period_sec + (int64_t)(bucketStartTimeNs + 6 * bucketSizeNs) / NS_PER_SEC +
+ 1,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+}
+
+TEST(AnomalyDetectionE2eTest, TestDurationMetric_SUM_long_refractory_period) {
+ const int num_buckets = 2;
+ const uint64_t threshold_ns = 3 * NS_PER_SEC;
+ auto config = CreateStatsdConfig(num_buckets, threshold_ns, DurationMetric::SUM, false);
+ int64_t bucketStartTimeNs = 10 * NS_PER_SEC;
+ int64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000;
+
+ const uint64_t alert_id = config.alert(0).id();
+ const uint32_t refractory_period_sec = 3 * bucketSizeNs / NS_PER_SEC;
+ config.mutable_alert(0)->set_refractory_period_secs(refractory_period_sec);
+
+ ConfigKey cfgKey;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ EXPECT_EQ(1u, processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers.size());
+
+ sp<AnomalyTracker> anomalyTracker =
+ processor->mMetricsManagers.begin()->second->mAllAnomalyTrackers[0];
+
+ auto screen_off_event = CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 1, android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
+ processor->OnLogEvent(screen_off_event.get());
+
+ // Acquire wakelock "wc1" in bucket #0.
+ auto acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 100,
+ attributionUids1, attributionTags1, "wl1");
+ processor->OnLogEvent(acquire_event.get());
+ EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3,
+ anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+ EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ // Acquire the wakelock "wc1" again.
+ acquire_event =
+ CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 2 * NS_PER_SEC + 1,
+ attributionUids1, attributionTags1, "wl1");
+ processor->OnLogEvent(acquire_event.get());
+ // The alarm does not change.
+ EXPECT_EQ((bucketStartTimeNs + bucketSizeNs) / NS_PER_SEC + 3,
+ anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+ EXPECT_EQ(0u, anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ // Anomaly alarm fired late.
+ const int64_t firedAlarmTimestampNs = bucketStartTimeNs + 2 * bucketSizeNs - NS_PER_SEC;
+ auto alarmSet = processor->getAnomalyAlarmMonitor()->popSoonerThan(
+ static_cast<uint32_t>(firedAlarmTimestampNs / NS_PER_SEC));
+ EXPECT_EQ(1u, alarmSet.size());
+ processor->onAnomalyAlarmFired(firedAlarmTimestampNs, alarmSet);
+ EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+ EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ acquire_event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs - 100,
+ attributionUids1, attributionTags1, "wl1");
+ processor->OnLogEvent(acquire_event.get());
+ EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+ EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ auto release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 1,
+ attributionUids1, attributionTags1, "wl1");
+ processor->OnLogEvent(release_event.get());
+ EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+ // Within the refractory period. No anomaly.
+ EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ // A new wakelock, but still within refractory period.
+ acquire_event =
+ CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 10 * NS_PER_SEC,
+ attributionUids1, attributionTags1, "wl1");
+ processor->OnLogEvent(acquire_event.get());
+ EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
+ anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+
+ release_event = CreateReleaseWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs - NS_PER_SEC,
+ attributionUids1, attributionTags1, "wl1");
+ // Still in the refractory period. No anomaly.
+ processor->OnLogEvent(release_event.get());
+ EXPECT_EQ(refractory_period_sec + firedAlarmTimestampNs / NS_PER_SEC,
+ anomalyTracker->getRefractoryPeriodEndsSec(dimensionKey1));
+
+ acquire_event =
+ CreateAcquireWakelockEvent(bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 5,
+ attributionUids1, attributionTags1, "wl1");
+ processor->OnLogEvent(acquire_event.get());
+ EXPECT_EQ((bucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC,
+ anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+
+ release_event =
+ CreateReleaseWakelockEvent(bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 4,
+ attributionUids1, attributionTags1, "wl1");
+ processor->OnLogEvent(release_event.get());
+ EXPECT_EQ(0u, anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+
+ acquire_event =
+ CreateAcquireWakelockEvent(bucketStartTimeNs + 5 * bucketSizeNs - 3 * NS_PER_SEC - 3,
+ attributionUids1, attributionTags1, "wl1");
+ processor->OnLogEvent(acquire_event.get());
+ EXPECT_EQ((bucketStartTimeNs + 5 * bucketSizeNs) / NS_PER_SEC,
+ anomalyTracker->getAlarmTimestampSec(dimensionKey1));
+}
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
diff --git a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
index 6051174..9e743f7 100644
--- a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
@@ -53,367 +53,318 @@
return config;
}
+// GMS core node is in the middle.
+std::vector<int> attributionUids1 = {111, 222, 333};
+std::vector<string> attributionTags1 = {"App1", "GMSCoreModule1", "App3"};
+
+// GMS core node is the last one.
+std::vector<int> attributionUids2 = {111, 333, 222};
+std::vector<string> attributionTags2 = {"App1", "App3", "GMSCoreModule1"};
+
+// GMS core node is the first one.
+std::vector<int> attributionUids3 = {222, 333};
+std::vector<string> attributionTags3 = {"GMSCoreModule1", "App3"};
+
+// Single GMS core node.
+std::vector<int> attributionUids4 = {222};
+std::vector<string> attributionTags4 = {"GMSCoreModule1"};
+
+// GMS core has another uid.
+std::vector<int> attributionUids5 = {111, 444, 333};
+std::vector<string> attributionTags5 = {"App1", "GMSCoreModule2", "App3"};
+
+// Multiple GMS core nodes.
+std::vector<int> attributionUids6 = {444, 222};
+std::vector<string> attributionTags6 = {"GMSCoreModule2", "GMSCoreModule1"};
+
+// No GMS core nodes
+std::vector<int> attributionUids7 = {111, 333};
+std::vector<string> attributionTags7 = {"App1", "App3"};
+
+std::vector<int> attributionUids8 = {111};
+std::vector<string> attributionTags8 = {"App1"};
+
+// GMS core node with isolated uid.
+const int isolatedUid = 666;
+std::vector<int> attributionUids9 = {isolatedUid};
+std::vector<string> attributionTags9 = {"GMSCoreModule3"};
+
+std::vector<int> attributionUids10 = {isolatedUid};
+std::vector<string> attributionTags10 = {"GMSCoreModule1"};
+
} // namespace
-// TODO(b/149590301): Update these tests to use new socket schema.
-//TEST(AttributionE2eTest, TestAttributionMatchAndSliceByFirstUid) {
-// auto config = CreateStatsdConfig(Position::FIRST);
-// int64_t bucketStartTimeNs = 10000000000;
-// int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
-//
-// ConfigKey cfgKey;
-// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-//
-// // Here it assumes that GMS core has two uids.
-// processor->getUidMap()->updateMap(
-// 1, {222, 444, 111, 333}, {1, 1, 2, 2},
-// {String16("v1"), String16("v1"), String16("v2"), String16("v2")},
-// {String16("com.android.gmscore"), String16("com.android.gmscore"), String16("app1"),
-// String16("APP3")},
-// {String16(""), String16(""), String16(""), String16("")});
-//
-// // GMS core node is in the middle.
-// std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1"),
-// CreateAttribution(222, "GMSCoreModule1"),
-// CreateAttribution(333, "App3")};
-//
-// // GMS core node is the last one.
-// std::vector<AttributionNodeInternal> attributions2 = {CreateAttribution(111, "App1"),
-// CreateAttribution(333, "App3"),
-// CreateAttribution(222, "GMSCoreModule1")};
-//
-// // GMS core node is the first one.
-// std::vector<AttributionNodeInternal> attributions3 = {CreateAttribution(222, "GMSCoreModule1"),
-// CreateAttribution(333, "App3")};
-//
-// // Single GMS core node.
-// std::vector<AttributionNodeInternal> attributions4 = {CreateAttribution(222, "GMSCoreModule1")};
-//
-// // GMS core has another uid.
-// std::vector<AttributionNodeInternal> attributions5 = {CreateAttribution(111, "App1"),
-// CreateAttribution(444, "GMSCoreModule2"),
-// CreateAttribution(333, "App3")};
-//
-// // Multiple GMS core nodes.
-// std::vector<AttributionNodeInternal> attributions6 = {CreateAttribution(444, "GMSCoreModule2"),
-// CreateAttribution(222, "GMSCoreModule1")};
-//
-// // No GMS core nodes.
-// std::vector<AttributionNodeInternal> attributions7 = {CreateAttribution(111, "App1"),
-// CreateAttribution(333, "App3")};
-// std::vector<AttributionNodeInternal> attributions8 = {CreateAttribution(111, "App1")};
-//
-// // GMS core node with isolated uid.
-// const int isolatedUid = 666;
-// std::vector<AttributionNodeInternal> attributions9 = {
-// CreateAttribution(isolatedUid, "GMSCoreModule3")};
-//
-// std::vector<std::unique_ptr<LogEvent>> events;
-// // Events 1~4 are in the 1st bucket.
-// events.push_back(CreateAcquireWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + 2));
-// events.push_back(CreateAcquireWakelockEvent(
-// attributions2, "wl1", bucketStartTimeNs + 200));
-// events.push_back(CreateAcquireWakelockEvent(
-// attributions3, "wl1", bucketStartTimeNs + bucketSizeNs - 1));
-// events.push_back(CreateAcquireWakelockEvent(
-// attributions4, "wl1", bucketStartTimeNs + bucketSizeNs));
-//
-// // Events 5~8 are in the 3rd bucket.
-// events.push_back(CreateAcquireWakelockEvent(
-// attributions5, "wl2", bucketStartTimeNs + 2 * bucketSizeNs + 1));
-// events.push_back(CreateAcquireWakelockEvent(
-// attributions6, "wl2", bucketStartTimeNs + 2 * bucketSizeNs + 100));
-// events.push_back(CreateAcquireWakelockEvent(
-// attributions7, "wl2", bucketStartTimeNs + 3 * bucketSizeNs - 2));
-// events.push_back(CreateAcquireWakelockEvent(
-// attributions8, "wl2", bucketStartTimeNs + 3 * bucketSizeNs));
-// events.push_back(CreateAcquireWakelockEvent(
-// attributions9, "wl2", bucketStartTimeNs + 3 * bucketSizeNs + 1));
-// events.push_back(CreateAcquireWakelockEvent(
-// attributions9, "wl2", bucketStartTimeNs + 3 * bucketSizeNs + 100));
-// events.push_back(CreateIsolatedUidChangedEvent(
-// isolatedUid, 222, true/* is_create*/, bucketStartTimeNs + 3 * bucketSizeNs - 1));
-// events.push_back(CreateIsolatedUidChangedEvent(
-// isolatedUid, 222, false/* is_create*/, bucketStartTimeNs + 3 * bucketSizeNs + 10));
-//
-// sortLogEventsByTimestamp(&events);
-//
-// for (const auto& event : events) {
-// processor->OnLogEvent(event.get());
-// }
-// ConfigMetricsReportList reports;
-// vector<uint8_t> buffer;
-// processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(reports.reports_size(), 1);
-// EXPECT_EQ(reports.reports(0).metrics_size(), 1);
-//
-// StatsLogReport::CountMetricDataWrapper countMetrics;
-// sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
-// EXPECT_EQ(countMetrics.data_size(), 4);
-//
-// auto data = countMetrics.data(0);
-// ValidateAttributionUidAndTagDimension(
-// data.dimensions_in_what(), android::util::WAKELOCK_STATE_CHANGED, 111,
-// "App1");
-// EXPECT_EQ(data.bucket_info_size(), 2);
-// EXPECT_EQ(data.bucket_info(0).count(), 2);
-// EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
-// EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
-// EXPECT_EQ(data.bucket_info(1).count(), 1);
-// EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
-// EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 3 * bucketSizeNs);
-//
-// data = countMetrics.data(1);
-// ValidateAttributionUidAndTagDimension(
-// data.dimensions_in_what(), android::util::WAKELOCK_STATE_CHANGED, 222,
-// "GMSCoreModule1");
-// EXPECT_EQ(data.bucket_info_size(), 2);
-// EXPECT_EQ(data.bucket_info(0).count(), 1);
-// EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
-// EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
-// EXPECT_EQ(data.bucket_info(1).count(), 1);
-// EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
-// EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
-//
-// data = countMetrics.data(2);
-// ValidateAttributionUidAndTagDimension(
-// data.dimensions_in_what(), android::util::WAKELOCK_STATE_CHANGED, 222,
-// "GMSCoreModule3");
-// EXPECT_EQ(data.bucket_info_size(), 1);
-// EXPECT_EQ(data.bucket_info(0).count(), 1);
-// EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs + 3 * bucketSizeNs);
-// EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + 4 * bucketSizeNs);
-//
-// data = countMetrics.data(3);
-// ValidateAttributionUidAndTagDimension(
-// data.dimensions_in_what(), android::util::WAKELOCK_STATE_CHANGED, 444,
-// "GMSCoreModule2");
-// EXPECT_EQ(data.bucket_info_size(), 1);
-// EXPECT_EQ(data.bucket_info(0).count(), 1);
-// EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
-// EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + 3 * bucketSizeNs);
-//}
-//
-//TEST(AttributionE2eTest, TestAttributionMatchAndSliceByChain) {
-// auto config = CreateStatsdConfig(Position::ALL);
-// int64_t bucketStartTimeNs = 10000000000;
-// int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
-//
-// ConfigKey cfgKey;
-// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-//
-// // Here it assumes that GMS core has two uids.
-// processor->getUidMap()->updateMap(
-// 1, {222, 444, 111, 333}, {1, 1, 2, 2},
-// {String16("v1"), String16("v1"), String16("v2"), String16("v2")},
-// {String16("com.android.gmscore"), String16("com.android.gmscore"), String16("app1"),
-// String16("APP3")},
-// {String16(""), String16(""), String16(""), String16("")});
-//
-// // GMS core node is in the middle.
-// std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1"),
-// CreateAttribution(222, "GMSCoreModule1"),
-// CreateAttribution(333, "App3")};
-//
-// // GMS core node is the last one.
-// std::vector<AttributionNodeInternal> attributions2 = {CreateAttribution(111, "App1"),
-// CreateAttribution(333, "App3"),
-// CreateAttribution(222, "GMSCoreModule1")};
-//
-// // GMS core node is the first one.
-// std::vector<AttributionNodeInternal> attributions3 = {CreateAttribution(222, "GMSCoreModule1"),
-// CreateAttribution(333, "App3")};
-//
-// // Single GMS core node.
-// std::vector<AttributionNodeInternal> attributions4 = {CreateAttribution(222, "GMSCoreModule1")};
-//
-// // GMS core has another uid.
-// std::vector<AttributionNodeInternal> attributions5 = {CreateAttribution(111, "App1"),
-// CreateAttribution(444, "GMSCoreModule2"),
-// CreateAttribution(333, "App3")};
-//
-// // Multiple GMS core nodes.
-// std::vector<AttributionNodeInternal> attributions6 = {CreateAttribution(444, "GMSCoreModule2"),
-// CreateAttribution(222, "GMSCoreModule1")};
-//
-// // No GMS core nodes.
-// std::vector<AttributionNodeInternal> attributions7 = {CreateAttribution(111, "App1"),
-// CreateAttribution(333, "App3")};
-// std::vector<AttributionNodeInternal> attributions8 = {CreateAttribution(111, "App1")};
-//
-// // GMS core node with isolated uid.
-// const int isolatedUid = 666;
-// std::vector<AttributionNodeInternal> attributions9 = {
-// CreateAttribution(isolatedUid, "GMSCoreModule1")};
-//
-// std::vector<std::unique_ptr<LogEvent>> events;
-// // Events 1~4 are in the 1st bucket.
-// events.push_back(CreateAcquireWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + 2));
-// events.push_back(CreateAcquireWakelockEvent(
-// attributions2, "wl1", bucketStartTimeNs + 200));
-// events.push_back(CreateAcquireWakelockEvent(
-// attributions3, "wl1", bucketStartTimeNs + bucketSizeNs - 1));
-// events.push_back(CreateAcquireWakelockEvent(
-// attributions4, "wl1", bucketStartTimeNs + bucketSizeNs));
-//
-// // Events 5~8 are in the 3rd bucket.
-// events.push_back(CreateAcquireWakelockEvent(
-// attributions5, "wl2", bucketStartTimeNs + 2 * bucketSizeNs + 1));
-// events.push_back(CreateAcquireWakelockEvent(
-// attributions6, "wl2", bucketStartTimeNs + 2 * bucketSizeNs + 100));
-// events.push_back(CreateAcquireWakelockEvent(
-// attributions7, "wl2", bucketStartTimeNs + 3 * bucketSizeNs - 2));
-// events.push_back(CreateAcquireWakelockEvent(
-// attributions8, "wl2", bucketStartTimeNs + 3 * bucketSizeNs));
-// events.push_back(CreateAcquireWakelockEvent(
-// attributions9, "wl2", bucketStartTimeNs + 3 * bucketSizeNs + 1));
-// events.push_back(CreateAcquireWakelockEvent(
-// attributions9, "wl2", bucketStartTimeNs + 3 * bucketSizeNs + 100));
-// events.push_back(CreateIsolatedUidChangedEvent(
-// isolatedUid, 222, true/* is_create*/, bucketStartTimeNs + 3 * bucketSizeNs - 1));
-// events.push_back(CreateIsolatedUidChangedEvent(
-// isolatedUid, 222, false/* is_create*/, bucketStartTimeNs + 3 * bucketSizeNs + 10));
-//
-// sortLogEventsByTimestamp(&events);
-//
-// for (const auto& event : events) {
-// processor->OnLogEvent(event.get());
-// }
-// ConfigMetricsReportList reports;
-// vector<uint8_t> buffer;
-// processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(reports.reports_size(), 1);
-// EXPECT_EQ(reports.reports(0).metrics_size(), 1);
-//
-// StatsLogReport::CountMetricDataWrapper countMetrics;
-// sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
-// EXPECT_EQ(countMetrics.data_size(), 6);
-//
-// auto data = countMetrics.data(0);
-// ValidateAttributionUidAndTagDimension(
-// data.dimensions_in_what(), android::util::WAKELOCK_STATE_CHANGED, 222, "GMSCoreModule1");
-// EXPECT_EQ(2, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
-// data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-// data.bucket_info(0).end_bucket_elapsed_nanos());
-// EXPECT_EQ(1, data.bucket_info(1).count());
-// EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
-// data.bucket_info(1).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + 4 * bucketSizeNs,
-// data.bucket_info(1).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(1);
-// ValidateUidDimension(
-// data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 222);
-// ValidateAttributionUidAndTagDimension(
-// data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 222, "GMSCoreModule1");
-// ValidateUidDimension(
-// data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 333);
-// ValidateAttributionUidAndTagDimension(
-// data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 333, "App3");
-// EXPECT_EQ(data.bucket_info_size(), 1);
-// EXPECT_EQ(data.bucket_info(0).count(), 1);
-// EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
-// EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
-//
-// data = countMetrics.data(2);
-// ValidateUidDimension(
-// data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 444);
-// ValidateAttributionUidAndTagDimension(
-// data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 444, "GMSCoreModule2");
-// ValidateUidDimension(
-// data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 222);
-// ValidateAttributionUidAndTagDimension(
-// data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 222, "GMSCoreModule1");
-// EXPECT_EQ(data.bucket_info_size(), 1);
-// EXPECT_EQ(data.bucket_info(0).count(), 1);
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-// data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
-// data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(3);
-// ValidateUidDimension(
-// data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111);
-// ValidateAttributionUidAndTagDimension(
-// data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111, "App1");
-// ValidateUidDimension(
-// data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 222);
-// ValidateAttributionUidAndTagDimension(
-// data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 222, "GMSCoreModule1");
-// ValidateUidDimension(
-// data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 333);
-// ValidateAttributionUidAndTagDimension(
-// data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 333, "App3");
-// EXPECT_EQ(data.bucket_info_size(), 1);
-// EXPECT_EQ(data.bucket_info(0).count(), 1);
-// EXPECT_EQ(bucketStartTimeNs,
-// data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
-// data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(4);
-// ValidateUidDimension(
-// data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111);
-// ValidateAttributionUidAndTagDimension(
-// data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111, "App1");
-// ValidateUidDimension(
-// data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 333);
-// ValidateAttributionUidAndTagDimension(
-// data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 333, "App3");
-// ValidateUidDimension(
-// data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 222);
-// ValidateAttributionUidAndTagDimension(
-// data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 222, "GMSCoreModule1");
-// EXPECT_EQ(data.bucket_info_size(), 1);
-// EXPECT_EQ(data.bucket_info(0).count(), 1);
-// EXPECT_EQ(bucketStartTimeNs,
-// data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
-// data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(5);
-// ValidateUidDimension(
-// data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111);
-// ValidateAttributionUidAndTagDimension(
-// data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111, "App1");
-// ValidateUidDimension(
-// data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 444);
-// ValidateAttributionUidAndTagDimension(
-// data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 444, "GMSCoreModule2");
-// ValidateUidDimension(
-// data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 333);
-// ValidateAttributionUidAndTagDimension(
-// data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 333, "App3");
-// EXPECT_EQ(data.bucket_info_size(), 1);
-// EXPECT_EQ(data.bucket_info(0).count(), 1);
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-// data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
-// data.bucket_info(0).end_bucket_elapsed_nanos());
-//}
+TEST(AttributionE2eTest, TestAttributionMatchAndSliceByFirstUid) {
+ auto config = CreateStatsdConfig(Position::FIRST);
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
+
+ ConfigKey cfgKey;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+
+ // Here it assumes that GMS core has two uids.
+ processor->getUidMap()->updateMap(
+ 1, {222, 444, 111, 333}, {1, 1, 2, 2},
+ {String16("v1"), String16("v1"), String16("v2"), String16("v2")},
+ {String16("com.android.gmscore"), String16("com.android.gmscore"), String16("app1"),
+ String16("APP3")},
+ {String16(""), String16(""), String16(""), String16("")});
+
+ std::vector<std::unique_ptr<LogEvent>> events;
+ // Events 1~4 are in the 1st bucket.
+ events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 2, attributionUids1,
+ attributionTags1, "wl1"));
+ events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 200, attributionUids2,
+ attributionTags2, "wl1"));
+ events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 1,
+ attributionUids3, attributionTags3, "wl1"));
+ events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs, attributionUids4,
+ attributionTags4, "wl1"));
+
+ // Events 5~8 are in the 3rd bucket.
+ events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 1,
+ attributionUids5, attributionTags5, "wl2"));
+ events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 100,
+ attributionUids6, attributionTags6, "wl2"));
+ events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs - 2,
+ attributionUids7, attributionTags7, "wl2"));
+ events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs,
+ attributionUids8, attributionTags8, "wl2"));
+ events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs + 1,
+ attributionUids9, attributionTags9, "wl2"));
+ events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs + 100,
+ attributionUids9, attributionTags9, "wl2"));
+ events.push_back(CreateIsolatedUidChangedEvent(bucketStartTimeNs + 3 * bucketSizeNs - 1, 222,
+ isolatedUid, true /*is_create*/));
+ events.push_back(CreateIsolatedUidChangedEvent(bucketStartTimeNs + 3 * bucketSizeNs + 10, 222,
+ isolatedUid, false /*is_create*/));
+
+ sortLogEventsByTimestamp(&events);
+
+ for (const auto& event : events) {
+ processor->OnLogEvent(event.get());
+ }
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, false, true, ADB_DUMP,
+ FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(reports.reports_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+
+ StatsLogReport::CountMetricDataWrapper countMetrics;
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
+ EXPECT_EQ(countMetrics.data_size(), 4);
+
+ auto data = countMetrics.data(0);
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_what(),
+ android::util::WAKELOCK_STATE_CHANGED, 111, "App1");
+ EXPECT_EQ(data.bucket_info_size(), 2);
+ EXPECT_EQ(data.bucket_info(0).count(), 2);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).count(), 1);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 2 * bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 3 * bucketSizeNs);
+
+ data = countMetrics.data(1);
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_what(),
+ android::util::WAKELOCK_STATE_CHANGED, 222,
+ "GMSCoreModule1");
+ EXPECT_EQ(data.bucket_info_size(), 2);
+ EXPECT_EQ(data.bucket_info(0).count(), 1);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).count(), 1);
+ EXPECT_EQ(data.bucket_info(1).start_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(1).end_bucket_elapsed_nanos(), bucketStartTimeNs + 2 * bucketSizeNs);
+
+ data = countMetrics.data(2);
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_what(),
+ android::util::WAKELOCK_STATE_CHANGED, 222,
+ "GMSCoreModule3");
+ EXPECT_EQ(data.bucket_info_size(), 1);
+ EXPECT_EQ(data.bucket_info(0).count(), 1);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 3 * bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + 4 * bucketSizeNs);
+
+ data = countMetrics.data(3);
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_what(),
+ android::util::WAKELOCK_STATE_CHANGED, 444,
+ "GMSCoreModule2");
+ EXPECT_EQ(data.bucket_info_size(), 1);
+ EXPECT_EQ(data.bucket_info(0).count(), 1);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 2 * bucketSizeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + 3 * bucketSizeNs);
+}
+
+TEST(AttributionE2eTest, TestAttributionMatchAndSliceByChain) {
+ auto config = CreateStatsdConfig(Position::ALL);
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
+
+ ConfigKey cfgKey;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+
+ // Here it assumes that GMS core has two uids.
+ processor->getUidMap()->updateMap(
+ 1, {222, 444, 111, 333}, {1, 1, 2, 2},
+ {String16("v1"), String16("v1"), String16("v2"), String16("v2")},
+ {String16("com.android.gmscore"), String16("com.android.gmscore"), String16("app1"),
+ String16("APP3")},
+ {String16(""), String16(""), String16(""), String16("")});
+
+ std::vector<std::unique_ptr<LogEvent>> events;
+ // Events 1~4 are in the 1st bucket.
+ events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 2, attributionUids1,
+ attributionTags1, "wl1"));
+ events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 200, attributionUids2,
+ attributionTags2, "wl1"));
+ events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 1,
+ attributionUids3, attributionTags3, "wl1"));
+ events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs, attributionUids4,
+ attributionTags4, "wl1"));
+
+ // Events 5~8 are in the 3rd bucket.
+ events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 1,
+ attributionUids5, attributionTags5, "wl2"));
+ events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 100,
+ attributionUids6, attributionTags6, "wl2"));
+ events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs - 2,
+ attributionUids7, attributionTags7, "wl2"));
+ events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs,
+ attributionUids8, attributionTags8, "wl2"));
+ events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs + 1,
+ attributionUids10, attributionTags10, "wl2"));
+ events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 3 * bucketSizeNs + 100,
+ attributionUids10, attributionTags10, "wl2"));
+ events.push_back(CreateIsolatedUidChangedEvent(bucketStartTimeNs + 3 * bucketSizeNs - 1, 222,
+ isolatedUid, true /*is_create*/));
+ events.push_back(CreateIsolatedUidChangedEvent(bucketStartTimeNs + 3 * bucketSizeNs + 10, 222,
+ isolatedUid, false /*is_create*/));
+
+ sortLogEventsByTimestamp(&events);
+
+ for (const auto& event : events) {
+ processor->OnLogEvent(event.get());
+ }
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, false, true, ADB_DUMP,
+ FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(reports.reports_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+
+ StatsLogReport::CountMetricDataWrapper countMetrics;
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
+ EXPECT_EQ(countMetrics.data_size(), 6);
+
+ auto data = countMetrics.data(0);
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_what(),
+ android::util::WAKELOCK_STATE_CHANGED, 222,
+ "GMSCoreModule1");
+ EXPECT_EQ(2, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+ EXPECT_EQ(1, data.bucket_info(1).count());
+ EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
+ data.bucket_info(1).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + 4 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(1);
+ ValidateUidDimension(data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 222);
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 0,
+ android::util::WAKELOCK_STATE_CHANGED, 222,
+ "GMSCoreModule1");
+ ValidateUidDimension(data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 333);
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 1,
+ android::util::WAKELOCK_STATE_CHANGED, 333, "App3");
+ EXPECT_EQ(data.bucket_info_size(), 1);
+ EXPECT_EQ(data.bucket_info(0).count(), 1);
+ EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+ EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
+
+ data = countMetrics.data(2);
+ ValidateUidDimension(data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 444);
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 0,
+ android::util::WAKELOCK_STATE_CHANGED, 444,
+ "GMSCoreModule2");
+ ValidateUidDimension(data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 222);
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 1,
+ android::util::WAKELOCK_STATE_CHANGED, 222,
+ "GMSCoreModule1");
+ EXPECT_EQ(data.bucket_info_size(), 1);
+ EXPECT_EQ(data.bucket_info(0).count(), 1);
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+ data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(3);
+ ValidateUidDimension(data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111);
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 0,
+ android::util::WAKELOCK_STATE_CHANGED, 111, "App1");
+ ValidateUidDimension(data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 222);
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 1,
+ android::util::WAKELOCK_STATE_CHANGED, 222,
+ "GMSCoreModule1");
+ ValidateUidDimension(data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 333);
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 2,
+ android::util::WAKELOCK_STATE_CHANGED, 333, "App3");
+ EXPECT_EQ(data.bucket_info_size(), 1);
+ EXPECT_EQ(data.bucket_info(0).count(), 1);
+ EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(4);
+ ValidateUidDimension(data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111);
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 0,
+ android::util::WAKELOCK_STATE_CHANGED, 111, "App1");
+ ValidateUidDimension(data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 333);
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 1,
+ android::util::WAKELOCK_STATE_CHANGED, 333, "App3");
+ ValidateUidDimension(data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 222);
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 2,
+ android::util::WAKELOCK_STATE_CHANGED, 222,
+ "GMSCoreModule1");
+ EXPECT_EQ(data.bucket_info_size(), 1);
+ EXPECT_EQ(data.bucket_info(0).count(), 1);
+ EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(5);
+ ValidateUidDimension(data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111);
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 0,
+ android::util::WAKELOCK_STATE_CHANGED, 111, "App1");
+ ValidateUidDimension(data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 444);
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 1,
+ android::util::WAKELOCK_STATE_CHANGED, 444,
+ "GMSCoreModule2");
+ ValidateUidDimension(data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 333);
+ ValidateAttributionUidAndTagDimension(data.dimensions_in_what(), 2,
+ android::util::WAKELOCK_STATE_CHANGED, 333, "App3");
+ EXPECT_EQ(data.bucket_info_size(), 1);
+ EXPECT_EQ(data.bucket_info(0).count(), 1);
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+ data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+}
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
diff --git a/cmds/statsd/tests/e2e/ConfigTtl_e2e_test.cpp b/cmds/statsd/tests/e2e/ConfigTtl_e2e_test.cpp
index f8edee5..102bb1e 100644
--- a/cmds/statsd/tests/e2e/ConfigTtl_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/ConfigTtl_e2e_test.cpp
@@ -56,54 +56,54 @@
} // namespace
-// TODO(b/149590301): Update this test to use new socket schema.
-//TEST(ConfigTtlE2eTest, TestCountMetric) {
-// const int num_buckets = 1;
-// const int threshold = 3;
-// auto config = CreateStatsdConfig(num_buckets, threshold);
-// const uint64_t alert_id = config.alert(0).id();
-// const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
-//
-// int64_t bucketStartTimeNs = 10000000000;
-// int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
-//
-// ConfigKey cfgKey;
-// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-//
-// std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1")};
-//
-// FieldValue fieldValue1(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
-// Value((int32_t)111));
-// HashableDimensionKey whatKey1({fieldValue1});
-// MetricDimensionKey dimensionKey1(whatKey1, DEFAULT_DIMENSION_KEY);
-//
-// FieldValue fieldValue2(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
-// Value((int32_t)222));
-// HashableDimensionKey whatKey2({fieldValue2});
-// MetricDimensionKey dimensionKey2(whatKey2, DEFAULT_DIMENSION_KEY);
-//
-// auto event = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 2);
-// processor->OnLogEvent(event.get());
-//
-// event = CreateAcquireWakelockEvent(attributions1, "wl2", bucketStartTimeNs + bucketSizeNs + 2);
-// processor->OnLogEvent(event.get());
-//
-// event = CreateAcquireWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + 25 * bucketSizeNs + 2);
-// processor->OnLogEvent(event.get());
-//
-// EXPECT_EQ((int64_t)(bucketStartTimeNs + 25 * bucketSizeNs + 2 + 2 * 3600 * NS_PER_SEC),
-// processor->mMetricsManagers.begin()->second->getTtlEndNs());
-//
-// // Clear the data stored on disk as a result of the ttl.
-// vector<uint8_t> buffer;
-// processor->onDumpReport(cfgKey, bucketStartTimeNs + 25 * bucketSizeNs + 3, false, true,
-// ADB_DUMP, FAST, &buffer);
-//}
+TEST(ConfigTtlE2eTest, TestCountMetric) {
+ const int num_buckets = 1;
+ const int threshold = 3;
+ auto config = CreateStatsdConfig(num_buckets, threshold);
+ const uint64_t alert_id = config.alert(0).id();
+ const uint32_t refractory_period_sec = config.alert(0).refractory_period_secs();
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
+
+ ConfigKey cfgKey;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+
+ std::vector<int> attributionUids1 = {111};
+ std::vector<string> attributionTags1 = {"App1"};
+
+ FieldValue fieldValue1(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
+ Value((int32_t)111));
+ HashableDimensionKey whatKey1({fieldValue1});
+ MetricDimensionKey dimensionKey1(whatKey1, DEFAULT_DIMENSION_KEY);
+
+ FieldValue fieldValue2(Field(android::util::WAKELOCK_STATE_CHANGED, (int32_t)0x02010101),
+ Value((int32_t)222));
+ HashableDimensionKey whatKey2({fieldValue2});
+ MetricDimensionKey dimensionKey2(whatKey2, DEFAULT_DIMENSION_KEY);
+
+ auto event = CreateAcquireWakelockEvent(bucketStartTimeNs + 2, attributionUids1,
+ attributionTags1, "wl1");
+ processor->OnLogEvent(event.get());
+
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs + 2, attributionUids1,
+ attributionTags1, "wl2");
+ processor->OnLogEvent(event.get());
+
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + 25 * bucketSizeNs + 2, attributionUids1,
+ attributionTags1, "wl1");
+ processor->OnLogEvent(event.get());
+
+ EXPECT_EQ((int64_t)(bucketStartTimeNs + 25 * bucketSizeNs + 2 + 2 * 3600 * NS_PER_SEC),
+ processor->mMetricsManagers.begin()->second->getTtlEndNs());
+
+ // Clear the data stored on disk as a result of the ttl.
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 25 * bucketSizeNs + 3, false, true,
+ ADB_DUMP, FAST, &buffer);
+}
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
diff --git a/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp b/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp
index a1f74a6..2cd7854 100644
--- a/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp
@@ -27,773 +27,775 @@
#ifdef __ANDROID__
-// TODO(b/149590301): Update these tests to use new socket schema.
-///**
-// * Test a count metric that has one slice_by_state with no primary fields.
-// *
-// * Once the CountMetricProducer is initialized, it has one atom id in
-// * mSlicedStateAtoms and no entries in mStateGroupMap.
-//
-// * One StateTracker tracks the state atom, and it has one listener which is the
-// * CountMetricProducer that was initialized.
-// */
-//TEST(CountMetricE2eTest, TestSlicedState) {
-// // Initialize config.
-// StatsdConfig config;
-// config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
-//
-// auto syncStartMatcher = CreateSyncStartAtomMatcher();
-// *config.add_atom_matcher() = syncStartMatcher;
-//
-// auto state = CreateScreenState();
-// *config.add_state() = state;
-//
-// // Create count metric that slices by screen state.
-// int64_t metricId = 123456;
-// auto countMetric = config.add_count_metric();
-// countMetric->set_id(metricId);
-// countMetric->set_what(syncStartMatcher.id());
-// countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
-// countMetric->add_slice_by_state(state.id());
-//
-// // Initialize StatsLogProcessor.
-// const uint64_t bucketStartTimeNs = 10000000000; // 0:10
-// const uint64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
-// int uid = 12345;
-// int64_t cfgId = 98765;
-// ConfigKey cfgKey(uid, cfgId);
-// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-//
-// // Check that CountMetricProducer was initialized correctly.
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-// EXPECT_TRUE(metricsManager->isConfigValid());
-// EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-// sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-// EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
-// EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID);
-// EXPECT_EQ(metricProducer->mStateGroupMap.size(), 0);
-//
-// // Check that StateTrackers were initialized correctly.
-// EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
-// EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
-//
-// /*
-// bucket #1 bucket #2
-// | 1 2 3 4 5 6 7 8 9 10 (minutes)
-// |-----------------------------|-----------------------------|--
-// x x x x x x (syncStartEvents)
-// | | (ScreenIsOnEvent)
-// | | (ScreenIsOffEvent)
-// | (ScreenUnknownEvent)
-// */
-// // Initialize log events - first bucket.
-// int appUid = 123;
-// std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(appUid, "App1")};
-// std::vector<std::unique_ptr<LogEvent>> events;
-// events.push_back(
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-// bucketStartTimeNs + 50 * NS_PER_SEC)); // 1:00
-// events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
-// bucketStartTimeNs + 75 * NS_PER_SEC)); // 1:25
-// events.push_back(
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
-// bucketStartTimeNs + 150 * NS_PER_SEC)); // 2:40
-// events.push_back(
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
-// bucketStartTimeNs + 200 * NS_PER_SEC)); // 3:30
-// events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
-// bucketStartTimeNs + 250 * NS_PER_SEC)); // 4:20
-//
-// // Initialize log events - second bucket.
-// events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
-// bucketStartTimeNs + 350 * NS_PER_SEC)); // 6:00
-// events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
-// bucketStartTimeNs + 400 * NS_PER_SEC)); // 6:50
-// events.push_back(
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-// bucketStartTimeNs + 450 * NS_PER_SEC)); // 7:40
-// events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
-// bucketStartTimeNs + 475 * NS_PER_SEC)); // 8:05
-// events.push_back(
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN,
-// bucketStartTimeNs + 500 * NS_PER_SEC)); // 8:30
-// events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
-// bucketStartTimeNs + 520 * NS_PER_SEC)); // 8:50
-//
-// // Send log events to StatsLogProcessor.
-// for (auto& event : events) {
-// processor->OnLogEvent(event.get());
-// }
-//
-// // Check dump report.
-// vector<uint8_t> buffer;
-// ConfigMetricsReportList reports;
-// processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP,
-// FAST, &buffer);
-// EXPECT_GT(buffer.size(), 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-//
-// EXPECT_EQ(1, reports.reports_size());
-// EXPECT_EQ(1, reports.reports(0).metrics_size());
-// EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
-// EXPECT_EQ(3, reports.reports(0).metrics(0).count_metrics().data_size());
-//
-// // For each CountMetricData, check StateValue info is correct and buckets
-// // have correct counts.
-// auto data = reports.reports(0).metrics(0).count_metrics().data(0);
-// EXPECT_EQ(1, data.slice_by_state_size());
-// EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-// EXPECT_TRUE(data.slice_by_state(0).has_value());
-// EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON, data.slice_by_state(0).value());
-// EXPECT_EQ(2, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(1, data.bucket_info(1).count());
-//
-// data = reports.reports(0).metrics(0).count_metrics().data(1);
-// EXPECT_EQ(1, data.slice_by_state_size());
-// EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-// EXPECT_TRUE(data.slice_by_state(0).has_value());
-// EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN, data.slice_by_state(0).value());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-//
-// data = reports.reports(0).metrics(0).count_metrics().data(2);
-// EXPECT_EQ(1, data.slice_by_state_size());
-// EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-// EXPECT_TRUE(data.slice_by_state(0).has_value());
-// EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, data.slice_by_state(0).value());
-// EXPECT_EQ(2, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(2, data.bucket_info(1).count());
-//}
-//
-///**
-// * Test a count metric that has one slice_by_state with a mapping and no
-// * primary fields.
-// *
-// * Once the CountMetricProducer is initialized, it has one atom id in
-// * mSlicedStateAtoms and has one entry per state value in mStateGroupMap.
-// *
-// * One StateTracker tracks the state atom, and it has one listener which is the
-// * CountMetricProducer that was initialized.
-// */
-//TEST(CountMetricE2eTest, TestSlicedStateWithMap) {
-// // Initialize config.
-// StatsdConfig config;
-// config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
-//
-// auto syncStartMatcher = CreateSyncStartAtomMatcher();
-// *config.add_atom_matcher() = syncStartMatcher;
-//
-// auto state = CreateScreenStateWithOnOffMap();
-// *config.add_state() = state;
-//
-// // Create count metric that slices by screen state with on/off map.
-// int64_t metricId = 123456;
-// auto countMetric = config.add_count_metric();
-// countMetric->set_id(metricId);
-// countMetric->set_what(syncStartMatcher.id());
-// countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
-// countMetric->add_slice_by_state(state.id());
-//
-// // Initialize StatsLogProcessor.
-// const uint64_t bucketStartTimeNs = 10000000000; // 0:10
-// const uint64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
-// int uid = 12345;
-// int64_t cfgId = 98765;
-// ConfigKey cfgKey(uid, cfgId);
-// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-//
-// // Check that StateTrackers were initialized correctly.
-// EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
-// EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
-//
-// // Check that CountMetricProducer was initialized correctly.
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-// EXPECT_TRUE(metricsManager->isConfigValid());
-// EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-// sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-// EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
-// EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID);
-// EXPECT_EQ(metricProducer->mStateGroupMap.size(), 1);
-//
-// StateMap map = state.map();
-// for (auto group : map.group()) {
-// for (auto value : group.value()) {
-// EXPECT_EQ(metricProducer->mStateGroupMap[SCREEN_STATE_ATOM_ID][value],
-// group.group_id());
-// }
-// }
-//
-// /*
-// bucket #1 bucket #2
-// | 1 2 3 4 5 6 7 8 9 10 (minutes)
-// |-----------------------------|-----------------------------|--
-// x x x x x x x x x (syncStartEvents)
-// -----------------------------------------------------------SCREEN_OFF events
-// | (ScreenStateUnknownEvent = 0)
-// | | (ScreenStateOffEvent = 1)
-// | (ScreenStateDozeEvent = 3)
-// | (ScreenStateDozeSuspendEvent = 4)
-// -----------------------------------------------------------SCREEN_ON events
-// | | (ScreenStateOnEvent = 2)
-// | (ScreenStateVrEvent = 5)
-// | (ScreenStateOnSuspendEvent = 6)
-// */
-// // Initialize log events - first bucket.
-// int appUid = 123;
-// std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(appUid, "App1")};
-//
-// std::vector<std::unique_ptr<LogEvent>> events;
-// events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
-// bucketStartTimeNs + 20 * NS_PER_SEC)); // 0:30
-// events.push_back(
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN,
-// bucketStartTimeNs + 30 * NS_PER_SEC)); // 0:40
-// events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
-// bucketStartTimeNs + 60 * NS_PER_SEC)); // 1:10
-// events.push_back(
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
-// bucketStartTimeNs + 90 * NS_PER_SEC)); // 1:40
-// events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
-// bucketStartTimeNs + 120 * NS_PER_SEC)); // 2:10
-// events.push_back(
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-// bucketStartTimeNs + 150 * NS_PER_SEC)); // 2:40
-// events.push_back(
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_VR,
-// bucketStartTimeNs + 180 * NS_PER_SEC)); // 3:10
-// events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
-// bucketStartTimeNs + 200 * NS_PER_SEC)); // 3:30
-// events.push_back(
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_DOZE,
-// bucketStartTimeNs + 210 * NS_PER_SEC)); // 3:40
-// events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
-// bucketStartTimeNs + 250 * NS_PER_SEC)); // 4:20
-// events.push_back(
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
-// bucketStartTimeNs + 280 * NS_PER_SEC)); // 4:50
-// events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
-// bucketStartTimeNs + 285 * NS_PER_SEC)); // 4:55
-//
-// // Initialize log events - second bucket.
-// events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
-// bucketStartTimeNs + 360 * NS_PER_SEC)); // 6:10
-// events.push_back(
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON_SUSPEND,
-// bucketStartTimeNs + 390 * NS_PER_SEC)); // 6:40
-// events.push_back(CreateScreenStateChangedEvent(
-// android::view::DisplayStateEnum::DISPLAY_STATE_DOZE_SUSPEND,
-// bucketStartTimeNs + 430 * NS_PER_SEC)); // 7:20
-// events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
-// bucketStartTimeNs + 440 * NS_PER_SEC)); // 7:30
-// events.push_back(
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-// bucketStartTimeNs + 540 * NS_PER_SEC)); // 9:10
-// events.push_back(CreateSyncStartEvent(attributions1, "sync_name",
-// bucketStartTimeNs + 570 * NS_PER_SEC)); // 9:40
-//
-// // Send log events to StatsLogProcessor.
-// for (auto& event : events) {
-// processor->OnLogEvent(event.get());
-// }
-//
-// // Check dump report.
-// vector<uint8_t> buffer;
-// ConfigMetricsReportList reports;
-// processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP,
-// FAST, &buffer);
-// EXPECT_GT(buffer.size(), 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-//
-// EXPECT_EQ(1, reports.reports_size());
-// EXPECT_EQ(1, reports.reports(0).metrics_size());
-// EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
-// EXPECT_EQ(3, reports.reports(0).metrics(0).count_metrics().data_size());
-//
-// // For each CountMetricData, check StateValue info is correct and buckets
-// // have correct counts.
-// auto data = reports.reports(0).metrics(0).count_metrics().data(0);
-// EXPECT_EQ(1, data.slice_by_state_size());
-// EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-// EXPECT_TRUE(data.slice_by_state(0).has_value());
-// EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, data.slice_by_state(0).value());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-//
-// data = reports.reports(0).metrics(0).count_metrics().data(1);
-// EXPECT_EQ(1, data.slice_by_state_size());
-// EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-// EXPECT_TRUE(data.slice_by_state(0).has_group_id());
-// EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id());
-// EXPECT_EQ(2, data.bucket_info_size());
-// EXPECT_EQ(4, data.bucket_info(0).count());
-// EXPECT_EQ(2, data.bucket_info(1).count());
-//
-// data = reports.reports(0).metrics(0).count_metrics().data(2);
-// EXPECT_EQ(1, data.slice_by_state_size());
-// EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-// EXPECT_TRUE(data.slice_by_state(0).has_group_id());
-// EXPECT_EQ(StringToId("SCREEN_ON"), data.slice_by_state(0).group_id());
-// EXPECT_EQ(2, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(1, data.bucket_info(1).count());
-//}
-//
-///**
-// * Test a count metric that has one slice_by_state with a primary field.
-//
-// * Once the CountMetricProducer is initialized, it should have one
-// * MetricStateLink stored. State querying using a non-empty primary key
-// * should also work as intended.
-// */
-//TEST(CountMetricE2eTest, TestSlicedStateWithPrimaryFields) {
-// // Initialize config.
-// StatsdConfig config;
-// config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
-//
-// auto appCrashMatcher =
-// CreateSimpleAtomMatcher("APP_CRASH_OCCURRED", android::util::APP_CRASH_OCCURRED);
-// *config.add_atom_matcher() = appCrashMatcher;
-//
-// auto state = CreateUidProcessState();
-// *config.add_state() = state;
-//
-// // Create count metric that slices by uid process state.
-// int64_t metricId = 123456;
-// auto countMetric = config.add_count_metric();
-// countMetric->set_id(metricId);
-// countMetric->set_what(appCrashMatcher.id());
-// countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
-// countMetric->add_slice_by_state(state.id());
-// MetricStateLink* stateLink = countMetric->add_state_link();
-// stateLink->set_state_atom_id(UID_PROCESS_STATE_ATOM_ID);
-// auto fieldsInWhat = stateLink->mutable_fields_in_what();
-// *fieldsInWhat = CreateDimensions(android::util::APP_CRASH_OCCURRED, {1 /* uid */});
-// auto fieldsInState = stateLink->mutable_fields_in_state();
-// *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /* uid */});
-//
-// // Initialize StatsLogProcessor.
-// const uint64_t bucketStartTimeNs = 10000000000; // 0:10
-// const uint64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
-// int uid = 12345;
-// int64_t cfgId = 98765;
-// ConfigKey cfgKey(uid, cfgId);
-// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-//
-// // Check that StateTrackers were initialized correctly.
-// EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
-// EXPECT_EQ(1, StateManager::getInstance().getListenersCount(UID_PROCESS_STATE_ATOM_ID));
-//
-// // Check that CountMetricProducer was initialized correctly.
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-// EXPECT_TRUE(metricsManager->isConfigValid());
-// EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-// sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-// EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
-// EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), UID_PROCESS_STATE_ATOM_ID);
-// EXPECT_EQ(metricProducer->mStateGroupMap.size(), 0);
-// EXPECT_EQ(metricProducer->mMetric2StateLinks.size(), 1);
-//
-// /*
-// NOTE: "1" or "2" represents the uid associated with the state/app crash event
-// bucket #1 bucket #2
-// | 1 2 3 4 5 6 7 8 9 10
-// |-----------------------------|-----------------------------|--
-// 1 1 1 1 1 2 1 1 2 (AppCrashEvents)
-// -----------------------------------------------------------PROCESS STATE events
-// 1 2 (ProcessStateTopEvent = 1002)
-// 1 1 (ProcessStateForegroundServiceEvent = 1003)
-// 2 (ProcessStateImportantBackgroundEvent = 1006)
-// 1 1 1 (ProcessStateImportantForegroundEvent = 1005)
-//
-// Based on the diagram above, an AppCrashEvent querying for process state value would return:
-// - StateTracker::kStateUnknown
-// - Important foreground
-// - Top
-// - Important foreground
-// - Foreground service
-// - Top (both the app crash and state still have matching uid = 2)
-//
-// - Foreground service
-// - Foreground service
-// - Important background
-// */
-// // Initialize log events - first bucket.
-// std::vector<std::unique_ptr<LogEvent>> events;
-// events.push_back(
-// CreateAppCrashOccurredEvent(1 /* uid */, bucketStartTimeNs + 20 * NS_PER_SEC)); // 0:30
-// events.push_back(CreateUidProcessStateChangedEvent(
-// 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
-// bucketStartTimeNs + 30 * NS_PER_SEC)); // 0:40
-// events.push_back(
-// CreateAppCrashOccurredEvent(1 /* uid */, bucketStartTimeNs + 60 * NS_PER_SEC)); // 1:10
-// events.push_back(CreateUidProcessStateChangedEvent(
-// 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_TOP,
-// bucketStartTimeNs + 90 * NS_PER_SEC)); // 1:40
-// events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
-// bucketStartTimeNs + 120 * NS_PER_SEC)); // 2:10
-// events.push_back(CreateUidProcessStateChangedEvent(
-// 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
-// bucketStartTimeNs + 150 * NS_PER_SEC)); // 2:40
-// events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
-// bucketStartTimeNs + 200 * NS_PER_SEC)); // 3:30
-// events.push_back(CreateUidProcessStateChangedEvent(
-// 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE,
-// bucketStartTimeNs + 210 * NS_PER_SEC)); // 3:40
-// events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
-// bucketStartTimeNs + 250 * NS_PER_SEC)); // 4:20
-// events.push_back(CreateUidProcessStateChangedEvent(
-// 2 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_TOP,
-// bucketStartTimeNs + 280 * NS_PER_SEC)); // 4:50
-// events.push_back(CreateAppCrashOccurredEvent(2 /* uid */,
-// bucketStartTimeNs + 285 * NS_PER_SEC)); // 4:55
-//
-// // Initialize log events - second bucket.
-// events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
-// bucketStartTimeNs + 360 * NS_PER_SEC)); // 6:10
-// events.push_back(CreateUidProcessStateChangedEvent(
-// 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE,
-// bucketStartTimeNs + 390 * NS_PER_SEC)); // 6:40
-// events.push_back(CreateUidProcessStateChangedEvent(
-// 2 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND,
-// bucketStartTimeNs + 430 * NS_PER_SEC)); // 7:20
-// events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
-// bucketStartTimeNs + 440 * NS_PER_SEC)); // 7:30
-// events.push_back(CreateUidProcessStateChangedEvent(
-// 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
-// bucketStartTimeNs + 540 * NS_PER_SEC)); // 9:10
-// events.push_back(CreateAppCrashOccurredEvent(2 /* uid */,
-// bucketStartTimeNs + 570 * NS_PER_SEC)); // 9:40
-//
-// // Send log events to StatsLogProcessor.
-// for (auto& event : events) {
-// processor->OnLogEvent(event.get());
-// }
-//
-// // Check dump report.
-// vector<uint8_t> buffer;
-// ConfigMetricsReportList reports;
-// processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP,
-// FAST, &buffer);
-// EXPECT_GT(buffer.size(), 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-//
-// EXPECT_EQ(1, reports.reports_size());
-// EXPECT_EQ(1, reports.reports(0).metrics_size());
-// EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
-// EXPECT_EQ(5, reports.reports(0).metrics(0).count_metrics().data_size());
-//
-// // For each CountMetricData, check StateValue info is correct and buckets
-// // have correct counts.
-// auto data = reports.reports(0).metrics(0).count_metrics().data(0);
-// EXPECT_EQ(1, data.slice_by_state_size());
-// EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-// EXPECT_TRUE(data.slice_by_state(0).has_value());
-// EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, data.slice_by_state(0).value());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-//
-// data = reports.reports(0).metrics(0).count_metrics().data(1);
-// EXPECT_EQ(1, data.slice_by_state_size());
-// EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-// EXPECT_TRUE(data.slice_by_state(0).has_value());
-// EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, data.slice_by_state(0).value());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-//
-// data = reports.reports(0).metrics(0).count_metrics().data(2);
-// EXPECT_EQ(1, data.slice_by_state_size());
-// EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-// EXPECT_TRUE(data.slice_by_state(0).has_value());
-// EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(0).value());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(2, data.bucket_info(0).count());
-//
-// data = reports.reports(0).metrics(0).count_metrics().data(3);
-// EXPECT_EQ(1, data.slice_by_state_size());
-// EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-// EXPECT_TRUE(data.slice_by_state(0).has_value());
-// EXPECT_EQ(android::app::PROCESS_STATE_TOP, data.slice_by_state(0).value());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(2, data.bucket_info(0).count());
-//
-// data = reports.reports(0).metrics(0).count_metrics().data(4);
-// EXPECT_EQ(1, data.slice_by_state_size());
-// EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-// EXPECT_TRUE(data.slice_by_state(0).has_value());
-// EXPECT_EQ(android::app::PROCESS_STATE_FOREGROUND_SERVICE, data.slice_by_state(0).value());
-// EXPECT_EQ(2, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(2, data.bucket_info(1).count());
-//}
-//
-//TEST(CountMetricE2eTest, TestMultipleSlicedStates) {
-// // Initialize config.
-// StatsdConfig config;
-// config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
-//
-// auto appCrashMatcher =
-// CreateSimpleAtomMatcher("APP_CRASH_OCCURRED", android::util::APP_CRASH_OCCURRED);
-// *config.add_atom_matcher() = appCrashMatcher;
-//
-// auto state1 = CreateScreenStateWithOnOffMap();
-// *config.add_state() = state1;
-// auto state2 = CreateUidProcessState();
-// *config.add_state() = state2;
-//
-// // Create count metric that slices by screen state with on/off map and
-// // slices by uid process state.
-// int64_t metricId = 123456;
-// auto countMetric = config.add_count_metric();
-// countMetric->set_id(metricId);
-// countMetric->set_what(appCrashMatcher.id());
-// countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
-// countMetric->add_slice_by_state(state1.id());
-// countMetric->add_slice_by_state(state2.id());
-// MetricStateLink* stateLink = countMetric->add_state_link();
-// stateLink->set_state_atom_id(UID_PROCESS_STATE_ATOM_ID);
-// auto fieldsInWhat = stateLink->mutable_fields_in_what();
-// *fieldsInWhat = CreateDimensions(android::util::APP_CRASH_OCCURRED, {1 /* uid */});
-// auto fieldsInState = stateLink->mutable_fields_in_state();
-// *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /* uid */});
-//
-// // Initialize StatsLogProcessor.
-// const uint64_t bucketStartTimeNs = 10000000000; // 0:10
-// const uint64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
-// int uid = 12345;
-// int64_t cfgId = 98765;
-// ConfigKey cfgKey(uid, cfgId);
-// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-//
-// // Check that StateTrackers were properly initialized.
-// EXPECT_EQ(2, StateManager::getInstance().getStateTrackersCount());
-// EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
-// EXPECT_EQ(1, StateManager::getInstance().getListenersCount(UID_PROCESS_STATE_ATOM_ID));
-//
-// // Check that CountMetricProducer was initialized correctly.
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-// EXPECT_TRUE(metricsManager->isConfigValid());
-// EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-// sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-// EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 2);
-// EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID);
-// EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(1), UID_PROCESS_STATE_ATOM_ID);
-// EXPECT_EQ(metricProducer->mStateGroupMap.size(), 1);
-// EXPECT_EQ(metricProducer->mMetric2StateLinks.size(), 1);
-//
-// StateMap map = state1.map();
-// for (auto group : map.group()) {
-// for (auto value : group.value()) {
-// EXPECT_EQ(metricProducer->mStateGroupMap[SCREEN_STATE_ATOM_ID][value],
-// group.group_id());
-// }
-// }
-//
-// /*
-// bucket #1 bucket #2
-// | 1 2 3 4 5 6 7 8 9 10 (minutes)
-// |-----------------------------|-----------------------------|--
-// 1 1 1 1 1 2 1 1 2 (AppCrashEvents)
-// -----------------------------------------------------------SCREEN_OFF events
-// | (ScreenStateUnknownEvent = 0)
-// | | (ScreenStateOffEvent = 1)
-// | (ScreenStateDozeEvent = 3)
-// -----------------------------------------------------------SCREEN_ON events
-// | | (ScreenStateOnEvent = 2)
-// | (ScreenStateOnSuspendEvent = 6)
-// -----------------------------------------------------------PROCESS STATE events
-// 1 2 (ProcessStateTopEvent = 1002)
-// 1 (ProcessStateForegroundServiceEvent = 1003)
-// 2 (ProcessStateImportantBackgroundEvent = 1006)
-// 1 1 1 (ProcessStateImportantForegroundEvent = 1005)
-//
-// Based on the diagram above, Screen State / Process State pairs for each
-// AppCrashEvent are:
-// - StateTracker::kStateUnknown / important foreground
-// - off / important foreground
-// - off / Top
-// - on / important foreground
-// - off / important foreground
-// - off / top
-//
-// - off / important foreground
-// - off / foreground service
-// - on / important background
-//
-// */
-// // Initialize log events - first bucket.
-// std::vector<std::unique_ptr<LogEvent>> events;
-// events.push_back(CreateUidProcessStateChangedEvent(
-// 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
-// bucketStartTimeNs + 5 * NS_PER_SEC)); // 0:15
-// events.push_back(
-// CreateAppCrashOccurredEvent(1 /* uid */, bucketStartTimeNs + 20 * NS_PER_SEC)); // 0:30
-// events.push_back(
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN,
-// bucketStartTimeNs + 30 * NS_PER_SEC)); // 0:40
-// events.push_back(
-// CreateAppCrashOccurredEvent(1 /* uid */, bucketStartTimeNs + 60 * NS_PER_SEC)); // 1:10
-// events.push_back(CreateUidProcessStateChangedEvent(
-// 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_TOP,
-// bucketStartTimeNs + 90 * NS_PER_SEC)); // 1:40
-// events.push_back(
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
-// bucketStartTimeNs + 90 * NS_PER_SEC)); // 1:40
-// events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
-// bucketStartTimeNs + 120 * NS_PER_SEC)); // 2:10
-// events.push_back(CreateUidProcessStateChangedEvent(
-// 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
-// bucketStartTimeNs + 150 * NS_PER_SEC)); // 2:40
-// events.push_back(
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-// bucketStartTimeNs + 160 * NS_PER_SEC)); // 2:50
-// events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
-// bucketStartTimeNs + 200 * NS_PER_SEC)); // 3:30
-// events.push_back(
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_DOZE,
-// bucketStartTimeNs + 210 * NS_PER_SEC)); // 3:40
-// events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
-// bucketStartTimeNs + 250 * NS_PER_SEC)); // 4:20
-// events.push_back(CreateUidProcessStateChangedEvent(
-// 2 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_TOP,
-// bucketStartTimeNs + 280 * NS_PER_SEC)); // 4:50
-// events.push_back(CreateAppCrashOccurredEvent(2 /* uid */,
-// bucketStartTimeNs + 285 * NS_PER_SEC)); // 4:55
-//
-// // Initialize log events - second bucket.
-// events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
-// bucketStartTimeNs + 360 * NS_PER_SEC)); // 6:10
-// events.push_back(CreateUidProcessStateChangedEvent(
-// 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE,
-// bucketStartTimeNs + 380 * NS_PER_SEC)); // 6:30
-// events.push_back(
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON_SUSPEND,
-// bucketStartTimeNs + 390 * NS_PER_SEC)); // 6:40
-// events.push_back(CreateUidProcessStateChangedEvent(
-// 2 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND,
-// bucketStartTimeNs + 420 * NS_PER_SEC)); // 7:10
-// events.push_back(
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
-// bucketStartTimeNs + 440 * NS_PER_SEC)); // 7:30
-// events.push_back(CreateAppCrashOccurredEvent(1 /* uid */,
-// bucketStartTimeNs + 450 * NS_PER_SEC)); // 7:40
-// events.push_back(
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-// bucketStartTimeNs + 520 * NS_PER_SEC)); // 8:50
-// events.push_back(CreateUidProcessStateChangedEvent(
-// 1 /* uid */, android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND,
-// bucketStartTimeNs + 540 * NS_PER_SEC)); // 9:10
-// events.push_back(CreateAppCrashOccurredEvent(2 /* uid */,
-// bucketStartTimeNs + 570 * NS_PER_SEC)); // 9:40
-//
-// // Send log events to StatsLogProcessor.
-// for (auto& event : events) {
-// processor->OnLogEvent(event.get());
-// }
-//
-// // Check dump report.
-// vector<uint8_t> buffer;
-// ConfigMetricsReportList reports;
-// processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP,
-// FAST, &buffer);
-// EXPECT_GT(buffer.size(), 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-//
-// EXPECT_EQ(1, reports.reports_size());
-// EXPECT_EQ(1, reports.reports(0).metrics_size());
-// EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
-// EXPECT_EQ(6, reports.reports(0).metrics(0).count_metrics().data_size());
-//
-// // For each CountMetricData, check StateValue info is correct and buckets
-// // have correct counts.
-// auto data = reports.reports(0).metrics(0).count_metrics().data(0);
-// EXPECT_EQ(2, data.slice_by_state_size());
-// EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-// EXPECT_TRUE(data.slice_by_state(0).has_group_id());
-// EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id());
-// EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
-// EXPECT_TRUE(data.slice_by_state(1).has_value());
-// EXPECT_EQ(android::app::PROCESS_STATE_FOREGROUND_SERVICE, data.slice_by_state(1).value());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-//
-// data = reports.reports(0).metrics(0).count_metrics().data(1);
-// EXPECT_EQ(2, data.slice_by_state_size());
-// EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-// EXPECT_TRUE(data.slice_by_state(0).has_value());
-// EXPECT_EQ(-1, data.slice_by_state(0).value());
-// EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
-// EXPECT_TRUE(data.slice_by_state(1).has_value());
-// EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-//
-// data = reports.reports(0).metrics(0).count_metrics().data(2);
-// EXPECT_EQ(2, data.slice_by_state_size());
-// EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-// EXPECT_TRUE(data.slice_by_state(0).has_group_id());
-// EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id());
-// EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
-// EXPECT_TRUE(data.slice_by_state(1).has_value());
-// EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value());
-// EXPECT_EQ(2, data.bucket_info_size());
-// EXPECT_EQ(2, data.bucket_info(0).count());
-// EXPECT_EQ(1, data.bucket_info(1).count());
-//
-// data = reports.reports(0).metrics(0).count_metrics().data(3);
-// EXPECT_EQ(2, data.slice_by_state_size());
-// EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-// EXPECT_TRUE(data.slice_by_state(0).has_group_id());
-// EXPECT_EQ(StringToId("SCREEN_ON"), data.slice_by_state(0).group_id());
-// EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
-// EXPECT_TRUE(data.slice_by_state(1).has_value());
-// EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-//
-// data = reports.reports(0).metrics(0).count_metrics().data(4);
-// EXPECT_EQ(2, data.slice_by_state_size());
-// EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-// EXPECT_TRUE(data.slice_by_state(0).has_group_id());
-// EXPECT_EQ(StringToId("SCREEN_ON"), data.slice_by_state(0).group_id());
-// EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
-// EXPECT_TRUE(data.slice_by_state(1).has_value());
-// EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, data.slice_by_state(1).value());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-//
-// data = reports.reports(0).metrics(0).count_metrics().data(5);
-// EXPECT_EQ(2, data.slice_by_state_size());
-// EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
-// EXPECT_TRUE(data.slice_by_state(0).has_group_id());
-// EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id());
-// EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
-// EXPECT_TRUE(data.slice_by_state(1).has_value());
-// EXPECT_EQ(android::app::PROCESS_STATE_TOP, data.slice_by_state(1).value());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(2, data.bucket_info(0).count());
-//}
+/**
+* Test a count metric that has one slice_by_state with no primary fields.
+*
+* Once the CountMetricProducer is initialized, it has one atom id in
+* mSlicedStateAtoms and no entries in mStateGroupMap.
+
+* One StateTracker tracks the state atom, and it has one listener which is the
+* CountMetricProducer that was initialized.
+*/
+TEST(CountMetricE2eTest, TestSlicedState) {
+ // Initialize config.
+ StatsdConfig config;
+ config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
+
+ auto syncStartMatcher = CreateSyncStartAtomMatcher();
+ *config.add_atom_matcher() = syncStartMatcher;
+
+ auto state = CreateScreenState();
+ *config.add_state() = state;
+
+ // Create count metric that slices by screen state.
+ int64_t metricId = 123456;
+ auto countMetric = config.add_count_metric();
+ countMetric->set_id(metricId);
+ countMetric->set_what(syncStartMatcher.id());
+ countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
+ countMetric->add_slice_by_state(state.id());
+
+ // Initialize StatsLogProcessor.
+ const uint64_t bucketStartTimeNs = 10000000000; // 0:10
+ const uint64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
+ int uid = 12345;
+ int64_t cfgId = 98765;
+ ConfigKey cfgKey(uid, cfgId);
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+
+ // Check that CountMetricProducer was initialized correctly.
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
+ EXPECT_TRUE(metricsManager->isConfigValid());
+ EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+ EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
+ EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID);
+ EXPECT_EQ(metricProducer->mStateGroupMap.size(), 0);
+
+ // Check that StateTrackers were initialized correctly.
+ EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
+ EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
+
+ /*
+ bucket #1 bucket #2
+ | 1 2 3 4 5 6 7 8 9 10 (minutes)
+ |-----------------------------|-----------------------------|--
+ x x x x x x (syncStartEvents)
+ | | (ScreenIsOnEvent)
+ | | (ScreenIsOffEvent)
+ | (ScreenUnknownEvent)
+ */
+ // Initialize log events - first bucket.
+ std::vector<int> attributionUids1 = {123};
+ std::vector<string> attributionTags1 = {"App1"};
+
+ std::vector<std::unique_ptr<LogEvent>> events;
+ events.push_back(CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 50 * NS_PER_SEC,
+ android::view::DisplayStateEnum::DISPLAY_STATE_ON)); // 1:00
+ events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 75 * NS_PER_SEC, attributionUids1,
+ attributionTags1, "sync_name")); // 1:25
+ events.push_back(CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 150 * NS_PER_SEC,
+ android::view::DisplayStateEnum::DISPLAY_STATE_OFF)); // 2:40
+ events.push_back(CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 200 * NS_PER_SEC,
+ android::view::DisplayStateEnum::DISPLAY_STATE_OFF)); // 3:30
+ events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 250 * NS_PER_SEC, attributionUids1,
+ attributionTags1, "sync_name")); // 4:20
+
+ // Initialize log events - second bucket.
+ events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 350 * NS_PER_SEC, attributionUids1,
+ attributionTags1, "sync_name")); // 6:00
+ events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 400 * NS_PER_SEC, attributionUids1,
+ attributionTags1, "sync_name")); // 6:50
+ events.push_back(CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 450 * NS_PER_SEC,
+ android::view::DisplayStateEnum::DISPLAY_STATE_ON)); // 7:40
+ events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 475 * NS_PER_SEC, attributionUids1,
+ attributionTags1, "sync_name")); // 8:05
+ events.push_back(CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 500 * NS_PER_SEC,
+ android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN)); // 8:30
+ events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 520 * NS_PER_SEC, attributionUids1,
+ attributionTags1, "sync_name")); // 8:50
+
+ // Send log events to StatsLogProcessor.
+ for (auto& event : events) {
+ processor->OnLogEvent(event.get());
+ }
+
+ // Check dump report.
+ vector<uint8_t> buffer;
+ ConfigMetricsReportList reports;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP,
+ FAST, &buffer);
+ EXPECT_GT(buffer.size(), 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
+ EXPECT_EQ(3, reports.reports(0).metrics(0).count_metrics().data_size());
+
+ // For each CountMetricData, check StateValue info is correct and buckets
+ // have correct counts.
+ auto data = reports.reports(0).metrics(0).count_metrics().data(0);
+ EXPECT_EQ(1, data.slice_by_state_size());
+ EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_value());
+ EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON, data.slice_by_state(0).value());
+ EXPECT_EQ(2, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(1, data.bucket_info(1).count());
+
+ data = reports.reports(0).metrics(0).count_metrics().data(1);
+ EXPECT_EQ(1, data.slice_by_state_size());
+ EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_value());
+ EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN,
+ data.slice_by_state(0).value());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+
+ data = reports.reports(0).metrics(0).count_metrics().data(2);
+ EXPECT_EQ(1, data.slice_by_state_size());
+ EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_value());
+ EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, data.slice_by_state(0).value());
+ EXPECT_EQ(2, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(2, data.bucket_info(1).count());
+}
+
+/**
+ * Test a count metric that has one slice_by_state with a mapping and no
+ * primary fields.
+ *
+ * Once the CountMetricProducer is initialized, it has one atom id in
+ * mSlicedStateAtoms and has one entry per state value in mStateGroupMap.
+ *
+ * One StateTracker tracks the state atom, and it has one listener which is the
+ * CountMetricProducer that was initialized.
+ */
+TEST(CountMetricE2eTest, TestSlicedStateWithMap) {
+ // Initialize config.
+ StatsdConfig config;
+ config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
+
+ auto syncStartMatcher = CreateSyncStartAtomMatcher();
+ *config.add_atom_matcher() = syncStartMatcher;
+
+ auto state = CreateScreenStateWithOnOffMap();
+ *config.add_state() = state;
+
+ // Create count metric that slices by screen state with on/off map.
+ int64_t metricId = 123456;
+ auto countMetric = config.add_count_metric();
+ countMetric->set_id(metricId);
+ countMetric->set_what(syncStartMatcher.id());
+ countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
+ countMetric->add_slice_by_state(state.id());
+
+ // Initialize StatsLogProcessor.
+ const uint64_t bucketStartTimeNs = 10000000000; // 0:10
+ const uint64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
+ int uid = 12345;
+ int64_t cfgId = 98765;
+ ConfigKey cfgKey(uid, cfgId);
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+
+ // Check that StateTrackers were initialized correctly.
+ EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
+ EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
+
+ // Check that CountMetricProducer was initialized correctly.
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
+ EXPECT_TRUE(metricsManager->isConfigValid());
+ EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+ EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
+ EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID);
+ EXPECT_EQ(metricProducer->mStateGroupMap.size(), 1);
+
+ StateMap map = state.map();
+ for (auto group : map.group()) {
+ for (auto value : group.value()) {
+ EXPECT_EQ(metricProducer->mStateGroupMap[SCREEN_STATE_ATOM_ID][value],
+ group.group_id());
+ }
+ }
+
+ /*
+ bucket #1 bucket #2
+ | 1 2 3 4 5 6 7 8 9 10 (minutes)
+ |-----------------------------|-----------------------------|--
+ x x x x x x x x x (syncStartEvents)
+ -----------------------------------------------------------SCREEN_OFF events
+ | (ScreenStateUnknownEvent = 0)
+ | | (ScreenStateOffEvent = 1)
+ | (ScreenStateDozeEvent = 3)
+ | (ScreenStateDozeSuspendEvent =
+ 4)
+ -----------------------------------------------------------SCREEN_ON events
+ | | (ScreenStateOnEvent = 2)
+ | (ScreenStateVrEvent = 5)
+ | (ScreenStateOnSuspendEvent = 6)
+ */
+ // Initialize log events - first bucket.
+ std::vector<int> attributionUids1 = {123};
+ std::vector<string> attributionTags1 = {"App1"};
+
+ std::vector<std::unique_ptr<LogEvent>> events;
+ events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 20 * NS_PER_SEC, attributionUids1,
+ attributionTags1, "sync_name")); // 0:30
+ events.push_back(CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 30 * NS_PER_SEC,
+ android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN)); // 0:40
+ events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 60 * NS_PER_SEC, attributionUids1,
+ attributionTags1, "sync_name")); // 1:10
+ events.push_back(CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 90 * NS_PER_SEC,
+ android::view::DisplayStateEnum::DISPLAY_STATE_OFF)); // 1:40
+ events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 120 * NS_PER_SEC, attributionUids1,
+ attributionTags1, "sync_name")); // 2:10
+ events.push_back(CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 150 * NS_PER_SEC,
+ android::view::DisplayStateEnum::DISPLAY_STATE_ON)); // 2:40
+ events.push_back(CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 180 * NS_PER_SEC,
+ android::view::DisplayStateEnum::DISPLAY_STATE_VR)); // 3:10
+ events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 200 * NS_PER_SEC, attributionUids1,
+ attributionTags1, "sync_name")); // 3:30
+ events.push_back(CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 210 * NS_PER_SEC,
+ android::view::DisplayStateEnum::DISPLAY_STATE_DOZE)); // 3:40
+ events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 250 * NS_PER_SEC, attributionUids1,
+ attributionTags1, "sync_name")); // 4:20
+ events.push_back(CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 280 * NS_PER_SEC,
+ android::view::DisplayStateEnum::DISPLAY_STATE_OFF)); // 4:50
+ events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 285 * NS_PER_SEC, attributionUids1,
+ attributionTags1, "sync_name")); // 4:55
+
+ // Initialize log events - second bucket.
+ events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 360 * NS_PER_SEC, attributionUids1,
+ attributionTags1, "sync_name")); // 6:10
+ events.push_back(CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 390 * NS_PER_SEC,
+ android::view::DisplayStateEnum::DISPLAY_STATE_ON_SUSPEND)); // 6:40
+ events.push_back(CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 430 * NS_PER_SEC,
+ android::view::DisplayStateEnum::DISPLAY_STATE_DOZE_SUSPEND)); // 7:20
+ events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 440 * NS_PER_SEC, attributionUids1,
+ attributionTags1, "sync_name")); // 7:30
+ events.push_back(CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 540 * NS_PER_SEC,
+ android::view::DisplayStateEnum::DISPLAY_STATE_ON)); // 9:10
+ events.push_back(CreateSyncStartEvent(bucketStartTimeNs + 570 * NS_PER_SEC, attributionUids1,
+ attributionTags1, "sync_name")); // 9:40
+
+ // Send log events to StatsLogProcessor.
+ for (auto& event : events) {
+ processor->OnLogEvent(event.get());
+ }
+
+ // Check dump report.
+ vector<uint8_t> buffer;
+ ConfigMetricsReportList reports;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP,
+ FAST, &buffer);
+ EXPECT_GT(buffer.size(), 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
+ EXPECT_EQ(3, reports.reports(0).metrics(0).count_metrics().data_size());
+
+ // For each CountMetricData, check StateValue info is correct and buckets
+ // have correct counts.
+ auto data = reports.reports(0).metrics(0).count_metrics().data(0);
+ EXPECT_EQ(1, data.slice_by_state_size());
+ EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_value());
+ EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, data.slice_by_state(0).value());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+
+ data = reports.reports(0).metrics(0).count_metrics().data(1);
+ EXPECT_EQ(1, data.slice_by_state_size());
+ EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_group_id());
+ EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id());
+ EXPECT_EQ(2, data.bucket_info_size());
+ EXPECT_EQ(4, data.bucket_info(0).count());
+ EXPECT_EQ(2, data.bucket_info(1).count());
+
+ data = reports.reports(0).metrics(0).count_metrics().data(2);
+ EXPECT_EQ(1, data.slice_by_state_size());
+ EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_group_id());
+ EXPECT_EQ(StringToId("SCREEN_ON"), data.slice_by_state(0).group_id());
+ EXPECT_EQ(2, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(1, data.bucket_info(1).count());
+}
+
+/**
+* Test a count metric that has one slice_by_state with a primary field.
+
+* Once the CountMetricProducer is initialized, it should have one
+* MetricStateLink stored. State querying using a non-empty primary key
+* should also work as intended.
+*/
+TEST(CountMetricE2eTest, TestSlicedStateWithPrimaryFields) {
+ // Initialize config.
+ StatsdConfig config;
+ config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
+
+ auto appCrashMatcher =
+ CreateSimpleAtomMatcher("APP_CRASH_OCCURRED", android::util::APP_CRASH_OCCURRED);
+ *config.add_atom_matcher() = appCrashMatcher;
+
+ auto state = CreateUidProcessState();
+ *config.add_state() = state;
+
+ // Create count metric that slices by uid process state.
+ int64_t metricId = 123456;
+ auto countMetric = config.add_count_metric();
+ countMetric->set_id(metricId);
+ countMetric->set_what(appCrashMatcher.id());
+ countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
+ countMetric->add_slice_by_state(state.id());
+ MetricStateLink* stateLink = countMetric->add_state_link();
+ stateLink->set_state_atom_id(UID_PROCESS_STATE_ATOM_ID);
+ auto fieldsInWhat = stateLink->mutable_fields_in_what();
+ *fieldsInWhat = CreateDimensions(android::util::APP_CRASH_OCCURRED, {1 /*uid*/});
+ auto fieldsInState = stateLink->mutable_fields_in_state();
+ *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /*uid*/});
+
+ // Initialize StatsLogProcessor.
+ const uint64_t bucketStartTimeNs = 10000000000; // 0:10
+ const uint64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
+ int uid = 12345;
+ int64_t cfgId = 98765;
+ ConfigKey cfgKey(uid, cfgId);
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+
+ // Check that StateTrackers were initialized correctly.
+ EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
+ EXPECT_EQ(1, StateManager::getInstance().getListenersCount(UID_PROCESS_STATE_ATOM_ID));
+
+ // Check that CountMetricProducer was initialized correctly.
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
+ EXPECT_TRUE(metricsManager->isConfigValid());
+ EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+ EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 1);
+ EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), UID_PROCESS_STATE_ATOM_ID);
+ EXPECT_EQ(metricProducer->mStateGroupMap.size(), 0);
+ EXPECT_EQ(metricProducer->mMetric2StateLinks.size(), 1);
+
+ /*
+ NOTE: "1" or "2" represents the uid associated with the state/app crash event
+ bucket #1 bucket #2
+ | 1 2 3 4 5 6 7 8 9 10
+ |------------------------|-------------------------|--
+ 1 1 1 1 1 2 1 1 2 (AppCrashEvents)
+ -----------------------------------------------------PROCESS STATE events
+ 1 2 (TopEvent = 1002)
+ 1 1 (ForegroundServiceEvent = 1003)
+ 2 (ImportantBackgroundEvent = 1006)
+ 1 1 1 (ImportantForegroundEvent = 1005)
+
+ Based on the diagram above, an AppCrashEvent querying for process state value would return:
+ - StateTracker::kStateUnknown
+ - Important foreground
+ - Top
+ - Important foreground
+ - Foreground service
+ - Top (both the app crash and state still have matching uid = 2)
+
+ - Foreground service
+ - Foreground service
+ - Important background
+ */
+ // Initialize log events - first bucket.
+ std::vector<std::unique_ptr<LogEvent>> events;
+ events.push_back(
+ CreateAppCrashOccurredEvent(bucketStartTimeNs + 20 * NS_PER_SEC, 1 /*uid*/)); // 0:30
+ events.push_back(CreateUidProcessStateChangedEvent(
+ bucketStartTimeNs + 30 * NS_PER_SEC, 1 /*uid*/,
+ android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND)); // 0:40
+ events.push_back(
+ CreateAppCrashOccurredEvent(bucketStartTimeNs + 60 * NS_PER_SEC, 1 /*uid*/)); // 1:10
+ events.push_back(CreateUidProcessStateChangedEvent(
+ bucketStartTimeNs + 90 * NS_PER_SEC, 1 /*uid*/,
+ android::app::ProcessStateEnum::PROCESS_STATE_TOP)); // 1:40
+ events.push_back(
+ CreateAppCrashOccurredEvent(bucketStartTimeNs + 120 * NS_PER_SEC, 1 /*uid*/)); // 2:10
+ events.push_back(CreateUidProcessStateChangedEvent(
+ bucketStartTimeNs + 150 * NS_PER_SEC, 1 /*uid*/,
+ android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND)); // 2:40
+ events.push_back(
+ CreateAppCrashOccurredEvent(bucketStartTimeNs + 200 * NS_PER_SEC, 1 /*uid*/)); // 3:30
+ events.push_back(CreateUidProcessStateChangedEvent(
+ bucketStartTimeNs + 210 * NS_PER_SEC, 1 /*uid*/,
+ android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE)); // 3:40
+ events.push_back(
+ CreateAppCrashOccurredEvent(bucketStartTimeNs + 250 * NS_PER_SEC, 1 /*uid*/)); // 4:20
+ events.push_back(CreateUidProcessStateChangedEvent(
+ bucketStartTimeNs + 280 * NS_PER_SEC, 2 /*uid*/,
+ android::app::ProcessStateEnum::PROCESS_STATE_TOP)); // 4:50
+ events.push_back(
+ CreateAppCrashOccurredEvent(bucketStartTimeNs + 285 * NS_PER_SEC, 2 /*uid*/)); // 4:55
+
+ // Initialize log events - second bucket.
+ events.push_back(
+ CreateAppCrashOccurredEvent(bucketStartTimeNs + 360 * NS_PER_SEC, 1 /*uid*/)); // 6:10
+ events.push_back(CreateUidProcessStateChangedEvent(
+ bucketStartTimeNs + 390 * NS_PER_SEC, 1 /*uid*/,
+ android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE)); // 6:40
+ events.push_back(CreateUidProcessStateChangedEvent(
+ bucketStartTimeNs + 430 * NS_PER_SEC, 2 /*uid*/,
+ android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND)); // 7:20
+ events.push_back(
+ CreateAppCrashOccurredEvent(bucketStartTimeNs + 440 * NS_PER_SEC, 1 /*uid*/)); // 7:30
+ events.push_back(CreateUidProcessStateChangedEvent(
+ bucketStartTimeNs + 540 * NS_PER_SEC, 1 /*uid*/,
+ android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND)); // 9:10
+ events.push_back(
+ CreateAppCrashOccurredEvent(bucketStartTimeNs + 570 * NS_PER_SEC, 2 /*uid*/)); // 9:40
+
+ // Send log events to StatsLogProcessor.
+ for (auto& event : events) {
+ processor->OnLogEvent(event.get());
+ }
+
+ // Check dump report.
+ vector<uint8_t> buffer;
+ ConfigMetricsReportList reports;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP,
+ FAST, &buffer);
+ EXPECT_GT(buffer.size(), 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
+ EXPECT_EQ(5, reports.reports(0).metrics(0).count_metrics().data_size());
+
+ // For each CountMetricData, check StateValue info is correct and buckets
+ // have correct counts.
+ auto data = reports.reports(0).metrics(0).count_metrics().data(0);
+ EXPECT_EQ(1, data.slice_by_state_size());
+ EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_value());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, data.slice_by_state(0).value());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+
+ data = reports.reports(0).metrics(0).count_metrics().data(1);
+ EXPECT_EQ(1, data.slice_by_state_size());
+ EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_value());
+ EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, data.slice_by_state(0).value());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+
+ data = reports.reports(0).metrics(0).count_metrics().data(2);
+ EXPECT_EQ(1, data.slice_by_state_size());
+ EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_value());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(0).value());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(2, data.bucket_info(0).count());
+
+ data = reports.reports(0).metrics(0).count_metrics().data(3);
+ EXPECT_EQ(1, data.slice_by_state_size());
+ EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_value());
+ EXPECT_EQ(android::app::PROCESS_STATE_TOP, data.slice_by_state(0).value());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(2, data.bucket_info(0).count());
+
+ data = reports.reports(0).metrics(0).count_metrics().data(4);
+ EXPECT_EQ(1, data.slice_by_state_size());
+ EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_value());
+ EXPECT_EQ(android::app::PROCESS_STATE_FOREGROUND_SERVICE, data.slice_by_state(0).value());
+ EXPECT_EQ(2, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(2, data.bucket_info(1).count());
+}
+
+TEST(CountMetricE2eTest, TestMultipleSlicedStates) {
+ // Initialize config.
+ StatsdConfig config;
+ config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
+
+ auto appCrashMatcher =
+ CreateSimpleAtomMatcher("APP_CRASH_OCCURRED", android::util::APP_CRASH_OCCURRED);
+ *config.add_atom_matcher() = appCrashMatcher;
+
+ auto state1 = CreateScreenStateWithOnOffMap();
+ *config.add_state() = state1;
+ auto state2 = CreateUidProcessState();
+ *config.add_state() = state2;
+
+ // Create count metric that slices by screen state with on/off map and
+ // slices by uid process state.
+ int64_t metricId = 123456;
+ auto countMetric = config.add_count_metric();
+ countMetric->set_id(metricId);
+ countMetric->set_what(appCrashMatcher.id());
+ countMetric->set_bucket(TimeUnit::FIVE_MINUTES);
+ countMetric->add_slice_by_state(state1.id());
+ countMetric->add_slice_by_state(state2.id());
+ MetricStateLink* stateLink = countMetric->add_state_link();
+ stateLink->set_state_atom_id(UID_PROCESS_STATE_ATOM_ID);
+ auto fieldsInWhat = stateLink->mutable_fields_in_what();
+ *fieldsInWhat = CreateDimensions(android::util::APP_CRASH_OCCURRED, {1 /*uid*/});
+ auto fieldsInState = stateLink->mutable_fields_in_state();
+ *fieldsInState = CreateDimensions(UID_PROCESS_STATE_ATOM_ID, {1 /*uid*/});
+
+ // Initialize StatsLogProcessor.
+ const uint64_t bucketStartTimeNs = 10000000000; // 0:10
+ const uint64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
+ int uid = 12345;
+ int64_t cfgId = 98765;
+ ConfigKey cfgKey(uid, cfgId);
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+
+ // Check that StateTrackers were properly initialized.
+ EXPECT_EQ(2, StateManager::getInstance().getStateTrackersCount());
+ EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID));
+ EXPECT_EQ(1, StateManager::getInstance().getListenersCount(UID_PROCESS_STATE_ATOM_ID));
+
+ // Check that CountMetricProducer was initialized correctly.
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
+ EXPECT_TRUE(metricsManager->isConfigValid());
+ EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+ EXPECT_EQ(metricProducer->mSlicedStateAtoms.size(), 2);
+ EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(0), SCREEN_STATE_ATOM_ID);
+ EXPECT_EQ(metricProducer->mSlicedStateAtoms.at(1), UID_PROCESS_STATE_ATOM_ID);
+ EXPECT_EQ(metricProducer->mStateGroupMap.size(), 1);
+ EXPECT_EQ(metricProducer->mMetric2StateLinks.size(), 1);
+
+ StateMap map = state1.map();
+ for (auto group : map.group()) {
+ for (auto value : group.value()) {
+ EXPECT_EQ(metricProducer->mStateGroupMap[SCREEN_STATE_ATOM_ID][value],
+ group.group_id());
+ }
+ }
+
+ /*
+ bucket #1 bucket #2
+ | 1 2 3 4 5 6 7 8 9 10 (minutes)
+ |------------------------|------------------------|--
+ 1 1 1 1 1 2 1 1 2 (AppCrashEvents)
+ ---------------------------------------------------SCREEN_OFF events
+ | (ScreenUnknownEvent = 0)
+ | | (ScreenOffEvent = 1)
+ | (ScreenDozeEvent = 3)
+ ---------------------------------------------------SCREEN_ON events
+ | | (ScreenOnEvent = 2)
+ | (ScreenOnSuspendEvent = 6)
+ ---------------------------------------------------PROCESS STATE events
+ 1 2 (TopEvent = 1002)
+ 1 (ForegroundServiceEvent = 1003)
+ 2 (ImportantBackgroundEvent = 1006)
+ 1 1 1 (ImportantForegroundEvent = 1005)
+
+ Based on the diagram above, Screen State / Process State pairs for each
+ AppCrashEvent are:
+ - StateTracker::kStateUnknown / important foreground
+ - off / important foreground
+ - off / Top
+ - on / important foreground
+ - off / important foreground
+ - off / top
+
+ - off / important foreground
+ - off / foreground service
+ - on / important background
+
+ */
+ // Initialize log events - first bucket.
+ std::vector<std::unique_ptr<LogEvent>> events;
+ events.push_back(CreateUidProcessStateChangedEvent(
+ bucketStartTimeNs + 5 * NS_PER_SEC, 1 /*uid*/,
+ android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND)); // 0:15
+ events.push_back(
+ CreateAppCrashOccurredEvent(bucketStartTimeNs + 20 * NS_PER_SEC, 1 /*uid*/)); // 0:30
+ events.push_back(CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 30 * NS_PER_SEC,
+ android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN)); // 0:40
+ events.push_back(
+ CreateAppCrashOccurredEvent(bucketStartTimeNs + 60 * NS_PER_SEC, 1 /*uid*/)); // 1:10
+ events.push_back(CreateUidProcessStateChangedEvent(
+ bucketStartTimeNs + 90 * NS_PER_SEC, 1 /*uid*/,
+ android::app::ProcessStateEnum::PROCESS_STATE_TOP)); // 1:40
+ events.push_back(CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 90 * NS_PER_SEC,
+ android::view::DisplayStateEnum::DISPLAY_STATE_OFF)); // 1:40
+ events.push_back(
+ CreateAppCrashOccurredEvent(bucketStartTimeNs + 120 * NS_PER_SEC, 1 /*uid*/)); // 2:10
+ events.push_back(CreateUidProcessStateChangedEvent(
+ bucketStartTimeNs + 150 * NS_PER_SEC, 1 /*uid*/,
+ android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND)); // 2:40
+ events.push_back(CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 160 * NS_PER_SEC,
+ android::view::DisplayStateEnum::DISPLAY_STATE_ON)); // 2:50
+ events.push_back(
+ CreateAppCrashOccurredEvent(bucketStartTimeNs + 200 * NS_PER_SEC, 1 /*uid*/)); // 3:30
+ events.push_back(CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 210 * NS_PER_SEC,
+ android::view::DisplayStateEnum::DISPLAY_STATE_DOZE)); // 3:40
+ events.push_back(
+ CreateAppCrashOccurredEvent(bucketStartTimeNs + 250 * NS_PER_SEC, 1 /*uid*/)); // 4:20
+ events.push_back(CreateUidProcessStateChangedEvent(
+ bucketStartTimeNs + 280 * NS_PER_SEC, 2 /*uid*/,
+ android::app::ProcessStateEnum::PROCESS_STATE_TOP)); // 4:50
+ events.push_back(
+ CreateAppCrashOccurredEvent(bucketStartTimeNs + 285 * NS_PER_SEC, 2 /*uid*/)); // 4:55
+
+ // Initialize log events - second bucket.
+ events.push_back(
+ CreateAppCrashOccurredEvent(bucketStartTimeNs + 360 * NS_PER_SEC, 1 /*uid*/)); // 6:10
+ events.push_back(CreateUidProcessStateChangedEvent(
+ bucketStartTimeNs + 380 * NS_PER_SEC, 1 /*uid*/,
+ android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE)); // 6:30
+ events.push_back(CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 390 * NS_PER_SEC,
+ android::view::DisplayStateEnum::DISPLAY_STATE_ON_SUSPEND)); // 6:40
+ events.push_back(CreateUidProcessStateChangedEvent(
+ bucketStartTimeNs + 420 * NS_PER_SEC, 2 /*uid*/,
+ android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND)); // 7:10
+ events.push_back(CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 440 * NS_PER_SEC,
+ android::view::DisplayStateEnum::DISPLAY_STATE_OFF)); // 7:30
+ events.push_back(
+ CreateAppCrashOccurredEvent(bucketStartTimeNs + 450 * NS_PER_SEC, 1 /*uid*/)); // 7:40
+ events.push_back(CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 520 * NS_PER_SEC,
+ android::view::DisplayStateEnum::DISPLAY_STATE_ON)); // 8:50
+ events.push_back(CreateUidProcessStateChangedEvent(
+ bucketStartTimeNs + 540 * NS_PER_SEC, 1 /*uid*/,
+ android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND)); // 9:10
+ events.push_back(
+ CreateAppCrashOccurredEvent(bucketStartTimeNs + 570 * NS_PER_SEC, 2 /*uid*/)); // 9:40
+
+ // Send log events to StatsLogProcessor.
+ for (auto& event : events) {
+ processor->OnLogEvent(event.get());
+ }
+
+ // Check dump report.
+ vector<uint8_t> buffer;
+ ConfigMetricsReportList reports;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs * 2 + 1, false, true, ADB_DUMP,
+ FAST, &buffer);
+ EXPECT_GT(buffer.size(), 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics());
+ EXPECT_EQ(6, reports.reports(0).metrics(0).count_metrics().data_size());
+
+ // For each CountMetricData, check StateValue info is correct and buckets
+ // have correct counts.
+ auto data = reports.reports(0).metrics(0).count_metrics().data(0);
+ EXPECT_EQ(2, data.slice_by_state_size());
+ EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_group_id());
+ EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id());
+ EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
+ EXPECT_TRUE(data.slice_by_state(1).has_value());
+ EXPECT_EQ(android::app::PROCESS_STATE_FOREGROUND_SERVICE, data.slice_by_state(1).value());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+
+ data = reports.reports(0).metrics(0).count_metrics().data(1);
+ EXPECT_EQ(2, data.slice_by_state_size());
+ EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_value());
+ EXPECT_EQ(-1, data.slice_by_state(0).value());
+ EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
+ EXPECT_TRUE(data.slice_by_state(1).has_value());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+
+ data = reports.reports(0).metrics(0).count_metrics().data(2);
+ EXPECT_EQ(2, data.slice_by_state_size());
+ EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_group_id());
+ EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id());
+ EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
+ EXPECT_TRUE(data.slice_by_state(1).has_value());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value());
+ EXPECT_EQ(2, data.bucket_info_size());
+ EXPECT_EQ(2, data.bucket_info(0).count());
+ EXPECT_EQ(1, data.bucket_info(1).count());
+
+ data = reports.reports(0).metrics(0).count_metrics().data(3);
+ EXPECT_EQ(2, data.slice_by_state_size());
+ EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_group_id());
+ EXPECT_EQ(StringToId("SCREEN_ON"), data.slice_by_state(0).group_id());
+ EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
+ EXPECT_TRUE(data.slice_by_state(1).has_value());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+
+ data = reports.reports(0).metrics(0).count_metrics().data(4);
+ EXPECT_EQ(2, data.slice_by_state_size());
+ EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_group_id());
+ EXPECT_EQ(StringToId("SCREEN_ON"), data.slice_by_state(0).group_id());
+ EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
+ EXPECT_TRUE(data.slice_by_state(1).has_value());
+ EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, data.slice_by_state(1).value());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+
+ data = reports.reports(0).metrics(0).count_metrics().data(5);
+ EXPECT_EQ(2, data.slice_by_state_size());
+ EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id());
+ EXPECT_TRUE(data.slice_by_state(0).has_group_id());
+ EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id());
+ EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id());
+ EXPECT_TRUE(data.slice_by_state(1).has_value());
+ EXPECT_EQ(android::app::PROCESS_STATE_TOP, data.slice_by_state(1).value());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(2, data.bucket_info(0).count());
+}
} // namespace statsd
} // namespace os
diff --git a/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp b/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp
index 8eb5f69..b586b06 100644
--- a/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp
@@ -26,688 +26,688 @@
#ifdef __ANDROID__
-// TODO(b/149590301): Update these tests to use new socket schema.
-//TEST(DurationMetricE2eTest, TestOneBucket) {
-// StatsdConfig config;
-// config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
-//
-// auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
-// auto screenOffMatcher = CreateScreenTurnedOffAtomMatcher();
-// *config.add_atom_matcher() = screenOnMatcher;
-// *config.add_atom_matcher() = screenOffMatcher;
-//
-// auto durationPredicate = CreateScreenIsOnPredicate();
-// *config.add_predicate() = durationPredicate;
-//
-// int64_t metricId = 123456;
-// auto durationMetric = config.add_duration_metric();
-// durationMetric->set_id(metricId);
-// durationMetric->set_what(durationPredicate.id());
-// durationMetric->set_bucket(FIVE_MINUTES);
-// durationMetric->set_aggregation_type(DurationMetric_AggregationType_SUM);
-//
-//
-// const int64_t baseTimeNs = 0; // 0:00
-// const int64_t configAddedTimeNs = baseTimeNs + 1 * NS_PER_SEC; // 0:01
-// const int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000LL * 1000LL;
-//
-// int uid = 12345;
-// int64_t cfgId = 98765;
-// ConfigKey cfgKey(uid, cfgId);
-//
-// auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey);
-//
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-// EXPECT_TRUE(metricsManager->isConfigValid());
-// EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-// sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-//
-// std::unique_ptr<LogEvent> event;
-//
-// // Screen is off at start of bucket.
-// event = CreateScreenStateChangedEvent(
-// android::view::DISPLAY_STATE_OFF, configAddedTimeNs); // 0:01
-// processor->OnLogEvent(event.get());
-//
-// // Turn screen on.
-// const int64_t durationStartNs = configAddedTimeNs + 10 * NS_PER_SEC; // 0:11
-// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, durationStartNs);
-// processor->OnLogEvent(event.get());
-//
-// // Turn off screen 30 seconds after turning on.
-// const int64_t durationEndNs = durationStartNs + 30 * NS_PER_SEC; // 0:41
-// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF, durationEndNs);
-// processor->OnLogEvent(event.get());
-//
-// event = CreateScreenBrightnessChangedEvent(64, durationEndNs + 1 * NS_PER_SEC); // 0:42
-// processor->OnLogEvent(event.get());
-//
-// ConfigMetricsReportList reports;
-// vector<uint8_t> buffer;
-// processor->onDumpReport(cfgKey, configAddedTimeNs + bucketSizeNs + 1 * NS_PER_SEC, false, true,
-// ADB_DUMP, FAST, &buffer); // 5:01
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(1, reports.reports_size());
-// EXPECT_EQ(1, reports.reports(0).metrics_size());
-// EXPECT_EQ(metricId, reports.reports(0).metrics(0).metric_id());
-// EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
-//
-// const StatsLogReport::DurationMetricDataWrapper& durationMetrics =
-// reports.reports(0).metrics(0).duration_metrics();
-// EXPECT_EQ(1, durationMetrics.data_size());
-//
-// auto data = durationMetrics.data(0);
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(durationEndNs - durationStartNs, data.bucket_info(0).duration_nanos());
-// EXPECT_EQ(configAddedTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-//}
-//
-//TEST(DurationMetricE2eTest, TestTwoBuckets) {
-// StatsdConfig config;
-// config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
-//
-// auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
-// auto screenOffMatcher = CreateScreenTurnedOffAtomMatcher();
-// *config.add_atom_matcher() = screenOnMatcher;
-// *config.add_atom_matcher() = screenOffMatcher;
-//
-// auto durationPredicate = CreateScreenIsOnPredicate();
-// *config.add_predicate() = durationPredicate;
-//
-// int64_t metricId = 123456;
-// auto durationMetric = config.add_duration_metric();
-// durationMetric->set_id(metricId);
-// durationMetric->set_what(durationPredicate.id());
-// durationMetric->set_bucket(FIVE_MINUTES);
-// durationMetric->set_aggregation_type(DurationMetric_AggregationType_SUM);
-//
-//
-// const int64_t baseTimeNs = 0; // 0:00
-// const int64_t configAddedTimeNs = baseTimeNs + 1 * NS_PER_SEC; // 0:01
-// const int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000LL * 1000LL;
-//
-// int uid = 12345;
-// int64_t cfgId = 98765;
-// ConfigKey cfgKey(uid, cfgId);
-//
-// auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey);
-//
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-// EXPECT_TRUE(metricsManager->isConfigValid());
-// EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-// sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-//
-// std::unique_ptr<LogEvent> event;
-//
-// // Screen is off at start of bucket.
-// event = CreateScreenStateChangedEvent(
-// android::view::DISPLAY_STATE_OFF, configAddedTimeNs); // 0:01
-// processor->OnLogEvent(event.get());
-//
-// // Turn screen on.
-// const int64_t durationStartNs = configAddedTimeNs + 10 * NS_PER_SEC; // 0:11
-// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, durationStartNs);
-// processor->OnLogEvent(event.get());
-//
-// // Turn off screen 30 seconds after turning on.
-// const int64_t durationEndNs = durationStartNs + 30 * NS_PER_SEC; // 0:41
-// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF, durationEndNs);
-// processor->OnLogEvent(event.get());
-//
-// event = CreateScreenBrightnessChangedEvent(64, durationEndNs + 1 * NS_PER_SEC); // 0:42
-// processor->OnLogEvent(event.get());
-//
-// ConfigMetricsReportList reports;
-// vector<uint8_t> buffer;
-// processor->onDumpReport(cfgKey, configAddedTimeNs + 2 * bucketSizeNs + 1 * NS_PER_SEC, false, true,
-// ADB_DUMP, FAST, &buffer); // 10:01
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(1, reports.reports_size());
-// EXPECT_EQ(1, reports.reports(0).metrics_size());
-// EXPECT_EQ(metricId, reports.reports(0).metrics(0).metric_id());
-// EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
-//
-// const StatsLogReport::DurationMetricDataWrapper& durationMetrics =
-// reports.reports(0).metrics(0).duration_metrics();
-// EXPECT_EQ(1, durationMetrics.data_size());
-//
-// auto data = durationMetrics.data(0);
-// EXPECT_EQ(1, data.bucket_info_size());
-//
-// auto bucketInfo = data.bucket_info(0);
-// EXPECT_EQ(0, bucketInfo.bucket_num());
-// EXPECT_EQ(durationEndNs - durationStartNs, bucketInfo.duration_nanos());
-// EXPECT_EQ(configAddedTimeNs, bucketInfo.start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
-//}
-//
-//TEST(DurationMetricE2eTest, TestWithActivation) {
-// StatsdConfig config;
-// config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
-//
-// auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
-// auto screenOffMatcher = CreateScreenTurnedOffAtomMatcher();
-// auto crashMatcher = CreateProcessCrashAtomMatcher();
-// *config.add_atom_matcher() = screenOnMatcher;
-// *config.add_atom_matcher() = screenOffMatcher;
-// *config.add_atom_matcher() = crashMatcher;
-//
-// auto durationPredicate = CreateScreenIsOnPredicate();
-// *config.add_predicate() = durationPredicate;
-//
-// int64_t metricId = 123456;
-// auto durationMetric = config.add_duration_metric();
-// durationMetric->set_id(metricId);
-// durationMetric->set_what(durationPredicate.id());
-// durationMetric->set_bucket(FIVE_MINUTES);
-// durationMetric->set_aggregation_type(DurationMetric_AggregationType_SUM);
-//
-// auto metric_activation1 = config.add_metric_activation();
-// metric_activation1->set_metric_id(metricId);
-// auto event_activation1 = metric_activation1->add_event_activation();
-// event_activation1->set_atom_matcher_id(crashMatcher.id());
-// event_activation1->set_ttl_seconds(30); // 30 secs.
-//
-// const int64_t bucketStartTimeNs = 10000000000;
-// const int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000LL * 1000LL;
-//
-// int uid = 12345;
-// int64_t cfgId = 98765;
-// ConfigKey cfgKey(uid, cfgId);
-//
-// sp<UidMap> m = new UidMap();
-// sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-// sp<AlarmMonitor> anomalyAlarmMonitor;
-// sp<AlarmMonitor> subscriberAlarmMonitor;
-// vector<int64_t> activeConfigsBroadcast;
-//
-// int broadcastCount = 0;
-// StatsLogProcessor processor(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor,
-// bucketStartTimeNs, [](const ConfigKey& key) { return true; },
-// [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
-// const vector<int64_t>& activeConfigs) {
-// broadcastCount++;
-// EXPECT_EQ(broadcastUid, uid);
-// activeConfigsBroadcast.clear();
-// activeConfigsBroadcast.insert(activeConfigsBroadcast.end(),
-// activeConfigs.begin(), activeConfigs.end());
-// return true;
-// });
-//
-// processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config); // 0:00
-//
-// EXPECT_EQ(processor.mMetricsManagers.size(), 1u);
-// sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
-// EXPECT_TRUE(metricsManager->isConfigValid());
-// EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-// sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-// auto& eventActivationMap = metricProducer->mEventActivationMap;
-//
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// EXPECT_EQ(eventActivationMap.size(), 1u);
-// EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
-//
-// std::unique_ptr<LogEvent> event;
-//
-// // Turn screen off.
-// event = CreateScreenStateChangedEvent(
-// android::view::DISPLAY_STATE_OFF, bucketStartTimeNs + 2 * NS_PER_SEC); // 0:02
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + 2 * NS_PER_SEC);
-//
-// // Turn screen on.
-// const int64_t durationStartNs = bucketStartTimeNs + 5 * NS_PER_SEC; // 0:05
-// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, durationStartNs);
-// processor.OnLogEvent(event.get(), durationStartNs);
-//
-// // Activate metric.
-// const int64_t activationStartNs = bucketStartTimeNs + 5 * NS_PER_SEC; // 0:10
-// const int64_t activationEndNs =
-// activationStartNs + event_activation1->ttl_seconds() * NS_PER_SEC; // 0:40
-// event = CreateAppCrashEvent(111, activationStartNs);
-// processor.OnLogEvent(event.get(), activationStartNs);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 1);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-// EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, activationStartNs);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
-//
-// // Expire activation.
-// const int64_t expirationNs = activationEndNs + 7 * NS_PER_SEC;
-// event = CreateScreenBrightnessChangedEvent(64, expirationNs); // 0:47
-// processor.OnLogEvent(event.get(), expirationNs);
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 2);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 0);
-// EXPECT_EQ(eventActivationMap.size(), 1u);
-// EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, activationStartNs);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
-//
-// // Turn off screen 10 seconds after activation expiration.
-// const int64_t durationEndNs = activationEndNs + 10 * NS_PER_SEC; // 0:50
-// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF, durationEndNs);
-// processor.OnLogEvent(event.get(),durationEndNs);
-//
-// // Turn screen on.
-// const int64_t duration2StartNs = durationEndNs + 5 * NS_PER_SEC; // 0:55
-// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, duration2StartNs);
-// processor.OnLogEvent(event.get(), duration2StartNs);
-//
-// // Turn off screen.
-// const int64_t duration2EndNs = duration2StartNs + 10 * NS_PER_SEC; // 1:05
-// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF, duration2EndNs);
-// processor.OnLogEvent(event.get(), duration2EndNs);
-//
-// // Activate metric.
-// const int64_t activation2StartNs = duration2EndNs + 5 * NS_PER_SEC; // 1:10
-// const int64_t activation2EndNs =
-// activation2StartNs + event_activation1->ttl_seconds() * NS_PER_SEC; // 1:40
-// event = CreateAppCrashEvent(211, activation2StartNs);
-// processor.OnLogEvent(event.get(), activation2StartNs);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 3);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-// EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, activation2StartNs);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
-//
-// ConfigMetricsReportList reports;
-// vector<uint8_t> buffer;
-// processor.onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1 * NS_PER_SEC, false, true,
-// ADB_DUMP, FAST, &buffer); // 5:01
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(1, reports.reports_size());
-// EXPECT_EQ(1, reports.reports(0).metrics_size());
-// EXPECT_EQ(metricId, reports.reports(0).metrics(0).metric_id());
-// EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
-//
-// const StatsLogReport::DurationMetricDataWrapper& durationMetrics =
-// reports.reports(0).metrics(0).duration_metrics();
-// EXPECT_EQ(1, durationMetrics.data_size());
-//
-// auto data = durationMetrics.data(0);
-// EXPECT_EQ(1, data.bucket_info_size());
-//
-// auto bucketInfo = data.bucket_info(0);
-// EXPECT_EQ(0, bucketInfo.bucket_num());
-// EXPECT_EQ(bucketStartTimeNs, bucketInfo.start_bucket_elapsed_nanos());
-// EXPECT_EQ(expirationNs, bucketInfo.end_bucket_elapsed_nanos());
-// EXPECT_EQ(expirationNs - durationStartNs, bucketInfo.duration_nanos());
-//}
-//
-//TEST(DurationMetricE2eTest, TestWithCondition) {
-// StatsdConfig config;
-// config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
-// *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
-// *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
-// *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher();
-// *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher();
-//
-// auto holdingWakelockPredicate = CreateHoldingWakelockPredicate();
-// *config.add_predicate() = holdingWakelockPredicate;
-//
-// auto isInBackgroundPredicate = CreateIsInBackgroundPredicate();
-// *config.add_predicate() = isInBackgroundPredicate;
-//
-// auto durationMetric = config.add_duration_metric();
-// durationMetric->set_id(StringToId("WakelockDuration"));
-// durationMetric->set_what(holdingWakelockPredicate.id());
-// durationMetric->set_condition(isInBackgroundPredicate.id());
-// durationMetric->set_aggregation_type(DurationMetric::SUM);
-// durationMetric->set_bucket(FIVE_MINUTES);
-//
-// ConfigKey cfgKey;
-// uint64_t bucketStartTimeNs = 10000000000;
-// uint64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-// EXPECT_TRUE(metricsManager->isConfigValid());
-// EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-// sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-// auto& eventActivationMap = metricProducer->mEventActivationMap;
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_TRUE(eventActivationMap.empty());
-//
-// int appUid = 123;
-// std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(appUid, "App1")};
-//
-// auto event = CreateAcquireWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + 10 * NS_PER_SEC); // 0:10
-// processor->OnLogEvent(event.get());
-//
-// event = CreateMoveToBackgroundEvent(appUid, bucketStartTimeNs + 22 * NS_PER_SEC); // 0:22
-// processor->OnLogEvent(event.get());
-//
-// event = CreateMoveToForegroundEvent(
-// appUid, bucketStartTimeNs + (3 * 60 + 15) * NS_PER_SEC); // 3:15
-// processor->OnLogEvent(event.get());
-//
-// event = CreateReleaseWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + 4 * 60 * NS_PER_SEC); // 4:00
-// processor->OnLogEvent(event.get());
-//
-// vector<uint8_t> buffer;
-// ConfigMetricsReportList reports;
-// processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_GT(buffer.size(), 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-//
-// EXPECT_EQ(1, reports.reports_size());
-// EXPECT_EQ(1, reports.reports(0).metrics_size());
-// EXPECT_EQ(1, reports.reports(0).metrics(0).duration_metrics().data_size());
-//
-// auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
-//
-// // Validate bucket info.
-// EXPECT_EQ(1, data.bucket_info_size());
-//
-// auto bucketInfo = data.bucket_info(0);
-// EXPECT_EQ(bucketStartTimeNs, bucketInfo.start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
-// EXPECT_EQ((2 * 60 + 53) * NS_PER_SEC, bucketInfo.duration_nanos());
-//}
-//
-//TEST(DurationMetricE2eTest, TestWithSlicedCondition) {
-// StatsdConfig config;
-// config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
-// auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
-// *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
-// *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
-// *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher();
-// *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher();
-//
-// auto holdingWakelockPredicate = CreateHoldingWakelockPredicate();
-// // The predicate is dimensioning by first attribution node by uid.
-// FieldMatcher dimensions = CreateAttributionUidDimensions(
-// android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
-// *holdingWakelockPredicate.mutable_simple_predicate()->mutable_dimensions() = dimensions;
-// *config.add_predicate() = holdingWakelockPredicate;
-//
-// auto isInBackgroundPredicate = CreateIsInBackgroundPredicate();
-// *isInBackgroundPredicate.mutable_simple_predicate()->mutable_dimensions() =
-// CreateDimensions(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {Position::FIRST});
-// *config.add_predicate() = isInBackgroundPredicate;
-//
-// auto durationMetric = config.add_duration_metric();
-// durationMetric->set_id(StringToId("WakelockDuration"));
-// durationMetric->set_what(holdingWakelockPredicate.id());
-// durationMetric->set_condition(isInBackgroundPredicate.id());
-// durationMetric->set_aggregation_type(DurationMetric::SUM);
-// // The metric is dimensioning by first attribution node and only by uid.
-// *durationMetric->mutable_dimensions_in_what() =
-// CreateAttributionUidDimensions(
-// android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
-// durationMetric->set_bucket(FIVE_MINUTES);
-//
-// // Links between wakelock state atom and condition of app is in background.
-// auto links = durationMetric->add_links();
-// links->set_condition(isInBackgroundPredicate.id());
-// auto dimensionWhat = links->mutable_fields_in_what();
-// dimensionWhat->set_field(android::util::WAKELOCK_STATE_CHANGED);
-// dimensionWhat->add_child()->set_field(1); // uid field.
-// *links->mutable_fields_in_condition() = CreateAttributionUidDimensions(
-// android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, { Position::FIRST });
-//
-// ConfigKey cfgKey;
-// uint64_t bucketStartTimeNs = 10000000000;
-// uint64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-// EXPECT_TRUE(metricsManager->isConfigValid());
-// EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-// sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-// auto& eventActivationMap = metricProducer->mEventActivationMap;
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_TRUE(eventActivationMap.empty());
-//
-// int appUid = 123;
-// std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(appUid, "App1")};
-//
-// auto event = CreateAcquireWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + 10 * NS_PER_SEC); // 0:10
-// processor->OnLogEvent(event.get());
-//
-// event = CreateMoveToBackgroundEvent(appUid, bucketStartTimeNs + 22 * NS_PER_SEC); // 0:22
-// processor->OnLogEvent(event.get());
-//
-// event = CreateReleaseWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + 60 * NS_PER_SEC); // 1:00
-// processor->OnLogEvent(event.get());
-//
-//
-// event = CreateMoveToForegroundEvent(
-// appUid, bucketStartTimeNs + (3 * 60 + 15) * NS_PER_SEC); // 3:15
-// processor->OnLogEvent(event.get());
-//
-// vector<uint8_t> buffer;
-// ConfigMetricsReportList reports;
-// processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_GT(buffer.size(), 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-//
-// EXPECT_EQ(1, reports.reports_size());
-// EXPECT_EQ(1, reports.reports(0).metrics_size());
-// EXPECT_EQ(1, reports.reports(0).metrics(0).duration_metrics().data_size());
-//
-// auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
-// // Validate dimension value.
-// ValidateAttributionUidDimension(data.dimensions_in_what(),
-// android::util::WAKELOCK_STATE_CHANGED, appUid);
-// // Validate bucket info.
-// EXPECT_EQ(1, data.bucket_info_size());
-//
-// auto bucketInfo = data.bucket_info(0);
-// EXPECT_EQ(bucketStartTimeNs, bucketInfo.start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
-// EXPECT_EQ(38 * NS_PER_SEC, bucketInfo.duration_nanos());
-//}
-//
-//TEST(DurationMetricE2eTest, TestWithActivationAndSlicedCondition) {
-// StatsdConfig config;
-// config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
-// auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
-// *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
-// *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
-// *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher();
-// *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher();
-// *config.add_atom_matcher() = screenOnMatcher;
-//
-// auto holdingWakelockPredicate = CreateHoldingWakelockPredicate();
-// // The predicate is dimensioning by first attribution node by uid.
-// FieldMatcher dimensions = CreateAttributionUidDimensions(
-// android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
-// *holdingWakelockPredicate.mutable_simple_predicate()->mutable_dimensions() = dimensions;
-// *config.add_predicate() = holdingWakelockPredicate;
-//
-// auto isInBackgroundPredicate = CreateIsInBackgroundPredicate();
-// *isInBackgroundPredicate.mutable_simple_predicate()->mutable_dimensions() =
-// CreateDimensions(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {Position::FIRST});
-// *config.add_predicate() = isInBackgroundPredicate;
-//
-// auto durationMetric = config.add_duration_metric();
-// durationMetric->set_id(StringToId("WakelockDuration"));
-// durationMetric->set_what(holdingWakelockPredicate.id());
-// durationMetric->set_condition(isInBackgroundPredicate.id());
-// durationMetric->set_aggregation_type(DurationMetric::SUM);
-// // The metric is dimensioning by first attribution node and only by uid.
-// *durationMetric->mutable_dimensions_in_what() =
-// CreateAttributionUidDimensions(
-// android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
-// durationMetric->set_bucket(FIVE_MINUTES);
-//
-// // Links between wakelock state atom and condition of app is in background.
-// auto links = durationMetric->add_links();
-// links->set_condition(isInBackgroundPredicate.id());
-// auto dimensionWhat = links->mutable_fields_in_what();
-// dimensionWhat->set_field(android::util::WAKELOCK_STATE_CHANGED);
-// dimensionWhat->add_child()->set_field(1); // uid field.
-// *links->mutable_fields_in_condition() = CreateAttributionUidDimensions(
-// android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, { Position::FIRST });
-//
-// auto metric_activation1 = config.add_metric_activation();
-// metric_activation1->set_metric_id(durationMetric->id());
-// auto event_activation1 = metric_activation1->add_event_activation();
-// event_activation1->set_atom_matcher_id(screenOnMatcher.id());
-// event_activation1->set_ttl_seconds(60 * 2); // 2 minutes.
-//
-// ConfigKey cfgKey;
-// uint64_t bucketStartTimeNs = 10000000000;
-// uint64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
-// EXPECT_TRUE(metricsManager->isConfigValid());
-// EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-// sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-// auto& eventActivationMap = metricProducer->mEventActivationMap;
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// EXPECT_EQ(eventActivationMap.size(), 1u);
-// EXPECT_TRUE(eventActivationMap.find(4) != eventActivationMap.end());
-// EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[4]->start_ns, 0);
-// EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
-//
-// int appUid = 123;
-// std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(appUid, "App1")};
-//
-// auto event = CreateAcquireWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + 10 * NS_PER_SEC); // 0:10
-// processor->OnLogEvent(event.get());
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[4]->start_ns, 0);
-// EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
-//
-// event = CreateMoveToBackgroundEvent(appUid, bucketStartTimeNs + 22 * NS_PER_SEC); // 0:22
-// processor->OnLogEvent(event.get());
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[4]->start_ns, 0);
-// EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
-//
-// const int64_t durationStartNs = bucketStartTimeNs + 30 * NS_PER_SEC; // 0:30
-// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, durationStartNs);
-// processor->OnLogEvent(event.get());
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[4]->start_ns, durationStartNs);
-// EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
-//
-// const int64_t durationEndNs =
-// durationStartNs + (event_activation1->ttl_seconds() + 30) * NS_PER_SEC; // 3:00
-// event = CreateAppCrashEvent(333, durationEndNs);
-// processor->OnLogEvent(event.get());
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[4]->start_ns, durationStartNs);
-// EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
-//
-// event = CreateMoveToForegroundEvent(
-// appUid, bucketStartTimeNs + (3 * 60 + 15) * NS_PER_SEC); // 3:15
-// processor->OnLogEvent(event.get());
-//
-// event = CreateReleaseWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + (4 * 60 + 17) * NS_PER_SEC); // 4:17
-// processor->OnLogEvent(event.get());
-//
-// event = CreateMoveToBackgroundEvent(
-// appUid, bucketStartTimeNs + (4 * 60 + 20) * NS_PER_SEC); // 4:20
-// processor->OnLogEvent(event.get());
-//
-// event = CreateAcquireWakelockEvent(
-// attributions1, "wl1", bucketStartTimeNs + (4 * 60 + 25) * NS_PER_SEC); // 4:25
-// processor->OnLogEvent(event.get());
-//
-// const int64_t duration2StartNs = bucketStartTimeNs + (4 * 60 + 30) * NS_PER_SEC; // 4:30
-// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, duration2StartNs);
-// processor->OnLogEvent(event.get());
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[4]->start_ns, duration2StartNs);
-// EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
-//
-// vector<uint8_t> buffer;
-// ConfigMetricsReportList reports;
-// processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_GT(buffer.size(), 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-//
-// EXPECT_EQ(1, reports.reports_size());
-// EXPECT_EQ(1, reports.reports(0).metrics_size());
-// EXPECT_EQ(1, reports.reports(0).metrics(0).duration_metrics().data_size());
-//
-// auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
-// // Validate dimension value.
-// ValidateAttributionUidDimension(data.dimensions_in_what(),
-// android::util::WAKELOCK_STATE_CHANGED, appUid);
-// // Validate bucket info.
-// EXPECT_EQ(2, data.bucket_info_size());
-//
-// auto bucketInfo = data.bucket_info(0);
-// EXPECT_EQ(bucketStartTimeNs, bucketInfo.start_bucket_elapsed_nanos());
-// EXPECT_EQ(durationEndNs, bucketInfo.end_bucket_elapsed_nanos());
-// EXPECT_EQ(durationEndNs - durationStartNs, bucketInfo.duration_nanos());
-//
-// bucketInfo = data.bucket_info(1);
-// EXPECT_EQ(durationEndNs, bucketInfo.start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - duration2StartNs, bucketInfo.duration_nanos());
-//}
+TEST(DurationMetricE2eTest, TestOneBucket) {
+ StatsdConfig config;
+ config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
+
+ auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
+ auto screenOffMatcher = CreateScreenTurnedOffAtomMatcher();
+ *config.add_atom_matcher() = screenOnMatcher;
+ *config.add_atom_matcher() = screenOffMatcher;
+
+ auto durationPredicate = CreateScreenIsOnPredicate();
+ *config.add_predicate() = durationPredicate;
+
+ int64_t metricId = 123456;
+ auto durationMetric = config.add_duration_metric();
+ durationMetric->set_id(metricId);
+ durationMetric->set_what(durationPredicate.id());
+ durationMetric->set_bucket(FIVE_MINUTES);
+ durationMetric->set_aggregation_type(DurationMetric_AggregationType_SUM);
+
+ const int64_t baseTimeNs = 0; // 0:00
+ const int64_t configAddedTimeNs = baseTimeNs + 1 * NS_PER_SEC; // 0:01
+ const int64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000LL * 1000LL;
+
+ int uid = 12345;
+ int64_t cfgId = 98765;
+ ConfigKey cfgKey(uid, cfgId);
+
+ auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey);
+
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
+ EXPECT_TRUE(metricsManager->isConfigValid());
+ EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+
+ std::unique_ptr<LogEvent> event;
+
+ // Screen is off at start of bucket.
+ event = CreateScreenStateChangedEvent(configAddedTimeNs,
+ android::view::DISPLAY_STATE_OFF); // 0:01
+ processor->OnLogEvent(event.get());
+
+ // Turn screen on.
+ const int64_t durationStartNs = configAddedTimeNs + 10 * NS_PER_SEC; // 0:11
+ event = CreateScreenStateChangedEvent(durationStartNs, android::view::DISPLAY_STATE_ON);
+ processor->OnLogEvent(event.get());
+
+ // Turn off screen 30 seconds after turning on.
+ const int64_t durationEndNs = durationStartNs + 30 * NS_PER_SEC; // 0:41
+ event = CreateScreenStateChangedEvent(durationEndNs, android::view::DISPLAY_STATE_OFF);
+ processor->OnLogEvent(event.get());
+
+ event = CreateScreenBrightnessChangedEvent(durationEndNs + 1 * NS_PER_SEC, 64); // 0:42
+ processor->OnLogEvent(event.get());
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, configAddedTimeNs + bucketSizeNs + 1 * NS_PER_SEC, false, true,
+ ADB_DUMP, FAST, &buffer); // 5:01
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ EXPECT_EQ(metricId, reports.reports(0).metrics(0).metric_id());
+ EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
+
+ const StatsLogReport::DurationMetricDataWrapper& durationMetrics =
+ reports.reports(0).metrics(0).duration_metrics();
+ EXPECT_EQ(1, durationMetrics.data_size());
+
+ auto data = durationMetrics.data(0);
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(durationEndNs - durationStartNs, data.bucket_info(0).duration_nanos());
+ EXPECT_EQ(configAddedTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+}
+
+TEST(DurationMetricE2eTest, TestTwoBuckets) {
+ StatsdConfig config;
+ config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
+
+ auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
+ auto screenOffMatcher = CreateScreenTurnedOffAtomMatcher();
+ *config.add_atom_matcher() = screenOnMatcher;
+ *config.add_atom_matcher() = screenOffMatcher;
+
+ auto durationPredicate = CreateScreenIsOnPredicate();
+ *config.add_predicate() = durationPredicate;
+
+ int64_t metricId = 123456;
+ auto durationMetric = config.add_duration_metric();
+ durationMetric->set_id(metricId);
+ durationMetric->set_what(durationPredicate.id());
+ durationMetric->set_bucket(FIVE_MINUTES);
+ durationMetric->set_aggregation_type(DurationMetric_AggregationType_SUM);
+
+ const int64_t baseTimeNs = 0; // 0:00
+ const int64_t configAddedTimeNs = baseTimeNs + 1 * NS_PER_SEC; // 0:01
+ const int64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000LL * 1000LL;
+
+ int uid = 12345;
+ int64_t cfgId = 98765;
+ ConfigKey cfgKey(uid, cfgId);
+
+ auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey);
+
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
+ EXPECT_TRUE(metricsManager->isConfigValid());
+ EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+
+ std::unique_ptr<LogEvent> event;
+
+ // Screen is off at start of bucket.
+ event = CreateScreenStateChangedEvent(configAddedTimeNs,
+ android::view::DISPLAY_STATE_OFF); // 0:01
+ processor->OnLogEvent(event.get());
+
+ // Turn screen on.
+ const int64_t durationStartNs = configAddedTimeNs + 10 * NS_PER_SEC; // 0:11
+ event = CreateScreenStateChangedEvent(durationStartNs, android::view::DISPLAY_STATE_ON);
+ processor->OnLogEvent(event.get());
+
+ // Turn off screen 30 seconds after turning on.
+ const int64_t durationEndNs = durationStartNs + 30 * NS_PER_SEC; // 0:41
+ event = CreateScreenStateChangedEvent(durationEndNs, android::view::DISPLAY_STATE_OFF);
+ processor->OnLogEvent(event.get());
+
+ event = CreateScreenBrightnessChangedEvent(durationEndNs + 1 * NS_PER_SEC, 64); // 0:42
+ processor->OnLogEvent(event.get());
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, configAddedTimeNs + 2 * bucketSizeNs + 1 * NS_PER_SEC, false,
+ true, ADB_DUMP, FAST, &buffer); // 10:01
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ EXPECT_EQ(metricId, reports.reports(0).metrics(0).metric_id());
+ EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
+
+ const StatsLogReport::DurationMetricDataWrapper& durationMetrics =
+ reports.reports(0).metrics(0).duration_metrics();
+ EXPECT_EQ(1, durationMetrics.data_size());
+
+ auto data = durationMetrics.data(0);
+ EXPECT_EQ(1, data.bucket_info_size());
+
+ auto bucketInfo = data.bucket_info(0);
+ EXPECT_EQ(0, bucketInfo.bucket_num());
+ EXPECT_EQ(durationEndNs - durationStartNs, bucketInfo.duration_nanos());
+ EXPECT_EQ(configAddedTimeNs, bucketInfo.start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
+}
+
+TEST(DurationMetricE2eTest, TestWithActivation) {
+ StatsdConfig config;
+ config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
+
+ auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
+ auto screenOffMatcher = CreateScreenTurnedOffAtomMatcher();
+ auto crashMatcher = CreateProcessCrashAtomMatcher();
+ *config.add_atom_matcher() = screenOnMatcher;
+ *config.add_atom_matcher() = screenOffMatcher;
+ *config.add_atom_matcher() = crashMatcher;
+
+ auto durationPredicate = CreateScreenIsOnPredicate();
+ *config.add_predicate() = durationPredicate;
+
+ int64_t metricId = 123456;
+ auto durationMetric = config.add_duration_metric();
+ durationMetric->set_id(metricId);
+ durationMetric->set_what(durationPredicate.id());
+ durationMetric->set_bucket(FIVE_MINUTES);
+ durationMetric->set_aggregation_type(DurationMetric_AggregationType_SUM);
+
+ auto metric_activation1 = config.add_metric_activation();
+ metric_activation1->set_metric_id(metricId);
+ auto event_activation1 = metric_activation1->add_event_activation();
+ event_activation1->set_atom_matcher_id(crashMatcher.id());
+ event_activation1->set_ttl_seconds(30); // 30 secs.
+
+ const int64_t bucketStartTimeNs = 10000000000;
+ const int64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000LL * 1000LL;
+
+ int uid = 12345;
+ int64_t cfgId = 98765;
+ ConfigKey cfgKey(uid, cfgId);
+
+ sp<UidMap> m = new UidMap();
+ sp<StatsPullerManager> pullerManager = new StatsPullerManager();
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> subscriberAlarmMonitor;
+ vector<int64_t> activeConfigsBroadcast;
+
+ int broadcastCount = 0;
+ StatsLogProcessor processor(
+ m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, bucketStartTimeNs,
+ [](const ConfigKey& key) { return true; },
+ [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
+ const vector<int64_t>& activeConfigs) {
+ broadcastCount++;
+ EXPECT_EQ(broadcastUid, uid);
+ activeConfigsBroadcast.clear();
+ activeConfigsBroadcast.insert(activeConfigsBroadcast.end(), activeConfigs.begin(),
+ activeConfigs.end());
+ return true;
+ });
+
+ processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config); // 0:00
+
+ EXPECT_EQ(processor.mMetricsManagers.size(), 1u);
+ sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
+ EXPECT_TRUE(metricsManager->isConfigValid());
+ EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+ auto& eventActivationMap = metricProducer->mEventActivationMap;
+
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap.size(), 1u);
+ EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
+
+ std::unique_ptr<LogEvent> event;
+
+ // Turn screen off.
+ event = CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * NS_PER_SEC,
+ android::view::DISPLAY_STATE_OFF); // 0:02
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + 2 * NS_PER_SEC);
+
+ // Turn screen on.
+ const int64_t durationStartNs = bucketStartTimeNs + 5 * NS_PER_SEC; // 0:05
+ event = CreateScreenStateChangedEvent(durationStartNs, android::view::DISPLAY_STATE_ON);
+ processor.OnLogEvent(event.get(), durationStartNs);
+
+ // Activate metric.
+ const int64_t activationStartNs = bucketStartTimeNs + 5 * NS_PER_SEC; // 0:10
+ const int64_t activationEndNs =
+ activationStartNs + event_activation1->ttl_seconds() * NS_PER_SEC; // 0:40
+ event = CreateAppCrashEvent(activationStartNs, 111);
+ processor.OnLogEvent(event.get(), activationStartNs);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 1);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, activationStartNs);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
+
+ // Expire activation.
+ const int64_t expirationNs = activationEndNs + 7 * NS_PER_SEC;
+ event = CreateScreenBrightnessChangedEvent(expirationNs, 64); // 0:47
+ processor.OnLogEvent(event.get(), expirationNs);
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 2);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+ EXPECT_EQ(eventActivationMap.size(), 1u);
+ EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, activationStartNs);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
+
+ // Turn off screen 10 seconds after activation expiration.
+ const int64_t durationEndNs = activationEndNs + 10 * NS_PER_SEC; // 0:50
+ event = CreateScreenStateChangedEvent(durationEndNs, android::view::DISPLAY_STATE_OFF);
+ processor.OnLogEvent(event.get(), durationEndNs);
+
+ // Turn screen on.
+ const int64_t duration2StartNs = durationEndNs + 5 * NS_PER_SEC; // 0:55
+ event = CreateScreenStateChangedEvent(duration2StartNs, android::view::DISPLAY_STATE_ON);
+ processor.OnLogEvent(event.get(), duration2StartNs);
+
+ // Turn off screen.
+ const int64_t duration2EndNs = duration2StartNs + 10 * NS_PER_SEC; // 1:05
+ event = CreateScreenStateChangedEvent(duration2EndNs, android::view::DISPLAY_STATE_OFF);
+ processor.OnLogEvent(event.get(), duration2EndNs);
+
+ // Activate metric.
+ const int64_t activation2StartNs = duration2EndNs + 5 * NS_PER_SEC; // 1:10
+ const int64_t activation2EndNs =
+ activation2StartNs + event_activation1->ttl_seconds() * NS_PER_SEC; // 1:40
+ event = CreateAppCrashEvent(activation2StartNs, 211);
+ processor.OnLogEvent(event.get(), activation2StartNs);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 3);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, activation2StartNs);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor.onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1 * NS_PER_SEC, false, true,
+ ADB_DUMP, FAST, &buffer); // 5:01
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ EXPECT_EQ(metricId, reports.reports(0).metrics(0).metric_id());
+ EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics());
+
+ const StatsLogReport::DurationMetricDataWrapper& durationMetrics =
+ reports.reports(0).metrics(0).duration_metrics();
+ EXPECT_EQ(1, durationMetrics.data_size());
+
+ auto data = durationMetrics.data(0);
+ EXPECT_EQ(1, data.bucket_info_size());
+
+ auto bucketInfo = data.bucket_info(0);
+ EXPECT_EQ(0, bucketInfo.bucket_num());
+ EXPECT_EQ(bucketStartTimeNs, bucketInfo.start_bucket_elapsed_nanos());
+ EXPECT_EQ(expirationNs, bucketInfo.end_bucket_elapsed_nanos());
+ EXPECT_EQ(expirationNs - durationStartNs, bucketInfo.duration_nanos());
+}
+
+TEST(DurationMetricE2eTest, TestWithCondition) {
+ StatsdConfig config;
+ config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
+ *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
+ *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
+ *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher();
+ *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher();
+
+ auto holdingWakelockPredicate = CreateHoldingWakelockPredicate();
+ *config.add_predicate() = holdingWakelockPredicate;
+
+ auto isInBackgroundPredicate = CreateIsInBackgroundPredicate();
+ *config.add_predicate() = isInBackgroundPredicate;
+
+ auto durationMetric = config.add_duration_metric();
+ durationMetric->set_id(StringToId("WakelockDuration"));
+ durationMetric->set_what(holdingWakelockPredicate.id());
+ durationMetric->set_condition(isInBackgroundPredicate.id());
+ durationMetric->set_aggregation_type(DurationMetric::SUM);
+ durationMetric->set_bucket(FIVE_MINUTES);
+
+ ConfigKey cfgKey;
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
+ EXPECT_TRUE(metricsManager->isConfigValid());
+ EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+ auto& eventActivationMap = metricProducer->mEventActivationMap;
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_TRUE(eventActivationMap.empty());
+
+ int appUid = 123;
+ vector<int> attributionUids1 = {appUid};
+ vector<string> attributionTags1 = {"App1"};
+
+ auto event = CreateAcquireWakelockEvent(bucketStartTimeNs + 10 * NS_PER_SEC, attributionUids1,
+ attributionTags1,
+ "wl1"); // 0:10
+ processor->OnLogEvent(event.get());
+
+ event = CreateMoveToBackgroundEvent(bucketStartTimeNs + 22 * NS_PER_SEC, appUid); // 0:22
+ processor->OnLogEvent(event.get());
+
+ event = CreateMoveToForegroundEvent(bucketStartTimeNs + (3 * 60 + 15) * NS_PER_SEC,
+ appUid); // 3:15
+ processor->OnLogEvent(event.get());
+
+ event = CreateReleaseWakelockEvent(bucketStartTimeNs + 4 * 60 * NS_PER_SEC, attributionUids1,
+ attributionTags1,
+ "wl1"); // 4:00
+ processor->OnLogEvent(event.get());
+
+ vector<uint8_t> buffer;
+ ConfigMetricsReportList reports;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1, false, true, ADB_DUMP,
+ FAST, &buffer);
+ EXPECT_GT(buffer.size(), 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ EXPECT_EQ(1, reports.reports(0).metrics(0).duration_metrics().data_size());
+
+ auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
+
+ // Validate bucket info.
+ EXPECT_EQ(1, data.bucket_info_size());
+
+ auto bucketInfo = data.bucket_info(0);
+ EXPECT_EQ(bucketStartTimeNs, bucketInfo.start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
+ EXPECT_EQ((2 * 60 + 53) * NS_PER_SEC, bucketInfo.duration_nanos());
+}
+
+TEST(DurationMetricE2eTest, TestWithSlicedCondition) {
+ StatsdConfig config;
+ config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
+ auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
+ *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
+ *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
+ *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher();
+ *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher();
+
+ auto holdingWakelockPredicate = CreateHoldingWakelockPredicate();
+ // The predicate is dimensioning by first attribution node by uid.
+ FieldMatcher dimensions = CreateAttributionUidDimensions(android::util::WAKELOCK_STATE_CHANGED,
+ {Position::FIRST});
+ *holdingWakelockPredicate.mutable_simple_predicate()->mutable_dimensions() = dimensions;
+ *config.add_predicate() = holdingWakelockPredicate;
+
+ auto isInBackgroundPredicate = CreateIsInBackgroundPredicate();
+ *isInBackgroundPredicate.mutable_simple_predicate()->mutable_dimensions() =
+ CreateDimensions(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {Position::FIRST});
+ *config.add_predicate() = isInBackgroundPredicate;
+
+ auto durationMetric = config.add_duration_metric();
+ durationMetric->set_id(StringToId("WakelockDuration"));
+ durationMetric->set_what(holdingWakelockPredicate.id());
+ durationMetric->set_condition(isInBackgroundPredicate.id());
+ durationMetric->set_aggregation_type(DurationMetric::SUM);
+ // The metric is dimensioning by first attribution node and only by uid.
+ *durationMetric->mutable_dimensions_in_what() = CreateAttributionUidDimensions(
+ android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
+ durationMetric->set_bucket(FIVE_MINUTES);
+
+ // Links between wakelock state atom and condition of app is in background.
+ auto links = durationMetric->add_links();
+ links->set_condition(isInBackgroundPredicate.id());
+ auto dimensionWhat = links->mutable_fields_in_what();
+ dimensionWhat->set_field(android::util::WAKELOCK_STATE_CHANGED);
+ dimensionWhat->add_child()->set_field(1); // uid field.
+ *links->mutable_fields_in_condition() = CreateAttributionUidDimensions(
+ android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {Position::FIRST});
+
+ ConfigKey cfgKey;
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
+ EXPECT_TRUE(metricsManager->isConfigValid());
+ EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+ auto& eventActivationMap = metricProducer->mEventActivationMap;
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_TRUE(eventActivationMap.empty());
+
+ int appUid = 123;
+ std::vector<int> attributionUids1 = {appUid};
+ std::vector<string> attributionTags1 = {"App1"};
+
+ auto event = CreateAcquireWakelockEvent(bucketStartTimeNs + 10 * NS_PER_SEC, attributionUids1,
+ attributionTags1, "wl1"); // 0:10
+ processor->OnLogEvent(event.get());
+
+ event = CreateMoveToBackgroundEvent(bucketStartTimeNs + 22 * NS_PER_SEC, appUid); // 0:22
+ processor->OnLogEvent(event.get());
+
+ event = CreateReleaseWakelockEvent(bucketStartTimeNs + 60 * NS_PER_SEC, attributionUids1,
+ attributionTags1, "wl1"); // 1:00
+ processor->OnLogEvent(event.get());
+
+ event = CreateMoveToForegroundEvent(bucketStartTimeNs + (3 * 60 + 15) * NS_PER_SEC,
+ appUid); // 3:15
+ processor->OnLogEvent(event.get());
+
+ vector<uint8_t> buffer;
+ ConfigMetricsReportList reports;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1, false, true, ADB_DUMP,
+ FAST, &buffer);
+ EXPECT_GT(buffer.size(), 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ EXPECT_EQ(1, reports.reports(0).metrics(0).duration_metrics().data_size());
+
+ auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
+ // Validate dimension value.
+ ValidateAttributionUidDimension(data.dimensions_in_what(),
+ android::util::WAKELOCK_STATE_CHANGED, appUid);
+ // Validate bucket info.
+ EXPECT_EQ(1, data.bucket_info_size());
+
+ auto bucketInfo = data.bucket_info(0);
+ EXPECT_EQ(bucketStartTimeNs, bucketInfo.start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
+ EXPECT_EQ(38 * NS_PER_SEC, bucketInfo.duration_nanos());
+}
+
+TEST(DurationMetricE2eTest, TestWithActivationAndSlicedCondition) {
+ StatsdConfig config;
+ config.add_allowed_log_source("AID_ROOT"); // LogEvent defaults to UID of root.
+ auto screenOnMatcher = CreateScreenTurnedOnAtomMatcher();
+ *config.add_atom_matcher() = CreateAcquireWakelockAtomMatcher();
+ *config.add_atom_matcher() = CreateReleaseWakelockAtomMatcher();
+ *config.add_atom_matcher() = CreateMoveToBackgroundAtomMatcher();
+ *config.add_atom_matcher() = CreateMoveToForegroundAtomMatcher();
+ *config.add_atom_matcher() = screenOnMatcher;
+
+ auto holdingWakelockPredicate = CreateHoldingWakelockPredicate();
+ // The predicate is dimensioning by first attribution node by uid.
+ FieldMatcher dimensions = CreateAttributionUidDimensions(android::util::WAKELOCK_STATE_CHANGED,
+ {Position::FIRST});
+ *holdingWakelockPredicate.mutable_simple_predicate()->mutable_dimensions() = dimensions;
+ *config.add_predicate() = holdingWakelockPredicate;
+
+ auto isInBackgroundPredicate = CreateIsInBackgroundPredicate();
+ *isInBackgroundPredicate.mutable_simple_predicate()->mutable_dimensions() =
+ CreateDimensions(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {Position::FIRST});
+ *config.add_predicate() = isInBackgroundPredicate;
+
+ auto durationMetric = config.add_duration_metric();
+ durationMetric->set_id(StringToId("WakelockDuration"));
+ durationMetric->set_what(holdingWakelockPredicate.id());
+ durationMetric->set_condition(isInBackgroundPredicate.id());
+ durationMetric->set_aggregation_type(DurationMetric::SUM);
+ // The metric is dimensioning by first attribution node and only by uid.
+ *durationMetric->mutable_dimensions_in_what() = CreateAttributionUidDimensions(
+ android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
+ durationMetric->set_bucket(FIVE_MINUTES);
+
+ // Links between wakelock state atom and condition of app is in background.
+ auto links = durationMetric->add_links();
+ links->set_condition(isInBackgroundPredicate.id());
+ auto dimensionWhat = links->mutable_fields_in_what();
+ dimensionWhat->set_field(android::util::WAKELOCK_STATE_CHANGED);
+ dimensionWhat->add_child()->set_field(1); // uid field.
+ *links->mutable_fields_in_condition() = CreateAttributionUidDimensions(
+ android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, {Position::FIRST});
+
+ auto metric_activation1 = config.add_metric_activation();
+ metric_activation1->set_metric_id(durationMetric->id());
+ auto event_activation1 = metric_activation1->add_event_activation();
+ event_activation1->set_atom_matcher_id(screenOnMatcher.id());
+ event_activation1->set_ttl_seconds(60 * 2); // 2 minutes.
+
+ ConfigKey cfgKey;
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ sp<MetricsManager> metricsManager = processor->mMetricsManagers.begin()->second;
+ EXPECT_TRUE(metricsManager->isConfigValid());
+ EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+ auto& eventActivationMap = metricProducer->mEventActivationMap;
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap.size(), 1u);
+ EXPECT_TRUE(eventActivationMap.find(4) != eventActivationMap.end());
+ EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[4]->start_ns, 0);
+ EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
+
+ int appUid = 123;
+ std::vector<int> attributionUids1 = {appUid};
+ std::vector<string> attributionTags1 = {"App1"};
+
+ auto event = CreateAcquireWakelockEvent(bucketStartTimeNs + 10 * NS_PER_SEC, attributionUids1,
+ attributionTags1, "wl1"); // 0:10
+ processor->OnLogEvent(event.get());
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[4]->start_ns, 0);
+ EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
+
+ event = CreateMoveToBackgroundEvent(bucketStartTimeNs + 22 * NS_PER_SEC, appUid); // 0:22
+ processor->OnLogEvent(event.get());
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[4]->start_ns, 0);
+ EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
+
+ const int64_t durationStartNs = bucketStartTimeNs + 30 * NS_PER_SEC; // 0:30
+ event = CreateScreenStateChangedEvent(durationStartNs, android::view::DISPLAY_STATE_ON);
+ processor->OnLogEvent(event.get());
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[4]->start_ns, durationStartNs);
+ EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
+
+ const int64_t durationEndNs =
+ durationStartNs + (event_activation1->ttl_seconds() + 30) * NS_PER_SEC; // 3:00
+ event = CreateAppCrashEvent(durationEndNs, 333);
+ processor->OnLogEvent(event.get());
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[4]->start_ns, durationStartNs);
+ EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
+
+ event = CreateMoveToForegroundEvent(bucketStartTimeNs + (3 * 60 + 15) * NS_PER_SEC,
+ appUid); // 3:15
+ processor->OnLogEvent(event.get());
+
+ event = CreateReleaseWakelockEvent(bucketStartTimeNs + (4 * 60 + 17) * NS_PER_SEC,
+ attributionUids1, attributionTags1, "wl1"); // 4:17
+ processor->OnLogEvent(event.get());
+
+ event = CreateMoveToBackgroundEvent(bucketStartTimeNs + (4 * 60 + 20) * NS_PER_SEC,
+ appUid); // 4:20
+ processor->OnLogEvent(event.get());
+
+ event = CreateAcquireWakelockEvent(bucketStartTimeNs + (4 * 60 + 25) * NS_PER_SEC,
+ attributionUids1, attributionTags1, "wl1"); // 4:25
+ processor->OnLogEvent(event.get());
+
+ const int64_t duration2StartNs = bucketStartTimeNs + (4 * 60 + 30) * NS_PER_SEC; // 4:30
+ event = CreateScreenStateChangedEvent(duration2StartNs, android::view::DISPLAY_STATE_ON);
+ processor->OnLogEvent(event.get());
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[4]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[4]->start_ns, duration2StartNs);
+ EXPECT_EQ(eventActivationMap[4]->ttl_ns, event_activation1->ttl_seconds() * NS_PER_SEC);
+
+ vector<uint8_t> buffer;
+ ConfigMetricsReportList reports;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1, false, true, ADB_DUMP,
+ FAST, &buffer);
+ EXPECT_GT(buffer.size(), 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ EXPECT_EQ(1, reports.reports(0).metrics(0).duration_metrics().data_size());
+
+ auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
+ // Validate dimension value.
+ ValidateAttributionUidDimension(data.dimensions_in_what(),
+ android::util::WAKELOCK_STATE_CHANGED, appUid);
+ // Validate bucket info.
+ EXPECT_EQ(2, data.bucket_info_size());
+
+ auto bucketInfo = data.bucket_info(0);
+ EXPECT_EQ(bucketStartTimeNs, bucketInfo.start_bucket_elapsed_nanos());
+ EXPECT_EQ(durationEndNs, bucketInfo.end_bucket_elapsed_nanos());
+ EXPECT_EQ(durationEndNs - durationStartNs, bucketInfo.duration_nanos());
+
+ bucketInfo = data.bucket_info(1);
+ EXPECT_EQ(durationEndNs, bucketInfo.start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - duration2StartNs, bucketInfo.duration_nanos());
+}
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
index 7f651d4..594c1e6 100644
--- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
+++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_pull_test.cpp
@@ -65,482 +65,465 @@
} // namespaces
-// TODO(b/149590301): Update this test to use new socket schema.
-//TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvents) {
-// auto config = CreateStatsdConfig(GaugeMetric::RANDOM_ONE_SAMPLE);
-// int64_t baseTimeNs = getElapsedRealtimeNs();
-// int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
-// int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
-//
-// ConfigKey cfgKey;
-// auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
-// SharedRefBase::make<FakeSubsystemSleepCallback>(),
-// ATOM_TAG);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-// processor->mPullerManager->ForceClearPullerCache();
-//
-// int startBucketNum = processor->mMetricsManagers.begin()->second->
-// mAllMetricProducers[0]->getCurrentBucketNum();
-// EXPECT_GT(startBucketNum, (int64_t)0);
-//
-// // When creating the config, the gauge metric producer should register the alarm at the
-// // end of the current bucket.
-// EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
-// EXPECT_EQ(bucketSizeNs,
-// processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
-// int64_t& nextPullTimeNs =
-// processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs;
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, nextPullTimeNs);
-//
-// auto screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-// configAddedTimeNs + 55);
-// processor->OnLogEvent(screenOffEvent.get());
-//
-// // Pulling alarm arrives on time and reset the sequential pulling alarm.
-// processor->informPullAlarmFired(nextPullTimeNs + 1);
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 2 * bucketSizeNs, nextPullTimeNs);
-//
-// auto screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-// configAddedTimeNs + bucketSizeNs + 10);
-// processor->OnLogEvent(screenOnEvent.get());
-//
-// screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-// configAddedTimeNs + bucketSizeNs + 100);
-// processor->OnLogEvent(screenOffEvent.get());
-//
-// processor->informPullAlarmFired(nextPullTimeNs + 1);
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 3 * bucketSizeNs,
-// nextPullTimeNs);
-//
-// processor->informPullAlarmFired(nextPullTimeNs + 1);
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 4 * bucketSizeNs, nextPullTimeNs);
-//
-// screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-// configAddedTimeNs + 3 * bucketSizeNs + 2);
-// processor->OnLogEvent(screenOnEvent.get());
-//
-// processor->informPullAlarmFired(nextPullTimeNs + 3);
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 5 * bucketSizeNs, nextPullTimeNs);
-//
-// screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-// configAddedTimeNs + 5 * bucketSizeNs + 1);
-// processor->OnLogEvent(screenOffEvent.get());
-//
-// processor->informPullAlarmFired(nextPullTimeNs + 2);
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 6 * bucketSizeNs, nextPullTimeNs);
-//
-// processor->informPullAlarmFired(nextPullTimeNs + 2);
-//
-// ConfigMetricsReportList reports;
-// vector<uint8_t> buffer;
-// processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(1, reports.reports_size());
-// EXPECT_EQ(1, reports.reports(0).metrics_size());
-// StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
-// sortMetricDataByDimensionsValue(
-// reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
-// EXPECT_GT((int)gaugeMetrics.data_size(), 1);
-//
-// auto data = gaugeMetrics.data(0);
-// EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* subsystem name field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
-// EXPECT_EQ(6, data.bucket_info_size());
-//
-// EXPECT_EQ(1, data.bucket_info(0).atom_size());
-// EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
-// EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
-// EXPECT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size());
-// EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-// EXPECT_TRUE(data.bucket_info(0).atom(0).subsystem_sleep_state().subsystem_name().empty());
-// EXPECT_GT(data.bucket_info(0).atom(0).subsystem_sleep_state().time_millis(), 0);
-//
-// EXPECT_EQ(1, data.bucket_info(1).atom_size());
-// EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs + 1,
-// data.bucket_info(1).elapsed_timestamp_nanos(0));
-// EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs + 1, data.bucket_info(1).elapsed_timestamp_nanos(0));
-// EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
-// EXPECT_TRUE(data.bucket_info(1).atom(0).subsystem_sleep_state().subsystem_name().empty());
-// EXPECT_GT(data.bucket_info(1).atom(0).subsystem_sleep_state().time_millis(), 0);
-//
-// EXPECT_EQ(1, data.bucket_info(2).atom_size());
-// EXPECT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size());
-// EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs + 1,
-// data.bucket_info(2).elapsed_timestamp_nanos(0));
-// EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
-// EXPECT_TRUE(data.bucket_info(2).atom(0).subsystem_sleep_state().subsystem_name().empty());
-// EXPECT_GT(data.bucket_info(2).atom(0).subsystem_sleep_state().time_millis(), 0);
-//
-// EXPECT_EQ(1, data.bucket_info(3).atom_size());
-// EXPECT_EQ(1, data.bucket_info(3).elapsed_timestamp_nanos_size());
-// EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs + 1,
-// data.bucket_info(3).elapsed_timestamp_nanos(0));
-// EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(3).start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(3).end_bucket_elapsed_nanos());
-// EXPECT_TRUE(data.bucket_info(3).atom(0).subsystem_sleep_state().subsystem_name().empty());
-// EXPECT_GT(data.bucket_info(3).atom(0).subsystem_sleep_state().time_millis(), 0);
-//
-// EXPECT_EQ(1, data.bucket_info(4).atom_size());
-// EXPECT_EQ(1, data.bucket_info(4).elapsed_timestamp_nanos_size());
-// EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs + 1,
-// data.bucket_info(4).elapsed_timestamp_nanos(0));
-// EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(4).start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(4).end_bucket_elapsed_nanos());
-// EXPECT_TRUE(data.bucket_info(4).atom(0).subsystem_sleep_state().subsystem_name().empty());
-// EXPECT_GT(data.bucket_info(4).atom(0).subsystem_sleep_state().time_millis(), 0);
-//
-// EXPECT_EQ(1, data.bucket_info(5).atom_size());
-// EXPECT_EQ(1, data.bucket_info(5).elapsed_timestamp_nanos_size());
-// EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs + 2,
-// data.bucket_info(5).elapsed_timestamp_nanos(0));
-// EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(5).start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + 9 * bucketSizeNs, data.bucket_info(5).end_bucket_elapsed_nanos());
-// EXPECT_TRUE(data.bucket_info(5).atom(0).subsystem_sleep_state().subsystem_name().empty());
-// EXPECT_GT(data.bucket_info(5).atom(0).subsystem_sleep_state().time_millis(), 0);
-//}
-//
-//TEST(GaugeMetricE2eTest, TestConditionChangeToTrueSamplePulledEvents) {
-// auto config = CreateStatsdConfig(GaugeMetric::CONDITION_CHANGE_TO_TRUE);
-// int64_t baseTimeNs = getElapsedRealtimeNs();
-// int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
-// int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
-//
-// ConfigKey cfgKey;
-// auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
-// SharedRefBase::make<FakeSubsystemSleepCallback>(),
-// ATOM_TAG);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-// processor->mPullerManager->ForceClearPullerCache();
-//
-// int startBucketNum = processor->mMetricsManagers.begin()->second->
-// mAllMetricProducers[0]->getCurrentBucketNum();
-// EXPECT_GT(startBucketNum, (int64_t)0);
-//
-// auto screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-// configAddedTimeNs + 55);
-// processor->OnLogEvent(screenOffEvent.get());
-//
-// auto screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-// configAddedTimeNs + bucketSizeNs + 10);
-// processor->OnLogEvent(screenOnEvent.get());
-//
-// screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-// configAddedTimeNs + bucketSizeNs + 100);
-// processor->OnLogEvent(screenOffEvent.get());
-//
-// screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-// configAddedTimeNs + 3 * bucketSizeNs + 2);
-// processor->OnLogEvent(screenOnEvent.get());
-//
-// screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-// configAddedTimeNs + 5 * bucketSizeNs + 1);
-// processor->OnLogEvent(screenOffEvent.get());
-// screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-// configAddedTimeNs + 5 * bucketSizeNs + 3);
-// processor->OnLogEvent(screenOnEvent.get());
-// screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-// configAddedTimeNs + 5 * bucketSizeNs + 10);
-// processor->OnLogEvent(screenOffEvent.get());
-//
-// ConfigMetricsReportList reports;
-// vector<uint8_t> buffer;
-// processor->onDumpReport(cfgKey, configAddedTimeNs + 8 * bucketSizeNs + 10, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(1, reports.reports_size());
-// EXPECT_EQ(1, reports.reports(0).metrics_size());
-// StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
-// sortMetricDataByDimensionsValue(
-// reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
-// EXPECT_GT((int)gaugeMetrics.data_size(), 1);
-//
-// auto data = gaugeMetrics.data(0);
-// EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* subsystem name field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
-// EXPECT_EQ(3, data.bucket_info_size());
-//
-// EXPECT_EQ(1, data.bucket_info(0).atom_size());
-// EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
-// EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
-// EXPECT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size());
-// EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-// EXPECT_TRUE(data.bucket_info(0).atom(0).subsystem_sleep_state().subsystem_name().empty());
-// EXPECT_GT(data.bucket_info(0).atom(0).subsystem_sleep_state().time_millis(), 0);
-//
-// EXPECT_EQ(1, data.bucket_info(1).atom_size());
-// EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs + 100,
-// data.bucket_info(1).elapsed_timestamp_nanos(0));
-// EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
-// EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
-// EXPECT_TRUE(data.bucket_info(1).atom(0).subsystem_sleep_state().subsystem_name().empty());
-// EXPECT_GT(data.bucket_info(1).atom(0).subsystem_sleep_state().time_millis(), 0);
-//
-// EXPECT_EQ(2, data.bucket_info(2).atom_size());
-// EXPECT_EQ(2, data.bucket_info(2).elapsed_timestamp_nanos_size());
-// EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs + 1,
-// data.bucket_info(2).elapsed_timestamp_nanos(0));
-// EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs + 10,
-// data.bucket_info(2).elapsed_timestamp_nanos(1));
-// EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
-// EXPECT_TRUE(data.bucket_info(2).atom(0).subsystem_sleep_state().subsystem_name().empty());
-// EXPECT_GT(data.bucket_info(2).atom(0).subsystem_sleep_state().time_millis(), 0);
-// EXPECT_TRUE(data.bucket_info(2).atom(1).subsystem_sleep_state().subsystem_name().empty());
-// EXPECT_GT(data.bucket_info(2).atom(1).subsystem_sleep_state().time_millis(), 0);
-//}
-//
-//
-//TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvent_LateAlarm) {
-// auto config = CreateStatsdConfig(GaugeMetric::RANDOM_ONE_SAMPLE);
-// int64_t baseTimeNs = getElapsedRealtimeNs();
-// int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
-// int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
-//
-// ConfigKey cfgKey;
-// auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
-// SharedRefBase::make<FakeSubsystemSleepCallback>(),
-// ATOM_TAG);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-// processor->mPullerManager->ForceClearPullerCache();
-//
-// int startBucketNum = processor->mMetricsManagers.begin()->second->
-// mAllMetricProducers[0]->getCurrentBucketNum();
-// EXPECT_GT(startBucketNum, (int64_t)0);
-//
-// // When creating the config, the gauge metric producer should register the alarm at the
-// // end of the current bucket.
-// EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
-// EXPECT_EQ(bucketSizeNs,
-// processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
-// int64_t& nextPullTimeNs =
-// processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs;
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, nextPullTimeNs);
-//
-// auto screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-// configAddedTimeNs + 55);
-// processor->OnLogEvent(screenOffEvent.get());
-//
-// auto screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-// configAddedTimeNs + bucketSizeNs + 10);
-// processor->OnLogEvent(screenOnEvent.get());
-//
-// // Pulling alarm arrives one bucket size late.
-// processor->informPullAlarmFired(nextPullTimeNs + bucketSizeNs);
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 3 * bucketSizeNs, nextPullTimeNs);
-//
-// screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-// configAddedTimeNs + 3 * bucketSizeNs + 11);
-// processor->OnLogEvent(screenOffEvent.get());
-//
-// // Pulling alarm arrives more than one bucket size late.
-// processor->informPullAlarmFired(nextPullTimeNs + bucketSizeNs + 12);
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 5 * bucketSizeNs, nextPullTimeNs);
-//
-// ConfigMetricsReportList reports;
-// vector<uint8_t> buffer;
-// processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(1, reports.reports_size());
-// EXPECT_EQ(1, reports.reports(0).metrics_size());
-// StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
-// sortMetricDataByDimensionsValue(
-// reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
-// EXPECT_GT((int)gaugeMetrics.data_size(), 1);
-//
-// auto data = gaugeMetrics.data(0);
-// EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* subsystem name field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
-// EXPECT_EQ(3, data.bucket_info_size());
-//
-// EXPECT_EQ(1, data.bucket_info(0).atom_size());
-// EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
-// EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
-// EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-// EXPECT_TRUE(data.bucket_info(0).atom(0).subsystem_sleep_state().subsystem_name().empty());
-// EXPECT_GT(data.bucket_info(0).atom(0).subsystem_sleep_state().time_millis(), 0);
-//
-// EXPECT_EQ(1, data.bucket_info(1).atom_size());
-// EXPECT_EQ(configAddedTimeNs + 3 * bucketSizeNs + 11,
-// data.bucket_info(1).elapsed_timestamp_nanos(0));
-// EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
-// EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
-// EXPECT_TRUE(data.bucket_info(1).atom(0).subsystem_sleep_state().subsystem_name().empty());
-// EXPECT_GT(data.bucket_info(1).atom(0).subsystem_sleep_state().time_millis(), 0);
-//
-// EXPECT_EQ(1, data.bucket_info(2).atom_size());
-// EXPECT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size());
-// EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs + 12,
-// data.bucket_info(2).elapsed_timestamp_nanos(0));
-// EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
-// EXPECT_TRUE(data.bucket_info(2).atom(0).subsystem_sleep_state().subsystem_name().empty());
-// EXPECT_GT(data.bucket_info(2).atom(0).subsystem_sleep_state().time_millis(), 0);
-//}
-//
-//TEST(GaugeMetricE2eTest, TestRandomSamplePulledEventsWithActivation) {
-// auto config = CreateStatsdConfig(GaugeMetric::RANDOM_ONE_SAMPLE, /*useCondition=*/false);
-//
-// int64_t baseTimeNs = getElapsedRealtimeNs();
-// int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
-// int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
-//
-// auto batterySaverStartMatcher = CreateBatterySaverModeStartAtomMatcher();
-// *config.add_atom_matcher() = batterySaverStartMatcher;
-// const int64_t ttlNs = 2 * bucketSizeNs; // Two buckets.
-// auto metric_activation = config.add_metric_activation();
-// metric_activation->set_metric_id(metricId);
-// metric_activation->set_activation_type(ACTIVATE_IMMEDIATELY);
-// auto event_activation = metric_activation->add_event_activation();
-// event_activation->set_atom_matcher_id(batterySaverStartMatcher.id());
-// event_activation->set_ttl_seconds(ttlNs / 1000000000);
-//
-// ConfigKey cfgKey;
-// auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
-// SharedRefBase::make<FakeSubsystemSleepCallback>(),
-// ATOM_TAG);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-// processor->mPullerManager->ForceClearPullerCache();
-//
-// int startBucketNum = processor->mMetricsManagers.begin()->second->
-// mAllMetricProducers[0]->getCurrentBucketNum();
-// EXPECT_GT(startBucketNum, (int64_t)0);
-// EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
-//
-// // When creating the config, the gauge metric producer should register the alarm at the
-// // end of the current bucket.
-// EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
-// EXPECT_EQ(bucketSizeNs,
-// processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
-// int64_t& nextPullTimeNs =
-// processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs;
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, nextPullTimeNs);
-//
-// // Pulling alarm arrives on time and reset the sequential pulling alarm.
-// // Event should not be kept.
-// processor->informPullAlarmFired(nextPullTimeNs + 1); // 15 mins + 1 ns.
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 2 * bucketSizeNs, nextPullTimeNs);
-// EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
-//
-// // Activate the metric. A pull occurs upon activation.
-// const int64_t activationNs = configAddedTimeNs + bucketSizeNs + (2 * 1000 * 1000); // 2 millis.
-// auto batterySaverOnEvent = CreateBatterySaverOnEvent(activationNs);
-// processor->OnLogEvent(batterySaverOnEvent.get()); // 15 mins + 2 ms.
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
-//
-// // This event should be kept. 2 total.
-// processor->informPullAlarmFired(nextPullTimeNs + 1); // 20 mins + 1 ns.
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 3 * bucketSizeNs,
-// nextPullTimeNs);
-//
-// // This event should be kept. 3 total.
-// processor->informPullAlarmFired(nextPullTimeNs + 2); // 25 mins + 2 ns.
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 4 * bucketSizeNs, nextPullTimeNs);
-//
-// // Create random event to deactivate metric.
-// auto deactivationEvent = CreateScreenBrightnessChangedEvent(50, activationNs + ttlNs + 1);
-// processor->OnLogEvent(deactivationEvent.get());
-// EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
-//
-// // Event should not be kept. 3 total.
-// processor->informPullAlarmFired(nextPullTimeNs + 3);
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 5 * bucketSizeNs, nextPullTimeNs);
-//
-// processor->informPullAlarmFired(nextPullTimeNs + 2);
-//
-// ConfigMetricsReportList reports;
-// vector<uint8_t> buffer;
-// processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(1, reports.reports_size());
-// EXPECT_EQ(1, reports.reports(0).metrics_size());
-// StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
-// sortMetricDataByDimensionsValue(
-// reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
-// EXPECT_GT((int)gaugeMetrics.data_size(), 0);
-//
-// auto data = gaugeMetrics.data(0);
-// EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* subsystem name field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
-// EXPECT_EQ(3, data.bucket_info_size());
-//
-// auto bucketInfo = data.bucket_info(0);
-// EXPECT_EQ(1, bucketInfo.atom_size());
-// EXPECT_EQ(1, bucketInfo.elapsed_timestamp_nanos_size());
-// EXPECT_EQ(activationNs, bucketInfo.elapsed_timestamp_nanos(0));
-// EXPECT_EQ(0, bucketInfo.wall_clock_timestamp_nanos_size());
-// EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, bucketInfo.start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
-// EXPECT_TRUE(bucketInfo.atom(0).subsystem_sleep_state().subsystem_name().empty());
-// EXPECT_GT(bucketInfo.atom(0).subsystem_sleep_state().time_millis(), 0);
-//
-// bucketInfo = data.bucket_info(1);
-// EXPECT_EQ(1, bucketInfo.atom_size());
-// EXPECT_EQ(1, bucketInfo.elapsed_timestamp_nanos_size());
-// EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs + 1, bucketInfo.elapsed_timestamp_nanos(0));
-// EXPECT_EQ(0, bucketInfo.wall_clock_timestamp_nanos_size());
-// EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, bucketInfo.start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
-// EXPECT_TRUE(bucketInfo.atom(0).subsystem_sleep_state().subsystem_name().empty());
-// EXPECT_GT(bucketInfo.atom(0).subsystem_sleep_state().time_millis(), 0);
-//
-// bucketInfo = data.bucket_info(2);
-// EXPECT_EQ(1, bucketInfo.atom_size());
-// EXPECT_EQ(1, bucketInfo.elapsed_timestamp_nanos_size());
-// EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs + 2, bucketInfo.elapsed_timestamp_nanos(0));
-// EXPECT_EQ(0, bucketInfo.wall_clock_timestamp_nanos_size());
-// EXPECT_EQ(MillisToNano(NanoToMillis(baseTimeNs + 5 * bucketSizeNs)),
-// bucketInfo.start_bucket_elapsed_nanos());
-// EXPECT_EQ(MillisToNano(NanoToMillis(activationNs + ttlNs + 1)),
-// bucketInfo.end_bucket_elapsed_nanos());
-// EXPECT_TRUE(bucketInfo.atom(0).subsystem_sleep_state().subsystem_name().empty());
-// EXPECT_GT(bucketInfo.atom(0).subsystem_sleep_state().time_millis(), 0);
-//}
+TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvents) {
+ auto config = CreateStatsdConfig(GaugeMetric::RANDOM_ONE_SAMPLE);
+ int64_t baseTimeNs = getElapsedRealtimeNs();
+ int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
+
+ ConfigKey cfgKey;
+ auto processor =
+ CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
+ SharedRefBase::make<FakeSubsystemSleepCallback>(), ATOM_TAG);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ processor->mPullerManager->ForceClearPullerCache();
+
+ int startBucketNum = processor->mMetricsManagers.begin()
+ ->second->mAllMetricProducers[0]
+ ->getCurrentBucketNum();
+ EXPECT_GT(startBucketNum, (int64_t)0);
+
+ // When creating the config, the gauge metric producer should register the alarm at the
+ // end of the current bucket.
+ EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
+ EXPECT_EQ(bucketSizeNs,
+ processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
+ int64_t& nextPullTimeNs =
+ processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs;
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, nextPullTimeNs);
+
+ auto screenOffEvent =
+ CreateScreenStateChangedEvent(configAddedTimeNs + 55, android::view::DISPLAY_STATE_OFF);
+ processor->OnLogEvent(screenOffEvent.get());
+
+ // Pulling alarm arrives on time and reset the sequential pulling alarm.
+ processor->informPullAlarmFired(nextPullTimeNs + 1);
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 2 * bucketSizeNs, nextPullTimeNs);
+
+ auto screenOnEvent = CreateScreenStateChangedEvent(configAddedTimeNs + bucketSizeNs + 10,
+ android::view::DISPLAY_STATE_ON);
+ processor->OnLogEvent(screenOnEvent.get());
+
+ screenOffEvent = CreateScreenStateChangedEvent(configAddedTimeNs + bucketSizeNs + 100,
+ android::view::DISPLAY_STATE_OFF);
+ processor->OnLogEvent(screenOffEvent.get());
+
+ processor->informPullAlarmFired(nextPullTimeNs + 1);
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 3 * bucketSizeNs, nextPullTimeNs);
+
+ processor->informPullAlarmFired(nextPullTimeNs + 1);
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 4 * bucketSizeNs, nextPullTimeNs);
+
+ screenOnEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 3 * bucketSizeNs + 2,
+ android::view::DISPLAY_STATE_ON);
+ processor->OnLogEvent(screenOnEvent.get());
+
+ processor->informPullAlarmFired(nextPullTimeNs + 3);
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 5 * bucketSizeNs, nextPullTimeNs);
+
+ screenOffEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 5 * bucketSizeNs + 1,
+ android::view::DISPLAY_STATE_OFF);
+ processor->OnLogEvent(screenOffEvent.get());
+
+ processor->informPullAlarmFired(nextPullTimeNs + 2);
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 6 * bucketSizeNs, nextPullTimeNs);
+
+ processor->informPullAlarmFired(nextPullTimeNs + 2);
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
+ ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
+ EXPECT_GT((int)gaugeMetrics.data_size(), 1);
+
+ auto data = gaugeMetrics.data(0);
+ EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* subsystem name field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
+ EXPECT_EQ(6, data.bucket_info_size());
+
+ EXPECT_EQ(1, data.bucket_info(0).atom_size());
+ EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
+ EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
+ EXPECT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size());
+ EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+ EXPECT_TRUE(data.bucket_info(0).atom(0).subsystem_sleep_state().subsystem_name().empty());
+ EXPECT_GT(data.bucket_info(0).atom(0).subsystem_sleep_state().time_millis(), 0);
+
+ EXPECT_EQ(1, data.bucket_info(1).atom_size());
+ EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs + 1, data.bucket_info(1).elapsed_timestamp_nanos(0));
+ EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs + 1, data.bucket_info(1).elapsed_timestamp_nanos(0));
+ EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
+ EXPECT_TRUE(data.bucket_info(1).atom(0).subsystem_sleep_state().subsystem_name().empty());
+ EXPECT_GT(data.bucket_info(1).atom(0).subsystem_sleep_state().time_millis(), 0);
+
+ EXPECT_EQ(1, data.bucket_info(2).atom_size());
+ EXPECT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size());
+ EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs + 1, data.bucket_info(2).elapsed_timestamp_nanos(0));
+ EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
+ EXPECT_TRUE(data.bucket_info(2).atom(0).subsystem_sleep_state().subsystem_name().empty());
+ EXPECT_GT(data.bucket_info(2).atom(0).subsystem_sleep_state().time_millis(), 0);
+
+ EXPECT_EQ(1, data.bucket_info(3).atom_size());
+ EXPECT_EQ(1, data.bucket_info(3).elapsed_timestamp_nanos_size());
+ EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs + 1, data.bucket_info(3).elapsed_timestamp_nanos(0));
+ EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(3).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(3).end_bucket_elapsed_nanos());
+ EXPECT_TRUE(data.bucket_info(3).atom(0).subsystem_sleep_state().subsystem_name().empty());
+ EXPECT_GT(data.bucket_info(3).atom(0).subsystem_sleep_state().time_millis(), 0);
+
+ EXPECT_EQ(1, data.bucket_info(4).atom_size());
+ EXPECT_EQ(1, data.bucket_info(4).elapsed_timestamp_nanos_size());
+ EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs + 1, data.bucket_info(4).elapsed_timestamp_nanos(0));
+ EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(4).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(4).end_bucket_elapsed_nanos());
+ EXPECT_TRUE(data.bucket_info(4).atom(0).subsystem_sleep_state().subsystem_name().empty());
+ EXPECT_GT(data.bucket_info(4).atom(0).subsystem_sleep_state().time_millis(), 0);
+
+ EXPECT_EQ(1, data.bucket_info(5).atom_size());
+ EXPECT_EQ(1, data.bucket_info(5).elapsed_timestamp_nanos_size());
+ EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs + 2, data.bucket_info(5).elapsed_timestamp_nanos(0));
+ EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(5).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 9 * bucketSizeNs, data.bucket_info(5).end_bucket_elapsed_nanos());
+ EXPECT_TRUE(data.bucket_info(5).atom(0).subsystem_sleep_state().subsystem_name().empty());
+ EXPECT_GT(data.bucket_info(5).atom(0).subsystem_sleep_state().time_millis(), 0);
+}
+
+TEST(GaugeMetricE2eTest, TestConditionChangeToTrueSamplePulledEvents) {
+ auto config = CreateStatsdConfig(GaugeMetric::CONDITION_CHANGE_TO_TRUE);
+ int64_t baseTimeNs = getElapsedRealtimeNs();
+ int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
+
+ ConfigKey cfgKey;
+ auto processor =
+ CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
+ SharedRefBase::make<FakeSubsystemSleepCallback>(), ATOM_TAG);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ processor->mPullerManager->ForceClearPullerCache();
+
+ int startBucketNum = processor->mMetricsManagers.begin()
+ ->second->mAllMetricProducers[0]
+ ->getCurrentBucketNum();
+ EXPECT_GT(startBucketNum, (int64_t)0);
+
+ auto screenOffEvent =
+ CreateScreenStateChangedEvent(configAddedTimeNs + 55, android::view::DISPLAY_STATE_OFF);
+ processor->OnLogEvent(screenOffEvent.get());
+
+ auto screenOnEvent = CreateScreenStateChangedEvent(configAddedTimeNs + bucketSizeNs + 10,
+ android::view::DISPLAY_STATE_ON);
+ processor->OnLogEvent(screenOnEvent.get());
+
+ screenOffEvent = CreateScreenStateChangedEvent(configAddedTimeNs + bucketSizeNs + 100,
+ android::view::DISPLAY_STATE_OFF);
+ processor->OnLogEvent(screenOffEvent.get());
+
+ screenOnEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 3 * bucketSizeNs + 2,
+ android::view::DISPLAY_STATE_ON);
+ processor->OnLogEvent(screenOnEvent.get());
+
+ screenOffEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 5 * bucketSizeNs + 1,
+ android::view::DISPLAY_STATE_OFF);
+ processor->OnLogEvent(screenOffEvent.get());
+ screenOnEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 5 * bucketSizeNs + 3,
+ android::view::DISPLAY_STATE_ON);
+ processor->OnLogEvent(screenOnEvent.get());
+ screenOffEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 5 * bucketSizeNs + 10,
+ android::view::DISPLAY_STATE_OFF);
+ processor->OnLogEvent(screenOffEvent.get());
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, configAddedTimeNs + 8 * bucketSizeNs + 10, false, true,
+ ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
+ EXPECT_GT((int)gaugeMetrics.data_size(), 1);
+
+ auto data = gaugeMetrics.data(0);
+ EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* subsystem name field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
+ EXPECT_EQ(3, data.bucket_info_size());
+
+ EXPECT_EQ(1, data.bucket_info(0).atom_size());
+ EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
+ EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
+ EXPECT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size());
+ EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+ EXPECT_TRUE(data.bucket_info(0).atom(0).subsystem_sleep_state().subsystem_name().empty());
+ EXPECT_GT(data.bucket_info(0).atom(0).subsystem_sleep_state().time_millis(), 0);
+
+ EXPECT_EQ(1, data.bucket_info(1).atom_size());
+ EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs + 100, data.bucket_info(1).elapsed_timestamp_nanos(0));
+ EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
+ EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
+ EXPECT_TRUE(data.bucket_info(1).atom(0).subsystem_sleep_state().subsystem_name().empty());
+ EXPECT_GT(data.bucket_info(1).atom(0).subsystem_sleep_state().time_millis(), 0);
+
+ EXPECT_EQ(2, data.bucket_info(2).atom_size());
+ EXPECT_EQ(2, data.bucket_info(2).elapsed_timestamp_nanos_size());
+ EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs + 1, data.bucket_info(2).elapsed_timestamp_nanos(0));
+ EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs + 10, data.bucket_info(2).elapsed_timestamp_nanos(1));
+ EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
+ EXPECT_TRUE(data.bucket_info(2).atom(0).subsystem_sleep_state().subsystem_name().empty());
+ EXPECT_GT(data.bucket_info(2).atom(0).subsystem_sleep_state().time_millis(), 0);
+ EXPECT_TRUE(data.bucket_info(2).atom(1).subsystem_sleep_state().subsystem_name().empty());
+ EXPECT_GT(data.bucket_info(2).atom(1).subsystem_sleep_state().time_millis(), 0);
+}
+
+TEST(GaugeMetricE2eTest, TestRandomSamplePulledEvent_LateAlarm) {
+ auto config = CreateStatsdConfig(GaugeMetric::RANDOM_ONE_SAMPLE);
+ int64_t baseTimeNs = getElapsedRealtimeNs();
+ int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
+
+ ConfigKey cfgKey;
+ auto processor =
+ CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
+ SharedRefBase::make<FakeSubsystemSleepCallback>(), ATOM_TAG);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ processor->mPullerManager->ForceClearPullerCache();
+
+ int startBucketNum = processor->mMetricsManagers.begin()
+ ->second->mAllMetricProducers[0]
+ ->getCurrentBucketNum();
+ EXPECT_GT(startBucketNum, (int64_t)0);
+
+ // When creating the config, the gauge metric producer should register the alarm at the
+ // end of the current bucket.
+ EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
+ EXPECT_EQ(bucketSizeNs,
+ processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
+ int64_t& nextPullTimeNs =
+ processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs;
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, nextPullTimeNs);
+
+ auto screenOffEvent =
+ CreateScreenStateChangedEvent(configAddedTimeNs + 55, android::view::DISPLAY_STATE_OFF);
+ processor->OnLogEvent(screenOffEvent.get());
+
+ auto screenOnEvent = CreateScreenStateChangedEvent(configAddedTimeNs + bucketSizeNs + 10,
+ android::view::DISPLAY_STATE_ON);
+ processor->OnLogEvent(screenOnEvent.get());
+
+ // Pulling alarm arrives one bucket size late.
+ processor->informPullAlarmFired(nextPullTimeNs + bucketSizeNs);
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 3 * bucketSizeNs, nextPullTimeNs);
+
+ screenOffEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 3 * bucketSizeNs + 11,
+ android::view::DISPLAY_STATE_OFF);
+ processor->OnLogEvent(screenOffEvent.get());
+
+ // Pulling alarm arrives more than one bucket size late.
+ processor->informPullAlarmFired(nextPullTimeNs + bucketSizeNs + 12);
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 5 * bucketSizeNs, nextPullTimeNs);
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
+ ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
+ EXPECT_GT((int)gaugeMetrics.data_size(), 1);
+
+ auto data = gaugeMetrics.data(0);
+ EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* subsystem name field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
+ EXPECT_EQ(3, data.bucket_info_size());
+
+ EXPECT_EQ(1, data.bucket_info(0).atom_size());
+ EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
+ EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
+ EXPECT_EQ(baseTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+ EXPECT_TRUE(data.bucket_info(0).atom(0).subsystem_sleep_state().subsystem_name().empty());
+ EXPECT_GT(data.bucket_info(0).atom(0).subsystem_sleep_state().time_millis(), 0);
+
+ EXPECT_EQ(1, data.bucket_info(1).atom_size());
+ EXPECT_EQ(configAddedTimeNs + 3 * bucketSizeNs + 11,
+ data.bucket_info(1).elapsed_timestamp_nanos(0));
+ EXPECT_EQ(configAddedTimeNs + 55, data.bucket_info(0).elapsed_timestamp_nanos(0));
+ EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
+ EXPECT_TRUE(data.bucket_info(1).atom(0).subsystem_sleep_state().subsystem_name().empty());
+ EXPECT_GT(data.bucket_info(1).atom(0).subsystem_sleep_state().time_millis(), 0);
+
+ EXPECT_EQ(1, data.bucket_info(2).atom_size());
+ EXPECT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size());
+ EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs + 12, data.bucket_info(2).elapsed_timestamp_nanos(0));
+ EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
+ EXPECT_TRUE(data.bucket_info(2).atom(0).subsystem_sleep_state().subsystem_name().empty());
+ EXPECT_GT(data.bucket_info(2).atom(0).subsystem_sleep_state().time_millis(), 0);
+}
+
+TEST(GaugeMetricE2eTest, TestRandomSamplePulledEventsWithActivation) {
+ auto config = CreateStatsdConfig(GaugeMetric::RANDOM_ONE_SAMPLE, /*useCondition=*/false);
+
+ int64_t baseTimeNs = getElapsedRealtimeNs();
+ int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
+
+ auto batterySaverStartMatcher = CreateBatterySaverModeStartAtomMatcher();
+ *config.add_atom_matcher() = batterySaverStartMatcher;
+ const int64_t ttlNs = 2 * bucketSizeNs; // Two buckets.
+ auto metric_activation = config.add_metric_activation();
+ metric_activation->set_metric_id(metricId);
+ metric_activation->set_activation_type(ACTIVATE_IMMEDIATELY);
+ auto event_activation = metric_activation->add_event_activation();
+ event_activation->set_atom_matcher_id(batterySaverStartMatcher.id());
+ event_activation->set_ttl_seconds(ttlNs / 1000000000);
+
+ ConfigKey cfgKey;
+ auto processor =
+ CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
+ SharedRefBase::make<FakeSubsystemSleepCallback>(), ATOM_TAG);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ processor->mPullerManager->ForceClearPullerCache();
+
+ int startBucketNum = processor->mMetricsManagers.begin()
+ ->second->mAllMetricProducers[0]
+ ->getCurrentBucketNum();
+ EXPECT_GT(startBucketNum, (int64_t)0);
+ EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
+
+ // When creating the config, the gauge metric producer should register the alarm at the
+ // end of the current bucket.
+ EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
+ EXPECT_EQ(bucketSizeNs,
+ processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
+ int64_t& nextPullTimeNs =
+ processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs;
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, nextPullTimeNs);
+
+ // Pulling alarm arrives on time and reset the sequential pulling alarm.
+ // Event should not be kept.
+ processor->informPullAlarmFired(nextPullTimeNs + 1); // 15 mins + 1 ns.
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 2 * bucketSizeNs, nextPullTimeNs);
+ EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
+
+ // Activate the metric. A pull occurs upon activation.
+ const int64_t activationNs = configAddedTimeNs + bucketSizeNs + (2 * 1000 * 1000); // 2 millis.
+ auto batterySaverOnEvent = CreateBatterySaverOnEvent(activationNs);
+ processor->OnLogEvent(batterySaverOnEvent.get()); // 15 mins + 2 ms.
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
+
+ // This event should be kept. 2 total.
+ processor->informPullAlarmFired(nextPullTimeNs + 1); // 20 mins + 1 ns.
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 3 * bucketSizeNs, nextPullTimeNs);
+
+ // This event should be kept. 3 total.
+ processor->informPullAlarmFired(nextPullTimeNs + 2); // 25 mins + 2 ns.
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 4 * bucketSizeNs, nextPullTimeNs);
+
+ // Create random event to deactivate metric.
+ auto deactivationEvent = CreateScreenBrightnessChangedEvent(activationNs + ttlNs + 1, 50);
+ processor->OnLogEvent(deactivationEvent.get());
+ EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
+
+ // Event should not be kept. 3 total.
+ processor->informPullAlarmFired(nextPullTimeNs + 3);
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 5 * bucketSizeNs, nextPullTimeNs);
+
+ processor->informPullAlarmFired(nextPullTimeNs + 2);
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
+ ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
+ EXPECT_GT((int)gaugeMetrics.data_size(), 0);
+
+ auto data = gaugeMetrics.data(0);
+ EXPECT_EQ(ATOM_TAG, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* subsystem name field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
+ EXPECT_EQ(3, data.bucket_info_size());
+
+ auto bucketInfo = data.bucket_info(0);
+ EXPECT_EQ(1, bucketInfo.atom_size());
+ EXPECT_EQ(1, bucketInfo.elapsed_timestamp_nanos_size());
+ EXPECT_EQ(activationNs, bucketInfo.elapsed_timestamp_nanos(0));
+ EXPECT_EQ(0, bucketInfo.wall_clock_timestamp_nanos_size());
+ EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, bucketInfo.start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
+ EXPECT_TRUE(bucketInfo.atom(0).subsystem_sleep_state().subsystem_name().empty());
+ EXPECT_GT(bucketInfo.atom(0).subsystem_sleep_state().time_millis(), 0);
+
+ bucketInfo = data.bucket_info(1);
+ EXPECT_EQ(1, bucketInfo.atom_size());
+ EXPECT_EQ(1, bucketInfo.elapsed_timestamp_nanos_size());
+ EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs + 1, bucketInfo.elapsed_timestamp_nanos(0));
+ EXPECT_EQ(0, bucketInfo.wall_clock_timestamp_nanos_size());
+ EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, bucketInfo.start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
+ EXPECT_TRUE(bucketInfo.atom(0).subsystem_sleep_state().subsystem_name().empty());
+ EXPECT_GT(bucketInfo.atom(0).subsystem_sleep_state().time_millis(), 0);
+
+ bucketInfo = data.bucket_info(2);
+ EXPECT_EQ(1, bucketInfo.atom_size());
+ EXPECT_EQ(1, bucketInfo.elapsed_timestamp_nanos_size());
+ EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs + 2, bucketInfo.elapsed_timestamp_nanos(0));
+ EXPECT_EQ(0, bucketInfo.wall_clock_timestamp_nanos_size());
+ EXPECT_EQ(MillisToNano(NanoToMillis(baseTimeNs + 5 * bucketSizeNs)),
+ bucketInfo.start_bucket_elapsed_nanos());
+ EXPECT_EQ(MillisToNano(NanoToMillis(activationNs + ttlNs + 1)),
+ bucketInfo.end_bucket_elapsed_nanos());
+ EXPECT_TRUE(bucketInfo.atom(0).subsystem_sleep_state().subsystem_name().empty());
+ EXPECT_GT(bucketInfo.atom(0).subsystem_sleep_state().time_millis(), 0);
+}
TEST(GaugeMetricE2eTest, TestRandomSamplePulledEventsNoCondition) {
auto config = CreateStatsdConfig(GaugeMetric::RANDOM_ONE_SAMPLE, /*useCondition=*/false);
diff --git a/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp b/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
index ef6e753..6e3d93a 100644
--- a/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
+++ b/cmds/statsd/tests/e2e/GaugeMetric_e2e_push_test.cpp
@@ -14,12 +14,13 @@
#include <gtest/gtest.h>
+#include <vector>
+
#include "src/StatsLogProcessor.h"
#include "src/stats_log_util.h"
+#include "stats_event.h"
#include "tests/statsd_test_util.h"
-#include <vector>
-
namespace android {
namespace os {
namespace statsd {
@@ -68,221 +69,227 @@
return config;
}
-// TODO(b/149590301): Update this helper to use new socket schema.
-//std::unique_ptr<LogEvent> CreateAppStartOccurredEvent(
-// const int uid, const string& pkg_name, AppStartOccurred::TransitionType type,
-// const string& activity_name, const string& calling_pkg_name, const bool is_instant_app,
-// int64_t activity_start_msec, uint64_t timestampNs) {
-// auto logEvent = std::make_unique<LogEvent>(
-// android::util::APP_START_OCCURRED, timestampNs);
-// logEvent->write(uid);
-// logEvent->write(pkg_name);
-// logEvent->write(type);
-// logEvent->write(activity_name);
-// logEvent->write(calling_pkg_name);
-// logEvent->write(is_instant_app);
-// logEvent->write(activity_start_msec);
-// logEvent->init();
-// return logEvent;
-//}
+std::unique_ptr<LogEvent> CreateAppStartOccurredEvent(
+ uint64_t timestampNs, const int uid, const string& pkg_name,
+ AppStartOccurred::TransitionType type, const string& activity_name,
+ const string& calling_pkg_name, const bool is_instant_app, int64_t activity_start_msec) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, android::util::APP_START_OCCURRED);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+ AStatsEvent_writeInt32(statsEvent, uid);
+ AStatsEvent_writeString(statsEvent, pkg_name.c_str());
+ AStatsEvent_writeInt32(statsEvent, type);
+ AStatsEvent_writeString(statsEvent, activity_name.c_str());
+ AStatsEvent_writeString(statsEvent, calling_pkg_name.c_str());
+ AStatsEvent_writeInt32(statsEvent, is_instant_app);
+ AStatsEvent_writeInt32(statsEvent, activity_start_msec);
+ 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;
+}
} // namespace
-// TODO(b/149590301): Update this test to use new socket schema.
-//TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent) {
-// for (const auto& sampling_type :
-// { GaugeMetric::FIRST_N_SAMPLES, GaugeMetric:: RANDOM_ONE_SAMPLE }) {
-// auto config = CreateStatsdConfigForPushedEvent(sampling_type);
-// int64_t bucketStartTimeNs = 10000000000;
-// int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
-//
-// ConfigKey cfgKey;
-// auto processor = CreateStatsLogProcessor(
-// bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-//
-// int appUid1 = 123;
-// int appUid2 = 456;
-// std::vector<std::unique_ptr<LogEvent>> events;
-// events.push_back(CreateMoveToBackgroundEvent(appUid1, bucketStartTimeNs + 15));
-// events.push_back(CreateMoveToForegroundEvent(
-// appUid1, bucketStartTimeNs + bucketSizeNs + 250));
-// events.push_back(CreateMoveToBackgroundEvent(
-// appUid1, bucketStartTimeNs + bucketSizeNs + 350));
-// events.push_back(CreateMoveToForegroundEvent(
-// appUid1, bucketStartTimeNs + 2 * bucketSizeNs + 100));
-//
-//
-// events.push_back(CreateAppStartOccurredEvent(
-// appUid1, "app1", AppStartOccurred::WARM, "activity_name1", "calling_pkg_name1",
-// true /*is_instant_app*/, 101 /*activity_start_msec*/, bucketStartTimeNs + 10));
-// events.push_back(CreateAppStartOccurredEvent(
-// appUid1, "app1", AppStartOccurred::HOT, "activity_name2", "calling_pkg_name2",
-// true /*is_instant_app*/, 102 /*activity_start_msec*/, bucketStartTimeNs + 20));
-// events.push_back(CreateAppStartOccurredEvent(
-// appUid1, "app1", AppStartOccurred::COLD, "activity_name3", "calling_pkg_name3",
-// true /*is_instant_app*/, 103 /*activity_start_msec*/, bucketStartTimeNs + 30));
-// events.push_back(CreateAppStartOccurredEvent(
-// appUid1, "app1", AppStartOccurred::WARM, "activity_name4", "calling_pkg_name4",
-// true /*is_instant_app*/, 104 /*activity_start_msec*/,
-// bucketStartTimeNs + bucketSizeNs + 30));
-// events.push_back(CreateAppStartOccurredEvent(
-// appUid1, "app1", AppStartOccurred::COLD, "activity_name5", "calling_pkg_name5",
-// true /*is_instant_app*/, 105 /*activity_start_msec*/,
-// bucketStartTimeNs + 2 * bucketSizeNs));
-// events.push_back(CreateAppStartOccurredEvent(
-// appUid1, "app1", AppStartOccurred::HOT, "activity_name6", "calling_pkg_name6",
-// false /*is_instant_app*/, 106 /*activity_start_msec*/,
-// bucketStartTimeNs + 2 * bucketSizeNs + 10));
-//
-// events.push_back(CreateMoveToBackgroundEvent(
-// appUid2, bucketStartTimeNs + bucketSizeNs + 10));
-// events.push_back(CreateAppStartOccurredEvent(
-// appUid2, "app2", AppStartOccurred::COLD, "activity_name7", "calling_pkg_name7",
-// true /*is_instant_app*/, 201 /*activity_start_msec*/,
-// bucketStartTimeNs + 2 * bucketSizeNs + 10));
-//
-// sortLogEventsByTimestamp(&events);
-//
-// for (const auto& event : events) {
-// processor->OnLogEvent(event.get());
-// }
-// ConfigMetricsReportList reports;
-// vector<uint8_t> buffer;
-// processor->onDumpReport(cfgKey, bucketStartTimeNs + 3 * bucketSizeNs, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(1, reports.reports_size());
-// EXPECT_EQ(1, reports.reports(0).metrics_size());
-// StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
-// sortMetricDataByDimensionsValue(
-// reports.reports(0).metrics(0).gauge_metrics(), &gaugeMetrics);
-// EXPECT_EQ(2, gaugeMetrics.data_size());
-//
-// auto data = gaugeMetrics.data(0);
-// EXPECT_EQ(android::util::APP_START_OCCURRED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(appUid1, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(3, data.bucket_info_size());
-// if (sampling_type == GaugeMetric::FIRST_N_SAMPLES) {
-// EXPECT_EQ(2, data.bucket_info(0).atom_size());
-// EXPECT_EQ(2, data.bucket_info(0).elapsed_timestamp_nanos_size());
-// EXPECT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size());
-// EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
-// data.bucket_info(0).end_bucket_elapsed_nanos());
-// EXPECT_EQ(AppStartOccurred::HOT,
-// data.bucket_info(0).atom(0).app_start_occurred().type());
-// EXPECT_EQ("activity_name2",
-// data.bucket_info(0).atom(0).app_start_occurred().activity_name());
-// EXPECT_EQ(102L,
-// data.bucket_info(0).atom(0).app_start_occurred().activity_start_millis());
-// EXPECT_EQ(AppStartOccurred::COLD,
-// data.bucket_info(0).atom(1).app_start_occurred().type());
-// EXPECT_EQ("activity_name3",
-// data.bucket_info(0).atom(1).app_start_occurred().activity_name());
-// EXPECT_EQ(103L,
-// data.bucket_info(0).atom(1).app_start_occurred().activity_start_millis());
-//
-// EXPECT_EQ(1, data.bucket_info(1).atom_size());
-// EXPECT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size());
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
-// data.bucket_info(1).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-// data.bucket_info(1).end_bucket_elapsed_nanos());
-// EXPECT_EQ(AppStartOccurred::WARM,
-// data.bucket_info(1).atom(0).app_start_occurred().type());
-// EXPECT_EQ("activity_name4",
-// data.bucket_info(1).atom(0).app_start_occurred().activity_name());
-// EXPECT_EQ(104L,
-// data.bucket_info(1).atom(0).app_start_occurred().activity_start_millis());
-//
-// EXPECT_EQ(2, data.bucket_info(2).atom_size());
-// EXPECT_EQ(2, data.bucket_info(2).elapsed_timestamp_nanos_size());
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-// data.bucket_info(2).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
-// data.bucket_info(2).end_bucket_elapsed_nanos());
-// EXPECT_EQ(AppStartOccurred::COLD,
-// data.bucket_info(2).atom(0).app_start_occurred().type());
-// EXPECT_EQ("activity_name5",
-// data.bucket_info(2).atom(0).app_start_occurred().activity_name());
-// EXPECT_EQ(105L,
-// data.bucket_info(2).atom(0).app_start_occurred().activity_start_millis());
-// EXPECT_EQ(AppStartOccurred::HOT,
-// data.bucket_info(2).atom(1).app_start_occurred().type());
-// EXPECT_EQ("activity_name6",
-// data.bucket_info(2).atom(1).app_start_occurred().activity_name());
-// EXPECT_EQ(106L,
-// data.bucket_info(2).atom(1).app_start_occurred().activity_start_millis());
-// } else {
-// EXPECT_EQ(1, data.bucket_info(0).atom_size());
-// EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
-// EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
-// data.bucket_info(0).end_bucket_elapsed_nanos());
-// EXPECT_EQ(AppStartOccurred::HOT,
-// data.bucket_info(0).atom(0).app_start_occurred().type());
-// EXPECT_EQ("activity_name2",
-// data.bucket_info(0).atom(0).app_start_occurred().activity_name());
-// EXPECT_EQ(102L,
-// data.bucket_info(0).atom(0).app_start_occurred().activity_start_millis());
-//
-// EXPECT_EQ(1, data.bucket_info(1).atom_size());
-// EXPECT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size());
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
-// data.bucket_info(1).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-// data.bucket_info(1).end_bucket_elapsed_nanos());
-// EXPECT_EQ(AppStartOccurred::WARM,
-// data.bucket_info(1).atom(0).app_start_occurred().type());
-// EXPECT_EQ("activity_name4",
-// data.bucket_info(1).atom(0).app_start_occurred().activity_name());
-// EXPECT_EQ(104L,
-// data.bucket_info(1).atom(0).app_start_occurred().activity_start_millis());
-//
-// EXPECT_EQ(1, data.bucket_info(2).atom_size());
-// EXPECT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size());
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-// data.bucket_info(2).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
-// data.bucket_info(2).end_bucket_elapsed_nanos());
-// EXPECT_EQ(AppStartOccurred::COLD,
-// data.bucket_info(2).atom(0).app_start_occurred().type());
-// EXPECT_EQ("activity_name5",
-// data.bucket_info(2).atom(0).app_start_occurred().activity_name());
-// EXPECT_EQ(105L,
-// data.bucket_info(2).atom(0).app_start_occurred().activity_start_millis());
-// }
-//
-// data = gaugeMetrics.data(1);
-//
-// EXPECT_EQ(data.dimensions_in_what().field(), android::util::APP_START_OCCURRED);
-// EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(appUid2, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).atom_size());
-// EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-// data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
-// data.bucket_info(0).end_bucket_elapsed_nanos());
-// EXPECT_EQ(AppStartOccurred::COLD, data.bucket_info(0).atom(0).app_start_occurred().type());
-// EXPECT_EQ("activity_name7",
-// data.bucket_info(0).atom(0).app_start_occurred().activity_name());
-// EXPECT_EQ(201L, data.bucket_info(0).atom(0).app_start_occurred().activity_start_millis());
-// }
-//}
+TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent) {
+ for (const auto& sampling_type :
+ {GaugeMetric::FIRST_N_SAMPLES, GaugeMetric::RANDOM_ONE_SAMPLE}) {
+ auto config = CreateStatsdConfigForPushedEvent(sampling_type);
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.gauge_metric(0).bucket()) * 1000000;
+
+ ConfigKey cfgKey;
+ auto processor =
+ CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+
+ int appUid1 = 123;
+ int appUid2 = 456;
+ std::vector<std::unique_ptr<LogEvent>> events;
+ events.push_back(CreateMoveToBackgroundEvent(bucketStartTimeNs + 15, appUid1));
+ events.push_back(
+ CreateMoveToForegroundEvent(bucketStartTimeNs + bucketSizeNs + 250, appUid1));
+ events.push_back(
+ CreateMoveToBackgroundEvent(bucketStartTimeNs + bucketSizeNs + 350, appUid1));
+ events.push_back(
+ CreateMoveToForegroundEvent(bucketStartTimeNs + 2 * bucketSizeNs + 100, appUid1));
+
+ events.push_back(CreateAppStartOccurredEvent(
+ bucketStartTimeNs + 10, appUid1, "app1", AppStartOccurred::WARM, "activity_name1",
+ "calling_pkg_name1", true /*is_instant_app*/, 101 /*activity_start_msec*/));
+ events.push_back(CreateAppStartOccurredEvent(
+ bucketStartTimeNs + 20, appUid1, "app1", AppStartOccurred::HOT, "activity_name2",
+ "calling_pkg_name2", true /*is_instant_app*/, 102 /*activity_start_msec*/));
+ events.push_back(CreateAppStartOccurredEvent(
+ bucketStartTimeNs + 30, appUid1, "app1", AppStartOccurred::COLD, "activity_name3",
+ "calling_pkg_name3", true /*is_instant_app*/, 103 /*activity_start_msec*/));
+ events.push_back(CreateAppStartOccurredEvent(
+ bucketStartTimeNs + bucketSizeNs + 30, appUid1, "app1", AppStartOccurred::WARM,
+ "activity_name4", "calling_pkg_name4", true /*is_instant_app*/,
+ 104 /*activity_start_msec*/));
+ events.push_back(CreateAppStartOccurredEvent(
+ bucketStartTimeNs + 2 * bucketSizeNs, appUid1, "app1", AppStartOccurred::COLD,
+ "activity_name5", "calling_pkg_name5", true /*is_instant_app*/,
+ 105 /*activity_start_msec*/));
+ events.push_back(CreateAppStartOccurredEvent(
+ bucketStartTimeNs + 2 * bucketSizeNs + 10, appUid1, "app1", AppStartOccurred::HOT,
+ "activity_name6", "calling_pkg_name6", false /*is_instant_app*/,
+ 106 /*activity_start_msec*/));
+
+ events.push_back(
+ CreateMoveToBackgroundEvent(bucketStartTimeNs + bucketSizeNs + 10, appUid2));
+ events.push_back(CreateAppStartOccurredEvent(
+ bucketStartTimeNs + 2 * bucketSizeNs + 10, appUid2, "app2", AppStartOccurred::COLD,
+ "activity_name7", "calling_pkg_name7", true /*is_instant_app*/,
+ 201 /*activity_start_msec*/));
+
+ sortLogEventsByTimestamp(&events);
+
+ for (const auto& event : events) {
+ processor->OnLogEvent(event.get());
+ }
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 3 * bucketSizeNs, false, true, ADB_DUMP,
+ FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ StatsLogReport::GaugeMetricDataWrapper gaugeMetrics;
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).gauge_metrics(),
+ &gaugeMetrics);
+ EXPECT_EQ(2, gaugeMetrics.data_size());
+
+ auto data = gaugeMetrics.data(0);
+ EXPECT_EQ(android::util::APP_START_OCCURRED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(appUid1, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(3, data.bucket_info_size());
+ if (sampling_type == GaugeMetric::FIRST_N_SAMPLES) {
+ EXPECT_EQ(2, data.bucket_info(0).atom_size());
+ EXPECT_EQ(2, data.bucket_info(0).elapsed_timestamp_nanos_size());
+ EXPECT_EQ(0, data.bucket_info(0).wall_clock_timestamp_nanos_size());
+ EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
+ data.bucket_info(0).end_bucket_elapsed_nanos());
+ EXPECT_EQ(AppStartOccurred::HOT,
+ data.bucket_info(0).atom(0).app_start_occurred().type());
+ EXPECT_EQ("activity_name2",
+ data.bucket_info(0).atom(0).app_start_occurred().activity_name());
+ EXPECT_EQ(102L,
+ data.bucket_info(0).atom(0).app_start_occurred().activity_start_millis());
+ EXPECT_EQ(AppStartOccurred::COLD,
+ data.bucket_info(0).atom(1).app_start_occurred().type());
+ EXPECT_EQ("activity_name3",
+ data.bucket_info(0).atom(1).app_start_occurred().activity_name());
+ EXPECT_EQ(103L,
+ data.bucket_info(0).atom(1).app_start_occurred().activity_start_millis());
+
+ EXPECT_EQ(1, data.bucket_info(1).atom_size());
+ EXPECT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
+ data.bucket_info(1).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+ data.bucket_info(1).end_bucket_elapsed_nanos());
+ EXPECT_EQ(AppStartOccurred::WARM,
+ data.bucket_info(1).atom(0).app_start_occurred().type());
+ EXPECT_EQ("activity_name4",
+ data.bucket_info(1).atom(0).app_start_occurred().activity_name());
+ EXPECT_EQ(104L,
+ data.bucket_info(1).atom(0).app_start_occurred().activity_start_millis());
+
+ EXPECT_EQ(2, data.bucket_info(2).atom_size());
+ EXPECT_EQ(2, data.bucket_info(2).elapsed_timestamp_nanos_size());
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+ data.bucket_info(2).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
+ data.bucket_info(2).end_bucket_elapsed_nanos());
+ EXPECT_EQ(AppStartOccurred::COLD,
+ data.bucket_info(2).atom(0).app_start_occurred().type());
+ EXPECT_EQ("activity_name5",
+ data.bucket_info(2).atom(0).app_start_occurred().activity_name());
+ EXPECT_EQ(105L,
+ data.bucket_info(2).atom(0).app_start_occurred().activity_start_millis());
+ EXPECT_EQ(AppStartOccurred::HOT,
+ data.bucket_info(2).atom(1).app_start_occurred().type());
+ EXPECT_EQ("activity_name6",
+ data.bucket_info(2).atom(1).app_start_occurred().activity_name());
+ EXPECT_EQ(106L,
+ data.bucket_info(2).atom(1).app_start_occurred().activity_start_millis());
+ } else {
+ EXPECT_EQ(1, data.bucket_info(0).atom_size());
+ EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
+ EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
+ data.bucket_info(0).end_bucket_elapsed_nanos());
+ EXPECT_EQ(AppStartOccurred::HOT,
+ data.bucket_info(0).atom(0).app_start_occurred().type());
+ EXPECT_EQ("activity_name2",
+ data.bucket_info(0).atom(0).app_start_occurred().activity_name());
+ EXPECT_EQ(102L,
+ data.bucket_info(0).atom(0).app_start_occurred().activity_start_millis());
+
+ EXPECT_EQ(1, data.bucket_info(1).atom_size());
+ EXPECT_EQ(1, data.bucket_info(1).elapsed_timestamp_nanos_size());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
+ data.bucket_info(1).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+ data.bucket_info(1).end_bucket_elapsed_nanos());
+ EXPECT_EQ(AppStartOccurred::WARM,
+ data.bucket_info(1).atom(0).app_start_occurred().type());
+ EXPECT_EQ("activity_name4",
+ data.bucket_info(1).atom(0).app_start_occurred().activity_name());
+ EXPECT_EQ(104L,
+ data.bucket_info(1).atom(0).app_start_occurred().activity_start_millis());
+
+ EXPECT_EQ(1, data.bucket_info(2).atom_size());
+ EXPECT_EQ(1, data.bucket_info(2).elapsed_timestamp_nanos_size());
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+ data.bucket_info(2).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
+ data.bucket_info(2).end_bucket_elapsed_nanos());
+ EXPECT_EQ(AppStartOccurred::COLD,
+ data.bucket_info(2).atom(0).app_start_occurred().type());
+ EXPECT_EQ("activity_name5",
+ data.bucket_info(2).atom(0).app_start_occurred().activity_name());
+ EXPECT_EQ(105L,
+ data.bucket_info(2).atom(0).app_start_occurred().activity_start_millis());
+ }
+
+ data = gaugeMetrics.data(1);
+
+ EXPECT_EQ(data.dimensions_in_what().field(), android::util::APP_START_OCCURRED);
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(appUid2, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).atom_size());
+ EXPECT_EQ(1, data.bucket_info(0).elapsed_timestamp_nanos_size());
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+ data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
+ data.bucket_info(0).end_bucket_elapsed_nanos());
+ EXPECT_EQ(AppStartOccurred::COLD, data.bucket_info(0).atom(0).app_start_occurred().type());
+ EXPECT_EQ("activity_name7",
+ data.bucket_info(0).atom(0).app_start_occurred().activity_name());
+ EXPECT_EQ(201L, data.bucket_info(0).atom(0).app_start_occurred().activity_start_millis());
+ }
+}
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
diff --git a/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
index f3f7df77..1dd90e2 100644
--- a/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
@@ -233,1609 +233,1602 @@
} // namespace
-// TODO(b/149590301): Update these tests to use new socket schema.
-//TEST(MetricActivationE2eTest, TestCountMetric) {
-// auto config = CreateStatsdConfig();
-//
-// int64_t bucketStartTimeNs = NS_PER_SEC * 10; // 10 secs
-// int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL;
-//
-// int uid = 12345;
-// int64_t cfgId = 98765;
-// ConfigKey cfgKey(uid, cfgId);
-//
-// sp<UidMap> m = new UidMap();
-// sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-// sp<AlarmMonitor> anomalyAlarmMonitor;
-// sp<AlarmMonitor> subscriberAlarmMonitor;
-// vector<int64_t> activeConfigsBroadcast;
-//
-// long timeBase1 = 1;
-// int broadcastCount = 0;
-// StatsLogProcessor processor(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor,
-// bucketStartTimeNs, [](const ConfigKey& key) { return true; },
-// [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
-// const vector<int64_t>& activeConfigs) {
-// broadcastCount++;
-// EXPECT_EQ(broadcastUid, uid);
-// activeConfigsBroadcast.clear();
-// activeConfigsBroadcast.insert(activeConfigsBroadcast.end(),
-// activeConfigs.begin(), activeConfigs.end());
-// return true;
-// });
-//
-// processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config);
-//
-// EXPECT_EQ(processor.mMetricsManagers.size(), 1u);
-// sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
-// EXPECT_TRUE(metricsManager->isConfigValid());
-// EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-// sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-// auto& eventActivationMap = metricProducer->mEventActivationMap;
-//
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// // Two activations: one is triggered by battery saver mode (tracker index 0), the other is
-// // triggered by screen on event (tracker index 2).
-// EXPECT_EQ(eventActivationMap.size(), 2u);
-// EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end());
-// EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, 0);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//
-// std::unique_ptr<LogEvent> event;
-//
-// event = CreateAppCrashEvent(111, bucketStartTimeNs + 5);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + 5);
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 0);
-//
-// // Activated by battery save mode.
-// event = CreateBatterySaverOnEvent(bucketStartTimeNs + 10);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + 10);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 1);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-// EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//
-// // First processed event.
-// event = CreateAppCrashEvent(222, bucketStartTimeNs + 15);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
-//
-// // Activated by screen on event.
-// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-// bucketStartTimeNs + 20);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + 20);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//
-// // 2nd processed event.
-// // The activation by screen_on event expires, but the one by battery save mode is still active.
-// event = CreateAppCrashEvent(333, bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// // No new broadcast since the config should still be active.
-// EXPECT_EQ(broadcastCount, 1);
-//
-// // 3rd processed event.
-// event = CreateAppCrashEvent(444, bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
-//
-// // All activations expired.
-// event = CreateAppCrashEvent(555, bucketStartTimeNs + NS_PER_SEC * 60 * 8);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8);
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// // New broadcast since the config is no longer active.
-// EXPECT_EQ(broadcastCount, 2);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 0);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//
-// // Re-activate metric via screen on.
-// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-// bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 3);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-// EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-//
-// // 4th processed event.
-// event = CreateAppCrashEvent(666, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
-//
-// ConfigMetricsReportList reports;
-// vector<uint8_t> buffer;
-// processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(1, reports.reports_size());
-// EXPECT_EQ(1, reports.reports(0).metrics_size());
-// EXPECT_EQ(4, reports.reports(0).metrics(0).count_metrics().data_size());
-//
-// StatsLogReport::CountMetricDataWrapper countMetrics;
-// sortMetricDataByDimensionsValue(
-// reports.reports(0).metrics(0).count_metrics(), &countMetrics);
-// EXPECT_EQ(4, countMetrics.data_size());
-//
-// auto data = countMetrics.data(0);
-// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(1);
-// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(2);
-// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// // Partial bucket as metric is deactivated.
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8,
-// data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(3);
-// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-// data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
-// data.bucket_info(0).end_bucket_elapsed_nanos());
-//}
-//
-//TEST(MetricActivationE2eTest, TestCountMetricWithOneDeactivation) {
-// auto config = CreateStatsdConfigWithOneDeactivation();
-//
-// int64_t bucketStartTimeNs = NS_PER_SEC * 10; // 10 secs
-// int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL;
-//
-// int uid = 12345;
-// int64_t cfgId = 98765;
-// ConfigKey cfgKey(uid, cfgId);
-//
-// sp<UidMap> m = new UidMap();
-// sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-// sp<AlarmMonitor> anomalyAlarmMonitor;
-// sp<AlarmMonitor> subscriberAlarmMonitor;
-// vector<int64_t> activeConfigsBroadcast;
-//
-// long timeBase1 = 1;
-// int broadcastCount = 0;
-// StatsLogProcessor processor(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor,
-// bucketStartTimeNs, [](const ConfigKey& key) { return true; },
-// [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
-// const vector<int64_t>& activeConfigs) {
-// broadcastCount++;
-// EXPECT_EQ(broadcastUid, uid);
-// activeConfigsBroadcast.clear();
-// activeConfigsBroadcast.insert(activeConfigsBroadcast.end(),
-// activeConfigs.begin(), activeConfigs.end());
-// return true;
-// });
-//
-// processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config);
-//
-// EXPECT_EQ(processor.mMetricsManagers.size(), 1u);
-// sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
-// EXPECT_TRUE(metricsManager->isConfigValid());
-// EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-// sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-// auto& eventActivationMap = metricProducer->mEventActivationMap;
-// auto& eventDeactivationMap = metricProducer->mEventDeactivationMap;
-//
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// // Two activations: one is triggered by battery saver mode (tracker index 0), the other is
-// // triggered by screen on event (tracker index 2).
-// EXPECT_EQ(eventActivationMap.size(), 2u);
-// EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end());
-// EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, 0);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap.size(), 1u);
-// EXPECT_TRUE(eventDeactivationMap.find(3) != eventDeactivationMap.end());
-// EXPECT_EQ(eventDeactivationMap[3].size(), 1u);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//
-// std::unique_ptr<LogEvent> event;
-//
-// event = CreateAppCrashEvent(111, bucketStartTimeNs + 5);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + 5);
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 0);
-//
-// // Activated by battery save mode.
-// event = CreateBatterySaverOnEvent(bucketStartTimeNs + 10);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + 10);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 1);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-// EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//
-// // First processed event.
-// event = CreateAppCrashEvent(222, bucketStartTimeNs + 15);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
-//
-// // Activated by screen on event.
-// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-// bucketStartTimeNs + 20);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + 20);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//
-// // 2nd processed event.
-// // The activation by screen_on event expires, but the one by battery save mode is still active.
-// event = CreateAppCrashEvent(333, bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
-// processor.OnLogEvent(event.get(),bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// // No new broadcast since the config should still be active.
-// EXPECT_EQ(broadcastCount, 1);
-//
-// // 3rd processed event.
-// event = CreateAppCrashEvent(444, bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
-//
-// // All activations expired.
-// event = CreateAppCrashEvent(555, bucketStartTimeNs + NS_PER_SEC * 60 * 8);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8);
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// // New broadcast since the config is no longer active.
-// EXPECT_EQ(broadcastCount, 2);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 0);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//
-// // Re-activate metric via screen on.
-// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-// bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 3);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-// EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//
-// // 4th processed event.
-// event = CreateAppCrashEvent(666, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
-//
-// // Re-enable battery saver mode activation.
-// event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 3);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-// EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//
-// // 5th processed event.
-// event = CreateAppCrashEvent(777, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
-//
-// // Cancel battery saver mode activation.
-// event = CreateScreenBrightnessChangedEvent(64, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 3);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-// EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//
-// // Screen-on activation expired.
-// event = CreateAppCrashEvent(888, bucketStartTimeNs + NS_PER_SEC * 60 * 13);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13);
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// // New broadcast since the config is no longer active.
-// EXPECT_EQ(broadcastCount, 4);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 0);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//
-// event = CreateAppCrashEvent(999, bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
-//
-// // Re-enable battery saver mode activation.
-// event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 5);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-// EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//
-// // Cancel battery saver mode activation.
-// event = CreateScreenBrightnessChangedEvent(140, bucketStartTimeNs + NS_PER_SEC * 60 * 16);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 16);
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 6);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 0);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-//
-// ConfigMetricsReportList reports;
-// vector<uint8_t> buffer;
-// processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(1, reports.reports_size());
-// EXPECT_EQ(1, reports.reports(0).metrics_size());
-// EXPECT_EQ(5, reports.reports(0).metrics(0).count_metrics().data_size());
-//
-// StatsLogReport::CountMetricDataWrapper countMetrics;
-// sortMetricDataByDimensionsValue(
-// reports.reports(0).metrics(0).count_metrics(), &countMetrics);
-// EXPECT_EQ(5, countMetrics.data_size());
-//
-// auto data = countMetrics.data(0);
-// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(1);
-// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(2);
-// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// // Partial bucket as metric is deactivated.
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8,
-// data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(3);
-// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-// data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 13,
-// data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(4);
-// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(777, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-// data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 13,
-// data.bucket_info(0).end_bucket_elapsed_nanos());
-//}
-//
-//TEST(MetricActivationE2eTest, TestCountMetricWithTwoDeactivations) {
-// auto config = CreateStatsdConfigWithTwoDeactivations();
-//
-// int64_t bucketStartTimeNs = NS_PER_SEC * 10; // 10 secs
-// int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL;
-//
-// int uid = 12345;
-// int64_t cfgId = 98765;
-// ConfigKey cfgKey(uid, cfgId);
-//
-// sp<UidMap> m = new UidMap();
-// sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-// sp<AlarmMonitor> anomalyAlarmMonitor;
-// sp<AlarmMonitor> subscriberAlarmMonitor;
-// vector<int64_t> activeConfigsBroadcast;
-//
-// long timeBase1 = 1;
-// int broadcastCount = 0;
-// StatsLogProcessor processor(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor,
-// bucketStartTimeNs, [](const ConfigKey& key) { return true; },
-// [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
-// const vector<int64_t>& activeConfigs) {
-// broadcastCount++;
-// EXPECT_EQ(broadcastUid, uid);
-// activeConfigsBroadcast.clear();
-// activeConfigsBroadcast.insert(activeConfigsBroadcast.end(),
-// activeConfigs.begin(), activeConfigs.end());
-// return true;
-// });
-//
-// processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config);
-//
-// EXPECT_EQ(processor.mMetricsManagers.size(), 1u);
-// sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
-// EXPECT_TRUE(metricsManager->isConfigValid());
-// EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-// sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-// auto& eventActivationMap = metricProducer->mEventActivationMap;
-// auto& eventDeactivationMap = metricProducer->mEventDeactivationMap;
-//
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// // Two activations: one is triggered by battery saver mode (tracker index 0), the other is
-// // triggered by screen on event (tracker index 2).
-// EXPECT_EQ(eventActivationMap.size(), 2u);
-// EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end());
-// EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, 0);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap.size(), 2u);
-// EXPECT_TRUE(eventDeactivationMap.find(3) != eventDeactivationMap.end());
-// EXPECT_TRUE(eventDeactivationMap.find(4) != eventDeactivationMap.end());
-// EXPECT_EQ(eventDeactivationMap[3].size(), 1u);
-// EXPECT_EQ(eventDeactivationMap[4].size(), 1u);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-//
-// std::unique_ptr<LogEvent> event;
-//
-// event = CreateAppCrashEvent(111, bucketStartTimeNs + 5);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + 5);
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 0);
-//
-// // Activated by battery save mode.
-// event = CreateBatterySaverOnEvent(bucketStartTimeNs + 10);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + 10);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 1);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-// EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-//
-// // First processed event.
-// event = CreateAppCrashEvent(222, bucketStartTimeNs + 15);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
-//
-// // Activated by screen on event.
-// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-// bucketStartTimeNs + 20);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + 20);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-//
-// // 2nd processed event.
-// // The activation by screen_on event expires, but the one by battery save mode is still active.
-// event = CreateAppCrashEvent(333, bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-// // No new broadcast since the config should still be active.
-// EXPECT_EQ(broadcastCount, 1);
-//
-// // 3rd processed event.
-// event = CreateAppCrashEvent(444, bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
-//
-// // All activations expired.
-// event = CreateAppCrashEvent(555, bucketStartTimeNs + NS_PER_SEC * 60 * 8);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8);
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// // New broadcast since the config is no longer active.
-// EXPECT_EQ(broadcastCount, 2);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 0);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-//
-// // Re-activate metric via screen on.
-// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-// bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 3);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-// EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-//
-// // 4th processed event.
-// event = CreateAppCrashEvent(666, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
-//
-// // Re-enable battery saver mode activation.
-// event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 3);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-// EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-//
-// // 5th processed event.
-// event = CreateAppCrashEvent(777, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
-//
-// // Cancel battery saver mode and screen on activation.
-// event = CreateScreenBrightnessChangedEvent(64, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60);
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// // New broadcast since the config is no longer active.
-// EXPECT_EQ(broadcastCount, 4);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 0);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-//
-// // Screen-on activation expired.
-// event = CreateAppCrashEvent(888, bucketStartTimeNs + NS_PER_SEC * 60 * 13);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13);
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 4);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 0);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-//
-// event = CreateAppCrashEvent(999, bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
-//
-// // Re-enable battery saver mode activation.
-// event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 5);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-// EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-//
-// // Cancel battery saver mode and screen on activation.
-// event = CreateScreenBrightnessChangedEvent(140, bucketStartTimeNs + NS_PER_SEC * 60 * 16);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 16);
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 6);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 0);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-//
-// ConfigMetricsReportList reports;
-// vector<uint8_t> buffer;
-// processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(1, reports.reports_size());
-// EXPECT_EQ(1, reports.reports(0).metrics_size());
-// EXPECT_EQ(5, reports.reports(0).metrics(0).count_metrics().data_size());
-//
-// StatsLogReport::CountMetricDataWrapper countMetrics;
-// sortMetricDataByDimensionsValue(
-// reports.reports(0).metrics(0).count_metrics(), &countMetrics);
-// EXPECT_EQ(5, countMetrics.data_size());
-//
-// auto data = countMetrics.data(0);
-// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(1);
-// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(2);
-// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// // Partial bucket as metric is deactivated.
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8,
-// data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(3);
-// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-// data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11,
-// data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(4);
-// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(777, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-// data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11,
-// data.bucket_info(0).end_bucket_elapsed_nanos());
-//}
-//
-//TEST(MetricActivationE2eTest, TestCountMetricWithSameDeactivation) {
-// auto config = CreateStatsdConfigWithSameDeactivations();
-//
-// int64_t bucketStartTimeNs = NS_PER_SEC * 10; // 10 secs
-// int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL;
-//
-// int uid = 12345;
-// int64_t cfgId = 98765;
-// ConfigKey cfgKey(uid, cfgId);
-//
-// sp<UidMap> m = new UidMap();
-// sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-// sp<AlarmMonitor> anomalyAlarmMonitor;
-// sp<AlarmMonitor> subscriberAlarmMonitor;
-// vector<int64_t> activeConfigsBroadcast;
-//
-// long timeBase1 = 1;
-// int broadcastCount = 0;
-// StatsLogProcessor processor(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor,
-// bucketStartTimeNs, [](const ConfigKey& key) { return true; },
-// [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
-// const vector<int64_t>& activeConfigs) {
-// broadcastCount++;
-// EXPECT_EQ(broadcastUid, uid);
-// activeConfigsBroadcast.clear();
-// activeConfigsBroadcast.insert(activeConfigsBroadcast.end(),
-// activeConfigs.begin(), activeConfigs.end());
-// return true;
-// });
-//
-// processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config);
-//
-// EXPECT_EQ(processor.mMetricsManagers.size(), 1u);
-// sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
-// EXPECT_TRUE(metricsManager->isConfigValid());
-// EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
-// sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-// auto& eventActivationMap = metricProducer->mEventActivationMap;
-// auto& eventDeactivationMap = metricProducer->mEventDeactivationMap;
-//
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// // Two activations: one is triggered by battery saver mode (tracker index 0), the other is
-// // triggered by screen on event (tracker index 2).
-// EXPECT_EQ(eventActivationMap.size(), 2u);
-// EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end());
-// EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, 0);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap.size(), 1u);
-// EXPECT_TRUE(eventDeactivationMap.find(3) != eventDeactivationMap.end());
-// EXPECT_EQ(eventDeactivationMap[3].size(), 2u);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// EXPECT_EQ(eventDeactivationMap[3][1], eventActivationMap[2]);
-// EXPECT_EQ(broadcastCount, 0);
-//
-// std::unique_ptr<LogEvent> event;
-//
-// // Event that should be ignored.
-// event = CreateAppCrashEvent(111, bucketStartTimeNs + 1);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + 1);
-//
-// // Activate metric via screen on for 2 minutes.
-// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON, bucketStartTimeNs + 10);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + 10);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 1);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-// EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 10);
-//
-// // 1st processed event.
-// event = CreateAppCrashEvent(222, bucketStartTimeNs + 15);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
-//
-// // Enable battery saver mode activation for 5 minutes.
-// event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 + 10);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 + 10);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 1);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 + 10);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 10);
-//
-// // 2nd processed event.
-// event = CreateAppCrashEvent(333, bucketStartTimeNs + NS_PER_SEC * 60 + 40);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 + 40);
-//
-// // Cancel battery saver mode and screen on activation.
-// int64_t firstDeactivation = bucketStartTimeNs + NS_PER_SEC * 61;
-// event = CreateScreenBrightnessChangedEvent(64, firstDeactivation);
-// processor.OnLogEvent(event.get(), firstDeactivation);
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// // New broadcast since the config is no longer active.
-// EXPECT_EQ(broadcastCount, 2);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 0);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-//
-// // Should be ignored
-// event = CreateAppCrashEvent(444, bucketStartTimeNs + NS_PER_SEC * 61 + 80);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 61 + 80);
-//
-// // Re-enable battery saver mode activation.
-// event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 15);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 15);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 3);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-// EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 15);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-//
-// // 3rd processed event.
-// event = CreateAppCrashEvent(555, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 80);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 80);
-//
-// // Cancel battery saver mode activation.
-// int64_t secondDeactivation = bucketStartTimeNs + NS_PER_SEC * 60 * 13;
-// event = CreateScreenBrightnessChangedEvent(140, secondDeactivation);
-// processor.OnLogEvent(event.get(), secondDeactivation);
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// EXPECT_EQ(broadcastCount, 4);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 0);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-//
-// // Should be ignored.
-// event = CreateAppCrashEvent(666, bucketStartTimeNs + NS_PER_SEC * 60 * 13 + 80);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13 + 80);
-//
-// ConfigMetricsReportList reports;
-// vector<uint8_t> buffer;
-// processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(1, reports.reports_size());
-// EXPECT_EQ(1, reports.reports(0).metrics_size());
-// EXPECT_EQ(3, reports.reports(0).metrics(0).count_metrics().data_size());
-//
-// StatsLogReport::CountMetricDataWrapper countMetrics;
-// sortMetricDataByDimensionsValue(
-// reports.reports(0).metrics(0).count_metrics(), &countMetrics);
-// EXPECT_EQ(3, countMetrics.data_size());
-//
-// auto data = countMetrics.data(0);
-// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(firstDeactivation, data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(1);
-// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(firstDeactivation, data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(2);
-// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(555, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// // Partial bucket as metric is deactivated.
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(secondDeactivation, data.bucket_info(0).end_bucket_elapsed_nanos());
-//}
-//
-//TEST(MetricActivationE2eTest, TestCountMetricWithTwoMetricsTwoDeactivations) {
-// auto config = CreateStatsdConfigWithTwoMetricsTwoDeactivations();
-//
-// int64_t bucketStartTimeNs = NS_PER_SEC * 10; // 10 secs
-// int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL;
-//
-// int uid = 12345;
-// int64_t cfgId = 98765;
-// ConfigKey cfgKey(uid, cfgId);
-//
-// sp<UidMap> m = new UidMap();
-// sp<StatsPullerManager> pullerManager = new StatsPullerManager();
-// sp<AlarmMonitor> anomalyAlarmMonitor;
-// sp<AlarmMonitor> subscriberAlarmMonitor;
-// vector<int64_t> activeConfigsBroadcast;
-//
-// long timeBase1 = 1;
-// int broadcastCount = 0;
-// StatsLogProcessor processor(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor,
-// bucketStartTimeNs, [](const ConfigKey& key) { return true; },
-// [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
-// const vector<int64_t>& activeConfigs) {
-// broadcastCount++;
-// EXPECT_EQ(broadcastUid, uid);
-// activeConfigsBroadcast.clear();
-// activeConfigsBroadcast.insert(activeConfigsBroadcast.end(),
-// activeConfigs.begin(), activeConfigs.end());
-// return true;
-// });
-//
-// processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config);
-//
-// EXPECT_EQ(processor.mMetricsManagers.size(), 1u);
-// sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
-// EXPECT_TRUE(metricsManager->isConfigValid());
-// EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 2);
-// sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
-// auto& eventActivationMap = metricProducer->mEventActivationMap;
-// auto& eventDeactivationMap = metricProducer->mEventDeactivationMap;
-// sp<MetricProducer> metricProducer2 = metricsManager->mAllMetricProducers[1];
-// auto& eventActivationMap2 = metricProducer2->mEventActivationMap;
-// auto& eventDeactivationMap2 = metricProducer2->mEventDeactivationMap;
-//
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// EXPECT_FALSE(metricProducer2->mIsActive);
-// // Two activations: one is triggered by battery saver mode (tracker index 0), the other is
-// // triggered by screen on event (tracker index 2).
-// EXPECT_EQ(eventActivationMap.size(), 2u);
-// EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end());
-// EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, 0);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap.size(), 2u);
-// EXPECT_TRUE(eventDeactivationMap.find(3) != eventDeactivationMap.end());
-// EXPECT_TRUE(eventDeactivationMap.find(4) != eventDeactivationMap.end());
-// EXPECT_EQ(eventDeactivationMap[3].size(), 1u);
-// EXPECT_EQ(eventDeactivationMap[4].size(), 1u);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-//
-// EXPECT_EQ(eventActivationMap2.size(), 2u);
-// EXPECT_TRUE(eventActivationMap2.find(0) != eventActivationMap2.end());
-// EXPECT_TRUE(eventActivationMap2.find(2) != eventActivationMap2.end());
-// EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap2[0]->start_ns, 0);
-// EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap2[2]->start_ns, 0);
-// EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap2.size(), 2u);
-// EXPECT_TRUE(eventDeactivationMap2.find(3) != eventDeactivationMap2.end());
-// EXPECT_TRUE(eventDeactivationMap2.find(4) != eventDeactivationMap2.end());
-// EXPECT_EQ(eventDeactivationMap[3].size(), 1u);
-// EXPECT_EQ(eventDeactivationMap[4].size(), 1u);
-// EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
-// EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
-//
-// std::unique_ptr<LogEvent> event;
-//
-// event = CreateAppCrashEvent(111, bucketStartTimeNs + 5);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + 5);
-// event = CreateMoveToForegroundEvent(1111, bucketStartTimeNs + 5);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + 5);
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_FALSE(metricProducer->mIsActive);
-// EXPECT_FALSE(metricProducer2->mIsActive);
-// EXPECT_EQ(broadcastCount, 0);
-//
-// // Activated by battery save mode.
-// event = CreateBatterySaverOnEvent(bucketStartTimeNs + 10);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + 10);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_EQ(broadcastCount, 1);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-// EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-// EXPECT_TRUE(metricProducer2->mIsActive);
-// EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap2[2]->start_ns, 0);
-// EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
-// EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
-//
-// // First processed event.
-// event = CreateAppCrashEvent(222, bucketStartTimeNs + 15);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
-// event = CreateMoveToForegroundEvent(2222, bucketStartTimeNs + 15);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
-//
-// // Activated by screen on event.
-// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-// bucketStartTimeNs + 20);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + 20);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-// EXPECT_TRUE(metricProducer2->mIsActive);
-// EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + 20);
-// EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
-// EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
-//
-// // 2nd processed event.
-// // The activation by screen_on event expires, but the one by battery save mode is still active.
-// event = CreateAppCrashEvent(333, bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
-// event = CreateMoveToForegroundEvent(3333, bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-// EXPECT_TRUE(metricProducer2->mIsActive);
-// EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + 20);
-// EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
-// EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
-// // No new broadcast since the config should still be active.
-// EXPECT_EQ(broadcastCount, 1);
-//
-// // 3rd processed event.
-// event = CreateAppCrashEvent(444, bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
-// event = CreateMoveToForegroundEvent(4444, bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
-//
-// // All activations expired.
-// event = CreateAppCrashEvent(555, bucketStartTimeNs + NS_PER_SEC * 60 * 8);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8);
-// event = CreateMoveToForegroundEvent(5555, bucketStartTimeNs + NS_PER_SEC * 60 * 8);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8);
-// EXPECT_FALSE(metricsManager->isActive());
-// // New broadcast since the config is no longer active.
-// EXPECT_EQ(broadcastCount, 2);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 0);
-// EXPECT_FALSE(metricProducer->mIsActive);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-// EXPECT_FALSE(metricProducer2->mIsActive);
-// EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + 20);
-// EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
-// EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
-//
-// // Re-activate metric via screen on.
-// event = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-// bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_EQ(broadcastCount, 3);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-// EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-// EXPECT_TRUE(metricProducer2->mIsActive);
-// EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10);
-// EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
-// EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
-//
-// // 4th processed event.
-// event = CreateAppCrashEvent(666, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
-// event = CreateMoveToForegroundEvent(6666, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
-//
-// // Re-enable battery saver mode activation.
-// event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_EQ(broadcastCount, 3);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-// EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-// EXPECT_TRUE(metricProducer2->mIsActive);
-// EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-// EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
-// EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
-//
-// // 5th processed event.
-// event = CreateAppCrashEvent(777, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
-// event = CreateMoveToForegroundEvent(7777, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
-//
-// // Cancel battery saver mode and screen on activation.
-// event = CreateScreenBrightnessChangedEvent(64, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60);
-// processor.OnLogEvent(event.get(),bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60);
-// EXPECT_FALSE(metricsManager->isActive());
-// // New broadcast since the config is no longer active.
-// EXPECT_EQ(broadcastCount, 4);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 0);
-// EXPECT_FALSE(metricProducer->mIsActive);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-// EXPECT_FALSE(metricProducer2->mIsActive);
-// EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-// EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
-// EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
-//
-// // Screen-on activation expired.
-// event = CreateAppCrashEvent(888, bucketStartTimeNs + NS_PER_SEC * 60 * 13);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13);
-// event = CreateMoveToForegroundEvent(8888, bucketStartTimeNs + NS_PER_SEC * 60 * 13);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13);
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_EQ(broadcastCount, 4);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 0);
-// EXPECT_FALSE(metricProducer->mIsActive);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-// EXPECT_FALSE(metricProducer2->mIsActive);
-// EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
-// EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
-// EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
-//
-// event = CreateAppCrashEvent(999, bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
-// event = CreateMoveToForegroundEvent(9999, bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
-//
-// // Re-enable battery saver mode activation.
-// event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-// processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-// EXPECT_TRUE(metricsManager->isActive());
-// EXPECT_EQ(broadcastCount, 5);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 1);
-// EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
-// EXPECT_TRUE(metricProducer->mIsActive);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-// EXPECT_TRUE(metricProducer2->mIsActive);
-// EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive);
-// EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-// EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
-// EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
-//
-// // Cancel battery saver mode and screen on activation.
-// event = CreateScreenBrightnessChangedEvent(140, bucketStartTimeNs + NS_PER_SEC * 60 * 16);
-// processor.OnLogEvent(event.get(),bucketStartTimeNs + NS_PER_SEC * 60 * 16);
-// EXPECT_FALSE(metricsManager->isActive());
-// EXPECT_EQ(broadcastCount, 6);
-// EXPECT_EQ(activeConfigsBroadcast.size(), 0);
-// EXPECT_FALSE(metricProducer->mIsActive);
-// EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-// EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
-// EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
-// EXPECT_FALSE(metricProducer2->mIsActive);
-// EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
-// EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
-// EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
-// EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
-// EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
-// EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
-// EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
-//
-// ConfigMetricsReportList reports;
-// vector<uint8_t> buffer;
-// processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(1, reports.reports_size());
-// EXPECT_EQ(2, reports.reports(0).metrics_size());
-// EXPECT_EQ(5, reports.reports(0).metrics(0).count_metrics().data_size());
-// EXPECT_EQ(5, reports.reports(0).metrics(1).count_metrics().data_size());
-//
-// StatsLogReport::CountMetricDataWrapper countMetrics;
-//
-// sortMetricDataByDimensionsValue(
-// reports.reports(0).metrics(0).count_metrics(), &countMetrics);
-// EXPECT_EQ(5, countMetrics.data_size());
-//
-// auto data = countMetrics.data(0);
-// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(1);
-// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(2);
-// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// // Partial bucket as metric is deactivated.
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8,
-// data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(3);
-// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-// data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11,
-// data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(4);
-// EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(777, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-// data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11,
-// data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-//
-// countMetrics.clear_data();
-// sortMetricDataByDimensionsValue(
-// reports.reports(0).metrics(1).count_metrics(), &countMetrics);
-// EXPECT_EQ(5, countMetrics.data_size());
-//
-// data = countMetrics.data(0);
-// EXPECT_EQ(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(2222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(1);
-// EXPECT_EQ(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(3333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(2);
-// EXPECT_EQ(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(4444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// // Partial bucket as metric is deactivated.
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8,
-// data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(3);
-// EXPECT_EQ(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(6666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-// data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11,
-// data.bucket_info(0).end_bucket_elapsed_nanos());
-//
-// data = countMetrics.data(4);
-// EXPECT_EQ(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* uid field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_EQ(7777, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
-// EXPECT_EQ(1, data.bucket_info_size());
-// EXPECT_EQ(1, data.bucket_info(0).count());
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-// data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11,
-// data.bucket_info(0).end_bucket_elapsed_nanos());
-//}
+TEST(MetricActivationE2eTest, TestCountMetric) {
+ auto config = CreateStatsdConfig();
+
+ int64_t bucketStartTimeNs = NS_PER_SEC * 10; // 10 secs
+ int64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL;
+
+ int uid = 12345;
+ int64_t cfgId = 98765;
+ ConfigKey cfgKey(uid, cfgId);
+
+ sp<UidMap> m = new UidMap();
+ sp<StatsPullerManager> pullerManager = new StatsPullerManager();
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> subscriberAlarmMonitor;
+ vector<int64_t> activeConfigsBroadcast;
+
+ long timeBase1 = 1;
+ int broadcastCount = 0;
+ StatsLogProcessor processor(
+ m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, bucketStartTimeNs,
+ [](const ConfigKey& key) { return true; },
+ [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
+ const vector<int64_t>& activeConfigs) {
+ broadcastCount++;
+ EXPECT_EQ(broadcastUid, uid);
+ activeConfigsBroadcast.clear();
+ activeConfigsBroadcast.insert(activeConfigsBroadcast.end(), activeConfigs.begin(),
+ activeConfigs.end());
+ return true;
+ });
+
+ processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config);
+
+ EXPECT_EQ(processor.mMetricsManagers.size(), 1u);
+ sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
+ EXPECT_TRUE(metricsManager->isConfigValid());
+ EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+ auto& eventActivationMap = metricProducer->mEventActivationMap;
+
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ // Two activations: one is triggered by battery saver mode (tracker index 0), the other is
+ // triggered by screen on event (tracker index 2).
+ EXPECT_EQ(eventActivationMap.size(), 2u);
+ EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end());
+ EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, 0);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+
+ std::unique_ptr<LogEvent> event;
+
+ event = CreateAppCrashEvent(bucketStartTimeNs + 5, 111);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + 5);
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 0);
+
+ // Activated by battery save mode.
+ event = CreateBatterySaverOnEvent(bucketStartTimeNs + 10);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + 10);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 1);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+
+ // First processed event.
+ event = CreateAppCrashEvent(bucketStartTimeNs + 15, 222);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
+
+ // Activated by screen on event.
+ event = CreateScreenStateChangedEvent(bucketStartTimeNs + 20, android::view::DISPLAY_STATE_ON);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + 20);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+
+ // 2nd processed event.
+ // The activation by screen_on event expires, but the one by battery save mode is still active.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25, 333);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ // No new broadcast since the config should still be active.
+ EXPECT_EQ(broadcastCount, 1);
+
+ // 3rd processed event.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25, 444);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
+
+ // All activations expired.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 8, 555);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8);
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ // New broadcast since the config is no longer active.
+ EXPECT_EQ(broadcastCount, 2);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+
+ // Re-activate metric via screen on.
+ event = CreateScreenStateChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10,
+ android::view::DISPLAY_STATE_ON);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 3);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+
+ // 4th processed event.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1, 666);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true,
+ ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ EXPECT_EQ(4, reports.reports(0).metrics(0).count_metrics().data_size());
+
+ StatsLogReport::CountMetricDataWrapper countMetrics;
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
+ EXPECT_EQ(4, countMetrics.data_size());
+
+ auto data = countMetrics.data(0);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(1);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(2);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ // Partial bucket as metric is deactivated.
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8,
+ data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(3);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+ data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+}
+
+TEST(MetricActivationE2eTest, TestCountMetricWithOneDeactivation) {
+ auto config = CreateStatsdConfigWithOneDeactivation();
+
+ int64_t bucketStartTimeNs = NS_PER_SEC * 10; // 10 secs
+ int64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL;
+
+ int uid = 12345;
+ int64_t cfgId = 98765;
+ ConfigKey cfgKey(uid, cfgId);
+
+ sp<UidMap> m = new UidMap();
+ sp<StatsPullerManager> pullerManager = new StatsPullerManager();
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> subscriberAlarmMonitor;
+ vector<int64_t> activeConfigsBroadcast;
+
+ long timeBase1 = 1;
+ int broadcastCount = 0;
+ StatsLogProcessor processor(
+ m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, bucketStartTimeNs,
+ [](const ConfigKey& key) { return true; },
+ [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
+ const vector<int64_t>& activeConfigs) {
+ broadcastCount++;
+ EXPECT_EQ(broadcastUid, uid);
+ activeConfigsBroadcast.clear();
+ activeConfigsBroadcast.insert(activeConfigsBroadcast.end(), activeConfigs.begin(),
+ activeConfigs.end());
+ return true;
+ });
+
+ processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config);
+
+ EXPECT_EQ(processor.mMetricsManagers.size(), 1u);
+ sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
+ EXPECT_TRUE(metricsManager->isConfigValid());
+ EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+ auto& eventActivationMap = metricProducer->mEventActivationMap;
+ auto& eventDeactivationMap = metricProducer->mEventDeactivationMap;
+
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ // Two activations: one is triggered by battery saver mode (tracker index 0), the other is
+ // triggered by screen on event (tracker index 2).
+ EXPECT_EQ(eventActivationMap.size(), 2u);
+ EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end());
+ EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, 0);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap.size(), 1u);
+ EXPECT_TRUE(eventDeactivationMap.find(3) != eventDeactivationMap.end());
+ EXPECT_EQ(eventDeactivationMap[3].size(), 1u);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+
+ std::unique_ptr<LogEvent> event;
+
+ event = CreateAppCrashEvent(bucketStartTimeNs + 5, 111);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + 5);
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 0);
+
+ // Activated by battery save mode.
+ event = CreateBatterySaverOnEvent(bucketStartTimeNs + 10);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + 10);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 1);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+
+ // First processed event.
+ event = CreateAppCrashEvent(bucketStartTimeNs + 15, 222);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
+
+ // Activated by screen on event.
+ event = CreateScreenStateChangedEvent(bucketStartTimeNs + 20, android::view::DISPLAY_STATE_ON);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + 20);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+
+ // 2nd processed event.
+ // The activation by screen_on event expires, but the one by battery save mode is still active.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25, 333);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ // No new broadcast since the config should still be active.
+ EXPECT_EQ(broadcastCount, 1);
+
+ // 3rd processed event.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25, 444);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
+
+ // All activations expired.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 8, 555);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8);
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ // New broadcast since the config is no longer active.
+ EXPECT_EQ(broadcastCount, 2);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+
+ // Re-activate metric via screen on.
+ event = CreateScreenStateChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10,
+ android::view::DISPLAY_STATE_ON);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 3);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+
+ // 4th processed event.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1, 666);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
+
+ // Re-enable battery saver mode activation.
+ event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 3);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+
+ // 5th processed event.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40, 777);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
+
+ // Cancel battery saver mode activation.
+ event = CreateScreenBrightnessChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60, 64);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 3);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+
+ // Screen-on activation expired.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 13, 888);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13);
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ // New broadcast since the config is no longer active.
+ EXPECT_EQ(broadcastCount, 4);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1, 999);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
+
+ // Re-enable battery saver mode activation.
+ event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 5);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+
+ // Cancel battery saver mode activation.
+ event = CreateScreenBrightnessChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 16, 140);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 16);
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 6);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true,
+ ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ EXPECT_EQ(5, reports.reports(0).metrics(0).count_metrics().data_size());
+
+ StatsLogReport::CountMetricDataWrapper countMetrics;
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
+ EXPECT_EQ(5, countMetrics.data_size());
+
+ auto data = countMetrics.data(0);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(1);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(2);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ // Partial bucket as metric is deactivated.
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8,
+ data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(3);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+ data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 13,
+ data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(4);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(777, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+ data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 13,
+ data.bucket_info(0).end_bucket_elapsed_nanos());
+}
+
+TEST(MetricActivationE2eTest, TestCountMetricWithTwoDeactivations) {
+ auto config = CreateStatsdConfigWithTwoDeactivations();
+
+ int64_t bucketStartTimeNs = NS_PER_SEC * 10; // 10 secs
+ int64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL;
+
+ int uid = 12345;
+ int64_t cfgId = 98765;
+ ConfigKey cfgKey(uid, cfgId);
+
+ sp<UidMap> m = new UidMap();
+ sp<StatsPullerManager> pullerManager = new StatsPullerManager();
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> subscriberAlarmMonitor;
+ vector<int64_t> activeConfigsBroadcast;
+
+ long timeBase1 = 1;
+ int broadcastCount = 0;
+ StatsLogProcessor processor(
+ m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, bucketStartTimeNs,
+ [](const ConfigKey& key) { return true; },
+ [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
+ const vector<int64_t>& activeConfigs) {
+ broadcastCount++;
+ EXPECT_EQ(broadcastUid, uid);
+ activeConfigsBroadcast.clear();
+ activeConfigsBroadcast.insert(activeConfigsBroadcast.end(), activeConfigs.begin(),
+ activeConfigs.end());
+ return true;
+ });
+
+ processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config);
+
+ EXPECT_EQ(processor.mMetricsManagers.size(), 1u);
+ sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
+ EXPECT_TRUE(metricsManager->isConfigValid());
+ EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+ auto& eventActivationMap = metricProducer->mEventActivationMap;
+ auto& eventDeactivationMap = metricProducer->mEventDeactivationMap;
+
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ // Two activations: one is triggered by battery saver mode (tracker index 0), the other is
+ // triggered by screen on event (tracker index 2).
+ EXPECT_EQ(eventActivationMap.size(), 2u);
+ EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end());
+ EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, 0);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap.size(), 2u);
+ EXPECT_TRUE(eventDeactivationMap.find(3) != eventDeactivationMap.end());
+ EXPECT_TRUE(eventDeactivationMap.find(4) != eventDeactivationMap.end());
+ EXPECT_EQ(eventDeactivationMap[3].size(), 1u);
+ EXPECT_EQ(eventDeactivationMap[4].size(), 1u);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+
+ std::unique_ptr<LogEvent> event;
+
+ event = CreateAppCrashEvent(bucketStartTimeNs + 5, 111);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + 5);
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 0);
+
+ // Activated by battery save mode.
+ event = CreateBatterySaverOnEvent(bucketStartTimeNs + 10);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + 10);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 1);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+
+ // First processed event.
+ event = CreateAppCrashEvent(bucketStartTimeNs + 15, 222);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
+
+ // Activated by screen on event.
+ event = CreateScreenStateChangedEvent(bucketStartTimeNs + 20, android::view::DISPLAY_STATE_ON);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + 20);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+
+ // 2nd processed event.
+ // The activation by screen_on event expires, but the one by battery save mode is still active.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25, 333);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+ // No new broadcast since the config should still be active.
+ EXPECT_EQ(broadcastCount, 1);
+
+ // 3rd processed event.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25, 444);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
+
+ // All activations expired.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 8, 555);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8);
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ // New broadcast since the config is no longer active.
+ EXPECT_EQ(broadcastCount, 2);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+
+ // Re-activate metric via screen on.
+ event = CreateScreenStateChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10,
+ android::view::DISPLAY_STATE_ON);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 3);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+
+ // 4th processed event.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1, 666);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
+
+ // Re-enable battery saver mode activation.
+ event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 3);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+
+ // 5th processed event.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40, 777);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
+
+ // Cancel battery saver mode and screen on activation.
+ event = CreateScreenBrightnessChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60, 64);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60);
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ // New broadcast since the config is no longer active.
+ EXPECT_EQ(broadcastCount, 4);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+
+ // Screen-on activation expired.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 13, 888);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13);
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 4);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1, 999);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
+
+ // Re-enable battery saver mode activation.
+ event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 5);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+
+ // Cancel battery saver mode and screen on activation.
+ event = CreateScreenBrightnessChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 16, 140);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 16);
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 6);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true,
+ ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ EXPECT_EQ(5, reports.reports(0).metrics(0).count_metrics().data_size());
+
+ StatsLogReport::CountMetricDataWrapper countMetrics;
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
+ EXPECT_EQ(5, countMetrics.data_size());
+
+ auto data = countMetrics.data(0);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(1);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(2);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ // Partial bucket as metric is deactivated.
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8,
+ data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(3);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+ data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11,
+ data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(4);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(777, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+ data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11,
+ data.bucket_info(0).end_bucket_elapsed_nanos());
+}
+
+TEST(MetricActivationE2eTest, TestCountMetricWithSameDeactivation) {
+ auto config = CreateStatsdConfigWithSameDeactivations();
+
+ int64_t bucketStartTimeNs = NS_PER_SEC * 10; // 10 secs
+ int64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL;
+
+ int uid = 12345;
+ int64_t cfgId = 98765;
+ ConfigKey cfgKey(uid, cfgId);
+
+ sp<UidMap> m = new UidMap();
+ sp<StatsPullerManager> pullerManager = new StatsPullerManager();
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> subscriberAlarmMonitor;
+ vector<int64_t> activeConfigsBroadcast;
+
+ long timeBase1 = 1;
+ int broadcastCount = 0;
+ StatsLogProcessor processor(
+ m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, bucketStartTimeNs,
+ [](const ConfigKey& key) { return true; },
+ [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
+ const vector<int64_t>& activeConfigs) {
+ broadcastCount++;
+ EXPECT_EQ(broadcastUid, uid);
+ activeConfigsBroadcast.clear();
+ activeConfigsBroadcast.insert(activeConfigsBroadcast.end(), activeConfigs.begin(),
+ activeConfigs.end());
+ return true;
+ });
+
+ processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config);
+
+ EXPECT_EQ(processor.mMetricsManagers.size(), 1u);
+ sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
+ EXPECT_TRUE(metricsManager->isConfigValid());
+ EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 1);
+ sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+ auto& eventActivationMap = metricProducer->mEventActivationMap;
+ auto& eventDeactivationMap = metricProducer->mEventDeactivationMap;
+
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ // Two activations: one is triggered by battery saver mode (tracker index 0), the other is
+ // triggered by screen on event (tracker index 2).
+ EXPECT_EQ(eventActivationMap.size(), 2u);
+ EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end());
+ EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, 0);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap.size(), 1u);
+ EXPECT_TRUE(eventDeactivationMap.find(3) != eventDeactivationMap.end());
+ EXPECT_EQ(eventDeactivationMap[3].size(), 2u);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ EXPECT_EQ(eventDeactivationMap[3][1], eventActivationMap[2]);
+ EXPECT_EQ(broadcastCount, 0);
+
+ std::unique_ptr<LogEvent> event;
+
+ // Event that should be ignored.
+ event = CreateAppCrashEvent(bucketStartTimeNs + 1, 111);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + 1);
+
+ // Activate metric via screen on for 2 minutes.
+ event = CreateScreenStateChangedEvent(bucketStartTimeNs + 10, android::view::DISPLAY_STATE_ON);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + 10);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 1);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 10);
+
+ // 1st processed event.
+ event = CreateAppCrashEvent(bucketStartTimeNs + 15, 222);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
+
+ // Enable battery saver mode activation for 5 minutes.
+ event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 + 10);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 + 10);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 1);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 + 10);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 10);
+
+ // 2nd processed event.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 + 40, 333);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 + 40);
+
+ // Cancel battery saver mode and screen on activation.
+ int64_t firstDeactivation = bucketStartTimeNs + NS_PER_SEC * 61;
+ event = CreateScreenBrightnessChangedEvent(firstDeactivation, 64);
+ processor.OnLogEvent(event.get(), firstDeactivation);
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ // New broadcast since the config is no longer active.
+ EXPECT_EQ(broadcastCount, 2);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+
+ // Should be ignored
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 61 + 80, 444);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 61 + 80);
+
+ // Re-enable battery saver mode activation.
+ event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 15);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 15);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 3);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 15);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+
+ // 3rd processed event.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 80, 555);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 80);
+
+ // Cancel battery saver mode activation.
+ int64_t secondDeactivation = bucketStartTimeNs + NS_PER_SEC * 60 * 13;
+ event = CreateScreenBrightnessChangedEvent(secondDeactivation, 140);
+ processor.OnLogEvent(event.get(), secondDeactivation);
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ EXPECT_EQ(broadcastCount, 4);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+
+ // Should be ignored.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 13 + 80, 666);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13 + 80);
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true,
+ ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ EXPECT_EQ(3, reports.reports(0).metrics(0).count_metrics().data_size());
+
+ StatsLogReport::CountMetricDataWrapper countMetrics;
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
+ EXPECT_EQ(3, countMetrics.data_size());
+
+ auto data = countMetrics.data(0);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(firstDeactivation, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(1);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(firstDeactivation, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(2);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(555, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ // Partial bucket as metric is deactivated.
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+ data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(secondDeactivation, data.bucket_info(0).end_bucket_elapsed_nanos());
+}
+
+TEST(MetricActivationE2eTest, TestCountMetricWithTwoMetricsTwoDeactivations) {
+ auto config = CreateStatsdConfigWithTwoMetricsTwoDeactivations();
+
+ int64_t bucketStartTimeNs = NS_PER_SEC * 10; // 10 secs
+ int64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000LL * 1000LL;
+
+ int uid = 12345;
+ int64_t cfgId = 98765;
+ ConfigKey cfgKey(uid, cfgId);
+
+ sp<UidMap> m = new UidMap();
+ sp<StatsPullerManager> pullerManager = new StatsPullerManager();
+ sp<AlarmMonitor> anomalyAlarmMonitor;
+ sp<AlarmMonitor> subscriberAlarmMonitor;
+ vector<int64_t> activeConfigsBroadcast;
+
+ long timeBase1 = 1;
+ int broadcastCount = 0;
+ StatsLogProcessor processor(
+ m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, bucketStartTimeNs,
+ [](const ConfigKey& key) { return true; },
+ [&uid, &broadcastCount, &activeConfigsBroadcast](const int& broadcastUid,
+ const vector<int64_t>& activeConfigs) {
+ broadcastCount++;
+ EXPECT_EQ(broadcastUid, uid);
+ activeConfigsBroadcast.clear();
+ activeConfigsBroadcast.insert(activeConfigsBroadcast.end(), activeConfigs.begin(),
+ activeConfigs.end());
+ return true;
+ });
+
+ processor.OnConfigUpdated(bucketStartTimeNs, cfgKey, config);
+
+ EXPECT_EQ(processor.mMetricsManagers.size(), 1u);
+ sp<MetricsManager> metricsManager = processor.mMetricsManagers.begin()->second;
+ EXPECT_TRUE(metricsManager->isConfigValid());
+ EXPECT_EQ(metricsManager->mAllMetricProducers.size(), 2);
+ sp<MetricProducer> metricProducer = metricsManager->mAllMetricProducers[0];
+ auto& eventActivationMap = metricProducer->mEventActivationMap;
+ auto& eventDeactivationMap = metricProducer->mEventDeactivationMap;
+ sp<MetricProducer> metricProducer2 = metricsManager->mAllMetricProducers[1];
+ auto& eventActivationMap2 = metricProducer2->mEventActivationMap;
+ auto& eventDeactivationMap2 = metricProducer2->mEventDeactivationMap;
+
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ EXPECT_FALSE(metricProducer2->mIsActive);
+ // Two activations: one is triggered by battery saver mode (tracker index 0), the other is
+ // triggered by screen on event (tracker index 2).
+ EXPECT_EQ(eventActivationMap.size(), 2u);
+ EXPECT_TRUE(eventActivationMap.find(0) != eventActivationMap.end());
+ EXPECT_TRUE(eventActivationMap.find(2) != eventActivationMap.end());
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, 0);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap.size(), 2u);
+ EXPECT_TRUE(eventDeactivationMap.find(3) != eventDeactivationMap.end());
+ EXPECT_TRUE(eventDeactivationMap.find(4) != eventDeactivationMap.end());
+ EXPECT_EQ(eventDeactivationMap[3].size(), 1u);
+ EXPECT_EQ(eventDeactivationMap[4].size(), 1u);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+
+ EXPECT_EQ(eventActivationMap2.size(), 2u);
+ EXPECT_TRUE(eventActivationMap2.find(0) != eventActivationMap2.end());
+ EXPECT_TRUE(eventActivationMap2.find(2) != eventActivationMap2.end());
+ EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap2[0]->start_ns, 0);
+ EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap2[2]->start_ns, 0);
+ EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap2.size(), 2u);
+ EXPECT_TRUE(eventDeactivationMap2.find(3) != eventDeactivationMap2.end());
+ EXPECT_TRUE(eventDeactivationMap2.find(4) != eventDeactivationMap2.end());
+ EXPECT_EQ(eventDeactivationMap[3].size(), 1u);
+ EXPECT_EQ(eventDeactivationMap[4].size(), 1u);
+ EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
+ EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
+
+ std::unique_ptr<LogEvent> event;
+
+ event = CreateAppCrashEvent(bucketStartTimeNs + 5, 111);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + 5);
+ event = CreateMoveToForegroundEvent(bucketStartTimeNs + 5, 1111);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + 5);
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_FALSE(metricProducer->mIsActive);
+ EXPECT_FALSE(metricProducer2->mIsActive);
+ EXPECT_EQ(broadcastCount, 0);
+
+ // Activated by battery save mode.
+ event = CreateBatterySaverOnEvent(bucketStartTimeNs + 10);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + 10);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_EQ(broadcastCount, 1);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, 0);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+ EXPECT_TRUE(metricProducer2->mIsActive);
+ EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap2[2]->start_ns, 0);
+ EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
+ EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
+
+ // First processed event.
+ event = CreateAppCrashEvent(bucketStartTimeNs + 15, 222);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
+ event = CreateMoveToForegroundEvent(bucketStartTimeNs + 15, 2222);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + 15);
+
+ // Activated by screen on event.
+ event = CreateScreenStateChangedEvent(bucketStartTimeNs + 20, android::view::DISPLAY_STATE_ON);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + 20);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+ EXPECT_TRUE(metricProducer2->mIsActive);
+ EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
+ EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
+
+ // 2nd processed event.
+ // The activation by screen_on event expires, but the one by battery save mode is still active.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25, 333);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
+ event = CreateMoveToForegroundEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25, 3333);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 2 + 25);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+ EXPECT_TRUE(metricProducer2->mIsActive);
+ EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
+ EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
+ // No new broadcast since the config should still be active.
+ EXPECT_EQ(broadcastCount, 1);
+
+ // 3rd processed event.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25, 444);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
+ event = CreateMoveToForegroundEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25, 4444);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 5 + 25);
+
+ // All activations expired.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 8, 555);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8);
+ event = CreateMoveToForegroundEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 8, 5555);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 8);
+ EXPECT_FALSE(metricsManager->isActive());
+ // New broadcast since the config is no longer active.
+ EXPECT_EQ(broadcastCount, 2);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+ EXPECT_FALSE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+ EXPECT_FALSE(metricProducer2->mIsActive);
+ EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + 20);
+ EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
+ EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
+
+ // Re-activate metric via screen on.
+ event = CreateScreenStateChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10,
+ android::view::DISPLAY_STATE_ON);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_EQ(broadcastCount, 3);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+ EXPECT_TRUE(metricProducer2->mIsActive);
+ EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + 10);
+ EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
+ EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
+
+ // 4th processed event.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1, 666);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
+ event = CreateMoveToForegroundEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1, 6666);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 1);
+
+ // Re-enable battery saver mode activation.
+ event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_EQ(broadcastCount, 3);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+ EXPECT_TRUE(metricProducer2->mIsActive);
+ EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
+ EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
+
+ // 5th processed event.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40, 777);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
+ event = CreateMoveToForegroundEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40, 7777);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 40);
+
+ // Cancel battery saver mode and screen on activation.
+ event = CreateScreenBrightnessChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60, 64);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 60);
+ EXPECT_FALSE(metricsManager->isActive());
+ // New broadcast since the config is no longer active.
+ EXPECT_EQ(broadcastCount, 4);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+ EXPECT_FALSE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+ EXPECT_FALSE(metricProducer2->mIsActive);
+ EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
+ EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
+
+ // Screen-on activation expired.
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 13, 888);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13);
+ event = CreateMoveToForegroundEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 13, 8888);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 13);
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_EQ(broadcastCount, 4);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+ EXPECT_FALSE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+ EXPECT_FALSE(metricProducer2->mIsActive);
+ EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 11 + 15);
+ EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
+ EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
+
+ event = CreateAppCrashEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1, 999);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
+ event = CreateMoveToForegroundEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1, 9999);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 14 + 1);
+
+ // Re-enable battery saver mode activation.
+ event = CreateBatterySaverOnEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+ EXPECT_TRUE(metricsManager->isActive());
+ EXPECT_EQ(broadcastCount, 5);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 1);
+ EXPECT_EQ(activeConfigsBroadcast[0], cfgId);
+ EXPECT_TRUE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+ EXPECT_TRUE(metricProducer2->mIsActive);
+ EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kActive);
+ EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+ EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
+ EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
+
+ // Cancel battery saver mode and screen on activation.
+ event = CreateScreenBrightnessChangedEvent(bucketStartTimeNs + NS_PER_SEC * 60 * 16, 140);
+ processor.OnLogEvent(event.get(), bucketStartTimeNs + NS_PER_SEC * 60 * 16);
+ EXPECT_FALSE(metricsManager->isActive());
+ EXPECT_EQ(broadcastCount, 6);
+ EXPECT_EQ(activeConfigsBroadcast.size(), 0);
+ EXPECT_FALSE(metricProducer->mIsActive);
+ EXPECT_EQ(eventActivationMap[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+ EXPECT_EQ(eventActivationMap[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap[3][0], eventActivationMap[0]);
+ EXPECT_EQ(eventDeactivationMap[4][0], eventActivationMap[2]);
+ EXPECT_FALSE(metricProducer2->mIsActive);
+ EXPECT_EQ(eventActivationMap2[0]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap2[0]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 15);
+ EXPECT_EQ(eventActivationMap2[0]->ttl_ns, 60 * 6 * NS_PER_SEC);
+ EXPECT_EQ(eventActivationMap2[2]->state, ActivationState::kNotActive);
+ EXPECT_EQ(eventActivationMap2[2]->start_ns, bucketStartTimeNs + NS_PER_SEC * 60 * 10 + 10);
+ EXPECT_EQ(eventActivationMap2[2]->ttl_ns, 60 * 2 * NS_PER_SEC);
+ EXPECT_EQ(eventDeactivationMap2[3][0], eventActivationMap2[0]);
+ EXPECT_EQ(eventDeactivationMap2[4][0], eventActivationMap2[2]);
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor.onDumpReport(cfgKey, bucketStartTimeNs + NS_PER_SEC * 60 * 15 + 1, false, true,
+ ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(2, reports.reports(0).metrics_size());
+ EXPECT_EQ(5, reports.reports(0).metrics(0).count_metrics().data_size());
+ EXPECT_EQ(5, reports.reports(0).metrics(1).count_metrics().data_size());
+
+ StatsLogReport::CountMetricDataWrapper countMetrics;
+
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
+ EXPECT_EQ(5, countMetrics.data_size());
+
+ auto data = countMetrics.data(0);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(1);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(2);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ // Partial bucket as metric is deactivated.
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8,
+ data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(3);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+ data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11,
+ data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(4);
+ EXPECT_EQ(android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(777, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+ data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11,
+ data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ countMetrics.clear_data();
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(1).count_metrics(), &countMetrics);
+ EXPECT_EQ(5, countMetrics.data_size());
+
+ data = countMetrics.data(0);
+ EXPECT_EQ(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(2222, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(1);
+ EXPECT_EQ(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(3333, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(2);
+ EXPECT_EQ(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(4444, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ // Partial bucket as metric is deactivated.
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 8,
+ data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(3);
+ EXPECT_EQ(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(6666, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+ data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11,
+ data.bucket_info(0).end_bucket_elapsed_nanos());
+
+ data = countMetrics.data(4);
+ EXPECT_EQ(android::util::ACTIVITY_FOREGROUND_STATE_CHANGED, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* uid field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_EQ(7777, data.dimensions_in_what().value_tuple().dimensions_value(0).value_int());
+ EXPECT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+ data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(bucketStartTimeNs + NS_PER_SEC * 60 * 11,
+ data.bucket_info(0).end_bucket_elapsed_nanos());
+}
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
diff --git a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
index 7d93fcc..e8fb523 100644
--- a/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/MetricConditionLink_e2e_test.cpp
@@ -97,250 +97,247 @@
}
} // namespace
-// TODO(b/149590301): Update these tests to use new socket schema.
-//// If we want to test multiple dump data, we must do it in separate tests, because in the e2e tests,
-//// we should use the real API which will clear the data after dump data is called.
-//TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks1) {
-// auto config = CreateStatsdConfig();
-// uint64_t bucketStartTimeNs = 10000000000;
-// uint64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
-//
-// ConfigKey cfgKey;
-// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-//
-// int appUid = 123;
-// auto crashEvent1 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 1);
-// auto crashEvent2 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 201);
-// auto crashEvent3= CreateAppCrashEvent(appUid, bucketStartTimeNs + 2 * bucketSizeNs - 101);
-//
-// auto crashEvent4 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 51);
-// auto crashEvent5 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 299);
-// auto crashEvent6 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 2001);
-//
-// auto crashEvent7 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 16);
-// auto crashEvent8 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 249);
-//
-// auto crashEvent9 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 351);
-// auto crashEvent10 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 2 * bucketSizeNs - 2);
-//
-// auto screenTurnedOnEvent =
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-// bucketStartTimeNs + 2);
-// auto screenTurnedOffEvent =
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
-// bucketStartTimeNs + 200);
-// auto screenTurnedOnEvent2 =
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-// bucketStartTimeNs + 2 * bucketSizeNs - 100);
-//
-// std::vector<AttributionNodeInternal> attributions = {
-// CreateAttribution(appUid, "App1"), CreateAttribution(appUid + 1, "GMSCoreModule1")};
-// auto syncOnEvent1 =
-// CreateSyncStartEvent(attributions, "ReadEmail", bucketStartTimeNs + 50);
-// auto syncOffEvent1 =
-// CreateSyncEndEvent(attributions, "ReadEmail", bucketStartTimeNs + bucketSizeNs + 300);
-// auto syncOnEvent2 =
-// CreateSyncStartEvent(attributions, "ReadDoc", bucketStartTimeNs + bucketSizeNs + 2000);
-//
-// auto moveToBackgroundEvent1 =
-// CreateMoveToBackgroundEvent(appUid, bucketStartTimeNs + 15);
-// auto moveToForegroundEvent1 =
-// CreateMoveToForegroundEvent(appUid, bucketStartTimeNs + bucketSizeNs + 250);
-//
-// auto moveToBackgroundEvent2 =
-// CreateMoveToBackgroundEvent(appUid, bucketStartTimeNs + bucketSizeNs + 350);
-// auto moveToForegroundEvent2 =
-// CreateMoveToForegroundEvent(appUid, bucketStartTimeNs + 2 * bucketSizeNs - 1);
-//
-// /*
-// bucket #1 bucket #2
-//
-//
-// | | | | | | | | | | (crashEvents)
-// |-------------------------------------|-----------------------------------|---------
-//
-// | | (MoveToBkground)
-//
-// | | (MoveToForeground)
-//
-// | | (SyncIsOn)
-// | (SyncIsOff)
-// | | (ScreenIsOn)
-// | (ScreenIsOff)
-// */
-// std::vector<std::unique_ptr<LogEvent>> events;
-// events.push_back(std::move(crashEvent1));
-// events.push_back(std::move(crashEvent2));
-// events.push_back(std::move(crashEvent3));
-// events.push_back(std::move(crashEvent4));
-// events.push_back(std::move(crashEvent5));
-// events.push_back(std::move(crashEvent6));
-// events.push_back(std::move(crashEvent7));
-// events.push_back(std::move(crashEvent8));
-// events.push_back(std::move(crashEvent9));
-// events.push_back(std::move(crashEvent10));
-// events.push_back(std::move(screenTurnedOnEvent));
-// events.push_back(std::move(screenTurnedOffEvent));
-// events.push_back(std::move(screenTurnedOnEvent2));
-// events.push_back(std::move(syncOnEvent1));
-// events.push_back(std::move(syncOffEvent1));
-// events.push_back(std::move(syncOnEvent2));
-// events.push_back(std::move(moveToBackgroundEvent1));
-// events.push_back(std::move(moveToForegroundEvent1));
-// events.push_back(std::move(moveToBackgroundEvent2));
-// events.push_back(std::move(moveToForegroundEvent2));
-//
-// sortLogEventsByTimestamp(&events);
-//
-// for (const auto& event : events) {
-// processor->OnLogEvent(event.get());
-// }
-// ConfigMetricsReportList reports;
-// vector<uint8_t> buffer;
-// processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(reports.reports_size(), 1);
-// EXPECT_EQ(reports.reports(0).metrics_size(), 1);
-// EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data_size(), 1);
-// EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info_size(), 1);
-// EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info(0).count(), 1);
-// auto data = reports.reports(0).metrics(0).count_metrics().data(0);
-// // Validate dimension value.
-// EXPECT_EQ(data.dimensions_in_what().field(), android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
-// EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
-// // Uid field.
-// EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
-// EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), appUid);
-//}
-//
-//TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks2) {
-// auto config = CreateStatsdConfig();
-// uint64_t bucketStartTimeNs = 10000000000;
-// uint64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
-//
-// ConfigKey cfgKey;
-// auto processor = CreateStatsLogProcessor(
-// bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-//
-// int appUid = 123;
-// auto crashEvent1 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 1);
-// auto crashEvent2 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 201);
-// auto crashEvent3 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 2 * bucketSizeNs - 101);
-//
-// auto crashEvent4 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 51);
-// auto crashEvent5 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 299);
-// auto crashEvent6 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 2001);
-//
-// auto crashEvent7 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 16);
-// auto crashEvent8 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 249);
-//
-// auto crashEvent9 = CreateAppCrashEvent(appUid, bucketStartTimeNs + bucketSizeNs + 351);
-// auto crashEvent10 = CreateAppCrashEvent(appUid, bucketStartTimeNs + 2 * bucketSizeNs - 2);
-//
-// auto screenTurnedOnEvent = CreateScreenStateChangedEvent(
-// android::view::DisplayStateEnum::DISPLAY_STATE_ON, bucketStartTimeNs + 2);
-// auto screenTurnedOffEvent = CreateScreenStateChangedEvent(
-// android::view::DisplayStateEnum::DISPLAY_STATE_OFF, bucketStartTimeNs + 200);
-// auto screenTurnedOnEvent2 =
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-// bucketStartTimeNs + 2 * bucketSizeNs - 100);
-//
-// std::vector<AttributionNodeInternal> attributions = {
-// CreateAttribution(appUid, "App1"), CreateAttribution(appUid + 1, "GMSCoreModule1")};
-// auto syncOnEvent1 = CreateSyncStartEvent(attributions, "ReadEmail", bucketStartTimeNs + 50);
-// auto syncOffEvent1 =
-// CreateSyncEndEvent(attributions, "ReadEmail", bucketStartTimeNs + bucketSizeNs + 300);
-// auto syncOnEvent2 =
-// CreateSyncStartEvent(attributions, "ReadDoc", bucketStartTimeNs + bucketSizeNs + 2000);
-//
-// auto moveToBackgroundEvent1 = CreateMoveToBackgroundEvent(appUid, bucketStartTimeNs + 15);
-// auto moveToForegroundEvent1 =
-// CreateMoveToForegroundEvent(appUid, bucketStartTimeNs + bucketSizeNs + 250);
-//
-// auto moveToBackgroundEvent2 =
-// CreateMoveToBackgroundEvent(appUid, bucketStartTimeNs + bucketSizeNs + 350);
-// auto moveToForegroundEvent2 =
-// CreateMoveToForegroundEvent(appUid, bucketStartTimeNs + 2 * bucketSizeNs - 1);
-//
-// /*
-// bucket #1 bucket #2
-//
-//
-// | | | | | | | | | | (crashEvents)
-// |-------------------------------------|-----------------------------------|---------
-//
-// | | (MoveToBkground)
-//
-// | | (MoveToForeground)
-//
-// | | (SyncIsOn)
-// | (SyncIsOff)
-// | | (ScreenIsOn)
-// | (ScreenIsOff)
-// */
-// std::vector<std::unique_ptr<LogEvent>> events;
-// events.push_back(std::move(crashEvent1));
-// events.push_back(std::move(crashEvent2));
-// events.push_back(std::move(crashEvent3));
-// events.push_back(std::move(crashEvent4));
-// events.push_back(std::move(crashEvent5));
-// events.push_back(std::move(crashEvent6));
-// events.push_back(std::move(crashEvent7));
-// events.push_back(std::move(crashEvent8));
-// events.push_back(std::move(crashEvent9));
-// events.push_back(std::move(crashEvent10));
-// events.push_back(std::move(screenTurnedOnEvent));
-// events.push_back(std::move(screenTurnedOffEvent));
-// events.push_back(std::move(screenTurnedOnEvent2));
-// events.push_back(std::move(syncOnEvent1));
-// events.push_back(std::move(syncOffEvent1));
-// events.push_back(std::move(syncOnEvent2));
-// events.push_back(std::move(moveToBackgroundEvent1));
-// events.push_back(std::move(moveToForegroundEvent1));
-// events.push_back(std::move(moveToBackgroundEvent2));
-// events.push_back(std::move(moveToForegroundEvent2));
-//
-// sortLogEventsByTimestamp(&events);
-//
-// for (const auto& event : events) {
-// processor->OnLogEvent(event.get());
-// }
-// ConfigMetricsReportList reports;
-// vector<uint8_t> buffer;
-//
-// processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(reports.reports_size(), 1);
-// EXPECT_EQ(reports.reports(0).metrics_size(), 1);
-// EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data_size(), 1);
-// EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info_size(), 2);
-// EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info(0).count(), 1);
-// EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info(1).count(), 3);
-// auto data = reports.reports(0).metrics(0).count_metrics().data(0);
-// // Validate dimension value.
-// EXPECT_EQ(data.dimensions_in_what().field(),
-// android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
-// EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
-// // Uid field.
-// EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
-// EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), appUid);
-//}
+// If we want to test multiple dump data, we must do it in separate tests, because in the e2e tests,
+// we should use the real API which will clear the data after dump data is called.
+TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks1) {
+ auto config = CreateStatsdConfig();
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
+
+ ConfigKey cfgKey;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+
+ int appUid = 123;
+ auto crashEvent1 = CreateAppCrashEvent(bucketStartTimeNs + 1, appUid);
+ auto crashEvent2 = CreateAppCrashEvent(bucketStartTimeNs + 201, appUid);
+ auto crashEvent3 = CreateAppCrashEvent(bucketStartTimeNs + 2 * bucketSizeNs - 101, appUid);
+
+ auto crashEvent4 = CreateAppCrashEvent(bucketStartTimeNs + 51, appUid);
+ auto crashEvent5 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 299, appUid);
+ auto crashEvent6 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 2001, appUid);
+
+ auto crashEvent7 = CreateAppCrashEvent(bucketStartTimeNs + 16, appUid);
+ auto crashEvent8 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 249, appUid);
+
+ auto crashEvent9 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 351, appUid);
+ auto crashEvent10 = CreateAppCrashEvent(bucketStartTimeNs + 2 * bucketSizeNs - 2, appUid);
+
+ auto screenTurnedOnEvent = CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 2, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
+ auto screenTurnedOffEvent = CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 200, android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
+ auto screenTurnedOnEvent2 =
+ CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs - 100,
+ android::view::DisplayStateEnum::DISPLAY_STATE_ON);
+
+ std::vector<int> attributionUids = {appUid, appUid + 1};
+ std::vector<string> attributionTags = {"App1", "GMSCoreModule1"};
+
+ auto syncOnEvent1 = CreateSyncStartEvent(bucketStartTimeNs + 50, attributionUids,
+ attributionTags, "ReadEmail");
+ auto syncOffEvent1 = CreateSyncEndEvent(bucketStartTimeNs + bucketSizeNs + 300, attributionUids,
+ attributionTags, "ReadEmail");
+ auto syncOnEvent2 = CreateSyncStartEvent(bucketStartTimeNs + bucketSizeNs + 2000,
+ attributionUids, attributionTags, "ReadDoc");
+
+ auto moveToBackgroundEvent1 = CreateMoveToBackgroundEvent(bucketStartTimeNs + 15, appUid);
+ auto moveToForegroundEvent1 =
+ CreateMoveToForegroundEvent(bucketStartTimeNs + bucketSizeNs + 250, appUid);
+
+ auto moveToBackgroundEvent2 =
+ CreateMoveToBackgroundEvent(bucketStartTimeNs + bucketSizeNs + 350, appUid);
+ auto moveToForegroundEvent2 =
+ CreateMoveToForegroundEvent(bucketStartTimeNs + 2 * bucketSizeNs - 1, appUid);
+
+ /*
+ bucket #1 bucket #2
+
+
+ | | | | | | | | | | (crashEvents)
+ |-------------------------------------|-----------------------------------|---------
+
+ | | (MoveToBkground)
+
+ | | (MoveToForeground)
+
+ | | (SyncIsOn)
+ | (SyncIsOff)
+ | | (ScreenIsOn)
+ | (ScreenIsOff)
+ */
+ std::vector<std::unique_ptr<LogEvent>> events;
+ events.push_back(std::move(crashEvent1));
+ events.push_back(std::move(crashEvent2));
+ events.push_back(std::move(crashEvent3));
+ events.push_back(std::move(crashEvent4));
+ events.push_back(std::move(crashEvent5));
+ events.push_back(std::move(crashEvent6));
+ events.push_back(std::move(crashEvent7));
+ events.push_back(std::move(crashEvent8));
+ events.push_back(std::move(crashEvent9));
+ events.push_back(std::move(crashEvent10));
+ events.push_back(std::move(screenTurnedOnEvent));
+ events.push_back(std::move(screenTurnedOffEvent));
+ events.push_back(std::move(screenTurnedOnEvent2));
+ events.push_back(std::move(syncOnEvent1));
+ events.push_back(std::move(syncOffEvent1));
+ events.push_back(std::move(syncOnEvent2));
+ events.push_back(std::move(moveToBackgroundEvent1));
+ events.push_back(std::move(moveToForegroundEvent1));
+ events.push_back(std::move(moveToBackgroundEvent2));
+ events.push_back(std::move(moveToForegroundEvent2));
+
+ sortLogEventsByTimestamp(&events);
+
+ for (const auto& event : events) {
+ processor->OnLogEvent(event.get());
+ }
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, true, ADB_DUMP,
+ FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(reports.reports_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info(0).count(), 1);
+ auto data = reports.reports(0).metrics(0).count_metrics().data(0);
+ // Validate dimension value.
+ EXPECT_EQ(data.dimensions_in_what().field(), android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
+ // Uid field.
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), appUid);
+}
+
+TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks2) {
+ auto config = CreateStatsdConfig();
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000LL;
+
+ ConfigKey cfgKey;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+
+ int appUid = 123;
+ auto crashEvent1 = CreateAppCrashEvent(bucketStartTimeNs + 1, appUid);
+ auto crashEvent2 = CreateAppCrashEvent(bucketStartTimeNs + 201, appUid);
+ auto crashEvent3 = CreateAppCrashEvent(bucketStartTimeNs + 2 * bucketSizeNs - 101, appUid);
+
+ auto crashEvent4 = CreateAppCrashEvent(bucketStartTimeNs + 51, appUid);
+ auto crashEvent5 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 299, appUid);
+ auto crashEvent6 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 2001, appUid);
+
+ auto crashEvent7 = CreateAppCrashEvent(bucketStartTimeNs + 16, appUid);
+ auto crashEvent8 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 249, appUid);
+
+ auto crashEvent9 = CreateAppCrashEvent(bucketStartTimeNs + bucketSizeNs + 351, appUid);
+ auto crashEvent10 = CreateAppCrashEvent(bucketStartTimeNs + 2 * bucketSizeNs - 2, appUid);
+
+ auto screenTurnedOnEvent = CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 2, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
+ auto screenTurnedOffEvent = CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 200, android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
+ auto screenTurnedOnEvent2 =
+ CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs - 100,
+ android::view::DisplayStateEnum::DISPLAY_STATE_ON);
+
+ std::vector<int> attributionUids = {appUid, appUid + 1};
+ std::vector<string> attributionTags = {"App1", "GMSCoreModule1"};
+
+ auto syncOnEvent1 = CreateSyncStartEvent(bucketStartTimeNs + 50, attributionUids,
+ attributionTags, "ReadEmail");
+ auto syncOffEvent1 = CreateSyncEndEvent(bucketStartTimeNs + bucketSizeNs + 300, attributionUids,
+ attributionTags, "ReadEmail");
+ auto syncOnEvent2 = CreateSyncStartEvent(bucketStartTimeNs + bucketSizeNs + 2000,
+ attributionUids, attributionTags, "ReadDoc");
+
+ auto moveToBackgroundEvent1 = CreateMoveToBackgroundEvent(bucketStartTimeNs + 15, appUid);
+ auto moveToForegroundEvent1 =
+ CreateMoveToForegroundEvent(bucketStartTimeNs + bucketSizeNs + 250, appUid);
+
+ auto moveToBackgroundEvent2 =
+ CreateMoveToBackgroundEvent(bucketStartTimeNs + bucketSizeNs + 350, appUid);
+ auto moveToForegroundEvent2 =
+ CreateMoveToForegroundEvent(bucketStartTimeNs + 2 * bucketSizeNs - 1, appUid);
+
+ /*
+ bucket #1 bucket #2
+
+
+ | | | | | | | | | | (crashEvents)
+ |-------------------------------------|-----------------------------------|---------
+
+ | | (MoveToBkground)
+
+ | | (MoveToForeground)
+
+ | | (SyncIsOn)
+ | (SyncIsOff)
+ | | (ScreenIsOn)
+ | (ScreenIsOff)
+ */
+ std::vector<std::unique_ptr<LogEvent>> events;
+ events.push_back(std::move(crashEvent1));
+ events.push_back(std::move(crashEvent2));
+ events.push_back(std::move(crashEvent3));
+ events.push_back(std::move(crashEvent4));
+ events.push_back(std::move(crashEvent5));
+ events.push_back(std::move(crashEvent6));
+ events.push_back(std::move(crashEvent7));
+ events.push_back(std::move(crashEvent8));
+ events.push_back(std::move(crashEvent9));
+ events.push_back(std::move(crashEvent10));
+ events.push_back(std::move(screenTurnedOnEvent));
+ events.push_back(std::move(screenTurnedOffEvent));
+ events.push_back(std::move(screenTurnedOnEvent2));
+ events.push_back(std::move(syncOnEvent1));
+ events.push_back(std::move(syncOffEvent1));
+ events.push_back(std::move(syncOnEvent2));
+ events.push_back(std::move(moveToBackgroundEvent1));
+ events.push_back(std::move(moveToForegroundEvent1));
+ events.push_back(std::move(moveToBackgroundEvent2));
+ events.push_back(std::move(moveToForegroundEvent2));
+
+ sortLogEventsByTimestamp(&events);
+
+ for (const auto& event : events) {
+ processor->OnLogEvent(event.get());
+ }
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true, ADB_DUMP,
+ FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(reports.reports_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info_size(), 2);
+ EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info(0).count(), 1);
+ EXPECT_EQ(reports.reports(0).metrics(0).count_metrics().data(0).bucket_info(1).count(), 3);
+ auto data = reports.reports(0).metrics(0).count_metrics().data(0);
+ // Validate dimension value.
+ EXPECT_EQ(data.dimensions_in_what().field(), android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value_size(), 1);
+ // Uid field.
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).field(), 1);
+ EXPECT_EQ(data.dimensions_in_what().value_tuple().dimensions_value(0).value_int(), appUid);
+}
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
diff --git a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
index 9ec831b..b975907 100644
--- a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
@@ -113,96 +113,107 @@
}
} // anonymous namespace
-// TODO(b/149590301): Update this test to use new socket schema.
-//TEST(PartialBucketE2eTest, TestCountMetricWithoutSplit) {
-// shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
-// SendConfig(service, MakeConfig());
-// int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
-// // initialized with.
-//
-// service->mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get());
-// service->mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 2).get());
-//
-// ConfigMetricsReport report = GetReports(service->mProcessor, start + 3);
-// // Expect no metrics since the bucket has not finished yet.
-// EXPECT_EQ(1, report.metrics_size());
-// EXPECT_EQ(0, report.metrics(0).count_metrics().data_size());
-//}
-//
-//TEST(PartialBucketE2eTest, TestCountMetricNoSplitOnNewApp) {
-// shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
-// SendConfig(service, MakeConfig());
-// int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
-// // initialized with.
-//
-// // Force the uidmap to update at timestamp 2.
-// service->mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get());
-// // This is a new installation, so there shouldn't be a split (should be same as the without
-// // split case).
-// service->mUidMap->updateApp(start + 2, String16(kApp1.c_str()), 1, 2, String16("v2"),
-// String16(""));
-// // Goes into the second bucket.
-// service->mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 3).get());
-//
-// ConfigMetricsReport report = GetReports(service->mProcessor, start + 4);
-// EXPECT_EQ(1, report.metrics_size());
-// EXPECT_EQ(0, report.metrics(0).count_metrics().data_size());
-//}
-//
-//TEST(PartialBucketE2eTest, TestCountMetricSplitOnUpgrade) {
-// shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
-// SendConfig(service, MakeConfig());
-// int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
-// // initialized with.
-// service->mUidMap->updateMap(start, {1}, {1}, {String16("v1")}, {String16(kApp1.c_str())},
-// {String16("")});
-//
-// // Force the uidmap to update at timestamp 2.
-// service->mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get());
-// service->mUidMap->updateApp(start + 2, String16(kApp1.c_str()), 1, 2, String16("v2"),
-// String16(""));
-// // Goes into the second bucket.
-// service->mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 3).get());
-//
-// ConfigMetricsReport report = GetReports(service->mProcessor, start + 4);
-// backfillStartEndTimestamp(&report);
-//
-// ASSERT_EQ(1, report.metrics_size());
-// ASSERT_EQ(1, report.metrics(0).count_metrics().data_size());
-// ASSERT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info_size());
-// EXPECT_TRUE(report.metrics(0).count_metrics().data(0).bucket_info(0).
-// has_start_bucket_elapsed_nanos());
-// EXPECT_TRUE(report.metrics(0).count_metrics().data(0).bucket_info(0).
-// has_end_bucket_elapsed_nanos());
-// EXPECT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info(0).count());
-//}
-//
-//TEST(PartialBucketE2eTest, TestCountMetricSplitOnRemoval) {
-// shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
-// SendConfig(service, MakeConfig());
-// int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
-// // initialized with.
-// service->mUidMap->updateMap(start, {1}, {1}, {String16("v1")}, {String16(kApp1.c_str())},
-// {String16("")});
-//
-// // Force the uidmap to update at timestamp 2.
-// service->mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get());
-// service->mUidMap->removeApp(start + 2, String16(kApp1.c_str()), 1);
-// // Goes into the second bucket.
-// service->mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 3).get());
-//
-// ConfigMetricsReport report = GetReports(service->mProcessor, start + 4);
-// backfillStartEndTimestamp(&report);
-//
-// ASSERT_EQ(1, report.metrics_size());
-// ASSERT_EQ(1, report.metrics(0).count_metrics().data_size());
-// ASSERT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info_size());
-// EXPECT_TRUE(report.metrics(0).count_metrics().data(0).bucket_info(0).
-// has_start_bucket_elapsed_nanos());
-// EXPECT_TRUE(report.metrics(0).count_metrics().data(0).bucket_info(0).
-// has_end_bucket_elapsed_nanos());
-// EXPECT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info(0).count());
-//}
+TEST(PartialBucketE2eTest, TestCountMetricWithoutSplit) {
+ shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
+ SendConfig(service, MakeConfig());
+ int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
+ // initialized with.
+
+ service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 1, 100).get());
+ service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 2, 100).get());
+
+ ConfigMetricsReport report = GetReports(service->mProcessor, start + 3);
+ // Expect no metrics since the bucket has not finished yet.
+ EXPECT_EQ(1, report.metrics_size());
+ EXPECT_EQ(0, report.metrics(0).count_metrics().data_size());
+}
+
+TEST(PartialBucketE2eTest, TestCountMetricNoSplitOnNewApp) {
+ shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
+ SendConfig(service, MakeConfig());
+ int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
+ // initialized with.
+
+ // Force the uidmap to update at timestamp 2.
+ service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 1, 100).get());
+ // This is a new installation, so there shouldn't be a split (should be same as the without
+ // split case).
+ service->mUidMap->updateApp(start + 2, String16(kApp1.c_str()), 1, 2, String16("v2"),
+ String16(""));
+ // Goes into the second bucket.
+ service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 3, 100).get());
+
+ ConfigMetricsReport report = GetReports(service->mProcessor, start + 4);
+ EXPECT_EQ(1, report.metrics_size());
+ EXPECT_EQ(0, report.metrics(0).count_metrics().data_size());
+}
+
+TEST(PartialBucketE2eTest, TestCountMetricSplitOnUpgrade) {
+ shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
+ SendConfig(service, MakeConfig());
+ int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
+ // initialized with.
+ service->mUidMap->updateMap(start, {1}, {1}, {String16("v1")}, {String16(kApp1.c_str())},
+ {String16("")});
+
+ // Force the uidmap to update at timestamp 2.
+ service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 1, 100).get());
+ service->mUidMap->updateApp(start + 2, String16(kApp1.c_str()), 1, 2, String16("v2"),
+ String16(""));
+ // Goes into the second bucket.
+ service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 3, 100).get());
+
+ ConfigMetricsReport report = GetReports(service->mProcessor, start + 4);
+ backfillStartEndTimestamp(&report);
+
+ ASSERT_EQ(1, report.metrics_size());
+ ASSERT_EQ(1, report.metrics(0).count_metrics().data_size());
+ ASSERT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info_size());
+ EXPECT_TRUE(report.metrics(0)
+ .count_metrics()
+ .data(0)
+ .bucket_info(0)
+ .has_start_bucket_elapsed_nanos());
+ EXPECT_TRUE(report.metrics(0)
+ .count_metrics()
+ .data(0)
+ .bucket_info(0)
+ .has_end_bucket_elapsed_nanos());
+ EXPECT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info(0).count());
+}
+
+TEST(PartialBucketE2eTest, TestCountMetricSplitOnRemoval) {
+ shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
+ SendConfig(service, MakeConfig());
+ int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are
+ // initialized with.
+ service->mUidMap->updateMap(start, {1}, {1}, {String16("v1")}, {String16(kApp1.c_str())},
+ {String16("")});
+
+ // Force the uidmap to update at timestamp 2.
+ service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 1, 100).get());
+ service->mUidMap->removeApp(start + 2, String16(kApp1.c_str()), 1);
+ // Goes into the second bucket.
+ service->mProcessor->OnLogEvent(CreateAppCrashEvent(start + 3, 100).get());
+
+ ConfigMetricsReport report = GetReports(service->mProcessor, start + 4);
+ backfillStartEndTimestamp(&report);
+
+ ASSERT_EQ(1, report.metrics_size());
+ ASSERT_EQ(1, report.metrics(0).count_metrics().data_size());
+ ASSERT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info_size());
+ EXPECT_TRUE(report.metrics(0)
+ .count_metrics()
+ .data(0)
+ .bucket_info(0)
+ .has_start_bucket_elapsed_nanos());
+ EXPECT_TRUE(report.metrics(0)
+ .count_metrics()
+ .data(0)
+ .bucket_info(0)
+ .has_end_bucket_elapsed_nanos());
+ EXPECT_EQ(1, report.metrics(0).count_metrics().data(0).bucket_info(0).count());
+}
TEST(PartialBucketE2eTest, TestValueMetricWithoutMinPartialBucket) {
shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(nullptr, nullptr);
diff --git a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
index 99dbaf1..a87bb71 100644
--- a/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/ValueMetric_pull_e2e_test.cpp
@@ -64,317 +64,313 @@
} // namespace
-// TODO(b/149590301): Update this test to use new socket schema.
-//TEST(ValueMetricE2eTest, TestPulledEvents) {
-// auto config = CreateStatsdConfig();
-// int64_t baseTimeNs = getElapsedRealtimeNs();
-// int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
-// int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.value_metric(0).bucket()) * 1000000;
-//
-// ConfigKey cfgKey;
-// auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
-// SharedRefBase::make<FakeSubsystemSleepCallback>(),
-// android::util::SUBSYSTEM_SLEEP_STATE);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-// processor->mPullerManager->ForceClearPullerCache();
-//
-// int startBucketNum = processor->mMetricsManagers.begin()->second->
-// mAllMetricProducers[0]->getCurrentBucketNum();
-// EXPECT_GT(startBucketNum, (int64_t)0);
-//
-// // When creating the config, the value metric producer should register the alarm at the
-// // end of the current bucket.
-// EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
-// EXPECT_EQ(bucketSizeNs,
-// processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
-// int64_t& expectedPullTimeNs =
-// processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs;
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, expectedPullTimeNs);
-//
-// auto screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-// configAddedTimeNs + 55);
-// processor->OnLogEvent(screenOffEvent.get());
-//
-// auto screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-// configAddedTimeNs + 65);
-// processor->OnLogEvent(screenOnEvent.get());
-//
-// screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-// configAddedTimeNs + 75);
-// processor->OnLogEvent(screenOffEvent.get());
-//
-// // Pulling alarm arrives on time and reset the sequential pulling alarm.
-// processor->informPullAlarmFired(expectedPullTimeNs + 1);
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 2 * bucketSizeNs, expectedPullTimeNs);
-//
-// processor->informPullAlarmFired(expectedPullTimeNs + 1);
-//
-// screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-// configAddedTimeNs + 2 * bucketSizeNs + 15);
-// processor->OnLogEvent(screenOnEvent.get());
-//
-// processor->informPullAlarmFired(expectedPullTimeNs + 1);
-//
-// processor->informPullAlarmFired(expectedPullTimeNs + 1);
-//
-// screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-// configAddedTimeNs + 4 * bucketSizeNs + 11);
-// processor->OnLogEvent(screenOffEvent.get());
-//
-// processor->informPullAlarmFired(expectedPullTimeNs + 1);
-//
-// processor->informPullAlarmFired(expectedPullTimeNs + 1);
-//
-// ConfigMetricsReportList reports;
-// vector<uint8_t> buffer;
-// processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(1, reports.reports_size());
-// EXPECT_EQ(1, reports.reports(0).metrics_size());
-// StatsLogReport::ValueMetricDataWrapper valueMetrics;
-// sortMetricDataByDimensionsValue(
-// reports.reports(0).metrics(0).value_metrics(), &valueMetrics);
-// EXPECT_GT((int)valueMetrics.data_size(), 1);
-//
-// auto data = valueMetrics.data(0);
-// EXPECT_EQ(android::util::SUBSYSTEM_SLEEP_STATE, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* subsystem name field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
-// // We have 4 buckets, the first one was incomplete since the condition was unknown.
-// EXPECT_EQ(4, data.bucket_info_size());
-//
-// EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-// EXPECT_EQ(1, data.bucket_info(0).values_size());
-//
-// EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
-// EXPECT_EQ(1, data.bucket_info(1).values_size());
-//
-// EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
-// EXPECT_EQ(1, data.bucket_info(2).values_size());
-//
-// EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(3).start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(3).end_bucket_elapsed_nanos());
-// EXPECT_EQ(1, data.bucket_info(3).values_size());
-//}
-//
-//TEST(ValueMetricE2eTest, TestPulledEvents_LateAlarm) {
-// auto config = CreateStatsdConfig();
-// int64_t baseTimeNs = getElapsedRealtimeNs();
-// // 10 mins == 2 bucket durations.
-// int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
-// int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.value_metric(0).bucket()) * 1000000;
-//
-// ConfigKey cfgKey;
-// auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
-// SharedRefBase::make<FakeSubsystemSleepCallback>(),
-// android::util::SUBSYSTEM_SLEEP_STATE);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-// processor->mPullerManager->ForceClearPullerCache();
-//
-// int startBucketNum = processor->mMetricsManagers.begin()->second->
-// mAllMetricProducers[0]->getCurrentBucketNum();
-// EXPECT_GT(startBucketNum, (int64_t)0);
-//
-// // When creating the config, the value metric producer should register the alarm at the
-// // end of the current bucket.
-// EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
-// EXPECT_EQ(bucketSizeNs,
-// processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
-// int64_t& expectedPullTimeNs =
-// processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs;
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, expectedPullTimeNs);
-//
-// // Screen off/on/off events.
-// auto screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-// configAddedTimeNs + 55);
-// processor->OnLogEvent(screenOffEvent.get());
-//
-// auto screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-// configAddedTimeNs + 65);
-// processor->OnLogEvent(screenOnEvent.get());
-//
-// screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-// configAddedTimeNs + 75);
-// processor->OnLogEvent(screenOffEvent.get());
-//
-// // Pulling alarm arrives late by 2 buckets and 1 ns. 2 buckets late is too far away in the
-// // future, data will be skipped.
-// processor->informPullAlarmFired(expectedPullTimeNs + 2 * bucketSizeNs + 1);
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 4 * bucketSizeNs, expectedPullTimeNs);
-//
-// // This screen state change will start a new bucket.
-// screenOnEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_ON,
-// configAddedTimeNs + 4 * bucketSizeNs + 65);
-// processor->OnLogEvent(screenOnEvent.get());
-//
-// // The alarm is delayed but we already created a bucket thanks to the screen state condition.
-// // This bucket does not have to be skipped since the alarm arrives in time for the next bucket.
-// processor->informPullAlarmFired(expectedPullTimeNs + bucketSizeNs + 21);
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 6 * bucketSizeNs, expectedPullTimeNs);
-//
-// screenOffEvent = CreateScreenStateChangedEvent(android::view::DISPLAY_STATE_OFF,
-// configAddedTimeNs + 6 * bucketSizeNs + 31);
-// processor->OnLogEvent(screenOffEvent.get());
-//
-// processor->informPullAlarmFired(expectedPullTimeNs + bucketSizeNs + 21);
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 8 * bucketSizeNs, expectedPullTimeNs);
-//
-// processor->informPullAlarmFired(expectedPullTimeNs + 1);
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 9 * bucketSizeNs, expectedPullTimeNs);
-//
-// ConfigMetricsReportList reports;
-// vector<uint8_t> buffer;
-// processor->onDumpReport(cfgKey, configAddedTimeNs + 9 * bucketSizeNs + 10, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(1, reports.reports_size());
-// EXPECT_EQ(1, reports.reports(0).metrics_size());
-// StatsLogReport::ValueMetricDataWrapper valueMetrics;
-// sortMetricDataByDimensionsValue(
-// reports.reports(0).metrics(0).value_metrics(), &valueMetrics);
-// EXPECT_GT((int)valueMetrics.data_size(), 1);
-//
-// auto data = valueMetrics.data(0);
-// EXPECT_EQ(android::util::SUBSYSTEM_SLEEP_STATE, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* subsystem name field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
-// EXPECT_EQ(3, data.bucket_info_size());
-//
-// EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
-// EXPECT_EQ(1, data.bucket_info(0).values_size());
-//
-// EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + 9 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
-// EXPECT_EQ(1, data.bucket_info(1).values_size());
-//
-// EXPECT_EQ(baseTimeNs + 9 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + 10 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
-// EXPECT_EQ(1, data.bucket_info(2).values_size());
-//}
-//
-//TEST(ValueMetricE2eTest, TestPulledEvents_WithActivation) {
-// auto config = CreateStatsdConfig(false);
-// int64_t baseTimeNs = getElapsedRealtimeNs();
-// int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
-// int64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.value_metric(0).bucket()) * 1000000;
-//
-// auto batterySaverStartMatcher = CreateBatterySaverModeStartAtomMatcher();
-// *config.add_atom_matcher() = batterySaverStartMatcher;
-// const int64_t ttlNs = 2 * bucketSizeNs; // Two buckets.
-// auto metric_activation = config.add_metric_activation();
-// metric_activation->set_metric_id(metricId);
-// metric_activation->set_activation_type(ACTIVATE_IMMEDIATELY);
-// auto event_activation = metric_activation->add_event_activation();
-// event_activation->set_atom_matcher_id(batterySaverStartMatcher.id());
-// event_activation->set_ttl_seconds(ttlNs / 1000000000);
-//
-// ConfigKey cfgKey;
-// auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
-// SharedRefBase::make<FakeSubsystemSleepCallback>(),
-// android::util::SUBSYSTEM_SLEEP_STATE);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-// processor->mPullerManager->ForceClearPullerCache();
-//
-// int startBucketNum = processor->mMetricsManagers.begin()->second->
-// mAllMetricProducers[0]->getCurrentBucketNum();
-// EXPECT_GT(startBucketNum, (int64_t)0);
-// EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
-//
-// // When creating the config, the value metric producer should register the alarm at the
-// // end of the current bucket.
-// EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
-// EXPECT_EQ(bucketSizeNs,
-// processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
-// int64_t& expectedPullTimeNs =
-// processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs;
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, expectedPullTimeNs);
-//
-// // Pulling alarm arrives on time and reset the sequential pulling alarm.
-// processor->informPullAlarmFired(expectedPullTimeNs + 1); // 15 mins + 1 ns.
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 2 * bucketSizeNs, expectedPullTimeNs);
-// EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
-//
-// // Activate the metric. A pull occurs here
-// const int64_t activationNs = configAddedTimeNs + bucketSizeNs + (2 * 1000 * 1000); // 2 millis.
-// auto batterySaverOnEvent = CreateBatterySaverOnEvent(activationNs);
-// processor->OnLogEvent(batterySaverOnEvent.get()); // 15 mins + 2 ms.
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
-//
-// processor->informPullAlarmFired(expectedPullTimeNs + 1); // 20 mins + 1 ns.
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 3 * bucketSizeNs, expectedPullTimeNs);
-//
-// processor->informPullAlarmFired(expectedPullTimeNs + 2); // 25 mins + 2 ns.
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 4 * bucketSizeNs, expectedPullTimeNs);
-//
-// // Create random event to deactivate metric.
-// auto deactivationEvent = CreateScreenBrightnessChangedEvent(50, activationNs + ttlNs + 1);
-// processor->OnLogEvent(deactivationEvent.get());
-// EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
-//
-// processor->informPullAlarmFired(expectedPullTimeNs + 3);
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 5 * bucketSizeNs, expectedPullTimeNs);
-//
-// processor->informPullAlarmFired(expectedPullTimeNs + 4);
-// EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 6 * bucketSizeNs, expectedPullTimeNs);
-//
-// ConfigMetricsReportList reports;
-// vector<uint8_t> buffer;
-// processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(1, reports.reports_size());
-// EXPECT_EQ(1, reports.reports(0).metrics_size());
-// StatsLogReport::ValueMetricDataWrapper valueMetrics;
-// sortMetricDataByDimensionsValue(
-// reports.reports(0).metrics(0).value_metrics(), &valueMetrics);
-// EXPECT_GT((int)valueMetrics.data_size(), 0);
-//
-// auto data = valueMetrics.data(0);
-// EXPECT_EQ(android::util::SUBSYSTEM_SLEEP_STATE, data.dimensions_in_what().field());
-// EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
-// EXPECT_EQ(1 /* subsystem name field */,
-// data.dimensions_in_what().value_tuple().dimensions_value(0).field());
-// EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
-// // We have 2 full buckets, the two surrounding the activation are dropped.
-// EXPECT_EQ(2, data.bucket_info_size());
-//
-// auto bucketInfo = data.bucket_info(0);
-// EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, bucketInfo.start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
-// EXPECT_EQ(1, bucketInfo.values_size());
-//
-// bucketInfo = data.bucket_info(1);
-// EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, bucketInfo.start_bucket_elapsed_nanos());
-// EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
-// EXPECT_EQ(1, bucketInfo.values_size());
-//}
+TEST(ValueMetricE2eTest, TestPulledEvents) {
+ auto config = CreateStatsdConfig();
+ int64_t baseTimeNs = getElapsedRealtimeNs();
+ int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.value_metric(0).bucket()) * 1000000;
+
+ ConfigKey cfgKey;
+ auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
+ SharedRefBase::make<FakeSubsystemSleepCallback>(),
+ android::util::SUBSYSTEM_SLEEP_STATE);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ processor->mPullerManager->ForceClearPullerCache();
+
+ int startBucketNum = processor->mMetricsManagers.begin()
+ ->second->mAllMetricProducers[0]
+ ->getCurrentBucketNum();
+ EXPECT_GT(startBucketNum, (int64_t)0);
+
+ // When creating the config, the value metric producer should register the alarm at the
+ // end of the current bucket.
+ EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
+ EXPECT_EQ(bucketSizeNs,
+ processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
+ int64_t& expectedPullTimeNs =
+ processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs;
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, expectedPullTimeNs);
+
+ auto screenOffEvent =
+ CreateScreenStateChangedEvent(configAddedTimeNs + 55, android::view::DISPLAY_STATE_OFF);
+ processor->OnLogEvent(screenOffEvent.get());
+
+ auto screenOnEvent =
+ CreateScreenStateChangedEvent(configAddedTimeNs + 65, android::view::DISPLAY_STATE_ON);
+ processor->OnLogEvent(screenOnEvent.get());
+
+ screenOffEvent =
+ CreateScreenStateChangedEvent(configAddedTimeNs + 75, android::view::DISPLAY_STATE_OFF);
+ processor->OnLogEvent(screenOffEvent.get());
+
+ // Pulling alarm arrives on time and reset the sequential pulling alarm.
+ processor->informPullAlarmFired(expectedPullTimeNs + 1);
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 2 * bucketSizeNs, expectedPullTimeNs);
+
+ processor->informPullAlarmFired(expectedPullTimeNs + 1);
+
+ screenOnEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 2 * bucketSizeNs + 15,
+ android::view::DISPLAY_STATE_ON);
+ processor->OnLogEvent(screenOnEvent.get());
+
+ processor->informPullAlarmFired(expectedPullTimeNs + 1);
+
+ processor->informPullAlarmFired(expectedPullTimeNs + 1);
+
+ screenOffEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 4 * bucketSizeNs + 11,
+ android::view::DISPLAY_STATE_OFF);
+ processor->OnLogEvent(screenOffEvent.get());
+
+ processor->informPullAlarmFired(expectedPullTimeNs + 1);
+
+ processor->informPullAlarmFired(expectedPullTimeNs + 1);
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
+ ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ StatsLogReport::ValueMetricDataWrapper valueMetrics;
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).value_metrics(), &valueMetrics);
+ EXPECT_GT((int)valueMetrics.data_size(), 1);
+
+ auto data = valueMetrics.data(0);
+ EXPECT_EQ(android::util::SUBSYSTEM_SLEEP_STATE, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* subsystem name field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
+ // We have 4 buckets, the first one was incomplete since the condition was unknown.
+ EXPECT_EQ(4, data.bucket_info_size());
+
+ EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+ EXPECT_EQ(1, data.bucket_info(0).values_size());
+
+ EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
+ EXPECT_EQ(1, data.bucket_info(1).values_size());
+
+ EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
+ EXPECT_EQ(1, data.bucket_info(2).values_size());
+
+ EXPECT_EQ(baseTimeNs + 7 * bucketSizeNs, data.bucket_info(3).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(3).end_bucket_elapsed_nanos());
+ EXPECT_EQ(1, data.bucket_info(3).values_size());
+}
+
+TEST(ValueMetricE2eTest, TestPulledEvents_LateAlarm) {
+ auto config = CreateStatsdConfig();
+ int64_t baseTimeNs = getElapsedRealtimeNs();
+ // 10 mins == 2 bucket durations.
+ int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.value_metric(0).bucket()) * 1000000;
+
+ ConfigKey cfgKey;
+ auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
+ SharedRefBase::make<FakeSubsystemSleepCallback>(),
+ android::util::SUBSYSTEM_SLEEP_STATE);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ processor->mPullerManager->ForceClearPullerCache();
+
+ int startBucketNum = processor->mMetricsManagers.begin()
+ ->second->mAllMetricProducers[0]
+ ->getCurrentBucketNum();
+ EXPECT_GT(startBucketNum, (int64_t)0);
+
+ // When creating the config, the value metric producer should register the alarm at the
+ // end of the current bucket.
+ EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
+ EXPECT_EQ(bucketSizeNs,
+ processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
+ int64_t& expectedPullTimeNs =
+ processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs;
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, expectedPullTimeNs);
+
+ // Screen off/on/off events.
+ auto screenOffEvent =
+ CreateScreenStateChangedEvent(configAddedTimeNs + 55, android::view::DISPLAY_STATE_OFF);
+ processor->OnLogEvent(screenOffEvent.get());
+
+ auto screenOnEvent =
+ CreateScreenStateChangedEvent(configAddedTimeNs + 65, android::view::DISPLAY_STATE_ON);
+ processor->OnLogEvent(screenOnEvent.get());
+
+ screenOffEvent =
+ CreateScreenStateChangedEvent(configAddedTimeNs + 75, android::view::DISPLAY_STATE_OFF);
+ processor->OnLogEvent(screenOffEvent.get());
+
+ // Pulling alarm arrives late by 2 buckets and 1 ns. 2 buckets late is too far away in the
+ // future, data will be skipped.
+ processor->informPullAlarmFired(expectedPullTimeNs + 2 * bucketSizeNs + 1);
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 4 * bucketSizeNs, expectedPullTimeNs);
+
+ // This screen state change will start a new bucket.
+ screenOnEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 4 * bucketSizeNs + 65,
+ android::view::DISPLAY_STATE_ON);
+ processor->OnLogEvent(screenOnEvent.get());
+
+ // The alarm is delayed but we already created a bucket thanks to the screen state condition.
+ // This bucket does not have to be skipped since the alarm arrives in time for the next bucket.
+ processor->informPullAlarmFired(expectedPullTimeNs + bucketSizeNs + 21);
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 6 * bucketSizeNs, expectedPullTimeNs);
+
+ screenOffEvent = CreateScreenStateChangedEvent(configAddedTimeNs + 6 * bucketSizeNs + 31,
+ android::view::DISPLAY_STATE_OFF);
+ processor->OnLogEvent(screenOffEvent.get());
+
+ processor->informPullAlarmFired(expectedPullTimeNs + bucketSizeNs + 21);
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 8 * bucketSizeNs, expectedPullTimeNs);
+
+ processor->informPullAlarmFired(expectedPullTimeNs + 1);
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 9 * bucketSizeNs, expectedPullTimeNs);
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, configAddedTimeNs + 9 * bucketSizeNs + 10, false, true,
+ ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ StatsLogReport::ValueMetricDataWrapper valueMetrics;
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).value_metrics(), &valueMetrics);
+ EXPECT_GT((int)valueMetrics.data_size(), 1);
+
+ auto data = valueMetrics.data(0);
+ EXPECT_EQ(android::util::SUBSYSTEM_SLEEP_STATE, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* subsystem name field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
+ EXPECT_EQ(3, data.bucket_info_size());
+
+ EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, data.bucket_info(0).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 6 * bucketSizeNs, data.bucket_info(0).end_bucket_elapsed_nanos());
+ EXPECT_EQ(1, data.bucket_info(0).values_size());
+
+ EXPECT_EQ(baseTimeNs + 8 * bucketSizeNs, data.bucket_info(1).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 9 * bucketSizeNs, data.bucket_info(1).end_bucket_elapsed_nanos());
+ EXPECT_EQ(1, data.bucket_info(1).values_size());
+
+ EXPECT_EQ(baseTimeNs + 9 * bucketSizeNs, data.bucket_info(2).start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 10 * bucketSizeNs, data.bucket_info(2).end_bucket_elapsed_nanos());
+ EXPECT_EQ(1, data.bucket_info(2).values_size());
+}
+
+TEST(ValueMetricE2eTest, TestPulledEvents_WithActivation) {
+ auto config = CreateStatsdConfig(false);
+ int64_t baseTimeNs = getElapsedRealtimeNs();
+ int64_t configAddedTimeNs = 10 * 60 * NS_PER_SEC + baseTimeNs;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(config.value_metric(0).bucket()) * 1000000;
+
+ auto batterySaverStartMatcher = CreateBatterySaverModeStartAtomMatcher();
+ *config.add_atom_matcher() = batterySaverStartMatcher;
+ const int64_t ttlNs = 2 * bucketSizeNs; // Two buckets.
+ auto metric_activation = config.add_metric_activation();
+ metric_activation->set_metric_id(metricId);
+ metric_activation->set_activation_type(ACTIVATE_IMMEDIATELY);
+ auto event_activation = metric_activation->add_event_activation();
+ event_activation->set_atom_matcher_id(batterySaverStartMatcher.id());
+ event_activation->set_ttl_seconds(ttlNs / 1000000000);
+
+ ConfigKey cfgKey;
+ auto processor = CreateStatsLogProcessor(baseTimeNs, configAddedTimeNs, config, cfgKey,
+ SharedRefBase::make<FakeSubsystemSleepCallback>(),
+ android::util::SUBSYSTEM_SLEEP_STATE);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ processor->mPullerManager->ForceClearPullerCache();
+
+ int startBucketNum = processor->mMetricsManagers.begin()
+ ->second->mAllMetricProducers[0]
+ ->getCurrentBucketNum();
+ EXPECT_GT(startBucketNum, (int64_t)0);
+ EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
+
+ // When creating the config, the value metric producer should register the alarm at the
+ // end of the current bucket.
+ EXPECT_EQ((size_t)1, processor->mPullerManager->mReceivers.size());
+ EXPECT_EQ(bucketSizeNs,
+ processor->mPullerManager->mReceivers.begin()->second.front().intervalNs);
+ int64_t& expectedPullTimeNs =
+ processor->mPullerManager->mReceivers.begin()->second.front().nextPullTimeNs;
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + bucketSizeNs, expectedPullTimeNs);
+
+ // Pulling alarm arrives on time and reset the sequential pulling alarm.
+ processor->informPullAlarmFired(expectedPullTimeNs + 1); // 15 mins + 1 ns.
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 2 * bucketSizeNs, expectedPullTimeNs);
+ EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
+
+ // Activate the metric. A pull occurs here
+ const int64_t activationNs = configAddedTimeNs + bucketSizeNs + (2 * 1000 * 1000); // 2 millis.
+ auto batterySaverOnEvent = CreateBatterySaverOnEvent(activationNs);
+ processor->OnLogEvent(batterySaverOnEvent.get()); // 15 mins + 2 ms.
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
+
+ processor->informPullAlarmFired(expectedPullTimeNs + 1); // 20 mins + 1 ns.
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 3 * bucketSizeNs, expectedPullTimeNs);
+
+ processor->informPullAlarmFired(expectedPullTimeNs + 2); // 25 mins + 2 ns.
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 4 * bucketSizeNs, expectedPullTimeNs);
+
+ // Create random event to deactivate metric.
+ auto deactivationEvent = CreateScreenBrightnessChangedEvent(activationNs + ttlNs + 1, 50);
+ processor->OnLogEvent(deactivationEvent.get());
+ EXPECT_FALSE(processor->mMetricsManagers.begin()->second->mAllMetricProducers[0]->isActive());
+
+ processor->informPullAlarmFired(expectedPullTimeNs + 3);
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 5 * bucketSizeNs, expectedPullTimeNs);
+
+ processor->informPullAlarmFired(expectedPullTimeNs + 4);
+ EXPECT_EQ(baseTimeNs + startBucketNum * bucketSizeNs + 6 * bucketSizeNs, expectedPullTimeNs);
+
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, configAddedTimeNs + 7 * bucketSizeNs + 10, false, true,
+ ADB_DUMP, FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(1, reports.reports_size());
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ StatsLogReport::ValueMetricDataWrapper valueMetrics;
+ sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).value_metrics(), &valueMetrics);
+ EXPECT_GT((int)valueMetrics.data_size(), 0);
+
+ auto data = valueMetrics.data(0);
+ EXPECT_EQ(android::util::SUBSYSTEM_SLEEP_STATE, data.dimensions_in_what().field());
+ EXPECT_EQ(1, data.dimensions_in_what().value_tuple().dimensions_value_size());
+ EXPECT_EQ(1 /* subsystem name field */,
+ data.dimensions_in_what().value_tuple().dimensions_value(0).field());
+ EXPECT_FALSE(data.dimensions_in_what().value_tuple().dimensions_value(0).value_str().empty());
+ // We have 2 full buckets, the two surrounding the activation are dropped.
+ EXPECT_EQ(2, data.bucket_info_size());
+
+ auto bucketInfo = data.bucket_info(0);
+ EXPECT_EQ(baseTimeNs + 3 * bucketSizeNs, bucketInfo.start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
+ EXPECT_EQ(1, bucketInfo.values_size());
+
+ bucketInfo = data.bucket_info(1);
+ EXPECT_EQ(baseTimeNs + 4 * bucketSizeNs, bucketInfo.start_bucket_elapsed_nanos());
+ EXPECT_EQ(baseTimeNs + 5 * bucketSizeNs, bucketInfo.end_bucket_elapsed_nanos());
+ EXPECT_EQ(1, bucketInfo.values_size());
+}
/**
* Test initialization of a simple value metric that is sliced by a state.
diff --git a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
index 21092e2..ddd8f95 100644
--- a/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/WakelockDuration_e2e_test.cpp
@@ -61,292 +61,290 @@
return config;
}
-std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1"),
- CreateAttribution(222, "GMSCoreModule1"),
- CreateAttribution(222, "GMSCoreModule2")};
+std::vector<int> attributionUids1 = {111, 222, 222};
+std::vector<string> attributionTags1 = {"App1", "GMSCoreModule1", "GMSCoreModule2"};
-std::vector<AttributionNodeInternal> attributions2 = {CreateAttribution(111, "App2"),
- CreateAttribution(222, "GMSCoreModule1"),
- CreateAttribution(222, "GMSCoreModule2")};
+std::vector<int> attributionUids2 = {111, 222, 222};
+std::vector<string> attributionTags2 = {"App2", "GMSCoreModule1", "GMSCoreModule2"};
-// TODO(b/149590301): Update this helper to use new socket schema.
-///*
-//Events:
-//Screen off is met from (200ns,1 min+500ns].
-//Acquire event for wl1 from 2ns to 1min+2ns
-//Acquire event for wl2 from 1min-10ns to 2min-15ns
-//*/
-//void FeedEvents(StatsdConfig config, sp<StatsLogProcessor> processor) {
-// uint64_t bucketStartTimeNs = 10000000000;
-// uint64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-//
-// auto screenTurnedOnEvent = CreateScreenStateChangedEvent(
-// android::view::DisplayStateEnum::DISPLAY_STATE_ON, bucketStartTimeNs + 1);
-// auto screenTurnedOffEvent = CreateScreenStateChangedEvent(
-// android::view::DisplayStateEnum::DISPLAY_STATE_OFF, bucketStartTimeNs + 200);
-// auto screenTurnedOnEvent2 =
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON,
-// bucketStartTimeNs + bucketSizeNs + 500);
-//
-// auto acquireEvent1 = CreateAcquireWakelockEvent(attributions1, "wl1", bucketStartTimeNs + 2);
-// auto releaseEvent1 =
-// CreateReleaseWakelockEvent(attributions1, "wl1", bucketStartTimeNs + bucketSizeNs + 2);
-// auto acquireEvent2 =
-// CreateAcquireWakelockEvent(attributions2, "wl2", bucketStartTimeNs + bucketSizeNs - 10);
-// auto releaseEvent2 = CreateReleaseWakelockEvent(attributions2, "wl2",
-// bucketStartTimeNs + 2 * bucketSizeNs - 15);
-//
-// std::vector<std::unique_ptr<LogEvent>> events;
-//
-// events.push_back(std::move(screenTurnedOnEvent));
-// events.push_back(std::move(screenTurnedOffEvent));
-// events.push_back(std::move(screenTurnedOnEvent2));
-// events.push_back(std::move(acquireEvent1));
-// events.push_back(std::move(acquireEvent2));
-// events.push_back(std::move(releaseEvent1));
-// events.push_back(std::move(releaseEvent2));
-//
-// sortLogEventsByTimestamp(&events);
-//
-// for (const auto& event : events) {
-// processor->OnLogEvent(event.get());
-// }
-//}
+/*
+Events:
+Screen off is met from (200ns,1 min+500ns].
+Acquire event for wl1 from 2ns to 1min+2ns
+Acquire event for wl2 from 1min-10ns to 2min-15ns
+*/
+void FeedEvents(StatsdConfig config, sp<StatsLogProcessor> processor) {
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+
+ auto screenTurnedOnEvent = CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 1, android::view::DisplayStateEnum::DISPLAY_STATE_ON);
+ auto screenTurnedOffEvent = CreateScreenStateChangedEvent(
+ bucketStartTimeNs + 200, android::view::DisplayStateEnum::DISPLAY_STATE_OFF);
+ auto screenTurnedOnEvent2 =
+ CreateScreenStateChangedEvent(bucketStartTimeNs + bucketSizeNs + 500,
+ android::view::DisplayStateEnum::DISPLAY_STATE_ON);
+
+ auto acquireEvent1 = CreateAcquireWakelockEvent(bucketStartTimeNs + 2, attributionUids1,
+ attributionTags1, "wl1");
+ auto releaseEvent1 = CreateReleaseWakelockEvent(bucketStartTimeNs + bucketSizeNs + 2,
+ attributionUids1, attributionTags1, "wl1");
+ auto acquireEvent2 = CreateAcquireWakelockEvent(bucketStartTimeNs + bucketSizeNs - 10,
+ attributionUids2, attributionTags2, "wl2");
+ auto releaseEvent2 = CreateReleaseWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs - 15,
+ attributionUids2, attributionTags2, "wl2");
+
+ std::vector<std::unique_ptr<LogEvent>> events;
+
+ events.push_back(std::move(screenTurnedOnEvent));
+ events.push_back(std::move(screenTurnedOffEvent));
+ events.push_back(std::move(screenTurnedOnEvent2));
+ events.push_back(std::move(acquireEvent1));
+ events.push_back(std::move(acquireEvent2));
+ events.push_back(std::move(releaseEvent1));
+ events.push_back(std::move(releaseEvent2));
+
+ sortLogEventsByTimestamp(&events);
+
+ for (const auto& event : events) {
+ processor->OnLogEvent(event.get());
+ }
+}
} // namespace
-// TODO(b/149590301): Update these tests to use new socket schema.
-//TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration1) {
-// ConfigKey cfgKey;
-// auto config = CreateStatsdConfig(DurationMetric::SUM);
-// uint64_t bucketStartTimeNs = 10000000000;
-// uint64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-// FeedEvents(config, processor);
-// vector<uint8_t> buffer;
-// ConfigMetricsReportList reports;
-// processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-//
-// EXPECT_EQ(reports.reports_size(), 1);
-// EXPECT_EQ(reports.reports(0).metrics_size(), 1);
-// // Only 1 dimension output. The tag dimension in the predicate has been aggregated.
-// EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
-//
-// auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
-// // Validate dimension value.
-// ValidateAttributionUidDimension(data.dimensions_in_what(),
-// android::util::WAKELOCK_STATE_CHANGED, 111);
-// // Validate bucket info.
-// EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 1);
-// data = reports.reports(0).metrics(0).duration_metrics().data(0);
-// // The wakelock holding interval starts from the screen off event and to the end of the 1st
-// // bucket.
-// EXPECT_EQ((unsigned long long)data.bucket_info(0).duration_nanos(), bucketSizeNs - 200);
-//}
-//
-//TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration2) {
-// ConfigKey cfgKey;
-// auto config = CreateStatsdConfig(DurationMetric::SUM);
-// uint64_t bucketStartTimeNs = 10000000000;
-// uint64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-// FeedEvents(config, processor);
-// vector<uint8_t> buffer;
-// ConfigMetricsReportList reports;
-// processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(reports.reports_size(), 1);
-// EXPECT_EQ(reports.reports(0).metrics_size(), 1);
-// EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
-// // Dump the report after the end of 2nd bucket.
-// EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 2);
-// auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
-// // Validate dimension value.
-// ValidateAttributionUidDimension(data.dimensions_in_what(),
-// android::util::WAKELOCK_STATE_CHANGED, 111);
-// // Two output buckets.
-// // The wakelock holding interval in the 1st bucket starts from the screen off event and to
-// // the end of the 1st bucket.
-// EXPECT_EQ((unsigned long long)data.bucket_info(0).duration_nanos(),
-// bucketStartTimeNs + bucketSizeNs - (bucketStartTimeNs + 200));
-// // The wakelock holding interval in the 2nd bucket starts at the beginning of the bucket and
-// // ends at the second screen on event.
-// EXPECT_EQ((unsigned long long)data.bucket_info(1).duration_nanos(), 500UL);
-//}
-//TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration3) {
-// ConfigKey cfgKey;
-// auto config = CreateStatsdConfig(DurationMetric::SUM);
-// uint64_t bucketStartTimeNs = 10000000000;
-// uint64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-// FeedEvents(config, processor);
-// vector<uint8_t> buffer;
-// ConfigMetricsReportList reports;
-//
-// std::vector<std::unique_ptr<LogEvent>> events;
-// events.push_back(
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
-// bucketStartTimeNs + 2 * bucketSizeNs + 90));
-// events.push_back(CreateAcquireWakelockEvent(attributions1, "wl3",
-// bucketStartTimeNs + 2 * bucketSizeNs + 100));
-// events.push_back(CreateReleaseWakelockEvent(attributions1, "wl3",
-// bucketStartTimeNs + 5 * bucketSizeNs + 100));
-// sortLogEventsByTimestamp(&events);
-// for (const auto& event : events) {
-// processor->OnLogEvent(event.get());
-// }
-//
-// processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(reports.reports_size(), 1);
-// EXPECT_EQ(reports.reports(0).metrics_size(), 1);
-// EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
-// EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 6);
-// auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
-// ValidateAttributionUidDimension(data.dimensions_in_what(),
-// android::util::WAKELOCK_STATE_CHANGED, 111);
-// // The last wakelock holding spans 4 buckets.
-// EXPECT_EQ((unsigned long long)data.bucket_info(2).duration_nanos(), bucketSizeNs - 100);
-// EXPECT_EQ((unsigned long long)data.bucket_info(3).duration_nanos(), bucketSizeNs);
-// EXPECT_EQ((unsigned long long)data.bucket_info(4).duration_nanos(), bucketSizeNs);
-// EXPECT_EQ((unsigned long long)data.bucket_info(5).duration_nanos(), 100UL);
-//}
-//
-//TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration1) {
-// ConfigKey cfgKey;
-// auto config = CreateStatsdConfig(DurationMetric::MAX_SPARSE);
-// uint64_t bucketStartTimeNs = 10000000000;
-// uint64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-// FeedEvents(config, processor);
-// ConfigMetricsReportList reports;
-// vector<uint8_t> buffer;
-// processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_TRUE(buffer.size() > 0);
-//
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-//
-// EXPECT_EQ(reports.reports_size(), 1);
-//
-// // When using ProtoOutputStream, if nothing written to a sub msg, it won't be treated as
-// // one. It was previsouly 1 because we had a fake onDumpReport which calls add_metric() by
-// // itself.
-// EXPECT_EQ(1, reports.reports(0).metrics_size());
-// EXPECT_EQ(0, reports.reports(0).metrics(0).duration_metrics().data_size());
-//}
-//
-//TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration2) {
-// ConfigKey cfgKey;
-// auto config = CreateStatsdConfig(DurationMetric::MAX_SPARSE);
-// uint64_t bucketStartTimeNs = 10000000000;
-// uint64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-// FeedEvents(config, processor);
-// ConfigMetricsReportList reports;
-// vector<uint8_t> buffer;
-// processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(reports.reports_size(), 1);
-// EXPECT_EQ(reports.reports(0).metrics_size(), 1);
-// EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
-// // Dump the report after the end of 2nd bucket. One dimension with one bucket.
-// EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 1);
-// auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
-// // Validate dimension value.
-// ValidateAttributionUidDimension(data.dimensions_in_what(),
-// android::util::WAKELOCK_STATE_CHANGED, 111);
-// // The max is acquire event for wl1 to screen off start.
-// EXPECT_EQ((unsigned long long)data.bucket_info(0).duration_nanos(), bucketSizeNs + 2 - 200);
-//}
-//
-//TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration3) {
-// ConfigKey cfgKey;
-// auto config = CreateStatsdConfig(DurationMetric::MAX_SPARSE);
-// uint64_t bucketStartTimeNs = 10000000000;
-// uint64_t bucketSizeNs =
-// TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
-// auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
-// EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
-// EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
-// FeedEvents(config, processor);
-// ConfigMetricsReportList reports;
-// vector<uint8_t> buffer;
-//
-// std::vector<std::unique_ptr<LogEvent>> events;
-// events.push_back(
-// CreateScreenStateChangedEvent(android::view::DisplayStateEnum::DISPLAY_STATE_OFF,
-// bucketStartTimeNs + 2 * bucketSizeNs + 90));
-// events.push_back(CreateAcquireWakelockEvent(attributions1, "wl3",
-// bucketStartTimeNs + 2 * bucketSizeNs + 100));
-// events.push_back(CreateReleaseWakelockEvent(attributions1, "wl3",
-// bucketStartTimeNs + 5 * bucketSizeNs + 100));
-// sortLogEventsByTimestamp(&events);
-// for (const auto& event : events) {
-// processor->OnLogEvent(event.get());
-// }
-//
-// processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, false, true,
-// ADB_DUMP, FAST, &buffer);
-// EXPECT_TRUE(buffer.size() > 0);
-// EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
-// backfillDimensionPath(&reports);
-// backfillStringInReport(&reports);
-// backfillStartEndTimestamp(&reports);
-// EXPECT_EQ(reports.reports_size(), 1);
-// EXPECT_EQ(reports.reports(0).metrics_size(), 1);
-// EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
-// EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 2);
-// auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
-// ValidateAttributionUidDimension(data.dimensions_in_what(),
-// android::util::WAKELOCK_STATE_CHANGED, 111);
-// // The last wakelock holding spans 4 buckets.
-// EXPECT_EQ((unsigned long long)data.bucket_info(1).duration_nanos(), 3 * bucketSizeNs);
-// EXPECT_EQ((unsigned long long)data.bucket_info(1).start_bucket_elapsed_nanos(),
-// bucketStartTimeNs + 5 * bucketSizeNs);
-// EXPECT_EQ((unsigned long long)data.bucket_info(1).end_bucket_elapsed_nanos(),
-// bucketStartTimeNs + 6 * bucketSizeNs);
-//}
+TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration1) {
+ ConfigKey cfgKey;
+ auto config = CreateStatsdConfig(DurationMetric::SUM);
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ FeedEvents(config, processor);
+ vector<uint8_t> buffer;
+ ConfigMetricsReportList reports;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, true, ADB_DUMP,
+ FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+
+ EXPECT_EQ(reports.reports_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+ // Only 1 dimension output. The tag dimension in the predicate has been aggregated.
+ EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
+
+ auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
+ // Validate dimension value.
+ ValidateAttributionUidDimension(data.dimensions_in_what(),
+ android::util::WAKELOCK_STATE_CHANGED, 111);
+ // Validate bucket info.
+ EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 1);
+ data = reports.reports(0).metrics(0).duration_metrics().data(0);
+ // The wakelock holding interval starts from the screen off event and to the end of the 1st
+ // bucket.
+ EXPECT_EQ((unsigned long long)data.bucket_info(0).duration_nanos(), bucketSizeNs - 200);
+}
+
+TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration2) {
+ ConfigKey cfgKey;
+ auto config = CreateStatsdConfig(DurationMetric::SUM);
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ FeedEvents(config, processor);
+ vector<uint8_t> buffer;
+ ConfigMetricsReportList reports;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true, ADB_DUMP,
+ FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(reports.reports_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
+ // Dump the report after the end of 2nd bucket.
+ EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 2);
+ auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
+ // Validate dimension value.
+ ValidateAttributionUidDimension(data.dimensions_in_what(),
+ android::util::WAKELOCK_STATE_CHANGED, 111);
+ // Two output buckets.
+ // The wakelock holding interval in the 1st bucket starts from the screen off event and to
+ // the end of the 1st bucket.
+ EXPECT_EQ((unsigned long long)data.bucket_info(0).duration_nanos(),
+ bucketStartTimeNs + bucketSizeNs - (bucketStartTimeNs + 200));
+ // The wakelock holding interval in the 2nd bucket starts at the beginning of the bucket and
+ // ends at the second screen on event.
+ EXPECT_EQ((unsigned long long)data.bucket_info(1).duration_nanos(), 500UL);
+}
+
+TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration3) {
+ ConfigKey cfgKey;
+ auto config = CreateStatsdConfig(DurationMetric::SUM);
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ FeedEvents(config, processor);
+ vector<uint8_t> buffer;
+ ConfigMetricsReportList reports;
+
+ std::vector<std::unique_ptr<LogEvent>> events;
+ events.push_back(
+ CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs + 90,
+ android::view::DisplayStateEnum::DISPLAY_STATE_OFF));
+ events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 100,
+ attributionUids1, attributionTags1, "wl3"));
+ events.push_back(CreateReleaseWakelockEvent(bucketStartTimeNs + 5 * bucketSizeNs + 100,
+ attributionUids1, attributionTags1, "wl3"));
+ sortLogEventsByTimestamp(&events);
+ for (const auto& event : events) {
+ processor->OnLogEvent(event.get());
+ }
+
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, false, true, ADB_DUMP,
+ FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(reports.reports_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 6);
+ auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
+ ValidateAttributionUidDimension(data.dimensions_in_what(),
+ android::util::WAKELOCK_STATE_CHANGED, 111);
+ // The last wakelock holding spans 4 buckets.
+ EXPECT_EQ((unsigned long long)data.bucket_info(2).duration_nanos(), bucketSizeNs - 100);
+ EXPECT_EQ((unsigned long long)data.bucket_info(3).duration_nanos(), bucketSizeNs);
+ EXPECT_EQ((unsigned long long)data.bucket_info(4).duration_nanos(), bucketSizeNs);
+ EXPECT_EQ((unsigned long long)data.bucket_info(5).duration_nanos(), 100UL);
+}
+
+TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration1) {
+ ConfigKey cfgKey;
+ auto config = CreateStatsdConfig(DurationMetric::MAX_SPARSE);
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ FeedEvents(config, processor);
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs - 1, false, true, ADB_DUMP,
+ FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+
+ EXPECT_EQ(reports.reports_size(), 1);
+
+ // When using ProtoOutputStream, if nothing written to a sub msg, it won't be treated as
+ // one. It was previsouly 1 because we had a fake onDumpReport which calls add_metric() by
+ // itself.
+ EXPECT_EQ(1, reports.reports(0).metrics_size());
+ EXPECT_EQ(0, reports.reports(0).metrics(0).duration_metrics().data_size());
+}
+
+TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration2) {
+ ConfigKey cfgKey;
+ auto config = CreateStatsdConfig(DurationMetric::MAX_SPARSE);
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ FeedEvents(config, processor);
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 2 * bucketSizeNs + 1, false, true, ADB_DUMP,
+ FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(reports.reports_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
+ // Dump the report after the end of 2nd bucket. One dimension with one bucket.
+ EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 1);
+ auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
+ // Validate dimension value.
+ ValidateAttributionUidDimension(data.dimensions_in_what(),
+ android::util::WAKELOCK_STATE_CHANGED, 111);
+ // The max is acquire event for wl1 to screen off start.
+ EXPECT_EQ((unsigned long long)data.bucket_info(0).duration_nanos(), bucketSizeNs + 2 - 200);
+}
+
+TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration3) {
+ ConfigKey cfgKey;
+ auto config = CreateStatsdConfig(DurationMetric::MAX_SPARSE);
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t bucketSizeNs =
+ TimeUnitToBucketSizeInMillis(config.duration_metric(0).bucket()) * 1000000LL;
+ auto processor = CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey);
+ EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+ EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+ FeedEvents(config, processor);
+ ConfigMetricsReportList reports;
+ vector<uint8_t> buffer;
+
+ std::vector<std::unique_ptr<LogEvent>> events;
+ events.push_back(
+ CreateScreenStateChangedEvent(bucketStartTimeNs + 2 * bucketSizeNs + 90,
+ android::view::DisplayStateEnum::DISPLAY_STATE_OFF));
+ events.push_back(CreateAcquireWakelockEvent(bucketStartTimeNs + 2 * bucketSizeNs + 100,
+ attributionUids1, attributionTags1, "wl3"));
+ events.push_back(CreateReleaseWakelockEvent(bucketStartTimeNs + 5 * bucketSizeNs + 100,
+ attributionUids1, attributionTags1, "wl3"));
+ sortLogEventsByTimestamp(&events);
+ for (const auto& event : events) {
+ processor->OnLogEvent(event.get());
+ }
+
+ processor->onDumpReport(cfgKey, bucketStartTimeNs + 6 * bucketSizeNs + 1, false, true, ADB_DUMP,
+ FAST, &buffer);
+ EXPECT_TRUE(buffer.size() > 0);
+ EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+ backfillDimensionPath(&reports);
+ backfillStringInReport(&reports);
+ backfillStartEndTimestamp(&reports);
+ EXPECT_EQ(reports.reports_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data_size(), 1);
+ EXPECT_EQ(reports.reports(0).metrics(0).duration_metrics().data(0).bucket_info_size(), 2);
+ auto data = reports.reports(0).metrics(0).duration_metrics().data(0);
+ ValidateAttributionUidDimension(data.dimensions_in_what(),
+ android::util::WAKELOCK_STATE_CHANGED, 111);
+ // The last wakelock holding spans 4 buckets.
+ EXPECT_EQ((unsigned long long)data.bucket_info(1).duration_nanos(), 3 * bucketSizeNs);
+ EXPECT_EQ((unsigned long long)data.bucket_info(1).start_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 5 * bucketSizeNs);
+ EXPECT_EQ((unsigned long long)data.bucket_info(1).end_bucket_elapsed_nanos(),
+ bucketStartTimeNs + 6 * bucketSizeNs);
+}
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
diff --git a/cmds/statsd/tests/external/StatsPuller_test.cpp b/cmds/statsd/tests/external/StatsPuller_test.cpp
index c0b4f43..e8200d5 100644
--- a/cmds/statsd/tests/external/StatsPuller_test.cpp
+++ b/cmds/statsd/tests/external/StatsPuller_test.cpp
@@ -15,11 +15,14 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <stdio.h>
+
#include <chrono>
#include <thread>
#include <vector>
+
#include "../metrics/metrics_test_helper.h"
#include "src/stats_log_util.h"
+#include "stats_event.h"
#include "tests/statsd_test_util.h"
#ifdef __ANDROID__
@@ -57,13 +60,22 @@
FakePuller puller;
-// TODO(b/149590301): Update this helper to use new socket schema.
-//shared_ptr<LogEvent> createSimpleEvent(int64_t eventTimeNs, int64_t value) {
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(pullTagId, eventTimeNs);
-// event->write(value);
-// event->init();
-// return event;
-//}
+std::unique_ptr<LogEvent> createSimpleEvent(int64_t eventTimeNs, int64_t value) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, pullTagId);
+ AStatsEvent_overwriteTimestamp(statsEvent, eventTimeNs);
+
+ AStatsEvent_writeInt64(statsEvent, value);
+ 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;
+}
class StatsPullerTest : public ::testing::Test {
public:
@@ -80,149 +92,148 @@
} // Anonymous namespace.
-// TODO(b/149590301): Update these tests to use new socket schema.
-//TEST_F(StatsPullerTest, PullSuccess) {
-// pullData.push_back(createSimpleEvent(1111L, 33));
-//
-// pullSuccess = true;
-//
-// vector<std::shared_ptr<LogEvent>> dataHolder;
-// EXPECT_TRUE(puller.Pull(&dataHolder));
-// EXPECT_EQ(1, dataHolder.size());
-// EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
-// EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs());
-// EXPECT_EQ(1, dataHolder[0]->size());
-// EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value);
-//
-// sleep_for(std::chrono::seconds(1));
-//
-// pullData.clear();
-// pullData.push_back(createSimpleEvent(2222L, 44));
-//
-// pullSuccess = true;
-//
-// EXPECT_TRUE(puller.Pull(&dataHolder));
-// EXPECT_EQ(1, dataHolder.size());
-// EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
-// EXPECT_EQ(2222L, dataHolder[0]->GetElapsedTimestampNs());
-// EXPECT_EQ(1, dataHolder[0]->size());
-// EXPECT_EQ(44, dataHolder[0]->getValues()[0].mValue.int_value);
-//}
-//
-//TEST_F(StatsPullerTest, PullFailAfterSuccess) {
-// pullData.push_back(createSimpleEvent(1111L, 33));
-//
-// pullSuccess = true;
-//
-// vector<std::shared_ptr<LogEvent>> dataHolder;
-// EXPECT_TRUE(puller.Pull(&dataHolder));
-// EXPECT_EQ(1, dataHolder.size());
-// EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
-// EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs());
-// EXPECT_EQ(1, dataHolder[0]->size());
-// EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value);
-//
-// sleep_for(std::chrono::seconds(1));
-//
-// pullData.clear();
-// pullData.push_back(createSimpleEvent(2222L, 44));
-//
-// pullSuccess = false;
-// dataHolder.clear();
-// EXPECT_FALSE(puller.Pull(&dataHolder));
-// EXPECT_EQ(0, dataHolder.size());
-//
-// pullSuccess = true;
-// dataHolder.clear();
-// EXPECT_FALSE(puller.Pull(&dataHolder));
-// EXPECT_EQ(0, dataHolder.size());
-//}
-//
-//// Test pull takes longer than timeout, 2nd pull happens shorter than cooldown
-//TEST_F(StatsPullerTest, PullTakeTooLongAndPullFast) {
-// pullData.push_back(createSimpleEvent(1111L, 33));
-// pullSuccess = true;
-// // timeout is 0.5
-// pullDelayNs = (long)(0.8 * NS_PER_SEC);
-//
-// vector<std::shared_ptr<LogEvent>> dataHolder;
-// EXPECT_FALSE(puller.Pull(&dataHolder));
-// EXPECT_EQ(0, dataHolder.size());
-//
-// pullData.clear();
-// pullData.push_back(createSimpleEvent(2222L, 44));
-//
-// pullSuccess = true;
-// dataHolder.clear();
-// EXPECT_FALSE(puller.Pull(&dataHolder));
-// EXPECT_EQ(0, dataHolder.size());
-//}
-//
-//TEST_F(StatsPullerTest, PullFail) {
-// pullData.push_back(createSimpleEvent(1111L, 33));
-//
-// pullSuccess = false;
-//
-// vector<std::shared_ptr<LogEvent>> dataHolder;
-// EXPECT_FALSE(puller.Pull(&dataHolder));
-// EXPECT_EQ(0, dataHolder.size());
-//}
-//
-//TEST_F(StatsPullerTest, PullTakeTooLong) {
-// pullData.push_back(createSimpleEvent(1111L, 33));
-//
-// pullSuccess = true;
-// pullDelayNs = NS_PER_SEC;
-//
-// vector<std::shared_ptr<LogEvent>> dataHolder;
-// EXPECT_FALSE(puller.Pull(&dataHolder));
-// EXPECT_EQ(0, dataHolder.size());
-//}
-//
-//TEST_F(StatsPullerTest, PullTooFast) {
-// pullData.push_back(createSimpleEvent(1111L, 33));
-//
-// pullSuccess = true;
-//
-// vector<std::shared_ptr<LogEvent>> dataHolder;
-// EXPECT_TRUE(puller.Pull(&dataHolder));
-// EXPECT_EQ(1, dataHolder.size());
-// EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
-// EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs());
-// EXPECT_EQ(1, dataHolder[0]->size());
-// EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value);
-//
-// pullData.clear();
-// pullData.push_back(createSimpleEvent(2222L, 44));
-//
-// pullSuccess = true;
-//
-// dataHolder.clear();
-// EXPECT_TRUE(puller.Pull(&dataHolder));
-// EXPECT_EQ(1, dataHolder.size());
-// EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
-// EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs());
-// EXPECT_EQ(1, dataHolder[0]->size());
-// EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value);
-//}
-//
-//TEST_F(StatsPullerTest, PullFailsAndTooFast) {
-// pullData.push_back(createSimpleEvent(1111L, 33));
-//
-// pullSuccess = false;
-//
-// vector<std::shared_ptr<LogEvent>> dataHolder;
-// EXPECT_FALSE(puller.Pull(&dataHolder));
-// EXPECT_EQ(0, dataHolder.size());
-//
-// pullData.clear();
-// pullData.push_back(createSimpleEvent(2222L, 44));
-//
-// pullSuccess = true;
-//
-// EXPECT_FALSE(puller.Pull(&dataHolder));
-// EXPECT_EQ(0, dataHolder.size());
-//}
+TEST_F(StatsPullerTest, PullSuccess) {
+ pullData.push_back(createSimpleEvent(1111L, 33));
+
+ pullSuccess = true;
+
+ vector<std::shared_ptr<LogEvent>> dataHolder;
+ EXPECT_TRUE(puller.Pull(&dataHolder));
+ EXPECT_EQ(1, dataHolder.size());
+ EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
+ EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs());
+ EXPECT_EQ(1, dataHolder[0]->size());
+ EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value);
+
+ sleep_for(std::chrono::seconds(1));
+
+ pullData.clear();
+ pullData.push_back(createSimpleEvent(2222L, 44));
+
+ pullSuccess = true;
+
+ EXPECT_TRUE(puller.Pull(&dataHolder));
+ EXPECT_EQ(1, dataHolder.size());
+ EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
+ EXPECT_EQ(2222L, dataHolder[0]->GetElapsedTimestampNs());
+ EXPECT_EQ(1, dataHolder[0]->size());
+ EXPECT_EQ(44, dataHolder[0]->getValues()[0].mValue.int_value);
+}
+
+TEST_F(StatsPullerTest, PullFailAfterSuccess) {
+ pullData.push_back(createSimpleEvent(1111L, 33));
+
+ pullSuccess = true;
+
+ vector<std::shared_ptr<LogEvent>> dataHolder;
+ EXPECT_TRUE(puller.Pull(&dataHolder));
+ EXPECT_EQ(1, dataHolder.size());
+ EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
+ EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs());
+ EXPECT_EQ(1, dataHolder[0]->size());
+ EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value);
+
+ sleep_for(std::chrono::seconds(1));
+
+ pullData.clear();
+ pullData.push_back(createSimpleEvent(2222L, 44));
+
+ pullSuccess = false;
+ dataHolder.clear();
+ EXPECT_FALSE(puller.Pull(&dataHolder));
+ EXPECT_EQ(0, dataHolder.size());
+
+ pullSuccess = true;
+ dataHolder.clear();
+ EXPECT_FALSE(puller.Pull(&dataHolder));
+ EXPECT_EQ(0, dataHolder.size());
+}
+
+// Test pull takes longer than timeout, 2nd pull happens shorter than cooldown
+TEST_F(StatsPullerTest, PullTakeTooLongAndPullFast) {
+ pullData.push_back(createSimpleEvent(1111L, 33));
+ pullSuccess = true;
+ // timeout is 0.5
+ pullDelayNs = (long)(0.8 * NS_PER_SEC);
+
+ vector<std::shared_ptr<LogEvent>> dataHolder;
+ EXPECT_FALSE(puller.Pull(&dataHolder));
+ EXPECT_EQ(0, dataHolder.size());
+
+ pullData.clear();
+ pullData.push_back(createSimpleEvent(2222L, 44));
+
+ pullSuccess = true;
+ dataHolder.clear();
+ EXPECT_FALSE(puller.Pull(&dataHolder));
+ EXPECT_EQ(0, dataHolder.size());
+}
+
+TEST_F(StatsPullerTest, PullFail) {
+ pullData.push_back(createSimpleEvent(1111L, 33));
+
+ pullSuccess = false;
+
+ vector<std::shared_ptr<LogEvent>> dataHolder;
+ EXPECT_FALSE(puller.Pull(&dataHolder));
+ EXPECT_EQ(0, dataHolder.size());
+}
+
+TEST_F(StatsPullerTest, PullTakeTooLong) {
+ pullData.push_back(createSimpleEvent(1111L, 33));
+
+ pullSuccess = true;
+ pullDelayNs = NS_PER_SEC;
+
+ vector<std::shared_ptr<LogEvent>> dataHolder;
+ EXPECT_FALSE(puller.Pull(&dataHolder));
+ EXPECT_EQ(0, dataHolder.size());
+}
+
+TEST_F(StatsPullerTest, PullTooFast) {
+ pullData.push_back(createSimpleEvent(1111L, 33));
+
+ pullSuccess = true;
+
+ vector<std::shared_ptr<LogEvent>> dataHolder;
+ EXPECT_TRUE(puller.Pull(&dataHolder));
+ EXPECT_EQ(1, dataHolder.size());
+ EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
+ EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs());
+ EXPECT_EQ(1, dataHolder[0]->size());
+ EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value);
+
+ pullData.clear();
+ pullData.push_back(createSimpleEvent(2222L, 44));
+
+ pullSuccess = true;
+
+ dataHolder.clear();
+ EXPECT_TRUE(puller.Pull(&dataHolder));
+ EXPECT_EQ(1, dataHolder.size());
+ EXPECT_EQ(pullTagId, dataHolder[0]->GetTagId());
+ EXPECT_EQ(1111L, dataHolder[0]->GetElapsedTimestampNs());
+ EXPECT_EQ(1, dataHolder[0]->size());
+ EXPECT_EQ(33, dataHolder[0]->getValues()[0].mValue.int_value);
+}
+
+TEST_F(StatsPullerTest, PullFailsAndTooFast) {
+ pullData.push_back(createSimpleEvent(1111L, 33));
+
+ pullSuccess = false;
+
+ vector<std::shared_ptr<LogEvent>> dataHolder;
+ EXPECT_FALSE(puller.Pull(&dataHolder));
+ EXPECT_EQ(0, dataHolder.size());
+
+ pullData.clear();
+ pullData.push_back(createSimpleEvent(2222L, 44));
+
+ pullSuccess = true;
+
+ EXPECT_FALSE(puller.Pull(&dataHolder));
+ EXPECT_EQ(0, dataHolder.size());
+}
} // namespace statsd
} // namespace os
diff --git a/cmds/statsd/tests/external/puller_util_test.cpp b/cmds/statsd/tests/external/puller_util_test.cpp
index 81590a2..f21954f2 100644
--- a/cmds/statsd/tests/external/puller_util_test.cpp
+++ b/cmds/statsd/tests/external/puller_util_test.cpp
@@ -13,12 +13,16 @@
// limitations under the License.
#include "external/puller_util.h"
+
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <stdio.h>
+
#include <vector>
-#include "statslog.h"
+
#include "../metrics/metrics_test_helper.h"
+#include "stats_event.h"
+#include "statslog.h"
#ifdef __ANDROID__
@@ -58,212 +62,187 @@
ret.push_back(vec);
}
}
+
+std::shared_ptr<LogEvent> makeUidLogEvent(uint64_t timestampNs, int uid, int data1, int data2) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, uidAtomTagId);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+ AStatsEvent_writeInt32(statsEvent, uid);
+ AStatsEvent_writeInt32(statsEvent, data1);
+ AStatsEvent_writeInt32(statsEvent, data2);
+ AStatsEvent_build(statsEvent);
+
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+
+ std::shared_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
+ logEvent->parseBuffer(buf, size);
+ AStatsEvent_release(statsEvent);
+ return logEvent;
+}
+
+std::shared_ptr<LogEvent> makeNonUidAtomLogEvent(uint64_t timestampNs, int data1) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, nonUidAtomTagId);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+ AStatsEvent_writeInt32(statsEvent, data1);
+ AStatsEvent_build(statsEvent);
+
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+
+ std::shared_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
+ logEvent->parseBuffer(buf, size);
+ AStatsEvent_release(statsEvent);
+ return logEvent;
+}
+
} // anonymous namespace
-// TODO(b/149590301): Update these tests to use new socket schema.
-//TEST(puller_util, MergeNoDimension) {
-// vector<shared_ptr<LogEvent>> inputData;
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(uidAtomTagId, timestamp);
-// // 30->22->31
-// event->write(isolatedUid);
-// event->write(hostNonAdditiveData);
-// event->write(isolatedAdditiveData);
-// event->init();
-// inputData.push_back(event);
-//
-// // 20->22->21
-// event = make_shared<LogEvent>(uidAtomTagId, timestamp);
-// event->write(hostUid);
-// event->write(hostNonAdditiveData);
-// event->write(hostAdditiveData);
-// event->init();
-// inputData.push_back(event);
-//
-// sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
-// EXPECT_CALL(*uidMap, getHostUidOrSelf(isolatedUid))
-// .WillRepeatedly(Return(hostUid));
-// EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid)))
-// .WillRepeatedly(ReturnArg<0>());
-// mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId, uidAdditiveFields);
-//
-// vector<vector<int>> actual;
-// extractIntoVector(inputData, actual);
-// vector<int> expectedV1 = {20, 22, 52};
-// EXPECT_EQ(1, (int)actual.size());
-// EXPECT_THAT(actual, Contains(expectedV1));
-//}
-//
-//TEST(puller_util, MergeWithDimension) {
-// vector<shared_ptr<LogEvent>> inputData;
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(uidAtomTagId, timestamp);
-// // 30->32->31
-// event->write(isolatedUid);
-// event->write(isolatedNonAdditiveData);
-// event->write(isolatedAdditiveData);
-// event->init();
-// inputData.push_back(event);
-//
-// // 20->32->21
-// event = make_shared<LogEvent>(uidAtomTagId, timestamp);
-// event->write(hostUid);
-// event->write(isolatedNonAdditiveData);
-// event->write(hostAdditiveData);
-// event->init();
-// inputData.push_back(event);
-//
-// // 20->22->21
-// event = make_shared<LogEvent>(uidAtomTagId, timestamp);
-// event->write(hostUid);
-// event->write(hostNonAdditiveData);
-// event->write(hostAdditiveData);
-// event->init();
-// inputData.push_back(event);
-//
-// sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
-// EXPECT_CALL(*uidMap, getHostUidOrSelf(isolatedUid))
-// .WillRepeatedly(Return(hostUid));
-// EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid)))
-// .WillRepeatedly(ReturnArg<0>());
-// mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId, uidAdditiveFields);
-//
-// vector<vector<int>> actual;
-// extractIntoVector(inputData, actual);
-// vector<int> expectedV1 = {20, 22, 21};
-// vector<int> expectedV2 = {20, 32, 52};
-// EXPECT_EQ(2, (int)actual.size());
-// EXPECT_THAT(actual, Contains(expectedV1));
-// EXPECT_THAT(actual, Contains(expectedV2));
-//}
-//
-//TEST(puller_util, NoMergeHostUidOnly) {
-// vector<shared_ptr<LogEvent>> inputData;
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(uidAtomTagId, timestamp);
-// // 20->32->31
-// event->write(hostUid);
-// event->write(isolatedNonAdditiveData);
-// event->write(isolatedAdditiveData);
-// event->init();
-// inputData.push_back(event);
-//
-// // 20->22->21
-// event = make_shared<LogEvent>(uidAtomTagId, timestamp);
-// event->write(hostUid);
-// event->write(hostNonAdditiveData);
-// event->write(hostAdditiveData);
-// event->init();
-// inputData.push_back(event);
-//
-// sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
-// EXPECT_CALL(*uidMap, getHostUidOrSelf(isolatedUid))
-// .WillRepeatedly(Return(hostUid));
-// EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid)))
-// .WillRepeatedly(ReturnArg<0>());
-// mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId, uidAdditiveFields);
-//
-// // 20->32->31
-// // 20->22->21
-// vector<vector<int>> actual;
-// extractIntoVector(inputData, actual);
-// vector<int> expectedV1 = {20, 32, 31};
-// vector<int> expectedV2 = {20, 22, 21};
-// EXPECT_EQ(2, (int)actual.size());
-// EXPECT_THAT(actual, Contains(expectedV1));
-// EXPECT_THAT(actual, Contains(expectedV2));
-//}
-//
-//TEST(puller_util, IsolatedUidOnly) {
-// vector<shared_ptr<LogEvent>> inputData;
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(uidAtomTagId, timestamp);
-// // 30->32->31
-// event->write(hostUid);
-// event->write(isolatedNonAdditiveData);
-// event->write(isolatedAdditiveData);
-// event->init();
-// inputData.push_back(event);
-//
-// // 30->22->21
-// event = make_shared<LogEvent>(uidAtomTagId, timestamp);
-// event->write(hostUid);
-// event->write(hostNonAdditiveData);
-// event->write(hostAdditiveData);
-// event->init();
-// inputData.push_back(event);
-//
-// sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
-// EXPECT_CALL(*uidMap, getHostUidOrSelf(isolatedUid))
-// .WillRepeatedly(Return(hostUid));
-// EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid)))
-// .WillRepeatedly(ReturnArg<0>());
-// mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId, uidAdditiveFields);
-//
-// // 20->32->31
-// // 20->22->21
-// vector<vector<int>> actual;
-// extractIntoVector(inputData, actual);
-// vector<int> expectedV1 = {20, 32, 31};
-// vector<int> expectedV2 = {20, 22, 21};
-// EXPECT_EQ(2, (int)actual.size());
-// EXPECT_THAT(actual, Contains(expectedV1));
-// EXPECT_THAT(actual, Contains(expectedV2));
-//}
-//
-//TEST(puller_util, MultipleIsolatedUidToOneHostUid) {
-// vector<shared_ptr<LogEvent>> inputData;
-// shared_ptr<LogEvent> event = make_shared<LogEvent>(uidAtomTagId, timestamp);
-// // 30->32->31
-// event->write(isolatedUid);
-// event->write(isolatedNonAdditiveData);
-// event->write(isolatedAdditiveData);
-// event->init();
-// inputData.push_back(event);
-//
-// // 31->32->21
-// event = make_shared<LogEvent>(uidAtomTagId, timestamp);
-// event->write(isolatedUid + 1);
-// event->write(isolatedNonAdditiveData);
-// event->write(hostAdditiveData);
-// event->init();
-// inputData.push_back(event);
-//
-// // 20->32->21
-// event = make_shared<LogEvent>(uidAtomTagId, timestamp);
-// event->write(hostUid);
-// event->write(isolatedNonAdditiveData);
-// event->write(hostAdditiveData);
-// event->init();
-// inputData.push_back(event);
-//
-// sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
-// EXPECT_CALL(*uidMap, getHostUidOrSelf(_)).WillRepeatedly(Return(hostUid));
-// mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId, uidAdditiveFields);
-//
-// vector<vector<int>> actual;
-// extractIntoVector(inputData, actual);
-// vector<int> expectedV1 = {20, 32, 73};
-// EXPECT_EQ(1, (int)actual.size());
-// EXPECT_THAT(actual, Contains(expectedV1));
-//}
-//
-//TEST(puller_util, NoNeedToMerge) {
-// vector<shared_ptr<LogEvent>> inputData;
-// shared_ptr<LogEvent> event =
-// make_shared<LogEvent>(nonUidAtomTagId, timestamp);
-// // 32
-// event->write(isolatedNonAdditiveData);
-// event->init();
-// inputData.push_back(event);
-//
-// event = make_shared<LogEvent>(nonUidAtomTagId, timestamp);
-// // 22
-// event->write(hostNonAdditiveData);
-// event->init();
-// inputData.push_back(event);
-//
-// sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
-// mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, nonUidAtomTagId, {} /*no additive fields*/);
-//
-// EXPECT_EQ(2, (int)inputData.size());
-//}
+TEST(puller_util, MergeNoDimension) {
+ vector<shared_ptr<LogEvent>> inputData;
+
+ // 30->22->31
+ inputData.push_back(
+ makeUidLogEvent(timestamp, isolatedUid, hostNonAdditiveData, isolatedAdditiveData));
+
+ // 20->22->21
+ inputData.push_back(makeUidLogEvent(timestamp, hostUid, hostNonAdditiveData, hostAdditiveData));
+
+ sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
+ EXPECT_CALL(*uidMap, getHostUidOrSelf(isolatedUid)).WillRepeatedly(Return(hostUid));
+ EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid))).WillRepeatedly(ReturnArg<0>());
+ mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId, uidAdditiveFields);
+
+ vector<vector<int>> actual;
+ extractIntoVector(inputData, actual);
+ vector<int> expectedV1 = {20, 22, 52};
+ EXPECT_EQ(1, (int)actual.size());
+ EXPECT_THAT(actual, Contains(expectedV1));
+}
+
+TEST(puller_util, MergeWithDimension) {
+ vector<shared_ptr<LogEvent>> inputData;
+
+ // 30->32->31
+ inputData.push_back(
+ makeUidLogEvent(timestamp, isolatedUid, isolatedNonAdditiveData, isolatedAdditiveData));
+
+ // 20->32->21
+ inputData.push_back(
+ makeUidLogEvent(timestamp, hostUid, isolatedNonAdditiveData, hostAdditiveData));
+
+ // 20->22->21
+ inputData.push_back(makeUidLogEvent(timestamp, hostUid, hostNonAdditiveData, hostAdditiveData));
+
+ sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
+ EXPECT_CALL(*uidMap, getHostUidOrSelf(isolatedUid)).WillRepeatedly(Return(hostUid));
+ EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid))).WillRepeatedly(ReturnArg<0>());
+ mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId, uidAdditiveFields);
+
+ vector<vector<int>> actual;
+ extractIntoVector(inputData, actual);
+ vector<int> expectedV1 = {20, 22, 21};
+ vector<int> expectedV2 = {20, 32, 52};
+ EXPECT_EQ(2, (int)actual.size());
+ EXPECT_THAT(actual, Contains(expectedV1));
+ EXPECT_THAT(actual, Contains(expectedV2));
+}
+
+TEST(puller_util, NoMergeHostUidOnly) {
+ vector<shared_ptr<LogEvent>> inputData;
+
+ // 20->32->31
+ inputData.push_back(
+ makeUidLogEvent(timestamp, hostUid, isolatedNonAdditiveData, isolatedAdditiveData));
+
+ // 20->22->21
+ inputData.push_back(makeUidLogEvent(timestamp, hostUid, hostNonAdditiveData, hostAdditiveData));
+
+ sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
+ EXPECT_CALL(*uidMap, getHostUidOrSelf(isolatedUid)).WillRepeatedly(Return(hostUid));
+ EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid))).WillRepeatedly(ReturnArg<0>());
+ mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId, uidAdditiveFields);
+
+ // 20->32->31
+ // 20->22->21
+ vector<vector<int>> actual;
+ extractIntoVector(inputData, actual);
+ vector<int> expectedV1 = {20, 32, 31};
+ vector<int> expectedV2 = {20, 22, 21};
+ EXPECT_EQ(2, (int)actual.size());
+ EXPECT_THAT(actual, Contains(expectedV1));
+ EXPECT_THAT(actual, Contains(expectedV2));
+}
+
+TEST(puller_util, IsolatedUidOnly) {
+ vector<shared_ptr<LogEvent>> inputData;
+
+ // 30->32->31
+ inputData.push_back(
+ makeUidLogEvent(timestamp, hostUid, isolatedNonAdditiveData, isolatedAdditiveData));
+
+ // 30->22->21
+ inputData.push_back(makeUidLogEvent(timestamp, hostUid, hostNonAdditiveData, hostAdditiveData));
+
+ sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
+ EXPECT_CALL(*uidMap, getHostUidOrSelf(isolatedUid)).WillRepeatedly(Return(hostUid));
+ EXPECT_CALL(*uidMap, getHostUidOrSelf(Ne(isolatedUid))).WillRepeatedly(ReturnArg<0>());
+ mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId, uidAdditiveFields);
+
+ // 20->32->31
+ // 20->22->21
+ vector<vector<int>> actual;
+ extractIntoVector(inputData, actual);
+ vector<int> expectedV1 = {20, 32, 31};
+ vector<int> expectedV2 = {20, 22, 21};
+ EXPECT_EQ(2, (int)actual.size());
+ EXPECT_THAT(actual, Contains(expectedV1));
+ EXPECT_THAT(actual, Contains(expectedV2));
+}
+
+TEST(puller_util, MultipleIsolatedUidToOneHostUid) {
+ vector<shared_ptr<LogEvent>> inputData;
+
+ // 30->32->31
+ inputData.push_back(
+ makeUidLogEvent(timestamp, isolatedUid, isolatedNonAdditiveData, isolatedAdditiveData));
+
+ // 31->32->21
+ inputData.push_back(
+ makeUidLogEvent(timestamp, isolatedUid + 1, isolatedNonAdditiveData, hostAdditiveData));
+
+ // 20->32->21
+ inputData.push_back(
+ makeUidLogEvent(timestamp, hostUid, isolatedNonAdditiveData, hostAdditiveData));
+
+ sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
+ EXPECT_CALL(*uidMap, getHostUidOrSelf(_)).WillRepeatedly(Return(hostUid));
+ mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, uidAtomTagId, uidAdditiveFields);
+
+ vector<vector<int>> actual;
+ extractIntoVector(inputData, actual);
+ vector<int> expectedV1 = {20, 32, 73};
+ EXPECT_EQ(1, (int)actual.size());
+ EXPECT_THAT(actual, Contains(expectedV1));
+}
+
+TEST(puller_util, NoNeedToMerge) {
+ vector<shared_ptr<LogEvent>> inputData;
+
+ // 32
+ inputData.push_back(makeNonUidAtomLogEvent(timestamp, isolatedNonAdditiveData));
+
+ // 22
+ inputData.push_back(makeNonUidAtomLogEvent(timestamp, hostNonAdditiveData));
+
+ sp<MockUidMap> uidMap = new NaggyMock<MockUidMap>();
+ mapAndMergeIsolatedUidsToHostUid(inputData, uidMap, nonUidAtomTagId, {} /*no additive fields*/);
+
+ EXPECT_EQ(2, (int)inputData.size());
+}
} // namespace statsd
} // namespace os
diff --git a/cmds/statsd/tests/log_event/LogEventQueue_test.cpp b/cmds/statsd/tests/log_event/LogEventQueue_test.cpp
index c4407f4..6dc041f 100644
--- a/cmds/statsd/tests/log_event/LogEventQueue_test.cpp
+++ b/cmds/statsd/tests/log_event/LogEventQueue_test.cpp
@@ -42,7 +42,7 @@
size_t size;
uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
- std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/-1, /*pid=*/-1);
+ std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0);
logEvent->parseBuffer(buf, size);
AStatsEvent_release(statsEvent);
return logEvent;
diff --git a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
index b882678..d55996c 100644
--- a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
@@ -13,16 +13,19 @@
// limitations under the License.
#include "src/metrics/CountMetricProducer.h"
-#include "src/stats_log_util.h"
-#include "metrics_test_helper.h"
-#include "tests/statsd_test_util.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <math.h>
#include <stdio.h>
+
#include <vector>
+#include "metrics_test_helper.h"
+#include "src/stats_log_util.h"
+#include "stats_event.h"
+#include "tests/statsd_test_util.h"
+
using namespace testing;
using android::sp;
using std::set;
@@ -37,366 +40,392 @@
const ConfigKey kConfigKey(0, 12345);
-// TODO(b/149590301): Update these tests to use new socket schema.
-//TEST(CountMetricProducerTest, TestFirstBucket) {
-// CountMetric metric;
-// metric.set_id(1);
-// metric.set_bucket(ONE_MINUTE);
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//
-// CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, 5,
-// 600 * NS_PER_SEC + NS_PER_SEC / 2);
-// EXPECT_EQ(600500000000, countProducer.mCurrentBucketStartTimeNs);
-// EXPECT_EQ(10, countProducer.mCurrentBucketNum);
-// EXPECT_EQ(660000000005, countProducer.getCurrentBucketEndTimeNs());
-//}
-//
-//TEST(CountMetricProducerTest, TestNonDimensionalEvents) {
-// int64_t bucketStartTimeNs = 10000000000;
-// int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-// int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
-// int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
-// int tagId = 1;
-//
-// CountMetric metric;
-// metric.set_id(1);
-// metric.set_bucket(ONE_MINUTE);
-//
-// LogEvent event1(tagId, bucketStartTimeNs + 1);
-// event1.init();
-// LogEvent event2(tagId, bucketStartTimeNs + 2);
-// event2.init();
-//
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//
-// CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-// bucketStartTimeNs, bucketStartTimeNs);
-//
-// // 2 events in bucket 1.
-// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
-// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
-//
-// // Flushes at event #2.
-// countProducer.flushIfNeededLocked(bucketStartTimeNs + 2);
-// EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
-//
-// // Flushes.
-// countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
-// EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
-// EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
-// countProducer.mPastBuckets.end());
-// const auto& buckets = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-// EXPECT_EQ(1UL, buckets.size());
-// EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs);
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[0].mBucketEndNs);
-// EXPECT_EQ(2LL, buckets[0].mCount);
-//
-// // 1 matched event happens in bucket 2.
-// LogEvent event3(tagId, bucketStartTimeNs + bucketSizeNs + 2);
-// event3.init();
-//
-// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
-// countProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
-// EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
-// EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
-// countProducer.mPastBuckets.end());
-// EXPECT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-// const auto& bucketInfo2 = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][1];
-// EXPECT_EQ(bucket2StartTimeNs, bucketInfo2.mBucketStartNs);
-// EXPECT_EQ(bucket2StartTimeNs + bucketSizeNs, bucketInfo2.mBucketEndNs);
-// EXPECT_EQ(1LL, bucketInfo2.mCount);
-//
-// // nothing happens in bucket 3. we should not record anything for bucket 3.
-// countProducer.flushIfNeededLocked(bucketStartTimeNs + 3 * bucketSizeNs + 1);
-// EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
-// EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
-// countProducer.mPastBuckets.end());
-// const auto& buckets3 = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-// EXPECT_EQ(2UL, buckets3.size());
-//}
-//
-//TEST(CountMetricProducerTest, TestEventsWithNonSlicedCondition) {
-// int64_t bucketStartTimeNs = 10000000000;
-// int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-//
-// CountMetric metric;
-// metric.set_id(1);
-// metric.set_bucket(ONE_MINUTE);
-// metric.set_condition(StringToId("SCREEN_ON"));
-//
-// LogEvent event1(1, bucketStartTimeNs + 1);
-// event1.init();
-//
-// LogEvent event2(1, bucketStartTimeNs + 10);
-// event2.init();
-//
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-//
-// CountMetricProducer countProducer(kConfigKey, metric, 1, wizard, bucketStartTimeNs,
-// bucketStartTimeNs);
-//
-// countProducer.onConditionChanged(true, bucketStartTimeNs);
-// countProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
-// EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
-//
-// countProducer.onConditionChanged(false /*new condition*/, bucketStartTimeNs + 2);
-// // Upon this match event, the matched event1 is flushed.
-// countProducer.onMatchedLogEvent(1 /*matcher index*/, event2);
-// EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
-//
-// countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
-// EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
-// EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
-// countProducer.mPastBuckets.end());
-// {
-// const auto& buckets = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-// EXPECT_EQ(1UL, buckets.size());
-// const auto& bucketInfo = buckets[0];
-// EXPECT_EQ(bucketStartTimeNs, bucketInfo.mBucketStartNs);
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.mBucketEndNs);
-// EXPECT_EQ(1LL, bucketInfo.mCount);
-// }
-//}
-//
-//TEST(CountMetricProducerTest, TestEventsWithSlicedCondition) {
-// int64_t bucketStartTimeNs = 10000000000;
-// int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-//
-// int tagId = 1;
-// int conditionTagId = 2;
-//
-// CountMetric metric;
-// metric.set_id(1);
-// metric.set_bucket(ONE_MINUTE);
-// metric.set_condition(StringToId("APP_IN_BACKGROUND_PER_UID_AND_SCREEN_ON"));
-// MetricConditionLink* link = metric.add_links();
-// link->set_condition(StringToId("APP_IN_BACKGROUND_PER_UID"));
-// buildSimpleAtomFieldMatcher(tagId, 1, link->mutable_fields_in_what());
-// buildSimpleAtomFieldMatcher(conditionTagId, 2, link->mutable_fields_in_condition());
-//
-// LogEvent event1(tagId, bucketStartTimeNs + 1);
-// event1.write("111"); // uid
-// event1.init();
-// ConditionKey key1;
-// key1[StringToId("APP_IN_BACKGROUND_PER_UID")] =
-// {getMockedDimensionKey(conditionTagId, 2, "111")};
-//
-// LogEvent event2(tagId, bucketStartTimeNs + 10);
-// event2.write("222"); // uid
-// event2.init();
-// ConditionKey key2;
-// key2[StringToId("APP_IN_BACKGROUND_PER_UID")] =
-// {getMockedDimensionKey(conditionTagId, 2, "222")};
-//
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-// EXPECT_CALL(*wizard, query(_, key1, _)).WillOnce(Return(ConditionState::kFalse));
-//
-// EXPECT_CALL(*wizard, query(_, key2, _)).WillOnce(Return(ConditionState::kTrue));
-//
-// CountMetricProducer countProducer(kConfigKey, metric, 1 /*condition tracker index*/, wizard,
-// bucketStartTimeNs, bucketStartTimeNs);
-//
-// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
-// countProducer.flushIfNeededLocked(bucketStartTimeNs + 1);
-// EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
-//
-// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
-// countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
-// EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
-// EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
-// countProducer.mPastBuckets.end());
-// const auto& buckets = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-// EXPECT_EQ(1UL, buckets.size());
-// const auto& bucketInfo = buckets[0];
-// EXPECT_EQ(bucketStartTimeNs, bucketInfo.mBucketStartNs);
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.mBucketEndNs);
-// EXPECT_EQ(1LL, bucketInfo.mCount);
-//}
-//
-//TEST(CountMetricProducerTest, TestEventWithAppUpgrade) {
-// sp<AlarmMonitor> alarmMonitor;
-// int64_t bucketStartTimeNs = 10000000000;
-// int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-// int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
-//
-// int tagId = 1;
-// int conditionTagId = 2;
-//
-// CountMetric metric;
-// metric.set_id(1);
-// metric.set_bucket(ONE_MINUTE);
-// Alert alert;
-// alert.set_num_buckets(3);
-// alert.set_trigger_if_sum_gt(2);
-// LogEvent event1(tagId, bucketStartTimeNs + 1);
-// event1.write("111"); // uid
-// event1.init();
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-// CountMetricProducer countProducer(kConfigKey, metric, -1 /* no condition */, wizard,
-// bucketStartTimeNs, bucketStartTimeNs);
-//
-// sp<AnomalyTracker> anomalyTracker = countProducer.addAnomalyTracker(alert, alarmMonitor);
-// EXPECT_TRUE(anomalyTracker != nullptr);
-//
-// // Bucket is flushed yet.
-// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
-// EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
-// EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
-//
-// // App upgrade forces bucket flush.
-// // Check that there's a past bucket and the bucket end is not adjusted.
-// countProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
-// EXPECT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-// EXPECT_EQ((long long)bucketStartTimeNs,
-// countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs);
-// EXPECT_EQ((long long)eventUpgradeTimeNs,
-// countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketEndNs);
-// EXPECT_EQ(eventUpgradeTimeNs, countProducer.mCurrentBucketStartTimeNs);
-// // Anomaly tracker only contains full buckets.
-// EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
-//
-// int64_t lastEndTimeNs = countProducer.getCurrentBucketEndTimeNs();
-// // Next event occurs in same bucket as partial bucket created.
-// LogEvent event2(tagId, bucketStartTimeNs + 59 * NS_PER_SEC + 10);
-// event2.write("222"); // uid
-// event2.init();
-// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
-// EXPECT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-// EXPECT_EQ(eventUpgradeTimeNs, countProducer.mCurrentBucketStartTimeNs);
-// EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
-//
-// // Third event in following bucket.
-// LogEvent event3(tagId, bucketStartTimeNs + 62 * NS_PER_SEC + 10);
-// event3.write("333"); // uid
-// event3.init();
-// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
-// EXPECT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-// EXPECT_EQ(lastEndTimeNs, countProducer.mCurrentBucketStartTimeNs);
-// EXPECT_EQ(2, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
-//}
-//
-//TEST(CountMetricProducerTest, TestEventWithAppUpgradeInNextBucket) {
-// int64_t bucketStartTimeNs = 10000000000;
-// int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-// int64_t eventUpgradeTimeNs = bucketStartTimeNs + 65 * NS_PER_SEC;
-//
-// int tagId = 1;
-// int conditionTagId = 2;
-//
-// CountMetric metric;
-// metric.set_id(1);
-// metric.set_bucket(ONE_MINUTE);
-// LogEvent event1(tagId, bucketStartTimeNs + 1);
-// event1.write("111"); // uid
-// event1.init();
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-// CountMetricProducer countProducer(kConfigKey, metric, -1 /* no condition */, wizard,
-// bucketStartTimeNs, bucketStartTimeNs);
-//
-// // Bucket is flushed yet.
-// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
-// EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
-//
-// // App upgrade forces bucket flush.
-// // Check that there's a past bucket and the bucket end is not adjusted.
-// countProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
-// EXPECT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-// EXPECT_EQ((int64_t)bucketStartTimeNs,
-// countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs);
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
-// countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketEndNs);
-// EXPECT_EQ(eventUpgradeTimeNs, countProducer.mCurrentBucketStartTimeNs);
-//
-// // Next event occurs in same bucket as partial bucket created.
-// LogEvent event2(tagId, bucketStartTimeNs + 70 * NS_PER_SEC + 10);
-// event2.write("222"); // uid
-// event2.init();
-// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
-// EXPECT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-//
-// // Third event in following bucket.
-// LogEvent event3(tagId, bucketStartTimeNs + 121 * NS_PER_SEC + 10);
-// event3.write("333"); // uid
-// event3.init();
-// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
-// EXPECT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-// EXPECT_EQ((int64_t)eventUpgradeTimeNs,
-// countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][1].mBucketStartNs);
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
-// countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][1].mBucketEndNs);
-//}
-//
-//TEST(CountMetricProducerTest, TestAnomalyDetectionUnSliced) {
-// sp<AlarmMonitor> alarmMonitor;
-// Alert alert;
-// alert.set_id(11);
-// alert.set_metric_id(1);
-// alert.set_trigger_if_sum_gt(2);
-// alert.set_num_buckets(2);
-// const int32_t refPeriodSec = 1;
-// alert.set_refractory_period_secs(refPeriodSec);
-//
-// int64_t bucketStartTimeNs = 10000000000;
-// int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-// int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
-// int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
-//
-// CountMetric metric;
-// metric.set_id(1);
-// metric.set_bucket(ONE_MINUTE);
-//
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-// CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-// bucketStartTimeNs, bucketStartTimeNs);
-//
-// sp<AnomalyTracker> anomalyTracker = countProducer.addAnomalyTracker(alert, alarmMonitor);
-//
-// int tagId = 1;
-// LogEvent event1(tagId, bucketStartTimeNs + 1);
-// event1.init();
-// LogEvent event2(tagId, bucketStartTimeNs + 2);
-// event2.init();
-// LogEvent event3(tagId, bucketStartTimeNs + 2 * bucketSizeNs + 1);
-// event3.init();
-// LogEvent event4(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 1);
-// event4.init();
-// LogEvent event5(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 2);
-// event5.init();
-// LogEvent event6(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 3);
-// event6.init();
-// LogEvent event7(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 2 * NS_PER_SEC);
-// event7.init();
-//
-// // Two events in bucket #0.
-// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
-// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
-//
-// EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
-// EXPECT_EQ(2L, countProducer.mCurrentSlicedCounter->begin()->second);
-// EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
-//
-// // One event in bucket #2. No alarm as bucket #0 is trashed out.
-// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
-// EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
-// EXPECT_EQ(1L, countProducer.mCurrentSlicedCounter->begin()->second);
-// EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
-//
-// // Two events in bucket #3.
-// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event4);
-// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event5);
-// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event6);
-// EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
-// EXPECT_EQ(3L, countProducer.mCurrentSlicedCounter->begin()->second);
-// // Anomaly at event 6 is within refractory period. The alarm is at event 5 timestamp not event 6
-// EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
-// std::ceil(1.0 * event5.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
-//
-// countProducer.onMatchedLogEvent(1 /*log matcher index*/, event7);
-// EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
-// EXPECT_EQ(4L, countProducer.mCurrentSlicedCounter->begin()->second);
-// EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
-// std::ceil(1.0 * event7.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
-//}
+namespace {
+
+void makeLogEvent(LogEvent* logEvent, int64_t timestampNs, int atomId) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, atomId);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+ AStatsEvent_build(statsEvent);
+
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+ logEvent->parseBuffer(buf, size);
+ AStatsEvent_release(statsEvent);
+}
+
+void makeLogEvent(LogEvent* logEvent, int64_t timestampNs, int atomId, string uid) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, atomId);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+ AStatsEvent_writeString(statsEvent, uid.c_str());
+ AStatsEvent_build(statsEvent);
+
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+ logEvent->parseBuffer(buf, size);
+ AStatsEvent_release(statsEvent);
+}
+
+} // namespace
+
+TEST(CountMetricProducerTest, TestFirstBucket) {
+ CountMetric metric;
+ metric.set_id(1);
+ metric.set_bucket(ONE_MINUTE);
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+ CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, 5,
+ 600 * NS_PER_SEC + NS_PER_SEC / 2);
+ EXPECT_EQ(600500000000, countProducer.mCurrentBucketStartTimeNs);
+ EXPECT_EQ(10, countProducer.mCurrentBucketNum);
+ EXPECT_EQ(660000000005, countProducer.getCurrentBucketEndTimeNs());
+}
+
+TEST(CountMetricProducerTest, TestNonDimensionalEvents) {
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+ int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
+ int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
+ int tagId = 1;
+
+ CountMetric metric;
+ metric.set_id(1);
+ metric.set_bucket(ONE_MINUTE);
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+ CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+ bucketStartTimeNs, bucketStartTimeNs);
+
+ // 2 events in bucket 1.
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event1, bucketStartTimeNs + 1, tagId);
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event2, bucketStartTimeNs + 2, tagId);
+
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
+
+ // Flushes at event #2.
+ countProducer.flushIfNeededLocked(bucketStartTimeNs + 2);
+ EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
+
+ // Flushes.
+ countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
+ EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
+ EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
+ countProducer.mPastBuckets.end());
+ const auto& buckets = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+ EXPECT_EQ(1UL, buckets.size());
+ EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs);
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[0].mBucketEndNs);
+ EXPECT_EQ(2LL, buckets[0].mCount);
+
+ // 1 matched event happens in bucket 2.
+ LogEvent event3(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event3, bucketStartTimeNs + bucketSizeNs + 2, tagId);
+
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
+
+ countProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
+ EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
+ EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
+ countProducer.mPastBuckets.end());
+ EXPECT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ const auto& bucketInfo2 = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][1];
+ EXPECT_EQ(bucket2StartTimeNs, bucketInfo2.mBucketStartNs);
+ EXPECT_EQ(bucket2StartTimeNs + bucketSizeNs, bucketInfo2.mBucketEndNs);
+ EXPECT_EQ(1LL, bucketInfo2.mCount);
+
+ // nothing happens in bucket 3. we should not record anything for bucket 3.
+ countProducer.flushIfNeededLocked(bucketStartTimeNs + 3 * bucketSizeNs + 1);
+ EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
+ EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
+ countProducer.mPastBuckets.end());
+ const auto& buckets3 = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+ EXPECT_EQ(2UL, buckets3.size());
+}
+
+TEST(CountMetricProducerTest, TestEventsWithNonSlicedCondition) {
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+
+ CountMetric metric;
+ metric.set_id(1);
+ metric.set_bucket(ONE_MINUTE);
+ metric.set_condition(StringToId("SCREEN_ON"));
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+ CountMetricProducer countProducer(kConfigKey, metric, 1, wizard, bucketStartTimeNs,
+ bucketStartTimeNs);
+
+ countProducer.onConditionChanged(true, bucketStartTimeNs);
+
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event1, bucketStartTimeNs + 1, /*atomId=*/1);
+ countProducer.onMatchedLogEvent(1 /*matcher index*/, event1);
+
+ EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
+
+ countProducer.onConditionChanged(false /*new condition*/, bucketStartTimeNs + 2);
+
+ // Upon this match event, the matched event1 is flushed.
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event2, bucketStartTimeNs + 10, /*atomId=*/1);
+ countProducer.onMatchedLogEvent(1 /*matcher index*/, event2);
+ EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
+
+ countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
+ EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
+ EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
+ countProducer.mPastBuckets.end());
+
+ const auto& buckets = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+ EXPECT_EQ(1UL, buckets.size());
+ const auto& bucketInfo = buckets[0];
+ EXPECT_EQ(bucketStartTimeNs, bucketInfo.mBucketStartNs);
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.mBucketEndNs);
+ EXPECT_EQ(1LL, bucketInfo.mCount);
+}
+
+TEST(CountMetricProducerTest, TestEventsWithSlicedCondition) {
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+
+ int tagId = 1;
+ int conditionTagId = 2;
+
+ CountMetric metric;
+ metric.set_id(1);
+ metric.set_bucket(ONE_MINUTE);
+ metric.set_condition(StringToId("APP_IN_BACKGROUND_PER_UID_AND_SCREEN_ON"));
+ MetricConditionLink* link = metric.add_links();
+ link->set_condition(StringToId("APP_IN_BACKGROUND_PER_UID"));
+ buildSimpleAtomFieldMatcher(tagId, 1, link->mutable_fields_in_what());
+ buildSimpleAtomFieldMatcher(conditionTagId, 2, link->mutable_fields_in_condition());
+
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event1, bucketStartTimeNs + 1, tagId, /*uid=*/"111");
+
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event2, bucketStartTimeNs + 10, tagId, /*uid=*/"222");
+
+ ConditionKey key1;
+ key1[StringToId("APP_IN_BACKGROUND_PER_UID")] = {
+ getMockedDimensionKey(conditionTagId, 2, "111")};
+
+ ConditionKey key2;
+ key2[StringToId("APP_IN_BACKGROUND_PER_UID")] = {
+ getMockedDimensionKey(conditionTagId, 2, "222")};
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ EXPECT_CALL(*wizard, query(_, key1, _)).WillOnce(Return(ConditionState::kFalse));
+
+ EXPECT_CALL(*wizard, query(_, key2, _)).WillOnce(Return(ConditionState::kTrue));
+
+ CountMetricProducer countProducer(kConfigKey, metric, 1 /*condition tracker index*/, wizard,
+ bucketStartTimeNs, bucketStartTimeNs);
+
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
+ countProducer.flushIfNeededLocked(bucketStartTimeNs + 1);
+ EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
+
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
+ countProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
+ EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
+ EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
+ countProducer.mPastBuckets.end());
+ const auto& buckets = countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+ EXPECT_EQ(1UL, buckets.size());
+ const auto& bucketInfo = buckets[0];
+ EXPECT_EQ(bucketStartTimeNs, bucketInfo.mBucketStartNs);
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.mBucketEndNs);
+ EXPECT_EQ(1LL, bucketInfo.mCount);
+}
+
+TEST(CountMetricProducerTest, TestEventWithAppUpgrade) {
+ sp<AlarmMonitor> alarmMonitor;
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+ int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
+
+ int tagId = 1;
+ int conditionTagId = 2;
+
+ CountMetric metric;
+ metric.set_id(1);
+ metric.set_bucket(ONE_MINUTE);
+ Alert alert;
+ alert.set_num_buckets(3);
+ alert.set_trigger_if_sum_gt(2);
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ CountMetricProducer countProducer(kConfigKey, metric, -1 /* no condition */, wizard,
+ bucketStartTimeNs, bucketStartTimeNs);
+
+ sp<AnomalyTracker> anomalyTracker = countProducer.addAnomalyTracker(alert, alarmMonitor);
+ EXPECT_TRUE(anomalyTracker != nullptr);
+
+ // Bucket is flushed yet.
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event1, bucketStartTimeNs + 1, tagId, /*uid=*/"111");
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
+ EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
+ EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
+
+ // App upgrade forces bucket flush.
+ // Check that there's a past bucket and the bucket end is not adjusted.
+ countProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
+ EXPECT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ EXPECT_EQ((long long)bucketStartTimeNs,
+ countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs);
+ EXPECT_EQ((long long)eventUpgradeTimeNs,
+ countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketEndNs);
+ EXPECT_EQ(eventUpgradeTimeNs, countProducer.mCurrentBucketStartTimeNs);
+ // Anomaly tracker only contains full buckets.
+ EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
+
+ int64_t lastEndTimeNs = countProducer.getCurrentBucketEndTimeNs();
+ // Next event occurs in same bucket as partial bucket created.
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event2, bucketStartTimeNs + 59 * NS_PER_SEC + 10, tagId, /*uid=*/"222");
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
+ EXPECT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ EXPECT_EQ(eventUpgradeTimeNs, countProducer.mCurrentBucketStartTimeNs);
+ EXPECT_EQ(0, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
+
+ // Third event in following bucket.
+ LogEvent event3(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event3, bucketStartTimeNs + 62 * NS_PER_SEC + 10, tagId, /*uid=*/"333");
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
+ EXPECT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ EXPECT_EQ(lastEndTimeNs, countProducer.mCurrentBucketStartTimeNs);
+ EXPECT_EQ(2, anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
+}
+
+TEST(CountMetricProducerTest, TestEventWithAppUpgradeInNextBucket) {
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+ int64_t eventUpgradeTimeNs = bucketStartTimeNs + 65 * NS_PER_SEC;
+
+ int tagId = 1;
+ int conditionTagId = 2;
+
+ CountMetric metric;
+ metric.set_id(1);
+ metric.set_bucket(ONE_MINUTE);
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ CountMetricProducer countProducer(kConfigKey, metric, -1 /* no condition */, wizard,
+ bucketStartTimeNs, bucketStartTimeNs);
+
+ // Bucket is flushed yet.
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event1, bucketStartTimeNs + 1, tagId, /*uid=*/"111");
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
+ EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
+
+ // App upgrade forces bucket flush.
+ // Check that there's a past bucket and the bucket end is not adjusted.
+ countProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
+ EXPECT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ EXPECT_EQ((int64_t)bucketStartTimeNs,
+ countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs);
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
+ countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketEndNs);
+ EXPECT_EQ(eventUpgradeTimeNs, countProducer.mCurrentBucketStartTimeNs);
+
+ // Next event occurs in same bucket as partial bucket created.
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event2, bucketStartTimeNs + 70 * NS_PER_SEC + 10, tagId, /*uid=*/"222");
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
+ EXPECT_EQ(1UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+
+ // Third event in following bucket.
+ LogEvent event3(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event3, bucketStartTimeNs + 121 * NS_PER_SEC + 10, tagId, /*uid=*/"333");
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
+ EXPECT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ EXPECT_EQ((int64_t)eventUpgradeTimeNs,
+ countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][1].mBucketStartNs);
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+ countProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][1].mBucketEndNs);
+}
+
+TEST(CountMetricProducerTest, TestAnomalyDetectionUnSliced) {
+ sp<AlarmMonitor> alarmMonitor;
+ Alert alert;
+ alert.set_id(11);
+ alert.set_metric_id(1);
+ alert.set_trigger_if_sum_gt(2);
+ alert.set_num_buckets(2);
+ const int32_t refPeriodSec = 1;
+ alert.set_refractory_period_secs(refPeriodSec);
+
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+ int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
+ int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
+
+ CountMetric metric;
+ metric.set_id(1);
+ metric.set_bucket(ONE_MINUTE);
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ CountMetricProducer countProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+ bucketStartTimeNs, bucketStartTimeNs);
+
+ sp<AnomalyTracker> anomalyTracker = countProducer.addAnomalyTracker(alert, alarmMonitor);
+
+ int tagId = 1;
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event1, bucketStartTimeNs + 1, tagId);
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event2, bucketStartTimeNs + 2, tagId);
+ LogEvent event3(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event3, bucketStartTimeNs + 2 * bucketSizeNs + 1, tagId);
+ LogEvent event4(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event4, bucketStartTimeNs + 3 * bucketSizeNs + 1, tagId);
+ LogEvent event5(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event5, bucketStartTimeNs + 3 * bucketSizeNs + 2, tagId);
+ LogEvent event6(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event6, bucketStartTimeNs + 3 * bucketSizeNs + 3, tagId);
+ LogEvent event7(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event7, bucketStartTimeNs + 3 * bucketSizeNs + 2 * NS_PER_SEC, tagId);
+
+ // Two events in bucket #0.
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1);
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2);
+
+ EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
+ EXPECT_EQ(2L, countProducer.mCurrentSlicedCounter->begin()->second);
+ EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
+
+ // One event in bucket #2. No alarm as bucket #0 is trashed out.
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3);
+ EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
+ EXPECT_EQ(1L, countProducer.mCurrentSlicedCounter->begin()->second);
+ EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY), 0U);
+
+ // Two events in bucket #3.
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event4);
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event5);
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event6);
+ EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
+ EXPECT_EQ(3L, countProducer.mCurrentSlicedCounter->begin()->second);
+ // Anomaly at event 6 is within refractory period. The alarm is at event 5 timestamp not event 6
+ EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
+ std::ceil(1.0 * event5.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
+
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event7);
+ EXPECT_EQ(1UL, countProducer.mCurrentSlicedCounter->size());
+ EXPECT_EQ(4L, countProducer.mCurrentSlicedCounter->begin()->second);
+ EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(DEFAULT_METRIC_DIMENSION_KEY),
+ std::ceil(1.0 * event7.GetElapsedTimestampNs() / NS_PER_SEC + refPeriodSec));
+}
TEST(CountMetricProducerTest, TestOneWeekTimeUnit) {
CountMetric metric;
diff --git a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
index 6661374..6143dc0 100644
--- a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
@@ -13,17 +13,20 @@
// limitations under the License.
#include "src/metrics/DurationMetricProducer.h"
-#include "src/stats_log_util.h"
-#include "metrics_test_helper.h"
-#include "src/condition/ConditionWizard.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <stdio.h>
+
#include <set>
#include <unordered_map>
#include <vector>
+#include "metrics_test_helper.h"
+#include "src/condition/ConditionWizard.h"
+#include "src/stats_log_util.h"
+#include "stats_event.h"
+
using namespace android::os::statsd;
using namespace testing;
using android::sp;
@@ -39,6 +42,22 @@
const ConfigKey kConfigKey(0, 12345);
+namespace {
+
+void makeLogEvent(LogEvent* logEvent, int64_t timestampNs, int atomId) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, atomId);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+ AStatsEvent_build(statsEvent);
+
+ size_t size;
+ uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
+ logEvent->parseBuffer(buf, size);
+ AStatsEvent_release(statsEvent);
+}
+
+} // namespace
+
TEST(DurationMetricTrackerTest, TestFirstBucket) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
DurationMetric metric;
@@ -56,383 +75,386 @@
EXPECT_EQ(660000000005, durationProducer.getCurrentBucketEndTimeNs());
}
-// TODO(b/149590301): Update these to use new socket schema.
-//TEST(DurationMetricTrackerTest, TestNoCondition) {
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-// int64_t bucketStartTimeNs = 10000000000;
-// int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-//
-// DurationMetric metric;
-// metric.set_id(1);
-// metric.set_bucket(ONE_MINUTE);
-// metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
-//
-// int tagId = 1;
-// LogEvent event1(tagId, bucketStartTimeNs + 1);
-// event1.init();
-// LogEvent event2(tagId, bucketStartTimeNs + bucketSizeNs + 2);
-// event2.init();
-//
-// FieldMatcher dimensions;
-// DurationMetricProducer durationProducer(
-// kConfigKey, metric, -1 /*no condition*/, 1 /* start index */, 2 /* stop index */,
-// 3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs);
-//
-// durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
-// durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
-// durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
-// EXPECT_EQ(1UL, durationProducer.mPastBuckets.size());
-// EXPECT_TRUE(durationProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
-// durationProducer.mPastBuckets.end());
-// const auto& buckets = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-// EXPECT_EQ(2UL, buckets.size());
-// EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs);
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[0].mBucketEndNs);
-// EXPECT_EQ(bucketSizeNs - 1LL, buckets[0].mDuration);
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[1].mBucketStartNs);
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[1].mBucketEndNs);
-// EXPECT_EQ(2LL, buckets[1].mDuration);
-//}
-//
-//TEST(DurationMetricTrackerTest, TestNonSlicedCondition) {
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-// int64_t bucketStartTimeNs = 10000000000;
-// int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-//
-// DurationMetric metric;
-// metric.set_id(1);
-// metric.set_bucket(ONE_MINUTE);
-// metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
-//
-// int tagId = 1;
-// LogEvent event1(tagId, bucketStartTimeNs + 1);
-// event1.init();
-// LogEvent event2(tagId, bucketStartTimeNs + 2);
-// event2.init();
-// LogEvent event3(tagId, bucketStartTimeNs + bucketSizeNs + 1);
-// event3.init();
-// LogEvent event4(tagId, bucketStartTimeNs + bucketSizeNs + 3);
-// event4.init();
-//
-// FieldMatcher dimensions;
-// DurationMetricProducer durationProducer(
-// kConfigKey, metric, 0 /* condition index */, 1 /* start index */, 2 /* stop index */,
-// 3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs);
-// durationProducer.mCondition = ConditionState::kFalse;
-//
-// EXPECT_FALSE(durationProducer.mCondition);
-// EXPECT_FALSE(durationProducer.isConditionSliced());
-//
-// durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
-// durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
-// durationProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
-// EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
-//
-// durationProducer.onMatchedLogEvent(1 /* start index*/, event3);
-// durationProducer.onConditionChanged(true /* condition */, bucketStartTimeNs + bucketSizeNs + 2);
-// durationProducer.onMatchedLogEvent(2 /* stop index*/, event4);
-// durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
-// EXPECT_EQ(1UL, durationProducer.mPastBuckets.size());
-// EXPECT_TRUE(durationProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
-// durationProducer.mPastBuckets.end());
-// const auto& buckets2 = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-// EXPECT_EQ(1UL, buckets2.size());
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets2[0].mBucketStartNs);
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets2[0].mBucketEndNs);
-// EXPECT_EQ(1LL, buckets2[0].mDuration);
-//}
-//
-//TEST(DurationMetricTrackerTest, TestNonSlicedConditionUnknownState) {
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-// int64_t bucketStartTimeNs = 10000000000;
-// int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-//
-// DurationMetric metric;
-// metric.set_id(1);
-// metric.set_bucket(ONE_MINUTE);
-// metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
-//
-// int tagId = 1;
-// LogEvent event1(tagId, bucketStartTimeNs + 1);
-// event1.init();
-// LogEvent event2(tagId, bucketStartTimeNs + 2);
-// event2.init();
-// LogEvent event3(tagId, bucketStartTimeNs + bucketSizeNs + 1);
-// event3.init();
-// LogEvent event4(tagId, bucketStartTimeNs + bucketSizeNs + 3);
-// event4.init();
-//
-// FieldMatcher dimensions;
-// DurationMetricProducer durationProducer(
-// kConfigKey, metric, 0 /* condition index */, 1 /* start index */, 2 /* stop index */,
-// 3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs);
-//
-// EXPECT_EQ(ConditionState::kUnknown, durationProducer.mCondition);
-// EXPECT_FALSE(durationProducer.isConditionSliced());
-//
-// durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
-// durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
-// durationProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
-// EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
-//
-// durationProducer.onMatchedLogEvent(1 /* start index*/, event3);
-// durationProducer.onConditionChanged(true /* condition */, bucketStartTimeNs + bucketSizeNs + 2);
-// durationProducer.onMatchedLogEvent(2 /* stop index*/, event4);
-// durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
-// EXPECT_EQ(1UL, durationProducer.mPastBuckets.size());
-// const auto& buckets2 = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-// EXPECT_EQ(1UL, buckets2.size());
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets2[0].mBucketStartNs);
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets2[0].mBucketEndNs);
-// EXPECT_EQ(1LL, buckets2[0].mDuration);
-//}
-//
-//TEST(DurationMetricTrackerTest, TestSumDurationWithUpgrade) {
-// /**
-// * The duration starts from the first bucket, through the two partial buckets (10-70sec),
-// * another bucket, and ends at the beginning of the next full bucket.
-// * Expected buckets:
-// * - [10,25]: 14 secs
-// * - [25,70]: All 45 secs
-// * - [70,130]: All 60 secs
-// * - [130, 210]: Only 5 secs (event ended at 135sec)
-// */
-// int64_t bucketStartTimeNs = 10000000000;
-// int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-// int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
-// int64_t startTimeNs = bucketStartTimeNs + 1 * NS_PER_SEC;
-// int64_t endTimeNs = startTimeNs + 125 * NS_PER_SEC;
-//
-// int tagId = 1;
-//
-// DurationMetric metric;
-// metric.set_id(1);
-// metric.set_bucket(ONE_MINUTE);
-// metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-// FieldMatcher dimensions;
-// DurationMetricProducer durationProducer(
-// kConfigKey, metric, -1 /* no condition */, 1 /* start index */, 2 /* stop index */,
-// 3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs);
-//
-// LogEvent start_event(tagId, startTimeNs);
-// start_event.init();
-// durationProducer.onMatchedLogEvent(1 /* start index*/, start_event);
-// EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
-// EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
-//
-// durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
-// EXPECT_EQ(1UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-// std::vector<DurationBucket> buckets =
-// durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-// EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs);
-// EXPECT_EQ(eventUpgradeTimeNs, buckets[0].mBucketEndNs);
-// EXPECT_EQ(eventUpgradeTimeNs - startTimeNs, buckets[0].mDuration);
-// EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
-//
-// // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
-// LogEvent end_event(tagId, endTimeNs);
-// end_event.init();
-// durationProducer.onMatchedLogEvent(2 /* stop index*/, end_event);
-// buckets = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-// EXPECT_EQ(3UL, buckets.size());
-// EXPECT_EQ(eventUpgradeTimeNs, buckets[1].mBucketStartNs);
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[1].mBucketEndNs);
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - eventUpgradeTimeNs, buckets[1].mDuration);
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[2].mBucketStartNs);
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[2].mBucketEndNs);
-// EXPECT_EQ(bucketSizeNs, buckets[2].mDuration);
-//}
-//
-//TEST(DurationMetricTrackerTest, TestSumDurationWithUpgradeInFollowingBucket) {
-// /**
-// * Expected buckets (start at 11s, upgrade at 75s, end at 135s):
-// * - [10,70]: 59 secs
-// * - [70,75]: 5 sec
-// * - [75,130]: 55 secs
-// */
-// int64_t bucketStartTimeNs = 10000000000;
-// int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-// int64_t eventUpgradeTimeNs = bucketStartTimeNs + 65 * NS_PER_SEC;
-// int64_t startTimeNs = bucketStartTimeNs + 1 * NS_PER_SEC;
-// int64_t endTimeNs = startTimeNs + 125 * NS_PER_SEC;
-//
-// int tagId = 1;
-//
-// DurationMetric metric;
-// metric.set_id(1);
-// metric.set_bucket(ONE_MINUTE);
-// metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-// FieldMatcher dimensions;
-// DurationMetricProducer durationProducer(
-// kConfigKey, metric, -1 /* no condition */, 1 /* start index */, 2 /* stop index */,
-// 3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs);
-//
-// LogEvent start_event(tagId, startTimeNs);
-// start_event.init();
-// durationProducer.onMatchedLogEvent(1 /* start index*/, start_event);
-// EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
-// EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
-//
-// durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
-// EXPECT_EQ(2UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-// std::vector<DurationBucket> buckets =
-// durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-// EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs);
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[0].mBucketEndNs);
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - startTimeNs, buckets[0].mDuration);
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[1].mBucketStartNs);
-// EXPECT_EQ(eventUpgradeTimeNs, buckets[1].mBucketEndNs);
-// EXPECT_EQ(eventUpgradeTimeNs - (bucketStartTimeNs + bucketSizeNs), buckets[1].mDuration);
-// EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
-//
-// // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
-// LogEvent end_event(tagId, endTimeNs);
-// end_event.init();
-// durationProducer.onMatchedLogEvent(2 /* stop index*/, end_event);
-// buckets = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-// EXPECT_EQ(3UL, buckets.size());
-// EXPECT_EQ(eventUpgradeTimeNs, buckets[2].mBucketStartNs);
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[2].mBucketEndNs);
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs - eventUpgradeTimeNs, buckets[2].mDuration);
-//}
-//
-//TEST(DurationMetricTrackerTest, TestSumDurationAnomalyWithUpgrade) {
-// sp<AlarmMonitor> alarmMonitor;
-// int64_t bucketStartTimeNs = 10000000000;
-// int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-// int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
-// int64_t startTimeNs = bucketStartTimeNs + 1;
-// int64_t endTimeNs = startTimeNs + 65 * NS_PER_SEC;
-//
-// int tagId = 1;
-//
-// // Setup metric with alert.
-// DurationMetric metric;
-// metric.set_id(1);
-// metric.set_bucket(ONE_MINUTE);
-// metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
-// Alert alert;
-// alert.set_num_buckets(3);
-// alert.set_trigger_if_sum_gt(2);
-//
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-// FieldMatcher dimensions;
-// DurationMetricProducer durationProducer(
-// kConfigKey, metric, -1 /* no condition */, 1 /* start index */, 2 /* stop index */,
-// 3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs);
-//
-// sp<AnomalyTracker> anomalyTracker = durationProducer.addAnomalyTracker(alert, alarmMonitor);
-// EXPECT_TRUE(anomalyTracker != nullptr);
-//
-// LogEvent start_event(tagId, startTimeNs);
-// start_event.init();
-// durationProducer.onMatchedLogEvent(1 /* start index*/, start_event);
-// durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
-// // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
-// LogEvent end_event(tagId, endTimeNs);
-// end_event.init();
-// durationProducer.onMatchedLogEvent(2 /* stop index*/, end_event);
-//
-// EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - startTimeNs,
-// anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
-//}
-//
-//TEST(DurationMetricTrackerTest, TestMaxDurationWithUpgrade) {
-// int64_t bucketStartTimeNs = 10000000000;
-// int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-// int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
-// int64_t startTimeNs = bucketStartTimeNs + 1;
-// int64_t endTimeNs = startTimeNs + 125 * NS_PER_SEC;
-//
-// int tagId = 1;
-//
-// DurationMetric metric;
-// metric.set_id(1);
-// metric.set_bucket(ONE_MINUTE);
-// metric.set_aggregation_type(DurationMetric_AggregationType_MAX_SPARSE);
-// LogEvent event1(tagId, startTimeNs);
-// event1.write("111"); // uid
-// event1.init();
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-// FieldMatcher dimensions;
-// DurationMetricProducer durationProducer(
-// kConfigKey, metric, -1 /* no condition */, 1 /* start index */, 2 /* stop index */,
-// 3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs);
-//
-// LogEvent start_event(tagId, startTimeNs);
-// start_event.init();
-// durationProducer.onMatchedLogEvent(1 /* start index*/, start_event);
-// EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
-// EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
-//
-// durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
-// EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-// EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
-//
-// // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
-// LogEvent end_event(tagId, endTimeNs);
-// end_event.init();
-// durationProducer.onMatchedLogEvent(2 /* stop index*/, end_event);
-// EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-//
-// durationProducer.flushIfNeededLocked(bucketStartTimeNs + 3 * bucketSizeNs + 1);
-// std::vector<DurationBucket> buckets =
-// durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-// EXPECT_EQ(1UL, buckets.size());
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[0].mBucketStartNs);
-// EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, buckets[0].mBucketEndNs);
-// EXPECT_EQ(endTimeNs - startTimeNs, buckets[0].mDuration);
-//}
-//
-//TEST(DurationMetricTrackerTest, TestMaxDurationWithUpgradeInNextBucket) {
-// int64_t bucketStartTimeNs = 10000000000;
-// int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
-// int64_t eventUpgradeTimeNs = bucketStartTimeNs + 65 * NS_PER_SEC;
-// int64_t startTimeNs = bucketStartTimeNs + 1;
-// int64_t endTimeNs = startTimeNs + 115 * NS_PER_SEC;
-//
-// int tagId = 1;
-//
-// DurationMetric metric;
-// metric.set_id(1);
-// metric.set_bucket(ONE_MINUTE);
-// metric.set_aggregation_type(DurationMetric_AggregationType_MAX_SPARSE);
-// LogEvent event1(tagId, startTimeNs);
-// event1.write("111"); // uid
-// event1.init();
-// sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
-// FieldMatcher dimensions;
-// DurationMetricProducer durationProducer(
-// kConfigKey, metric, -1 /* no condition */, 1 /* start index */, 2 /* stop index */,
-// 3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs, bucketStartTimeNs);
-//
-// LogEvent start_event(tagId, startTimeNs);
-// start_event.init();
-// durationProducer.onMatchedLogEvent(1 /* start index*/, start_event);
-// EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
-// EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
-//
-// durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
-// EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-// EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
-//
-// // Stop occurs in the same partial bucket as created for the app upgrade.
-// LogEvent end_event(tagId, endTimeNs);
-// end_event.init();
-// durationProducer.onMatchedLogEvent(2 /* stop index*/, end_event);
-// EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-// EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
-//
-// durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
-// std::vector<DurationBucket> buckets =
-// durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
-// EXPECT_EQ(1UL, buckets.size());
-// EXPECT_EQ(eventUpgradeTimeNs, buckets[0].mBucketStartNs);
-// EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[0].mBucketEndNs);
-// EXPECT_EQ(endTimeNs - startTimeNs, buckets[0].mDuration);
-//}
+TEST(DurationMetricTrackerTest, TestNoCondition) {
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+
+ DurationMetric metric;
+ metric.set_id(1);
+ metric.set_bucket(ONE_MINUTE);
+ metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
+
+ int tagId = 1;
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event1, bucketStartTimeNs + 1, tagId);
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event2, bucketStartTimeNs + bucketSizeNs + 2, tagId);
+
+ FieldMatcher dimensions;
+ DurationMetricProducer durationProducer(kConfigKey, metric, -1 /*no condition*/,
+ 1 /* start index */, 2 /* stop index */,
+ 3 /* stop_all index */, false /*nesting*/, wizard,
+ dimensions, bucketStartTimeNs, bucketStartTimeNs);
+
+ durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
+ durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
+ durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
+ EXPECT_EQ(1UL, durationProducer.mPastBuckets.size());
+ EXPECT_TRUE(durationProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
+ durationProducer.mPastBuckets.end());
+ const auto& buckets = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+ EXPECT_EQ(2UL, buckets.size());
+ EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs);
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[0].mBucketEndNs);
+ EXPECT_EQ(bucketSizeNs - 1LL, buckets[0].mDuration);
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[1].mBucketStartNs);
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[1].mBucketEndNs);
+ EXPECT_EQ(2LL, buckets[1].mDuration);
+}
+
+TEST(DurationMetricTrackerTest, TestNonSlicedCondition) {
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+
+ DurationMetric metric;
+ metric.set_id(1);
+ metric.set_bucket(ONE_MINUTE);
+ metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
+
+ int tagId = 1;
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event1, bucketStartTimeNs + 1, tagId);
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event2, bucketStartTimeNs + 2, tagId);
+ LogEvent event3(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event3, bucketStartTimeNs + bucketSizeNs + 1, tagId);
+ LogEvent event4(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event4, bucketStartTimeNs + bucketSizeNs + 3, tagId);
+
+ FieldMatcher dimensions;
+ DurationMetricProducer durationProducer(kConfigKey, metric, 0 /* condition index */,
+ 1 /* start index */, 2 /* stop index */,
+ 3 /* stop_all index */, false /*nesting*/, wizard,
+ dimensions, bucketStartTimeNs, bucketStartTimeNs);
+ durationProducer.mCondition = ConditionState::kFalse;
+
+ EXPECT_FALSE(durationProducer.mCondition);
+ EXPECT_FALSE(durationProducer.isConditionSliced());
+
+ durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
+ durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
+ durationProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
+ EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
+
+ durationProducer.onMatchedLogEvent(1 /* start index*/, event3);
+ durationProducer.onConditionChanged(true /* condition */, bucketStartTimeNs + bucketSizeNs + 2);
+ durationProducer.onMatchedLogEvent(2 /* stop index*/, event4);
+ durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
+ EXPECT_EQ(1UL, durationProducer.mPastBuckets.size());
+ EXPECT_TRUE(durationProducer.mPastBuckets.find(DEFAULT_METRIC_DIMENSION_KEY) !=
+ durationProducer.mPastBuckets.end());
+ const auto& buckets2 = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+ EXPECT_EQ(1UL, buckets2.size());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets2[0].mBucketStartNs);
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets2[0].mBucketEndNs);
+ EXPECT_EQ(1LL, buckets2[0].mDuration);
+}
+
+TEST(DurationMetricTrackerTest, TestNonSlicedConditionUnknownState) {
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+
+ DurationMetric metric;
+ metric.set_id(1);
+ metric.set_bucket(ONE_MINUTE);
+ metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
+
+ int tagId = 1;
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event1, bucketStartTimeNs + 1, tagId);
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event2, bucketStartTimeNs + 2, tagId);
+ LogEvent event3(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event3, bucketStartTimeNs + bucketSizeNs + 1, tagId);
+ LogEvent event4(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event4, bucketStartTimeNs + bucketSizeNs + 3, tagId);
+
+ FieldMatcher dimensions;
+ DurationMetricProducer durationProducer(kConfigKey, metric, 0 /* condition index */,
+ 1 /* start index */, 2 /* stop index */,
+ 3 /* stop_all index */, false /*nesting*/, wizard,
+ dimensions, bucketStartTimeNs, bucketStartTimeNs);
+
+ EXPECT_EQ(ConditionState::kUnknown, durationProducer.mCondition);
+ EXPECT_FALSE(durationProducer.isConditionSliced());
+
+ durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
+ durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
+ durationProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
+ EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
+
+ durationProducer.onMatchedLogEvent(1 /* start index*/, event3);
+ durationProducer.onConditionChanged(true /* condition */, bucketStartTimeNs + bucketSizeNs + 2);
+ durationProducer.onMatchedLogEvent(2 /* stop index*/, event4);
+ durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
+ EXPECT_EQ(1UL, durationProducer.mPastBuckets.size());
+ const auto& buckets2 = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+ EXPECT_EQ(1UL, buckets2.size());
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets2[0].mBucketStartNs);
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets2[0].mBucketEndNs);
+ EXPECT_EQ(1LL, buckets2[0].mDuration);
+}
+
+TEST(DurationMetricTrackerTest, TestSumDurationWithUpgrade) {
+ /**
+ * The duration starts from the first bucket, through the two partial buckets (10-70sec),
+ * another bucket, and ends at the beginning of the next full bucket.
+ * Expected buckets:
+ * - [10,25]: 14 secs
+ * - [25,70]: All 45 secs
+ * - [70,130]: All 60 secs
+ * - [130, 210]: Only 5 secs (event ended at 135sec)
+ */
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+ int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
+ int64_t startTimeNs = bucketStartTimeNs + 1 * NS_PER_SEC;
+ int64_t endTimeNs = startTimeNs + 125 * NS_PER_SEC;
+
+ int tagId = 1;
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event1, startTimeNs, tagId);
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event2, endTimeNs, tagId);
+
+ DurationMetric metric;
+ metric.set_id(1);
+ metric.set_bucket(ONE_MINUTE);
+ metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ FieldMatcher dimensions;
+ DurationMetricProducer durationProducer(kConfigKey, metric, -1 /* no condition */,
+ 1 /* start index */, 2 /* stop index */,
+ 3 /* stop_all index */, false /*nesting*/, wizard,
+ dimensions, bucketStartTimeNs, bucketStartTimeNs);
+
+ durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
+ EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
+ EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
+
+ durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
+ EXPECT_EQ(1UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ std::vector<DurationBucket> buckets =
+ durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+ EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs);
+ EXPECT_EQ(eventUpgradeTimeNs, buckets[0].mBucketEndNs);
+ EXPECT_EQ(eventUpgradeTimeNs - startTimeNs, buckets[0].mDuration);
+ EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
+
+ // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
+ durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
+ buckets = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+ EXPECT_EQ(3UL, buckets.size());
+ EXPECT_EQ(eventUpgradeTimeNs, buckets[1].mBucketStartNs);
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[1].mBucketEndNs);
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - eventUpgradeTimeNs, buckets[1].mDuration);
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[2].mBucketStartNs);
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[2].mBucketEndNs);
+ EXPECT_EQ(bucketSizeNs, buckets[2].mDuration);
+}
+
+TEST(DurationMetricTrackerTest, TestSumDurationWithUpgradeInFollowingBucket) {
+ /**
+ * Expected buckets (start at 11s, upgrade at 75s, end at 135s):
+ * - [10,70]: 59 secs
+ * - [70,75]: 5 sec
+ * - [75,130]: 55 secs
+ */
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+ int64_t eventUpgradeTimeNs = bucketStartTimeNs + 65 * NS_PER_SEC;
+ int64_t startTimeNs = bucketStartTimeNs + 1 * NS_PER_SEC;
+ int64_t endTimeNs = startTimeNs + 125 * NS_PER_SEC;
+
+ int tagId = 1;
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event1, startTimeNs, tagId);
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event2, endTimeNs, tagId);
+
+ DurationMetric metric;
+ metric.set_id(1);
+ metric.set_bucket(ONE_MINUTE);
+ metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ FieldMatcher dimensions;
+ DurationMetricProducer durationProducer(kConfigKey, metric, -1 /* no condition */,
+ 1 /* start index */, 2 /* stop index */,
+ 3 /* stop_all index */, false /*nesting*/, wizard,
+ dimensions, bucketStartTimeNs, bucketStartTimeNs);
+
+ durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
+ EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
+ EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
+
+ durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
+ EXPECT_EQ(2UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ std::vector<DurationBucket> buckets =
+ durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+ EXPECT_EQ(bucketStartTimeNs, buckets[0].mBucketStartNs);
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[0].mBucketEndNs);
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - startTimeNs, buckets[0].mDuration);
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, buckets[1].mBucketStartNs);
+ EXPECT_EQ(eventUpgradeTimeNs, buckets[1].mBucketEndNs);
+ EXPECT_EQ(eventUpgradeTimeNs - (bucketStartTimeNs + bucketSizeNs), buckets[1].mDuration);
+ EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
+
+ // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
+ durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
+ buckets = durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+ EXPECT_EQ(3UL, buckets.size());
+ EXPECT_EQ(eventUpgradeTimeNs, buckets[2].mBucketStartNs);
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[2].mBucketEndNs);
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs - eventUpgradeTimeNs, buckets[2].mDuration);
+}
+
+TEST(DurationMetricTrackerTest, TestSumDurationAnomalyWithUpgrade) {
+ sp<AlarmMonitor> alarmMonitor;
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+ int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
+ int64_t startTimeNs = bucketStartTimeNs + 1;
+ int64_t endTimeNs = startTimeNs + 65 * NS_PER_SEC;
+
+ int tagId = 1;
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event1, startTimeNs, tagId);
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event2, endTimeNs, tagId);
+
+ // Setup metric with alert.
+ DurationMetric metric;
+ metric.set_id(1);
+ metric.set_bucket(ONE_MINUTE);
+ metric.set_aggregation_type(DurationMetric_AggregationType_SUM);
+ Alert alert;
+ alert.set_num_buckets(3);
+ alert.set_trigger_if_sum_gt(2);
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ FieldMatcher dimensions;
+ DurationMetricProducer durationProducer(kConfigKey, metric, -1 /* no condition */,
+ 1 /* start index */, 2 /* stop index */,
+ 3 /* stop_all index */, false /*nesting*/, wizard,
+ dimensions, bucketStartTimeNs, bucketStartTimeNs);
+
+ sp<AnomalyTracker> anomalyTracker = durationProducer.addAnomalyTracker(alert, alarmMonitor);
+ EXPECT_TRUE(anomalyTracker != nullptr);
+
+ durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
+ durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
+
+ // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
+ durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs - startTimeNs,
+ anomalyTracker->getSumOverPastBuckets(DEFAULT_METRIC_DIMENSION_KEY));
+}
+
+TEST(DurationMetricTrackerTest, TestMaxDurationWithUpgrade) {
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+ int64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC;
+ int64_t startTimeNs = bucketStartTimeNs + 1;
+ int64_t endTimeNs = startTimeNs + 125 * NS_PER_SEC;
+
+ int tagId = 1;
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event1, startTimeNs, tagId);
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event2, endTimeNs, tagId);
+
+ DurationMetric metric;
+ metric.set_id(1);
+ metric.set_bucket(ONE_MINUTE);
+ metric.set_aggregation_type(DurationMetric_AggregationType_MAX_SPARSE);
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ FieldMatcher dimensions;
+ DurationMetricProducer durationProducer(kConfigKey, metric, -1 /* no condition */,
+ 1 /* start index */, 2 /* stop index */,
+ 3 /* stop_all index */, false /*nesting*/, wizard,
+ dimensions, bucketStartTimeNs, bucketStartTimeNs);
+
+ durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
+ EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
+ EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
+
+ durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
+ EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
+
+ // We skip ahead one bucket, so we fill in the first two partial buckets and one full bucket.
+ durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
+ EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+
+ durationProducer.flushIfNeededLocked(bucketStartTimeNs + 3 * bucketSizeNs + 1);
+ std::vector<DurationBucket> buckets =
+ durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+ EXPECT_EQ(1UL, buckets.size());
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[0].mBucketStartNs);
+ EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs, buckets[0].mBucketEndNs);
+ EXPECT_EQ(endTimeNs - startTimeNs, buckets[0].mDuration);
+}
+
+TEST(DurationMetricTrackerTest, TestMaxDurationWithUpgradeInNextBucket) {
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL;
+ int64_t eventUpgradeTimeNs = bucketStartTimeNs + 65 * NS_PER_SEC;
+ int64_t startTimeNs = bucketStartTimeNs + 1;
+ int64_t endTimeNs = startTimeNs + 115 * NS_PER_SEC;
+
+ int tagId = 1;
+ LogEvent event1(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event1, startTimeNs, tagId);
+ LogEvent event2(/*uid=*/0, /*pid=*/0);
+ makeLogEvent(&event2, endTimeNs, tagId);
+
+ DurationMetric metric;
+ metric.set_id(1);
+ metric.set_bucket(ONE_MINUTE);
+ metric.set_aggregation_type(DurationMetric_AggregationType_MAX_SPARSE);
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ FieldMatcher dimensions;
+ DurationMetricProducer durationProducer(kConfigKey, metric, -1 /* no condition */,
+ 1 /* start index */, 2 /* stop index */,
+ 3 /* stop_all index */, false /*nesting*/, wizard,
+ dimensions, bucketStartTimeNs, bucketStartTimeNs);
+
+ durationProducer.onMatchedLogEvent(1 /* start index*/, event1);
+ EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
+ EXPECT_EQ(bucketStartTimeNs, durationProducer.mCurrentBucketStartTimeNs);
+
+ durationProducer.notifyAppUpgrade(eventUpgradeTimeNs, "ANY.APP", 1, 1);
+ EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
+
+ // Stop occurs in the same partial bucket as created for the app upgrade.
+ durationProducer.onMatchedLogEvent(2 /* stop index*/, event2);
+ EXPECT_EQ(0UL, durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+ EXPECT_EQ(eventUpgradeTimeNs, durationProducer.mCurrentBucketStartTimeNs);
+
+ durationProducer.flushIfNeededLocked(bucketStartTimeNs + 2 * bucketSizeNs + 1);
+ std::vector<DurationBucket> buckets =
+ durationProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY];
+ EXPECT_EQ(1UL, buckets.size());
+ EXPECT_EQ(eventUpgradeTimeNs, buckets[0].mBucketStartNs);
+ EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs, buckets[0].mBucketEndNs);
+ EXPECT_EQ(endTimeNs - startTimeNs, buckets[0].mDuration);
+}
} // namespace statsd
} // namespace os
diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp
index d416f13..e2eee03 100644
--- a/cmds/statsd/tests/statsd_test_util.cpp
+++ b/cmds/statsd/tests/statsd_test_util.cpp
@@ -410,40 +410,75 @@
return dimensions;
}
-// TODO(b/149590301): Update these helpers to use new socket schema.
-//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);
-// EXPECT_TRUE(event->write(state));
-// event->init();
-// return event;
-//}
-//
-//std::unique_ptr<LogEvent> CreateBatterySaverOnEvent(uint64_t timestampNs) {
-// auto event = std::make_unique<LogEvent>(
-// android::util::BATTERY_SAVER_MODE_STATE_CHANGED, timestampNs);
-// EXPECT_TRUE(event->write(BatterySaverModeStateChanged::ON));
-// event->init();
-// return event;
-//}
-//
-//std::unique_ptr<LogEvent> CreateBatterySaverOffEvent(uint64_t timestampNs) {
-// auto event = std::make_unique<LogEvent>(
-// android::util::BATTERY_SAVER_MODE_STATE_CHANGED, timestampNs);
-// EXPECT_TRUE(event->write(BatterySaverModeStateChanged::OFF));
-// event->init();
-// return event;
-//}
-//
-//std::unique_ptr<LogEvent> CreateScreenBrightnessChangedEvent(
-// int level, uint64_t timestampNs) {
-// auto event = std::make_unique<LogEvent>(android::util::SCREEN_BRIGHTNESS_CHANGED, timestampNs);
-// EXPECT_TRUE(event->write(level));
-// event->init();
-// return event;
-//
-//}
-//
+std::unique_ptr<LogEvent> CreateScreenStateChangedEvent(
+ uint64_t timestampNs, const android::view::DisplayStateEnum state) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, android::util::SCREEN_STATE_CHANGED);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+ 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> CreateBatterySaverOnEvent(uint64_t timestampNs) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, android::util::BATTERY_SAVER_MODE_STATE_CHANGED);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+ AStatsEvent_writeInt32(statsEvent, BatterySaverModeStateChanged::ON);
+ 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> CreateBatterySaverOffEvent(uint64_t timestampNs) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, android::util::BATTERY_SAVER_MODE_STATE_CHANGED);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+ AStatsEvent_writeInt32(statsEvent, BatterySaverModeStateChanged::OFF);
+ 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> CreateScreenBrightnessChangedEvent(uint64_t timestampNs, int level) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, android::util::SCREEN_BRIGHTNESS_CHANGED);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+ AStatsEvent_writeInt32(statsEvent, level);
+ 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) {
@@ -470,121 +505,212 @@
// 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> CreateProcessLifeCycleStateChangedEvent(
-// const int uid, const ProcessLifeCycleStateChanged::State state, uint64_t timestampNs) {
-// auto logEvent = std::make_unique<LogEvent>(
-// android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED, timestampNs);
-// logEvent->write(uid);
-// logEvent->write("");
-// logEvent->write(state);
-// logEvent->init();
-// return logEvent;
-//}
-//
-//std::unique_ptr<LogEvent> CreateAppCrashEvent(const int uid, uint64_t timestampNs) {
-// return CreateProcessLifeCycleStateChangedEvent(
-// uid, ProcessLifeCycleStateChanged::CRASHED, timestampNs);
-//}
-//
-//std::unique_ptr<LogEvent> CreateAppCrashOccurredEvent(const int uid, uint64_t timestampNs) {
-// auto event = std::make_unique<LogEvent>(android::util::APP_CRASH_OCCURRED, timestampNs);
-// event->write(uid);
-// event->write("eventType");
-// event->write("processName");
-// event->init();
-// return event;
-//}
-//
-//std::unique_ptr<LogEvent> CreateIsolatedUidChangedEvent(
-// int isolatedUid, int hostUid, bool is_create, uint64_t timestampNs) {
-// auto logEvent = std::make_unique<LogEvent>(
-// android::util::ISOLATED_UID_CHANGED, timestampNs);
-// logEvent->write(hostUid);
-// logEvent->write(isolatedUid);
-// logEvent->write(is_create);
-// logEvent->init();
-// return logEvent;
-//}
-//
-//std::unique_ptr<LogEvent> CreateUidProcessStateChangedEvent(
-// int uid, const android::app::ProcessStateEnum state, uint64_t timestampNs) {
-// auto event = std::make_unique<LogEvent>(android::util::UID_PROCESS_STATE_CHANGED, timestampNs);
-// event->write(uid);
-// event->write(state);
-// event->init();
-// return event;
-//}
+std::unique_ptr<LogEvent> CreateWakelockStateChangedEvent(uint64_t timestampNs,
+ const vector<int>& attributionUids,
+ const vector<string>& attributionTags,
+ const string& wakelockName,
+ const WakelockStateChanged::State state) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, android::util::WAKELOCK_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_writeInt32(statsEvent, android::os::WakeLockLevelEnum::PARTIAL_WAKE_LOCK);
+ AStatsEvent_writeString(statsEvent, wakelockName.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> CreateAcquireWakelockEvent(uint64_t timestampNs,
+ const vector<int>& attributionUids,
+ const vector<string>& attributionTags,
+ const string& wakelockName) {
+ return CreateWakelockStateChangedEvent(timestampNs, attributionUids, attributionTags,
+ wakelockName, WakelockStateChanged::ACQUIRE);
+}
+
+std::unique_ptr<LogEvent> CreateReleaseWakelockEvent(uint64_t timestampNs,
+ const vector<int>& attributionUids,
+ const vector<string>& attributionTags,
+ const string& wakelockName) {
+ return CreateWakelockStateChangedEvent(timestampNs, attributionUids, attributionTags,
+ wakelockName, WakelockStateChanged::RELEASE);
+}
+
+std::unique_ptr<LogEvent> CreateActivityForegroundStateChangedEvent(
+ uint64_t timestampNs, const int uid, const ActivityForegroundStateChanged::State state) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, android::util::ACTIVITY_FOREGROUND_STATE_CHANGED);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+ AStatsEvent_writeInt32(statsEvent, uid);
+ AStatsEvent_writeString(statsEvent, "pkg_name");
+ AStatsEvent_writeString(statsEvent, "class_name");
+ 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> CreateMoveToBackgroundEvent(uint64_t timestampNs, const int uid) {
+ return CreateActivityForegroundStateChangedEvent(timestampNs, uid,
+ ActivityForegroundStateChanged::BACKGROUND);
+}
+
+std::unique_ptr<LogEvent> CreateMoveToForegroundEvent(uint64_t timestampNs, const int uid) {
+ return CreateActivityForegroundStateChangedEvent(timestampNs, uid,
+ ActivityForegroundStateChanged::FOREGROUND);
+}
+
+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, android::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);
+}
+
+std::unique_ptr<LogEvent> CreateProcessLifeCycleStateChangedEvent(
+ uint64_t timestampNs, const int uid, const ProcessLifeCycleStateChanged::State state) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, android::util::PROCESS_LIFE_CYCLE_STATE_CHANGED);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+ AStatsEvent_writeInt32(statsEvent, uid);
+ AStatsEvent_writeString(statsEvent, "");
+ 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> CreateAppCrashEvent(uint64_t timestampNs, const int uid) {
+ return CreateProcessLifeCycleStateChangedEvent(timestampNs, uid,
+ ProcessLifeCycleStateChanged::CRASHED);
+}
+
+std::unique_ptr<LogEvent> CreateAppCrashOccurredEvent(uint64_t timestampNs, const int uid) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, android::util::APP_CRASH_OCCURRED);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+ AStatsEvent_writeInt32(statsEvent, uid);
+ AStatsEvent_writeString(statsEvent, "eventType");
+ AStatsEvent_writeString(statsEvent, "processName");
+ 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> CreateIsolatedUidChangedEvent(uint64_t timestampNs, int hostUid,
+ int isolatedUid, bool is_create) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, android::util::ISOLATED_UID_CHANGED);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+ AStatsEvent_writeInt32(statsEvent, hostUid);
+ AStatsEvent_writeInt32(statsEvent, isolatedUid);
+ AStatsEvent_writeInt32(statsEvent, is_create);
+ 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> CreateUidProcessStateChangedEvent(
+ uint64_t timestampNs, int uid, const android::app::ProcessStateEnum state) {
+ AStatsEvent* statsEvent = AStatsEvent_obtain();
+ AStatsEvent_setAtomId(statsEvent, android::util::UID_PROCESS_STATE_CHANGED);
+ AStatsEvent_overwriteTimestamp(statsEvent, timestampNs);
+
+ AStatsEvent_writeInt32(statsEvent, uid);
+ 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;
+}
sp<StatsLogProcessor> CreateStatsLogProcessor(const int64_t timeBaseNs, const int64_t currentTimeNs,
const StatsdConfig& config, const ConfigKey& key,
diff --git a/cmds/statsd/tests/statsd_test_util.h b/cmds/statsd/tests/statsd_test_util.h
index c8326ee..4371015 100644
--- a/cmds/statsd/tests/statsd_test_util.h
+++ b/cmds/statsd/tests/statsd_test_util.h
@@ -166,11 +166,10 @@
// Create log event for screen state changed.
std::unique_ptr<LogEvent> CreateScreenStateChangedEvent(
- const android::view::DisplayStateEnum state, uint64_t timestampNs);
+ uint64_t timestampNs, const android::view::DisplayStateEnum state);
// Create log event for screen brightness state changed.
-std::unique_ptr<LogEvent> CreateScreenBrightnessChangedEvent(
- int level, uint64_t timestampNs);
+std::unique_ptr<LogEvent> CreateScreenBrightnessChangedEvent(uint64_t timestampNs, int level);
// Create log event when scheduled job starts.
std::unique_ptr<LogEvent> CreateStartScheduledJobEvent(
@@ -188,45 +187,42 @@
std::unique_ptr<LogEvent> CreateBatterySaverOffEvent(uint64_t timestampNs);
// Create log event for app moving to background.
-std::unique_ptr<LogEvent> CreateMoveToBackgroundEvent(const int uid, uint64_t timestampNs);
+std::unique_ptr<LogEvent> CreateMoveToBackgroundEvent(uint64_t timestampNs, const int uid);
// Create log event for app moving to foreground.
-std::unique_ptr<LogEvent> CreateMoveToForegroundEvent(const int uid, uint64_t timestampNs);
+std::unique_ptr<LogEvent> CreateMoveToForegroundEvent(uint64_t timestampNs, const int uid);
// Create log event when the app sync starts.
-std::unique_ptr<LogEvent> CreateSyncStartEvent(
- const std::vector<AttributionNodeInternal>& attributions, const string& name,
- uint64_t timestampNs);
+std::unique_ptr<LogEvent> CreateSyncStartEvent(uint64_t timestampNs, const vector<int>& uids,
+ const vector<string>& tags, const string& name);
// 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> CreateSyncEndEvent(uint64_t timestampNs, const vector<int>& uids,
+ const vector<string>& tags, const string& name);
// Create log event when the app sync ends.
-std::unique_ptr<LogEvent> CreateAppCrashEvent(
- const int uid, uint64_t timestampNs);
+std::unique_ptr<LogEvent> CreateAppCrashEvent(uint64_t timestampNs, const int uid);
// Create log event for an app crash.
-std::unique_ptr<LogEvent> CreateAppCrashOccurredEvent(const int uid, uint64_t timestampNs);
+std::unique_ptr<LogEvent> CreateAppCrashOccurredEvent(uint64_t timestampNs, const int uid);
// Create log event for acquiring wakelock.
-std::unique_ptr<LogEvent> CreateAcquireWakelockEvent(
- const std::vector<AttributionNodeInternal>& attributions, const string& wakelockName,
- uint64_t timestampNs);
+std::unique_ptr<LogEvent> CreateAcquireWakelockEvent(uint64_t timestampNs, const vector<int>& uids,
+ const vector<string>& tags,
+ const string& wakelockName);
// Create log event for releasing wakelock.
-std::unique_ptr<LogEvent> CreateReleaseWakelockEvent(
- const std::vector<AttributionNodeInternal>& attributions, const string& wakelockName,
- uint64_t timestampNs);
+std::unique_ptr<LogEvent> CreateReleaseWakelockEvent(uint64_t timestampNs, const vector<int>& uids,
+ const vector<string>& tags,
+ const string& wakelockName);
// 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> CreateIsolatedUidChangedEvent(uint64_t timestampNs, int hostUid,
+ int isolatedUid, bool is_create);
// Create log event for uid process state change.
std::unique_ptr<LogEvent> CreateUidProcessStateChangedEvent(
- int uid, const android::app::ProcessStateEnum state, uint64_t timestampNs);
+ uint64_t timestampNs, int uid, const android::app::ProcessStateEnum state);
// Helper function to create an AttributionNodeInternal proto.
AttributionNodeInternal CreateAttribution(const int& uid, const string& tag);
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 3a3eea9..e7036bb 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -48,6 +48,7 @@
import android.util.SparseArray;
import android.view.Display;
import android.view.KeyEvent;
+import android.view.SurfaceControl;
import android.view.SurfaceView;
import android.view.WindowManager;
import android.view.WindowManagerImpl;
@@ -1937,8 +1938,8 @@
* to declare the capability to take screenshot by setting the
* {@link android.R.styleable#AccessibilityService_canTakeScreenshot}
* property in its meta-data. For details refer to {@link #SERVICE_META_DATA}.
- * Besides, This API is only supported for default display now
- * {@link Display#DEFAULT_DISPLAY}.
+ * This API only will support {@link Display#DEFAULT_DISPLAY} until {@link SurfaceControl}
+ * supports non-default displays.
* </p>
*
* @param displayId The logic display id, must be {@link Display#DEFAULT_DISPLAY} for
@@ -1948,11 +1949,17 @@
*
* @return {@code true} if the taking screenshot accepted, {@code false} if too little time
* has elapsed since the last screenshot, invalid display or internal errors.
+ * @throws IllegalArgumentException if displayId is not {@link Display#DEFAULT_DISPLAY}.
*/
public boolean takeScreenshot(int displayId, @NonNull @CallbackExecutor Executor executor,
@NonNull Consumer<ScreenshotResult> callback) {
Preconditions.checkNotNull(executor, "executor cannot be null");
Preconditions.checkNotNull(callback, "callback cannot be null");
+
+ if (displayId != Display.DEFAULT_DISPLAY) {
+ throw new IllegalArgumentException("DisplayId isn't the default display");
+ }
+
final IAccessibilityServiceConnection connection =
AccessibilityInteractionClient.getInstance().getConnection(
mConnectionId);
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index ca37e9b..2c41e8d 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -18,6 +18,7 @@
import android.annotation.CallSuper;
import android.annotation.IntDef;
+import android.annotation.Nullable;
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
@@ -269,6 +270,11 @@
private float mDurationScale = -1f;
/**
+ * Animation handler used to schedule updates for this animation.
+ */
+ private AnimationHandler mAnimationHandler;
+
+ /**
* Public constants
*/
@@ -1684,6 +1690,15 @@
* @hide
*/
public AnimationHandler getAnimationHandler() {
- return AnimationHandler.getInstance();
+ return mAnimationHandler != null ? mAnimationHandler : AnimationHandler.getInstance();
+ }
+
+ /**
+ * Sets the animation handler used to schedule updates for this animator or {@code null} to use
+ * the default handler.
+ * @hide
+ */
+ public void setAnimationHandler(@Nullable AnimationHandler animationHandler) {
+ mAnimationHandler = animationHandler;
}
}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 8d6bc72..6480a6a 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -5829,7 +5829,7 @@
intent.prepareToLeaveProcess(this);
result = ActivityTaskManager.getService()
.startActivity(mMainThread.getApplicationThread(), getBasePackageName(),
- getFeatureId(), intent,
+ getAttributionTag(), intent,
intent.resolveTypeIfNeeded(getContentResolver()), mToken, mEmbeddedID,
requestCode, ActivityManager.START_FLAG_ONLY_IF_NEEDED, null, options);
} catch (RemoteException e) {
@@ -6624,12 +6624,10 @@
String packageName = getPackageName();
try {
data.prepareToLeaveProcess(this);
- IIntentSender target =
- ActivityManager.getService().getIntentSenderWithFeature(
- ActivityManager.INTENT_SENDER_ACTIVITY_RESULT, packageName, getFeatureId(),
- mParent == null ? mToken : mParent.mToken,
- mEmbeddedID, requestCode, new Intent[] { data }, null, flags, null,
- getUserId());
+ IIntentSender target = ActivityManager.getService().getIntentSenderWithFeature(
+ ActivityManager.INTENT_SENDER_ACTIVITY_RESULT, packageName, getAttributionTag(),
+ mParent == null ? mToken : mParent.mToken, mEmbeddedID, requestCode,
+ new Intent[]{data}, null, flags, null, getUserId());
return target != null ? new PendingIntent(target) : null;
} catch (RemoteException e) {
// Empty
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index dd4788e..1a92b75 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -4243,6 +4243,7 @@
* @hide
*/
@SystemApi
+ @TestApi
@RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION)
public boolean updateMccMncConfiguration(@NonNull String mcc, @NonNull String mnc) {
if (mcc == null || mnc == null) {
diff --git a/core/java/android/app/AppOps.md b/core/java/android/app/AppOps.md
new file mode 100644
index 0000000..bee701a
--- /dev/null
+++ b/core/java/android/app/AppOps.md
@@ -0,0 +1,212 @@
+<!--
+ 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
+ -->
+
+# App-ops
+
+App-ops are used for two purposes: Access control and tracking.
+
+App-ops cover a wide variety of functionality from helping with runtime permissions to battery
+consumption tracking.
+
+App-ops are defined in `AppOpsManager` as `OP_...` and need to be continuously numbered. The
+integer values of the app-ops are not exposed. For app-ops visible to 3rd party apps,
+the name of the app-op might be exposed as `OPSTR_`. As the integers are not part of the API, they
+might (and have) changed between platform versions and OEM implementations.
+`AppOpsManager.opToPublicName` and `AppOpsManager.strOpToOp` allow for conversion between integer
+and string identifier for the op.
+
+## App-ops as access restrictions
+
+App-ops can either be controlled for each [uid](../os/Users.md#int-uid) or for each package. Which
+one is used depends on the API provider maintaining this app-op.
+
+For any security or privacy related app-ops the provider needs to control the app-op per uid
+as all security and privacy is based on uid in Android.
+
+App-op used for non-security related tasks are usually controlled per package to provide finer
+granularity.
+
+### Setting the app-op mode
+
+To control access the app-op can be set to:
+
+`MODE_DEFAULT`
+: Default behavior, might differ from app-op to app-op
+
+`MODE_ALLOWED`
+: Allow the access
+
+`MODE_FOREGROUND`
+: Allow the access but only if the app is currently in the [foreground](#foreground)
+
+`MODE_IGNORED`
+: Don't allow the access, i.e. don't perform the requested action or return dummy data
+
+`MODE_ERRORED`
+: Throw a `SecurityException` on access. This can be suppressed by using a `...noThrow` method to
+check the mode
+
+The initial state of an app-op is defined in `AppOpsManager.sOpDefaultMode`. Confusingly the
+initial state is often not `MODE_DEFAULT`
+
+Per-package modes can be set using `AppOpsManager.setMode` and per-uid modes can be set using
+`AppOpsManager.setUidMode`.
+
+**Warning**: Do not use `setMode` and `setUidMode` for the same app-op. Due to the way the
+internal storage for the mode works this can lead to very confusing behavior. If this ever happened
+by accident this needs to be cleaned up for any affected user as the app-op mode is retained over
+reboot.
+
+App-ops can also be set via the shell using the `appops set` command. The target package/uid can be
+defined via parameters to this command.
+
+The current state of the app-op can be read via the `appops get` command or via `dumpsys appops`.
+If the app-op is not mentioned in the output the app-op is in it's initial state.
+
+For example `dumpsys appops`:
+```
+[...]
+ Uid 2000:
+ [...]
+ COARSE_LOCATION: mode=foreground
+ START_FOREGROUND: mode=foreground
+ LEGACY_STORAGE: mode=ignore
+ [...]
+```
+
+### Guarding access based on app-ops
+
+API providers need to check the mode returned by `AppOpsManager.noteOp` if they are are allowing
+access to operations gated by the app-op. `AppOpsManager.unsafeCheckOp` should be used to check the
+mode if no access is granted. E.g. this can be for displaying app-op state in the UI or when
+checking the state before later calling `noteOp` anyway.
+
+If an operation refers to a time span (e.g. a audio-recording session) the API provider should
+use `AppOpsManager.startOp` and `AppOpsManager.finishOp` instead of `noteOp`.
+
+`noteOp` and `startOp` take a `packageName` and `featureId` parameter. These need to be read from
+the calling apps context as `Context.getOpPackageName` and `Context.getFeatureId`, then send to
+the data provider and then passed on the `noteOp`/`startOp` method.
+
+#### App-ops and permissions
+
+Access guarding is often done in combination with permissions using [runtime permissions
+](../permission/Permissions.md#runtime-permissions-and-app-ops) or [app-op permissions
+](../permission/Permissions.md#app-op-permissions). This is preferred over just using an app-op
+ as permissions a concept more familiar to app developers.
+
+### Foreground
+
+The `AppOpsService` tracks the apps' proc state (== foreground-ness) by following the
+`ActivityManagerService`'s proc state. It reduces the possible proc states to only those needed
+for app-ops. It also delays the changes by a _settle time_. This delay is needed as the proc state
+can fluctuate when switching apps. By delaying the change the appops service is not affected by
+those.
+
+The proc state is used for two use cases: Firstly, Tracking remembers the proc state for each
+tracked event. Secondly, `noteOp`/`checkOp` calls for app-op that are set to `MODE_FOREGROUND` are
+translated using the `AppOpsService.UidState.evalMode` method into `MODE_ALLOWED` when the app is
+counted as foreground and `MODE_IGNORED` when the app is counted as background. `checkOpRaw`
+calls are not affected.
+
+The current proc state for an app can be read from `dumpsys appops`. The tracking information can
+be read from `dumpsys appops`
+
+```
+Uid u0a118:
+ state=fg
+ capability=6
+```
+
+## App-ops for tracking
+
+App-ops track many important events, including all accesses to runtime permission protected
+APIs. This is done by tracking when an app-op was noted or started. The tracked data can only be
+read by system components.
+
+**Note:** Only `noteOp`/`startOp` calls are tracked; `unsafeCheckOp` is not tracked. Hence it is
+important to eventually call `noteOp` or `startOp` when providing access to protected operations
+or data.
+
+Some apps are forwarding access to other apps. E.g. an app might get the location from the
+system's location provider and then send the location further to a 3rd app. In this case the
+app passing on the data needs to call `AppOpsManager.noteProxyOp` to signal the access proxying.
+This might also make sense inside of a single app if the access is forwarded between two features of
+the app. In this case an app-op is noted for the forwarding app (proxy) and the app that received
+the data (proxied). As any app can do it is important to track how much the system trusts this
+proxy-access-tracking. For more details see `AppOpService.noteProxyOperation`.
+
+The tracking information can be read from `dumpsys appops` split by feature, proc state and
+proxying information with the syntax
+
+```
+Package THE_PACKAGE_NAME:
+ AN_APP_OP (CURRENT_MODE):
+ FEATURE_ID (or null for default feature)=[
+ ACCESS_OR_REJECT: [PROC_STATE-PROXYING_TAG] TIME proxy[INFO_ABOUT_PROXY IF_PROXY_ACCESS]
+```
+
+Example:
+
+```
+Package com.google.android.gms:
+ READ_CONTACTS (allow):
+ null=[
+ Access: [fgsvc-s] 2020-02-14 14:24:10.559 (-3d23h15m43s642ms)
+ Access: [fgsvc-tp] 2020-02-14 14:23:58.189 (-3d23h15m56s12ms)
+ ]
+ apkappcontext=[
+ Access: [fg-tp] 2020-02-17 14:24:54.721 (-23h14m59s480ms)
+ ]
+ com.google.android.gms.icing=[
+ Access: [fgsvc-tpd] 2020-02-14 14:26:27.018 (-3d23h13m27s183ms) proxy[uid=10070, pkg=com.android.providers.contacts, feature=null]
+ Access: [fg-tpd] 2020-02-18 02:26:08.711 (-11h13m45s490ms) proxy[uid=10070, pkg=com.android.providers.contacts, feature=null]
+ Access: [bg-tpd] 2020-02-14 14:34:55.310 (-3d23h4m58s891ms) proxy[uid=10070, pkg=com.android.providers.contacts, feature=null]
+ ]
+ MANAGE_EXTERNAL_STORAGE (default):
+ null=[
+ Reject: [fg-s]2020-02-18 08:00:04.444 (-5h39m49s757ms)
+ Reject: [bg-s]2020-02-18 08:00:04.427 (-5h39m49s774ms)
+ ]
+```
+
+### Tracking an app's own private data accesses
+
+An app can register an `AppOpsManager.OnOpNotedCallback` to get informed about what accesses the
+system is tracking for it. As each runtime permission has an associated app-op this API is
+particularly useful for an app that want to find unexpected private data accesses.
+
+## Listening to app-op events
+
+System apps (with the appropriate permissions) can listen to most app-op events, such as
+
+`noteOp`
+: `startWatchingNoted`
+
+`startOp`/`finishOp`
+: `startWatchingActive`
+
+mode changes
+: `startWatchingMode`
+
+[foreground](#foreground)-ness changes
+: `startWatchingMode` using the `WATCH_FOREGROUND_CHANGES` flag
+
+Watching such events is only ever as good as the tracked events. E.g. if the audio provider does
+not call `startOp` for a audio-session, the app's activeness for the record-audio app-op is not
+changed. Further there were cases where app-ops were noted even though no data was accessed or
+operation was performed. Hence before relying on the data from app-ops, double check if the data
+is actually reliable.
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index eeb5d41..f6a79cd 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -27,6 +27,7 @@
import android.annotation.SystemService;
import android.annotation.TestApi;
import android.app.usage.UsageStatsManager;
+import android.compat.Compatibility;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
import android.compat.annotation.UnsupportedAppUsage;
@@ -159,8 +160,8 @@
* <p>Some apps are forwarding access to other apps. E.g. an app might get the location from the
* system's location provider and then send the location further to a 3rd app. In this case the
* app passing on the data needs to call {@link #noteProxyOp} to signal the access proxying. This
- * might also make sense inside of a single app if the access is forwarded between two features of
- * the app.
+ * might also make sense inside of a single app if the access is forwarded between two parts of
+ * the tagged with different attribution tags.
*
* <p>An app can register an {@link OnOpNotedCallback} to get informed about what accesses the
* system is tracking for it. As each runtime permission has an associated app-op this API is
@@ -385,6 +386,13 @@
*/
public static final int WATCH_FOREGROUND_CHANGES = 1 << 0;
+ /**
+ * Flag for {@link #startWatchingMode} that causes the callback to happen on the switch-op
+ * instead the op the callback was registered. (This simulates pre-R behavior).
+ *
+ * @hide
+ */
+ public static final int CALL_BACK_ON_SWITCHED_OP = 1 << 1;
/**
* Flag to determine whether we should log noteOp/startOp calls to make sure they
@@ -1988,108 +1996,108 @@
};
/**
- * This specifies whether each option should allow the system
- * (and system ui) to bypass the user restriction when active.
+ * In which cases should an app be allowed to bypass the {@link #setUserRestriction user
+ * restriction} for a certain app-op.
*/
- private static boolean[] sOpAllowSystemRestrictionBypass = new boolean[] {
- true, //COARSE_LOCATION
- true, //FINE_LOCATION
- false, //GPS
- false, //VIBRATE
- false, //READ_CONTACTS
- false, //WRITE_CONTACTS
- false, //READ_CALL_LOG
- false, //WRITE_CALL_LOG
- false, //READ_CALENDAR
- false, //WRITE_CALENDAR
- true, //WIFI_SCAN
- false, //POST_NOTIFICATION
- false, //NEIGHBORING_CELLS
- false, //CALL_PHONE
- false, //READ_SMS
- false, //WRITE_SMS
- false, //RECEIVE_SMS
- false, //RECEIVE_EMERGECY_SMS
- false, //RECEIVE_MMS
- false, //RECEIVE_WAP_PUSH
- false, //SEND_SMS
- false, //READ_ICC_SMS
- false, //WRITE_ICC_SMS
- false, //WRITE_SETTINGS
- true, //SYSTEM_ALERT_WINDOW
- false, //ACCESS_NOTIFICATIONS
- false, //CAMERA
- false, //RECORD_AUDIO
- false, //PLAY_AUDIO
- false, //READ_CLIPBOARD
- false, //WRITE_CLIPBOARD
- false, //TAKE_MEDIA_BUTTONS
- false, //TAKE_AUDIO_FOCUS
- false, //AUDIO_MASTER_VOLUME
- false, //AUDIO_VOICE_VOLUME
- false, //AUDIO_RING_VOLUME
- false, //AUDIO_MEDIA_VOLUME
- false, //AUDIO_ALARM_VOLUME
- false, //AUDIO_NOTIFICATION_VOLUME
- false, //AUDIO_BLUETOOTH_VOLUME
- false, //WAKE_LOCK
- false, //MONITOR_LOCATION
- false, //MONITOR_HIGH_POWER_LOCATION
- false, //GET_USAGE_STATS
- false, //MUTE_MICROPHONE
- true, //TOAST_WINDOW
- false, //PROJECT_MEDIA
- false, //ACTIVATE_VPN
- false, //WALLPAPER
- false, //ASSIST_STRUCTURE
- false, //ASSIST_SCREENSHOT
- false, //READ_PHONE_STATE
- false, //ADD_VOICEMAIL
- false, // USE_SIP
- false, // PROCESS_OUTGOING_CALLS
- false, // USE_FINGERPRINT
- false, // BODY_SENSORS
- false, // READ_CELL_BROADCASTS
- false, // MOCK_LOCATION
- false, // READ_EXTERNAL_STORAGE
- false, // WRITE_EXTERNAL_STORAGE
- false, // TURN_ON_SCREEN
- false, // GET_ACCOUNTS
- false, // RUN_IN_BACKGROUND
- false, // AUDIO_ACCESSIBILITY_VOLUME
- false, // READ_PHONE_NUMBERS
- false, // REQUEST_INSTALL_PACKAGES
- false, // ENTER_PICTURE_IN_PICTURE_ON_HIDE
- false, // INSTANT_APP_START_FOREGROUND
- false, // ANSWER_PHONE_CALLS
- false, // OP_RUN_ANY_IN_BACKGROUND
- false, // OP_CHANGE_WIFI_STATE
- false, // OP_REQUEST_DELETE_PACKAGES
- false, // OP_BIND_ACCESSIBILITY_SERVICE
- false, // ACCEPT_HANDOVER
- false, // MANAGE_IPSEC_HANDOVERS
- false, // START_FOREGROUND
- true, // BLUETOOTH_SCAN
- false, // USE_BIOMETRIC
- false, // ACTIVITY_RECOGNITION
- false, // SMS_FINANCIAL_TRANSACTIONS
- false, // READ_MEDIA_AUDIO
- false, // WRITE_MEDIA_AUDIO
- false, // READ_MEDIA_VIDEO
- false, // WRITE_MEDIA_VIDEO
- false, // READ_MEDIA_IMAGES
- false, // WRITE_MEDIA_IMAGES
- false, // LEGACY_STORAGE
- false, // ACCESS_ACCESSIBILITY
- false, // READ_DEVICE_IDENTIFIERS
- false, // ACCESS_MEDIA_LOCATION
- false, // QUERY_ALL_PACKAGES
- false, // MANAGE_EXTERNAL_STORAGE
- false, // INTERACT_ACROSS_PROFILES
- false, // ACTIVATE_PLATFORM_VPN
- false, // LOADER_USAGE_STATS
- false, // ACCESS_CALL_AUDIO
- false, // AUTO_REVOKE_PERMISSIONS_IF_UNUSED
+ private static RestrictionBypass[] sOpAllowSystemRestrictionBypass = new RestrictionBypass[] {
+ new RestrictionBypass(true, false), //COARSE_LOCATION
+ new RestrictionBypass(true, false), //FINE_LOCATION
+ null, //GPS
+ null, //VIBRATE
+ null, //READ_CONTACTS
+ null, //WRITE_CONTACTS
+ null, //READ_CALL_LOG
+ null, //WRITE_CALL_LOG
+ null, //READ_CALENDAR
+ null, //WRITE_CALENDAR
+ new RestrictionBypass(true, false), //WIFI_SCAN
+ null, //POST_NOTIFICATION
+ null, //NEIGHBORING_CELLS
+ null, //CALL_PHONE
+ null, //READ_SMS
+ null, //WRITE_SMS
+ null, //RECEIVE_SMS
+ null, //RECEIVE_EMERGECY_SMS
+ null, //RECEIVE_MMS
+ null, //RECEIVE_WAP_PUSH
+ null, //SEND_SMS
+ null, //READ_ICC_SMS
+ null, //WRITE_ICC_SMS
+ null, //WRITE_SETTINGS
+ new RestrictionBypass(true, false), //SYSTEM_ALERT_WINDOW
+ null, //ACCESS_NOTIFICATIONS
+ null, //CAMERA
+ new RestrictionBypass(false, true), //RECORD_AUDIO
+ null, //PLAY_AUDIO
+ null, //READ_CLIPBOARD
+ null, //WRITE_CLIPBOARD
+ null, //TAKE_MEDIA_BUTTONS
+ null, //TAKE_AUDIO_FOCUS
+ null, //AUDIO_MASTER_VOLUME
+ null, //AUDIO_VOICE_VOLUME
+ null, //AUDIO_RING_VOLUME
+ null, //AUDIO_MEDIA_VOLUME
+ null, //AUDIO_ALARM_VOLUME
+ null, //AUDIO_NOTIFICATION_VOLUME
+ null, //AUDIO_BLUETOOTH_VOLUME
+ null, //WAKE_LOCK
+ null, //MONITOR_LOCATION
+ null, //MONITOR_HIGH_POWER_LOCATION
+ null, //GET_USAGE_STATS
+ null, //MUTE_MICROPHONE
+ new RestrictionBypass(true, false), //TOAST_WINDOW
+ null, //PROJECT_MEDIA
+ null, //ACTIVATE_VPN
+ null, //WALLPAPER
+ null, //ASSIST_STRUCTURE
+ null, //ASSIST_SCREENSHOT
+ null, //READ_PHONE_STATE
+ null, //ADD_VOICEMAIL
+ null, // USE_SIP
+ null, // PROCESS_OUTGOING_CALLS
+ null, // USE_FINGERPRINT
+ null, // BODY_SENSORS
+ null, // READ_CELL_BROADCASTS
+ null, // MOCK_LOCATION
+ null, // READ_EXTERNAL_STORAGE
+ null, // WRITE_EXTERNAL_STORAGE
+ null, // TURN_ON_SCREEN
+ null, // GET_ACCOUNTS
+ null, // RUN_IN_BACKGROUND
+ null, // AUDIO_ACCESSIBILITY_VOLUME
+ null, // READ_PHONE_NUMBERS
+ null, // REQUEST_INSTALL_PACKAGES
+ null, // ENTER_PICTURE_IN_PICTURE_ON_HIDE
+ null, // INSTANT_APP_START_FOREGROUND
+ null, // ANSWER_PHONE_CALLS
+ null, // OP_RUN_ANY_IN_BACKGROUND
+ null, // OP_CHANGE_WIFI_STATE
+ null, // OP_REQUEST_DELETE_PACKAGES
+ null, // OP_BIND_ACCESSIBILITY_SERVICE
+ null, // ACCEPT_HANDOVER
+ null, // MANAGE_IPSEC_HANDOVERS
+ null, // START_FOREGROUND
+ new RestrictionBypass(true, false), // BLUETOOTH_SCAN
+ null, // USE_BIOMETRIC
+ null, // ACTIVITY_RECOGNITION
+ null, // SMS_FINANCIAL_TRANSACTIONS
+ null, // READ_MEDIA_AUDIO
+ null, // WRITE_MEDIA_AUDIO
+ null, // READ_MEDIA_VIDEO
+ null, // WRITE_MEDIA_VIDEO
+ null, // READ_MEDIA_IMAGES
+ null, // WRITE_MEDIA_IMAGES
+ null, // LEGACY_STORAGE
+ null, // ACCESS_ACCESSIBILITY
+ null, // READ_DEVICE_IDENTIFIERS
+ null, // ACCESS_MEDIA_LOCATION
+ null, // QUERY_ALL_PACKAGES
+ null, // MANAGE_EXTERNAL_STORAGE
+ null, // INTERACT_ACROSS_PROFILES
+ null, // ACTIVATE_PLATFORM_VPN
+ null, // LOADER_USAGE_STATS
+ null, // ACCESS_CALL_AUDIO
+ null, // AUTO_REVOKE_PERMISSIONS_IF_UNUSED
};
/**
@@ -2485,11 +2493,11 @@
}
/**
- * Retrieve whether the op allows the system (and system ui) to
- * bypass the user restriction.
+ * Retrieve whether the op allows to bypass the user restriction.
+ *
* @hide
*/
- public static boolean opAllowSystemBypassRestriction(int op) {
+ public static RestrictionBypass opAllowSystemBypassRestriction(int op) {
return sOpAllowSystemRestrictionBypass[op];
}
@@ -2536,6 +2544,29 @@
}
/**
+ * When to not enforce {@link #setUserRestriction restrictions}.
+ *
+ * @hide
+ */
+ public static class RestrictionBypass {
+ /** Does the app need to be privileged to bypass the restriction */
+ public boolean isPrivileged;
+
+ /**
+ * Does the app need to have the EXEMPT_FROM_AUDIO_RESTRICTIONS permission to bypass the
+ * restriction
+ */
+ public boolean isRecordAudioRestrictionExcept;
+
+ public RestrictionBypass(boolean isPrivileged, boolean isRecordAudioRestrictionExcept) {
+ this.isPrivileged = isPrivileged;
+ this.isRecordAudioRestrictionExcept = isRecordAudioRestrictionExcept;
+ }
+
+ public static RestrictionBypass UNRESTRICTED = new RestrictionBypass(true, true);
+ }
+
+ /**
* Class holding all of the operation information associated with an app.
* @hide
*/
@@ -2627,23 +2658,23 @@
private @IntRange(from = 0) int mUid;
/** Package of the proxy that noted the op */
private @Nullable String mPackageName;
- /** ID of the feature of the proxy that noted the op */
- private @Nullable String mFeatureId;
+ /** Attribution tag of the proxy that noted the op */
+ private @Nullable String mAttributionTag;
/**
* Reinit existing object with new state.
*
* @param uid UID of the proxy app that noted the op
* @param packageName Package of the proxy that noted the op
- * @param featureId ID of the feature of the proxy that noted the op
+ * @param attributionTag attribution tag of the proxy that noted the op
*
* @hide
*/
public void reinit(@IntRange(from = 0) int uid, @Nullable String packageName,
- @Nullable String featureId) {
+ @Nullable String attributionTag) {
mUid = Preconditions.checkArgumentNonnegative(uid);
mPackageName = packageName;
- mFeatureId = featureId;
+ mAttributionTag = attributionTag;
}
@@ -2668,21 +2699,21 @@
* UID of the proxy app that noted the op
* @param packageName
* Package of the proxy that noted the op
- * @param featureId
- * ID of the feature of the proxy that noted the op
+ * @param attributionTag
+ * Attribution tag of the proxy that noted the op
* @hide
*/
@DataClass.Generated.Member
public OpEventProxyInfo(
@IntRange(from = 0) int uid,
@Nullable String packageName,
- @Nullable String featureId) {
+ @Nullable String attributionTag) {
this.mUid = uid;
com.android.internal.util.AnnotationValidations.validate(
IntRange.class, null, mUid,
"from", 0);
this.mPackageName = packageName;
- this.mFeatureId = featureId;
+ this.mAttributionTag = attributionTag;
// onConstructed(); // You can define this method to get a callback
}
@@ -2696,7 +2727,7 @@
public OpEventProxyInfo(@NonNull OpEventProxyInfo orig) {
mUid = orig.mUid;
mPackageName = orig.mPackageName;
- mFeatureId = orig.mFeatureId;
+ mAttributionTag = orig.mAttributionTag;
}
/**
@@ -2716,11 +2747,11 @@
}
/**
- * ID of the feature of the proxy that noted the op
+ * Attribution tag of the proxy that noted the op
*/
@DataClass.Generated.Member
- public @Nullable String getFeatureId() {
- return mFeatureId;
+ public @Nullable String getAttributionTag() {
+ return mAttributionTag;
}
@Override
@@ -2731,11 +2762,11 @@
byte flg = 0;
if (mPackageName != null) flg |= 0x2;
- if (mFeatureId != null) flg |= 0x4;
+ if (mAttributionTag != null) flg |= 0x4;
dest.writeByte(flg);
dest.writeInt(mUid);
if (mPackageName != null) dest.writeString(mPackageName);
- if (mFeatureId != null) dest.writeString(mFeatureId);
+ if (mAttributionTag != null) dest.writeString(mAttributionTag);
}
@Override
@@ -2752,14 +2783,14 @@
byte flg = in.readByte();
int uid = in.readInt();
String packageName = (flg & 0x2) == 0 ? null : in.readString();
- String featureId = (flg & 0x4) == 0 ? null : in.readString();
+ String attributionTag = (flg & 0x4) == 0 ? null : in.readString();
this.mUid = uid;
com.android.internal.util.AnnotationValidations.validate(
IntRange.class, null, mUid,
"from", 0);
this.mPackageName = packageName;
- this.mFeatureId = featureId;
+ this.mAttributionTag = attributionTag;
// onConstructed(); // You can define this method to get a callback
}
@@ -2783,7 +2814,7 @@
time = 1576814974615L,
codegenVersion = "1.0.14",
sourceFile = "frameworks/base/core/java/android/app/AppOpsManager.java",
- inputSignatures = "private @android.annotation.IntRange(from=0L) int mUid\nprivate @android.annotation.Nullable java.lang.String mPackageName\nprivate @android.annotation.Nullable java.lang.String mFeatureId\npublic void reinit(int,java.lang.String,java.lang.String)\nclass OpEventProxyInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true, genHiddenCopyConstructor=true)")
+ inputSignatures = "private @android.annotation.IntRange(from=0L) int mUid\nprivate @android.annotation.Nullable java.lang.String mPackageName\nprivate @android.annotation.Nullable java.lang.String mAttributionTag\npublic void reinit(int,java.lang.String,java.lang.String)\nclass OpEventProxyInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true, genHiddenCopyConstructor=true)")
@Deprecated
private void __metadata() {}
*/
@@ -2982,7 +3013,7 @@
/**
* Last {@link #noteOp} and {@link #startOp} events performed for a single op and a specific
- * {@link Context#createFeatureContext(String) feature} for all uidModes and opFlags.
+ * {@link Context#createAttributionContext(String) attribution} for all uidModes and opFlags.
*
* @hide
*/
@@ -2991,7 +3022,7 @@
@Immutable
// @DataClass(genHiddenConstructor = true) codegen verifier is broken
@DataClass.Suppress({"getAccessEvents", "getRejectEvents", "getOp"})
- public static final class OpFeatureEntry implements Parcelable {
+ public static final class AttributedOpEntry implements Parcelable {
/** The code of the op */
private final @IntRange(from = 0, to = _NUM_OP - 1) int mOp;
/** Whether the op is running */
@@ -3290,8 +3321,8 @@
}
/**
- * Gets the proxy info of the app that performed the last access on behalf of this feature
- * and as a result blamed the op on this app.
+ * Gets the proxy info of the app that performed the last access on behalf of this
+ * attribution and as a result blamed the op on this attribution.
*
* @param flags The op flags
*
@@ -3308,7 +3339,7 @@
/**
* Gets the proxy info of the app that performed the last foreground access on behalf of
- * this feature and as a result blamed the op on this app.
+ * this attribution and as a result blamed the op on this attribution.
*
* @param flags The op flags
*
@@ -3326,7 +3357,7 @@
/**
* Gets the proxy info of the app that performed the last background access on behalf of
- * this feature and as a result blamed the op on this app.
+ * this attribution and as a result blamed the op on this attribution.
*
* @param flags The op flags
*
@@ -3343,8 +3374,8 @@
}
/**
- * Gets the proxy info of the app that performed the last access on behalf of this feature
- * and as a result blamed the op on this app.
+ * Gets the proxy info of the app that performed the last access on behalf of this
+ * attribution and as a result blamed the op on this attribution.
*
* @param fromUidState The lowest UID state for which to query
* @param toUidState The highest UID state for which to query (inclusive)
@@ -3419,7 +3450,7 @@
/**
- * Creates a new OpFeatureEntry.
+ * Creates a new OpAttributionEntry.
*
* @param op
* The code of the op
@@ -3432,7 +3463,7 @@
* @hide
*/
@DataClass.Generated.Member
- public OpFeatureEntry(
+ public AttributedOpEntry(
@IntRange(from = 0, to = _NUM_OP - 1) int op,
boolean running,
@Nullable LongSparseArray<NoteOpEvent> accessEvents,
@@ -3502,7 +3533,7 @@
/** @hide */
@SuppressWarnings({"unchecked", "RedundantCast"})
@DataClass.Generated.Member
- /* package-private */ OpFeatureEntry(@NonNull Parcel in) {
+ /* package-private */ AttributedOpEntry(@NonNull Parcel in) {
// You can override field unparcelling by defining methods like:
// static FieldType unparcelFieldName(Parcel in) { ... }
@@ -3525,16 +3556,16 @@
}
@DataClass.Generated.Member
- public static final @NonNull Parcelable.Creator<OpFeatureEntry> CREATOR
- = new Parcelable.Creator<OpFeatureEntry>() {
+ public static final @NonNull Parcelable.Creator<AttributedOpEntry> CREATOR
+ = new Parcelable.Creator<AttributedOpEntry>() {
@Override
- public OpFeatureEntry[] newArray(int size) {
- return new OpFeatureEntry[size];
+ public AttributedOpEntry[] newArray(int size) {
+ return new AttributedOpEntry[size];
}
@Override
- public OpFeatureEntry createFromParcel(@NonNull Parcel in) {
- return new OpFeatureEntry(in);
+ public AttributedOpEntry createFromParcel(@NonNull Parcel in) {
+ return new AttributedOpEntry(in);
}
};
@@ -3543,7 +3574,7 @@
time = 1574809856239L,
codegenVersion = "1.0.14",
sourceFile = "frameworks/base/core/java/android/app/AppOpsManager.java",
- inputSignatures = "private final @android.annotation.IntRange(from=0L, to=_NUM_OP - 1) int mOp\nprivate final boolean mRunning\nprivate final @com.android.internal.util.DataClass.ParcelWith(android.app.OpFeatureEntry.LongSparseArrayParceling.class) @android.annotation.Nullable android.util.LongSparseArray<android.app.NoteOpEvent> mAccessEvents\nprivate final @com.android.internal.util.DataClass.ParcelWith(android.app.OpFeatureEntry.LongSparseArrayParceling.class) @android.annotation.Nullable android.util.LongSparseArray<android.app.NoteOpEvent> mRejectEvents\npublic @android.annotation.NonNull android.util.ArraySet<java.lang.Long> collectKeys()\npublic @android.app.UidState int getLastAccessUidState(int)\npublic @android.app.UidState int getLastForegroundAccessUidState(int)\npublic @android.app.UidState int getLastBackgroundAccessUidState(int)\npublic @android.app.UidState int getLastRejectUidState(int)\npublic @android.app.UidState int getLastForegroundRejectUidState(int)\npublic @android.app.UidState int getLastBackgroundRejectUidState(int)\npublic long getAccessTime(int,int)\npublic long getRejectTime(int,int)\npublic long getDuration(int,int)\npublic int getProxyUid(int,int)\npublic @android.annotation.Nullable java.lang.String getProxyPackageName(int,int)\npublic @android.annotation.Nullable java.lang.String getProxyFeatureId(int,int)\nclass OpFeatureEntry extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true)")
+ inputSignatures = "private final @android.annotation.IntRange(from=0L, to=_NUM_OP - 1) int mOp\nprivate final boolean mRunning\nprivate final @com.android.internal.util.DataClass.ParcelWith(android.app.OpAttributionEntry.LongSparseArrayParceling.class) @android.annotation.Nullable android.util.LongSparseArray<android.app.NoteOpEvent> mAccessEvents\nprivate final @com.android.internal.util.DataClass.ParcelWith(android.app.OpAttributionEntry.LongSparseArrayParceling.class) @android.annotation.Nullable android.util.LongSparseArray<android.app.NoteOpEvent> mRejectEvents\npublic @android.annotation.NonNull android.util.ArraySet<java.lang.Long> collectKeys()\npublic @android.app.UidState int getLastAccessUidState(int)\npublic @android.app.UidState int getLastForegroundAccessUidState(int)\npublic @android.app.UidState int getLastBackgroundAccessUidState(int)\npublic @android.app.UidState int getLastRejectUidState(int)\npublic @android.app.UidState int getLastForegroundRejectUidState(int)\npublic @android.app.UidState int getLastBackgroundRejectUidState(int)\npublic long getAccessTime(int,int)\npublic long getRejectTime(int,int)\npublic long getDuration(int,int)\npublic int getProxyUid(int,int)\npublic @android.annotation.Nullable java.lang.String getProxyPackageName(int,int)\npublic @android.annotation.Nullable java.lang.String getProxyAttributionTag(int,int)\nclass OpAttributionEntry extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true)")
@Deprecated
private void __metadata() {}
*/
@@ -3569,8 +3600,8 @@
private final @IntRange(from = 0, to = _NUM_OP - 1) int mOp;
/** The mode of the op */
private final @Mode int mMode;
- /** The features that have been used when checking the op */
- private final @NonNull Map<String, OpFeatureEntry> mFeatures;
+ /** The attributed entries by attribution tag */
+ private final @NonNull Map<String, AttributedOpEntry> mAttributedOpEntries;
/**
* @hide
@@ -3611,7 +3642,7 @@
* @see #getLastAccessForegroundTime(int)
* @see #getLastAccessBackgroundTime(int)
* @see #getLastAccessTime(int, int, int)
- * @see OpFeatureEntry#getLastAccessTime(int)
+ * @see AttributedOpEntry#getLastAccessTime(int)
*/
public long getLastAccessTime(@OpFlags int flags) {
return getLastAccessTime(MAX_PRIORITY_UID_STATE, MIN_PRIORITY_UID_STATE, flags);
@@ -3628,7 +3659,7 @@
* @see #getLastAccessTime(int)
* @see #getLastAccessBackgroundTime(int)
* @see #getLastAccessTime(int, int, int)
- * @see OpFeatureEntry#getLastAccessForegroundTime(int)
+ * @see AttributedOpEntry#getLastAccessForegroundTime(int)
*/
public long getLastAccessForegroundTime(@OpFlags int flags) {
return getLastAccessTime(MAX_PRIORITY_UID_STATE, resolveFirstUnrestrictedUidState(mOp),
@@ -3646,7 +3677,7 @@
* @see #getLastAccessTime(int)
* @see #getLastAccessForegroundTime(int)
* @see #getLastAccessTime(int, int, int)
- * @see OpFeatureEntry#getLastAccessBackgroundTime(int)
+ * @see AttributedOpEntry#getLastAccessBackgroundTime(int)
*/
public long getLastAccessBackgroundTime(@OpFlags int flags) {
return getLastAccessTime(resolveLastRestrictedUidState(mOp), MIN_PRIORITY_UID_STATE,
@@ -3663,13 +3694,14 @@
private @Nullable NoteOpEvent getLastAccessEvent(@UidState int fromUidState,
@UidState int toUidState, @OpFlags int flags) {
NoteOpEvent lastAccessEvent = null;
- for (OpFeatureEntry featureEntry : mFeatures.values()) {
- NoteOpEvent lastFeatureAccessEvent = featureEntry.getLastAccessEvent(fromUidState,
- toUidState, flags);
+ for (AttributedOpEntry attributionEntry : mAttributedOpEntries.values()) {
+ NoteOpEvent lastAttributionAccessEvent = attributionEntry.getLastAccessEvent(
+ fromUidState, toUidState, flags);
- if (lastAccessEvent == null || (lastFeatureAccessEvent != null
- && lastFeatureAccessEvent.getNoteTime() > lastAccessEvent.getNoteTime())) {
- lastAccessEvent = lastFeatureAccessEvent;
+ if (lastAccessEvent == null || (lastAttributionAccessEvent != null
+ && lastAttributionAccessEvent.getNoteTime()
+ > lastAccessEvent.getNoteTime())) {
+ lastAccessEvent = lastAttributionAccessEvent;
}
}
@@ -3689,7 +3721,7 @@
* @see #getLastAccessTime(int)
* @see #getLastAccessForegroundTime(int)
* @see #getLastAccessBackgroundTime(int)
- * @see OpFeatureEntry#getLastAccessTime(int, int, int)
+ * @see AttributedOpEntry#getLastAccessTime(int, int, int)
*/
public long getLastAccessTime(@UidState int fromUidState, @UidState int toUidState,
@OpFlags int flags) {
@@ -3725,7 +3757,7 @@
* @see #getLastRejectForegroundTime(int)
* @see #getLastRejectBackgroundTime(int)
* @see #getLastRejectTime(int, int, int)
- * @see OpFeatureEntry#getLastRejectTime(int)
+ * @see AttributedOpEntry#getLastRejectTime(int)
*/
public long getLastRejectTime(@OpFlags int flags) {
return getLastRejectTime(MAX_PRIORITY_UID_STATE, MIN_PRIORITY_UID_STATE, flags);
@@ -3742,7 +3774,7 @@
* @see #getLastRejectTime(int)
* @see #getLastRejectBackgroundTime(int)
* @see #getLastRejectTime(int, int, int)
- * @see OpFeatureEntry#getLastRejectForegroundTime(int)
+ * @see AttributedOpEntry#getLastRejectForegroundTime(int)
*/
public long getLastRejectForegroundTime(@OpFlags int flags) {
return getLastRejectTime(MAX_PRIORITY_UID_STATE, resolveFirstUnrestrictedUidState(mOp),
@@ -3760,7 +3792,7 @@
* @see #getLastRejectTime(int)
* @see #getLastRejectForegroundTime(int)
* @see #getLastRejectTime(int, int, int)
- * @see OpFeatureEntry#getLastRejectBackgroundTime(int)
+ * @see AttributedOpEntry#getLastRejectBackgroundTime(int)
*/
public long getLastRejectBackgroundTime(@OpFlags int flags) {
return getLastRejectTime(resolveLastRestrictedUidState(mOp), MIN_PRIORITY_UID_STATE,
@@ -3777,13 +3809,14 @@
private @Nullable NoteOpEvent getLastRejectEvent(@UidState int fromUidState,
@UidState int toUidState, @OpFlags int flags) {
NoteOpEvent lastAccessEvent = null;
- for (OpFeatureEntry featureEntry : mFeatures.values()) {
- NoteOpEvent lastFeatureAccessEvent = featureEntry.getLastRejectEvent(fromUidState,
- toUidState, flags);
+ for (AttributedOpEntry attributionEntry : mAttributedOpEntries.values()) {
+ NoteOpEvent lastAttributionAccessEvent = attributionEntry.getLastRejectEvent(
+ fromUidState, toUidState, flags);
- if (lastAccessEvent == null || (lastFeatureAccessEvent != null
- && lastFeatureAccessEvent.getNoteTime() > lastAccessEvent.getNoteTime())) {
- lastAccessEvent = lastFeatureAccessEvent;
+ if (lastAccessEvent == null || (lastAttributionAccessEvent != null
+ && lastAttributionAccessEvent.getNoteTime()
+ > lastAccessEvent.getNoteTime())) {
+ lastAccessEvent = lastAttributionAccessEvent;
}
}
@@ -3804,7 +3837,7 @@
* @see #getLastRejectForegroundTime(int)
* @see #getLastRejectBackgroundTime(int)
* @see #getLastRejectTime(int, int, int)
- * @see OpFeatureEntry#getLastRejectTime(int, int, int)
+ * @see AttributedOpEntry#getLastRejectTime(int, int, int)
*/
public long getLastRejectTime(@UidState int fromUidState, @UidState int toUidState,
@OpFlags int flags) {
@@ -3820,8 +3853,8 @@
* @return Whether the operation is running.
*/
public boolean isRunning() {
- for (OpFeatureEntry opFeatureEntry : mFeatures.values()) {
- if (opFeatureEntry.isRunning()) {
+ for (AttributedOpEntry opAttributionEntry : mAttributedOpEntries.values()) {
+ if (opAttributionEntry.isRunning()) {
return true;
}
}
@@ -3847,7 +3880,7 @@
* @see #getLastForegroundDuration(int)
* @see #getLastBackgroundDuration(int)
* @see #getLastDuration(int, int, int)
- * @see OpFeatureEntry#getLastDuration(int)
+ * @see AttributedOpEntry#getLastDuration(int)
*/
public long getLastDuration(@OpFlags int flags) {
return getLastDuration(MAX_PRIORITY_UID_STATE, MIN_PRIORITY_UID_STATE, flags);
@@ -3863,7 +3896,7 @@
* @see #getLastDuration(int)
* @see #getLastBackgroundDuration(int)
* @see #getLastDuration(int, int, int)
- * @see OpFeatureEntry#getLastForegroundDuration(int)
+ * @see AttributedOpEntry#getLastForegroundDuration(int)
*/
public long getLastForegroundDuration(@OpFlags int flags) {
return getLastDuration(MAX_PRIORITY_UID_STATE, resolveFirstUnrestrictedUidState(mOp),
@@ -3880,7 +3913,7 @@
* @see #getLastDuration(int)
* @see #getLastForegroundDuration(int)
* @see #getLastDuration(int, int, int)
- * @see OpFeatureEntry#getLastBackgroundDuration(int)
+ * @see AttributedOpEntry#getLastBackgroundDuration(int)
*/
public long getLastBackgroundDuration(@OpFlags int flags) {
return getLastDuration(resolveLastRestrictedUidState(mOp), MIN_PRIORITY_UID_STATE,
@@ -3899,7 +3932,7 @@
* @see #getLastDuration(int)
* @see #getLastForegroundDuration(int)
* @see #getLastBackgroundDuration(int)
- * @see OpFeatureEntry#getLastDuration(int, int, int)
+ * @see AttributedOpEntry#getLastDuration(int, int, int)
*/
public long getLastDuration(@UidState int fromUidState, @UidState int toUidState,
@OpFlags int flags) {
@@ -3974,7 +4007,7 @@
* @see #getLastForegroundProxyInfo(int)
* @see #getLastBackgroundProxyInfo(int)
* @see #getLastProxyInfo(int, int, int)
- * @see OpFeatureEntry#getLastProxyInfo(int)
+ * @see AttributedOpEntry#getLastProxyInfo(int)
*/
public @Nullable OpEventProxyInfo getLastProxyInfo(@OpFlags int flags) {
return getLastProxyInfo(MAX_PRIORITY_UID_STATE, MIN_PRIORITY_UID_STATE, flags);
@@ -3991,7 +4024,7 @@
* @see #getLastProxyInfo(int)
* @see #getLastBackgroundProxyInfo(int)
* @see #getLastProxyInfo(int, int, int)
- * @see OpFeatureEntry#getLastForegroundProxyInfo(int)
+ * @see AttributedOpEntry#getLastForegroundProxyInfo(int)
*/
public @Nullable OpEventProxyInfo getLastForegroundProxyInfo(@OpFlags int flags) {
return getLastProxyInfo(MAX_PRIORITY_UID_STATE, resolveFirstUnrestrictedUidState(mOp),
@@ -4009,7 +4042,7 @@
* @see #getLastProxyInfo(int)
* @see #getLastForegroundProxyInfo(int)
* @see #getLastProxyInfo(int, int, int)
- * @see OpFeatureEntry#getLastBackgroundProxyInfo(int)
+ * @see AttributedOpEntry#getLastBackgroundProxyInfo(int)
*/
public @Nullable OpEventProxyInfo getLastBackgroundProxyInfo(@OpFlags int flags) {
return getLastProxyInfo(resolveLastRestrictedUidState(mOp), MIN_PRIORITY_UID_STATE,
@@ -4029,7 +4062,7 @@
* @see #getLastProxyInfo(int)
* @see #getLastForegroundProxyInfo(int)
* @see #getLastBackgroundProxyInfo(int)
- * @see OpFeatureEntry#getLastProxyInfo(int, int, int)
+ * @see AttributedOpEntry#getLastProxyInfo(int, int, int)
*/
public @Nullable OpEventProxyInfo getLastProxyInfo(@UidState int fromUidState,
@UidState int toUidState, @OpFlags int flags) {
@@ -4063,15 +4096,15 @@
* The code of the op
* @param mode
* The mode of the op
- * @param features
- * The features that have been used when checking the op
+ * @param attributedOpEntries
+ * The attributions that have been used when noting the op
* @hide
*/
@DataClass.Generated.Member
public OpEntry(
@IntRange(from = 0, to = _NUM_OP - 1) int op,
@Mode int mode,
- @NonNull Map<String,OpFeatureEntry> features) {
+ @NonNull Map<String, AttributedOpEntry> attributedOpEntries) {
this.mOp = op;
com.android.internal.util.AnnotationValidations.validate(
IntRange.class, null, mOp,
@@ -4080,9 +4113,9 @@
this.mMode = mode;
com.android.internal.util.AnnotationValidations.validate(
Mode.class, null, mMode);
- this.mFeatures = features;
+ this.mAttributedOpEntries = attributedOpEntries;
com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mFeatures);
+ NonNull.class, null, mAttributedOpEntries);
// onConstructed(); // You can define this method to get a callback
}
@@ -4096,14 +4129,14 @@
}
/**
- * The features that have been used when checking the op keyed by id of the feature.
+ * The attributed entries keyed by attribution tag.
*
- * @see Context#createFeatureContext(String)
+ * @see Context#createAttributionContext(String)
* @see #noteOp(String, int, String, String, String)
*/
@DataClass.Generated.Member
- public @NonNull Map<String,OpFeatureEntry> getFeatures() {
- return mFeatures;
+ public @NonNull Map<String, AttributedOpEntry> getAttributedOpEntries() {
+ return mAttributedOpEntries;
}
@Override
@@ -4114,7 +4147,7 @@
dest.writeInt(mOp);
dest.writeInt(mMode);
- dest.writeMap(mFeatures);
+ dest.writeMap(mAttributedOpEntries);
}
@Override
@@ -4130,8 +4163,8 @@
int op = in.readInt();
int mode = in.readInt();
- Map<String,OpFeatureEntry> features = new java.util.LinkedHashMap<>();
- in.readMap(features, OpFeatureEntry.class.getClassLoader());
+ Map<String, AttributedOpEntry> attributions = new java.util.LinkedHashMap<>();
+ in.readMap(attributions, AttributedOpEntry.class.getClassLoader());
this.mOp = op;
com.android.internal.util.AnnotationValidations.validate(
@@ -4141,9 +4174,9 @@
this.mMode = mode;
com.android.internal.util.AnnotationValidations.validate(
Mode.class, null, mMode);
- this.mFeatures = features;
+ this.mAttributedOpEntries = attributions;
com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, mFeatures);
+ NonNull.class, null, mAttributedOpEntries);
// onConstructed(); // You can define this method to get a callback
}
@@ -4167,7 +4200,7 @@
time = 1574809856259L,
codegenVersion = "1.0.14",
sourceFile = "frameworks/base/core/java/android/app/AppOpsManager.java",
- inputSignatures = "private final @android.annotation.IntRange(from=0L, to=_NUM_OP - 1) int mOp\nprivate final @android.app.Mode int mMode\nprivate final @android.annotation.NonNull java.util.Map<java.lang.String,android.app.OpFeatureEntry> mFeatures\npublic @android.annotation.UnsupportedAppUsage(maxTargetSdk=Build.VERSION_CODES.Q, publicAlternatives=\"{@code \" + \"#getOpStr()}\") int getOp()\npublic @android.annotation.NonNull java.lang.String getOpStr()\npublic @java.lang.Deprecated @android.annotation.UnsupportedAppUsage(maxTargetSdk=Build.VERSION_CODES.Q, publicAlternatives=\"{@code \" + \"#getAccessTime(int, int)}\") long getTime()\npublic @java.lang.Deprecated long getLastAccessTime(int)\npublic @java.lang.Deprecated long getLastAccessForegroundTime(int)\npublic @java.lang.Deprecated long getLastAccessBackgroundTime(int)\npublic @java.lang.Deprecated long getLastAccessTime(int,int,int)\npublic @java.lang.Deprecated @android.annotation.UnsupportedAppUsage(maxTargetSdk=Build.VERSION_CODES.Q, publicAlternatives=\"{@code \" + \"#getLastRejectTime(int, int, int)}\") long getRejectTime()\npublic @java.lang.Deprecated long getLastRejectTime(int)\npublic @java.lang.Deprecated long getLastRejectForegroundTime(int)\npublic @java.lang.Deprecated long getLastRejectBackgroundTime(int)\npublic @java.lang.Deprecated long getLastRejectTime(int,int,int)\npublic long getAccessTime(int,int)\npublic long getRejectTime(int,int)\npublic boolean isRunning()\nprivate android.app.NoteOpEvent getLastAccessEvent(int,int,int)\npublic @java.lang.Deprecated long getDuration()\npublic @java.lang.Deprecated long getLastForegroundDuration(int)\npublic @java.lang.Deprecated long getLastBackgroundDuration(int)\npublic @java.lang.Deprecated long getLastDuration(int,int,int)\npublic @java.lang.Deprecated int getProxyUid()\npublic @java.lang.Deprecated @android.annotation.Nullable java.lang.String getProxyPackageName()\nprivate @android.app.UidState int getLastAccessUidStateForFlagsInStatesOfAllFeatures(int,int,int)\npublic @android.app.UidState int getLastAccessUidState(int)\npublic @android.app.UidState int getLastForegroundAccessUidState(int)\npublic @android.app.UidState int getLastBackgroundAccessUidState(int)\nprivate @android.app.UidState int getLastRejectUidStateForFlagsInStatesOfAllFeatures(int,int,int)\npublic @android.app.UidState int getLastRejectUidState(int)\npublic @android.app.UidState int getLastForegroundRejectUidState(int)\npublic @android.app.UidState int getLastBackgroundRejectUidState(int)\npublic long getDuration(int,int)\npublic int getProxyUid(int,int)\nprivate int getProxyUid(int,int,int)\npublic @android.annotation.Nullable java.lang.String getProxyPackageName(int,int)\nprivate @android.annotation.Nullable java.lang.String getProxyPackageName(int,int,int)\nclass OpEntry extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true)")
+ inputSignatures = "private final @android.annotation.IntRange(from=0L, to=_NUM_OP - 1) int mOp\nprivate final @android.app.Mode int mMode\nprivate final @android.annotation.NonNull java.util.Map<java.lang.String,android.app.OpAttributionEntry> mAttributions\npublic @android.annotation.UnsupportedAppUsage(maxTargetSdk=Build.VERSION_CODES.Q, publicAlternatives=\"{@code \" + \"#getOpStr()}\") int getOp()\npublic @android.annotation.NonNull java.lang.String getOpStr()\npublic @java.lang.Deprecated @android.annotation.UnsupportedAppUsage(maxTargetSdk=Build.VERSION_CODES.Q, publicAlternatives=\"{@code \" + \"#getAccessTime(int, int)}\") long getTime()\npublic @java.lang.Deprecated long getLastAccessTime(int)\npublic @java.lang.Deprecated long getLastAccessForegroundTime(int)\npublic @java.lang.Deprecated long getLastAccessBackgroundTime(int)\npublic @java.lang.Deprecated long getLastAccessTime(int,int,int)\npublic @java.lang.Deprecated @android.annotation.UnsupportedAppUsage(maxTargetSdk=Build.VERSION_CODES.Q, publicAlternatives=\"{@code \" + \"#getLastRejectTime(int, int, int)}\") long getRejectTime()\npublic @java.lang.Deprecated long getLastRejectTime(int)\npublic @java.lang.Deprecated long getLastRejectForegroundTime(int)\npublic @java.lang.Deprecated long getLastRejectBackgroundTime(int)\npublic @java.lang.Deprecated long getLastRejectTime(int,int,int)\npublic long getAccessTime(int,int)\npublic long getRejectTime(int,int)\npublic boolean isRunning()\nprivate android.app.NoteOpEvent getLastAccessEvent(int,int,int)\npublic @java.lang.Deprecated long getDuration()\npublic @java.lang.Deprecated long getLastForegroundDuration(int)\npublic @java.lang.Deprecated long getLastBackgroundDuration(int)\npublic @java.lang.Deprecated long getLastDuration(int,int,int)\npublic @java.lang.Deprecated int getProxyUid()\npublic @java.lang.Deprecated @android.annotation.Nullable java.lang.String getProxyPackageName()\nprivate @android.app.UidState int getLastAccessUidStateForFlagsInStatesOfAllAttributions(int,int,int)\npublic @android.app.UidState int getLastAccessUidState(int)\npublic @android.app.UidState int getLastForegroundAccessUidState(int)\npublic @android.app.UidState int getLastBackgroundAccessUidState(int)\nprivate @android.app.UidState int getLastRejectUidStateForFlagsInStatesOfAllAttributions(int,int,int)\npublic @android.app.UidState int getLastRejectUidState(int)\npublic @android.app.UidState int getLastForegroundRejectUidState(int)\npublic @android.app.UidState int getLastBackgroundRejectUidState(int)\npublic long getDuration(int,int)\npublic int getProxyUid(int,int)\nprivate int getProxyUid(int,int,int)\npublic @android.annotation.Nullable java.lang.String getProxyPackageName(int,int)\nprivate @android.annotation.Nullable java.lang.String getProxyPackageName(int,int,int)\nclass OpEntry extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true)")
@Deprecated
private void __metadata() {}
*/
@@ -4183,7 +4216,7 @@
void visitHistoricalOps(@NonNull HistoricalOps ops);
void visitHistoricalUidOps(@NonNull HistoricalUidOps ops);
void visitHistoricalPackageOps(@NonNull HistoricalPackageOps ops);
- void visitHistoricalFeatureOps(@NonNull HistoricalFeatureOps ops);
+ void visitHistoricalAttributionOps(@NonNull AttributedHistoricalOps ops);
void visitHistoricalOp(@NonNull HistoricalOp ops);
}
@@ -4196,7 +4229,7 @@
@IntDef(flag = true, prefix = { "FILTER_BY_" }, value = {
FILTER_BY_UID,
FILTER_BY_PACKAGE_NAME,
- FILTER_BY_FEATURE_ID,
+ FILTER_BY_ATTRIBUTION_TAG,
FILTER_BY_OP_NAMES
})
public @interface HistoricalOpsRequestFilter {}
@@ -4216,11 +4249,11 @@
public static final int FILTER_BY_PACKAGE_NAME = 1<<1;
/**
- * Filter historical appop request by feature id.
+ * Filter historical appop request by attribution tag.
*
* @hide
*/
- public static final int FILTER_BY_FEATURE_ID = 1<<2;
+ public static final int FILTER_BY_ATTRIBUTION_TAG = 1<<2;
/**
* Filter historical appop request by op names.
@@ -4241,7 +4274,7 @@
public static final class HistoricalOpsRequest {
private final int mUid;
private final @Nullable String mPackageName;
- private final @Nullable String mFeatureId;
+ private final @Nullable String mAttributionTag;
private final @Nullable List<String> mOpNames;
private final @HistoricalOpsRequestFilter int mFilter;
private final long mBeginTimeMillis;
@@ -4249,12 +4282,12 @@
private final @OpFlags int mFlags;
private HistoricalOpsRequest(int uid, @Nullable String packageName,
- @Nullable String featureId, @Nullable List<String> opNames,
+ @Nullable String attributionTag, @Nullable List<String> opNames,
@HistoricalOpsRequestFilter int filter, long beginTimeMillis,
long endTimeMillis, @OpFlags int flags) {
mUid = uid;
mPackageName = packageName;
- mFeatureId = featureId;
+ mAttributionTag = attributionTag;
mOpNames = opNames;
mFilter = filter;
mBeginTimeMillis = beginTimeMillis;
@@ -4272,7 +4305,7 @@
public static final class Builder {
private int mUid = Process.INVALID_UID;
private @Nullable String mPackageName;
- private @Nullable String mFeatureId;
+ private @Nullable String mAttributionTag;
private @Nullable List<String> mOpNames;
private @HistoricalOpsRequestFilter int mFilter;
private final long mBeginTimeMillis;
@@ -4336,14 +4369,14 @@
}
/**
- * Sets the feature id to query for.
+ * Sets the attribution tag to query for.
*
- * @param featureId The id of the feature.
+ * @param attributionTag attribution tag
* @return This builder.
*/
- public @NonNull Builder setFeatureId(@Nullable String featureId) {
- mFeatureId = featureId;
- mFilter |= FILTER_BY_FEATURE_ID;
+ public @NonNull Builder setAttributionTag(@Nullable String attributionTag) {
+ mAttributionTag = attributionTag;
+ mFilter |= FILTER_BY_ATTRIBUTION_TAG;
return this;
}
@@ -4394,7 +4427,7 @@
* @return a new {@link HistoricalOpsRequest}.
*/
public @NonNull HistoricalOpsRequest build() {
- return new HistoricalOpsRequest(mUid, mPackageName, mFeatureId, mOpNames,
+ return new HistoricalOpsRequest(mUid, mPackageName, mAttributionTag, mOpNames,
mFilter, mBeginTimeMillis, mEndTimeMillis, mFlags);
}
}
@@ -4554,7 +4587,7 @@
*
* @param uid Uid to filter for.
* @param packageName Package to filter for.
- * @param featureId Package to filter for.
+ * @param attributionTag attribution tag to filter for
* @param opNames Ops to filter for.
* @param filter Which parameters to filter on.
* @param beginTimeMillis The begin time to filter for or {@link Long#MIN_VALUE} for all.
@@ -4562,7 +4595,7 @@
*
* @hide
*/
- public void filter(int uid, @Nullable String packageName, @Nullable String featureId,
+ public void filter(int uid, @Nullable String packageName, @Nullable String attributionTag,
@Nullable String[] opNames, @HistoricalOpsRequestFilter int filter,
long beginTimeMillis, long endTimeMillis) {
final long durationMillis = getDurationMillis();
@@ -4576,7 +4609,7 @@
if ((filter & FILTER_BY_UID) != 0 && uid != uidOp.getUid()) {
mHistoricalUidOps.removeAt(i);
} else {
- uidOp.filter(packageName, featureId, opNames, filter, scaleFactor);
+ uidOp.filter(packageName, attributionTag, opNames, filter, scaleFactor);
if (uidOp.getPackageCount() == 0) {
mHistoricalUidOps.removeAt(i);
}
@@ -4607,28 +4640,28 @@
/** @hide */
@TestApi
public void increaseAccessCount(int opCode, int uid, @NonNull String packageName,
- @Nullable String featureId, @UidState int uidState, @OpFlags int flags,
+ @Nullable String attributionTag, @UidState int uidState, @OpFlags int flags,
long increment) {
getOrCreateHistoricalUidOps(uid).increaseAccessCount(opCode,
- packageName, featureId, uidState, flags, increment);
+ packageName, attributionTag, uidState, flags, increment);
}
/** @hide */
@TestApi
public void increaseRejectCount(int opCode, int uid, @NonNull String packageName,
- @Nullable String featureId, @UidState int uidState, @OpFlags int flags,
+ @Nullable String attributionTag, @UidState int uidState, @OpFlags int flags,
long increment) {
getOrCreateHistoricalUidOps(uid).increaseRejectCount(opCode,
- packageName, featureId, uidState, flags, increment);
+ packageName, attributionTag, uidState, flags, increment);
}
/** @hide */
@TestApi
public void increaseAccessDuration(int opCode, int uid, @NonNull String packageName,
- @Nullable String featureId, @UidState int uidState, @OpFlags int flags,
+ @Nullable String attributionTag, @UidState int uidState, @OpFlags int flags,
long increment) {
getOrCreateHistoricalUidOps(uid).increaseAccessDuration(opCode,
- packageName, featureId, uidState, flags, increment);
+ packageName, attributionTag, uidState, flags, increment);
}
/** @hide */
@@ -4908,7 +4941,7 @@
}
}
- private void filter(@Nullable String packageName, @Nullable String featureId,
+ private void filter(@Nullable String packageName, @Nullable String attributionTag,
@Nullable String[] opNames, @HistoricalOpsRequestFilter int filter,
double fractionToRemove) {
final int packageCount = getPackageCount();
@@ -4918,8 +4951,8 @@
packageOps.getPackageName())) {
mHistoricalPackageOps.removeAt(i);
} else {
- packageOps.filter(featureId, opNames, filter, fractionToRemove);
- if (packageOps.getFeatureCount() == 0) {
+ packageOps.filter(attributionTag, opNames, filter, fractionToRemove);
+ if (packageOps.getAttributedOpsCount() == 0) {
mHistoricalPackageOps.removeAt(i);
}
}
@@ -4938,24 +4971,24 @@
}
private void increaseAccessCount(int opCode, @NonNull String packageName,
- @Nullable String featureId, @UidState int uidState, @OpFlags int flags,
+ @Nullable String attributionTag, @UidState int uidState, @OpFlags int flags,
long increment) {
getOrCreateHistoricalPackageOps(packageName).increaseAccessCount(
- opCode, featureId, uidState, flags, increment);
+ opCode, attributionTag, uidState, flags, increment);
}
private void increaseRejectCount(int opCode, @NonNull String packageName,
- @Nullable String featureId, @UidState int uidState, @OpFlags int flags,
+ @Nullable String attributionTag, @UidState int uidState, @OpFlags int flags,
long increment) {
getOrCreateHistoricalPackageOps(packageName).increaseRejectCount(
- opCode, featureId, uidState, flags, increment);
+ opCode, attributionTag, uidState, flags, increment);
}
private void increaseAccessDuration(int opCode, @NonNull String packageName,
- @Nullable String featureId, @UidState int uidState, @OpFlags int flags,
+ @Nullable String attributionTag, @UidState int uidState, @OpFlags int flags,
long increment) {
getOrCreateHistoricalPackageOps(packageName).increaseAccessDuration(
- opCode, featureId, uidState, flags, increment);
+ opCode, attributionTag, uidState, flags, increment);
}
/**
@@ -5100,7 +5133,7 @@
@SystemApi
public static final class HistoricalPackageOps implements Parcelable {
private final @NonNull String mPackageName;
- private @Nullable ArrayMap<String, HistoricalFeatureOps> mHistoricalFeatureOps;
+ private @Nullable ArrayMap<String, AttributedHistoricalOps> mAttributedHistoricalOps;
/** @hide */
public HistoricalPackageOps(@NonNull String packageName) {
@@ -5109,70 +5142,71 @@
private HistoricalPackageOps(@NonNull HistoricalPackageOps other) {
mPackageName = other.mPackageName;
- final int opCount = other.getFeatureCount();
+ final int opCount = other.getAttributedOpsCount();
for (int i = 0; i < opCount; i++) {
- final HistoricalFeatureOps origOps = other.getFeatureOpsAt(i);
- final HistoricalFeatureOps cloneOps = new HistoricalFeatureOps(origOps);
- if (mHistoricalFeatureOps == null) {
- mHistoricalFeatureOps = new ArrayMap<>(opCount);
+ final AttributedHistoricalOps origOps = other.getAttributedOpsAt(i);
+ final AttributedHistoricalOps cloneOps = new AttributedHistoricalOps(origOps);
+ if (mAttributedHistoricalOps == null) {
+ mAttributedHistoricalOps = new ArrayMap<>(opCount);
}
- mHistoricalFeatureOps.put(cloneOps.getFeatureId(), cloneOps);
+ mAttributedHistoricalOps.put(cloneOps.getTag(), cloneOps);
}
}
private HistoricalPackageOps(@NonNull Parcel parcel) {
mPackageName = parcel.readString();
- mHistoricalFeatureOps = parcel.createTypedArrayMap(HistoricalFeatureOps.CREATOR);
+ mAttributedHistoricalOps = parcel.createTypedArrayMap(AttributedHistoricalOps.CREATOR);
}
private @Nullable HistoricalPackageOps splice(double fractionToRemove) {
HistoricalPackageOps splice = null;
- final int featureCount = getFeatureCount();
- for (int i = 0; i < featureCount; i++) {
- final HistoricalFeatureOps origOps = getFeatureOpsAt(i);
- final HistoricalFeatureOps spliceOps = origOps.splice(fractionToRemove);
+ final int attributionCount = getAttributedOpsCount();
+ for (int i = 0; i < attributionCount; i++) {
+ final AttributedHistoricalOps origOps = getAttributedOpsAt(i);
+ final AttributedHistoricalOps spliceOps = origOps.splice(fractionToRemove);
if (spliceOps != null) {
if (splice == null) {
splice = new HistoricalPackageOps(mPackageName);
}
- if (splice.mHistoricalFeatureOps == null) {
- splice.mHistoricalFeatureOps = new ArrayMap<>();
+ if (splice.mAttributedHistoricalOps == null) {
+ splice.mAttributedHistoricalOps = new ArrayMap<>();
}
- splice.mHistoricalFeatureOps.put(spliceOps.getFeatureId(), spliceOps);
+ splice.mAttributedHistoricalOps.put(spliceOps.getTag(), spliceOps);
}
}
return splice;
}
private void merge(@NonNull HistoricalPackageOps other) {
- final int featureCount = other.getFeatureCount();
- for (int i = 0; i < featureCount; i++) {
- final HistoricalFeatureOps otherFeatureOps = other.getFeatureOpsAt(i);
- final HistoricalFeatureOps thisFeatureOps = getFeatureOps(
- otherFeatureOps.getFeatureId());
- if (thisFeatureOps != null) {
- thisFeatureOps.merge(otherFeatureOps);
+ final int attributionCount = other.getAttributedOpsCount();
+ for (int i = 0; i < attributionCount; i++) {
+ final AttributedHistoricalOps otherAttributionOps = other.getAttributedOpsAt(i);
+ final AttributedHistoricalOps thisAttributionOps = getAttributedOps(
+ otherAttributionOps.getTag());
+ if (thisAttributionOps != null) {
+ thisAttributionOps.merge(otherAttributionOps);
} else {
- if (mHistoricalFeatureOps == null) {
- mHistoricalFeatureOps = new ArrayMap<>();
+ if (mAttributedHistoricalOps == null) {
+ mAttributedHistoricalOps = new ArrayMap<>();
}
- mHistoricalFeatureOps.put(otherFeatureOps.getFeatureId(), otherFeatureOps);
+ mAttributedHistoricalOps.put(otherAttributionOps.getTag(),
+ otherAttributionOps);
}
}
}
- private void filter(@Nullable String featureId, @Nullable String[] opNames,
+ private void filter(@Nullable String attributionTag, @Nullable String[] opNames,
@HistoricalOpsRequestFilter int filter, double fractionToRemove) {
- final int featureCount = getFeatureCount();
- for (int i = featureCount - 1; i >= 0; i--) {
- final HistoricalFeatureOps featureOps = getFeatureOpsAt(i);
- if ((filter & FILTER_BY_FEATURE_ID) != 0 && !Objects.equals(featureId,
- featureOps.getFeatureId())) {
- mHistoricalFeatureOps.removeAt(i);
+ final int attributionCount = getAttributedOpsCount();
+ for (int i = attributionCount - 1; i >= 0; i--) {
+ final AttributedHistoricalOps attributionOps = getAttributedOpsAt(i);
+ if ((filter & FILTER_BY_ATTRIBUTION_TAG) != 0 && !Objects.equals(attributionTag,
+ attributionOps.getTag())) {
+ mAttributedHistoricalOps.removeAt(i);
} else {
- featureOps.filter(opNames, filter, fractionToRemove);
- if (featureOps.getOpCount() == 0) {
- mHistoricalFeatureOps.removeAt(i);
+ attributionOps.filter(opNames, filter, fractionToRemove);
+ if (attributionOps.getOpCount() == 0) {
+ mAttributedHistoricalOps.removeAt(i);
}
}
}
@@ -5180,38 +5214,38 @@
private void accept(@NonNull HistoricalOpsVisitor visitor) {
visitor.visitHistoricalPackageOps(this);
- final int featureCount = getFeatureCount();
- for (int i = 0; i < featureCount; i++) {
- getFeatureOpsAt(i).accept(visitor);
+ final int attributionCount = getAttributedOpsCount();
+ for (int i = 0; i < attributionCount; i++) {
+ getAttributedOpsAt(i).accept(visitor);
}
}
private boolean isEmpty() {
- final int featureCount = getFeatureCount();
- for (int i = featureCount - 1; i >= 0; i--) {
- final HistoricalFeatureOps featureOps = mHistoricalFeatureOps.valueAt(i);
- if (!featureOps.isEmpty()) {
+ final int attributionCount = getAttributedOpsCount();
+ for (int i = attributionCount - 1; i >= 0; i--) {
+ final AttributedHistoricalOps attributionOps = mAttributedHistoricalOps.valueAt(i);
+ if (!attributionOps.isEmpty()) {
return false;
}
}
return true;
}
- private void increaseAccessCount(int opCode, @Nullable String featureId,
+ private void increaseAccessCount(int opCode, @Nullable String attributionTag,
@UidState int uidState, @OpFlags int flags, long increment) {
- getOrCreateHistoricalFeatureOps(featureId).increaseAccessCount(
+ getOrCreateAttributedHistoricalOps(attributionTag).increaseAccessCount(
opCode, uidState, flags, increment);
}
- private void increaseRejectCount(int opCode, @Nullable String featureId,
+ private void increaseRejectCount(int opCode, @Nullable String attributionTag,
@UidState int uidState, @OpFlags int flags, long increment) {
- getOrCreateHistoricalFeatureOps(featureId).increaseRejectCount(
+ getOrCreateAttributedHistoricalOps(attributionTag).increaseRejectCount(
opCode, uidState, flags, increment);
}
- private void increaseAccessDuration(int opCode, @Nullable String featureId,
+ private void increaseAccessDuration(int opCode, @Nullable String attributionTag,
@UidState int uidState, @OpFlags int flags, long increment) {
- getOrCreateHistoricalFeatureOps(featureId).increaseAccessDuration(
+ getOrCreateAttributedHistoricalOps(attributionTag).increaseAccessDuration(
opCode, uidState, flags, increment);
}
@@ -5224,17 +5258,18 @@
return mPackageName;
}
- private @NonNull HistoricalFeatureOps getOrCreateHistoricalFeatureOps(
- @Nullable String featureId) {
- if (mHistoricalFeatureOps == null) {
- mHistoricalFeatureOps = new ArrayMap<>();
+ private @NonNull AttributedHistoricalOps getOrCreateAttributedHistoricalOps(
+ @Nullable String attributionTag) {
+ if (mAttributedHistoricalOps == null) {
+ mAttributedHistoricalOps = new ArrayMap<>();
}
- HistoricalFeatureOps historicalFeatureOp = mHistoricalFeatureOps.get(featureId);
- if (historicalFeatureOp == null) {
- historicalFeatureOp = new HistoricalFeatureOps(featureId);
- mHistoricalFeatureOps.put(featureId, historicalFeatureOp);
+ AttributedHistoricalOps historicalAttributionOp = mAttributedHistoricalOps.get(
+ attributionTag);
+ if (historicalAttributionOp == null) {
+ historicalAttributionOp = new AttributedHistoricalOps(attributionTag);
+ mAttributedHistoricalOps.put(attributionTag, historicalAttributionOp);
}
- return historicalFeatureOp;
+ return historicalAttributionOp;
}
/**
@@ -5245,13 +5280,13 @@
*/
public @IntRange(from = 0) int getOpCount() {
int numOps = 0;
- int numFeatures = getFeatureCount();
+ int numAttributions = getAttributedOpsCount();
for (int code = 0; code < _NUM_OP; code++) {
String opName = opToPublicName(code);
- for (int featureNum = 0; featureNum < numFeatures; featureNum++) {
- if (getFeatureOpsAt(featureNum).getOp(opName) != null) {
+ for (int attributionNum = 0; attributionNum < numAttributions; attributionNum++) {
+ if (getAttributedOpsAt(attributionNum).getOp(opName) != null) {
numOps++;
break;
}
@@ -5264,7 +5299,7 @@
/**
* Gets the historical op at a given index.
*
- * <p>This combines the counts from all features.
+ * <p>This combines the counts from all attributions.
*
* @param index The index to lookup.
* @return The op at the given index.
@@ -5272,13 +5307,13 @@
*/
public @NonNull HistoricalOp getOpAt(@IntRange(from = 0) int index) {
int numOpsFound = 0;
- int numFeatures = getFeatureCount();
+ int numAttributions = getAttributedOpsCount();
for (int code = 0; code < _NUM_OP; code++) {
String opName = opToPublicName(code);
- for (int featureNum = 0; featureNum < numFeatures; featureNum++) {
- if (getFeatureOpsAt(featureNum).getOp(opName) != null) {
+ for (int attributionNum = 0; attributionNum < numAttributions; attributionNum++) {
+ if (getAttributedOpsAt(attributionNum).getOp(opName) != null) {
if (numOpsFound == index) {
return getOp(opName);
} else {
@@ -5295,25 +5330,25 @@
/**
* Gets the historical entry for a given op name.
*
- * <p>This combines the counts from all features.
+ * <p>This combines the counts from all attributions.
*
* @param opName The op name.
* @return The historical entry for that op name.
*/
public @Nullable HistoricalOp getOp(@NonNull String opName) {
- if (mHistoricalFeatureOps == null) {
+ if (mAttributedHistoricalOps == null) {
return null;
}
HistoricalOp combinedOp = null;
- int numFeatures = getFeatureCount();
- for (int i = 0; i < numFeatures; i++) {
- HistoricalOp featureOp = getFeatureOpsAt(i).getOp(opName);
- if (featureOp != null) {
+ int numAttributions = getAttributedOpsCount();
+ for (int i = 0; i < numAttributions; i++) {
+ HistoricalOp attributionOp = getAttributedOpsAt(i).getOp(opName);
+ if (attributionOp != null) {
if (combinedOp == null) {
- combinedOp = new HistoricalOp(featureOp);
+ combinedOp = new HistoricalOp(attributionOp);
} else {
- combinedOp.merge(featureOp);
+ combinedOp.merge(attributionOp);
}
}
}
@@ -5329,7 +5364,7 @@
@Override
public void writeToParcel(@NonNull Parcel parcel, int flags) {
parcel.writeString(mPackageName);
- parcel.writeTypedArrayMap(mHistoricalFeatureOps, flags);
+ parcel.writeTypedArrayMap(mAttributedHistoricalOps, flags);
}
public static final @android.annotation.NonNull Creator<HistoricalPackageOps> CREATOR =
@@ -5357,11 +5392,11 @@
if (!mPackageName.equals(other.mPackageName)) {
return false;
}
- if (mHistoricalFeatureOps == null) {
- if (other.mHistoricalFeatureOps != null) {
+ if (mAttributedHistoricalOps == null) {
+ if (other.mAttributedHistoricalOps != null) {
return false;
}
- } else if (!mHistoricalFeatureOps.equals(other.mHistoricalFeatureOps)) {
+ } else if (!mAttributedHistoricalOps.equals(other.mAttributedHistoricalOps)) {
return false;
}
return true;
@@ -5370,58 +5405,58 @@
@Override
public int hashCode() {
int result = mPackageName != null ? mPackageName.hashCode() : 0;
- result = 31 * result + (mHistoricalFeatureOps != null ? mHistoricalFeatureOps.hashCode()
- : 0);
+ result = 31 * result + (mAttributedHistoricalOps != null
+ ? mAttributedHistoricalOps.hashCode() : 0);
return result;
}
/**
- * Gets number of feature with historical ops.
+ * Gets number of attributed historical ops.
*
- * @return The number of feature with historical ops.
+ * @return The number of attribution with historical ops.
*
- * @see #getFeatureOpsAt(int)
+ * @see #getAttributedOpsAt(int)
*/
- public @IntRange(from = 0) int getFeatureCount() {
- if (mHistoricalFeatureOps == null) {
+ public @IntRange(from = 0) int getAttributedOpsCount() {
+ if (mAttributedHistoricalOps == null) {
return 0;
}
- return mHistoricalFeatureOps.size();
+ return mAttributedHistoricalOps.size();
}
/**
- * Gets the historical feature ops at a given index.
+ * Gets the attributed historical ops at a given index.
*
* @param index The index.
*
- * @return The historical feature ops at the given index.
+ * @return The historical attribution ops at the given index.
*
- * @see #getFeatureCount()
+ * @see #getAttributedOpsCount()
*/
- public @NonNull HistoricalFeatureOps getFeatureOpsAt(@IntRange(from = 0) int index) {
- if (mHistoricalFeatureOps == null) {
+ public @NonNull AttributedHistoricalOps getAttributedOpsAt(@IntRange(from = 0) int index) {
+ if (mAttributedHistoricalOps == null) {
throw new IndexOutOfBoundsException();
}
- return mHistoricalFeatureOps.valueAt(index);
+ return mAttributedHistoricalOps.valueAt(index);
}
/**
- * Gets the historical feature ops for a given feature.
+ * Gets the attributed historical ops for a given attribution tag.
*
- * @param featureId The feature id.
+ * @param attributionTag The attribution tag.
*
- * @return The historical ops for the feature.
+ * @return The historical ops for the attribution.
*/
- public @Nullable HistoricalFeatureOps getFeatureOps(@NonNull String featureId) {
- if (mHistoricalFeatureOps == null) {
+ public @Nullable AttributedHistoricalOps getAttributedOps(@NonNull String attributionTag) {
+ if (mAttributedHistoricalOps == null) {
return null;
}
- return mHistoricalFeatureOps.get(featureId);
+ return mAttributedHistoricalOps.get(attributionTag);
}
}
/**
- * This class represents historical app op information about a feature in a package.
+ * This class represents historical app op information about a attribution in a package.
*
* @hide
*/
@@ -5431,20 +5466,20 @@
@DataClass(genHiddenConstructor = true,
genEqualsHashCode = true, genHiddenCopyConstructor = true) */
@DataClass.Suppress("getHistoricalOps")
- public static final class HistoricalFeatureOps implements Parcelable {
- /** Id of the {@link Context#createFeatureContext feature} in the package */
- private final @Nullable String mFeatureId;
+ public static final class AttributedHistoricalOps implements Parcelable {
+ /** {@link Context#createAttributionContext attribution} tag */
+ private final @Nullable String mTag;
- /** Ops for this feature */
+ /** Ops for this attribution */
private @Nullable ArrayMap<String, HistoricalOp> mHistoricalOps;
/** @hide */
- public HistoricalFeatureOps(@NonNull String featureId) {
- mFeatureId = featureId;
+ public AttributedHistoricalOps(@NonNull String tag) {
+ mTag = tag;
}
- private HistoricalFeatureOps(@NonNull HistoricalFeatureOps other) {
- mFeatureId = other.mFeatureId;
+ private AttributedHistoricalOps(@NonNull AttributedHistoricalOps other) {
+ mTag = other.mTag;
final int opCount = other.getOpCount();
for (int i = 0; i < opCount; i++) {
final HistoricalOp origOp = other.getOpAt(i);
@@ -5456,15 +5491,15 @@
}
}
- private @Nullable HistoricalFeatureOps splice(double fractionToRemove) {
- HistoricalFeatureOps splice = null;
+ private @Nullable AttributedHistoricalOps splice(double fractionToRemove) {
+ AttributedHistoricalOps splice = null;
final int opCount = getOpCount();
for (int i = 0; i < opCount; i++) {
final HistoricalOp origOps = getOpAt(i);
final HistoricalOp spliceOps = origOps.splice(fractionToRemove);
if (spliceOps != null) {
if (splice == null) {
- splice = new HistoricalFeatureOps(mFeatureId, null);
+ splice = new AttributedHistoricalOps(mTag, null);
}
if (splice.mHistoricalOps == null) {
splice.mHistoricalOps = new ArrayMap<>();
@@ -5475,7 +5510,7 @@
return splice;
}
- private void merge(@NonNull HistoricalFeatureOps other) {
+ private void merge(@NonNull AttributedHistoricalOps other) {
final int opCount = other.getOpCount();
for (int i = 0; i < opCount; i++) {
final HistoricalOp otherOp = other.getOpAt(i);
@@ -5572,7 +5607,7 @@
}
private void accept(@NonNull HistoricalOpsVisitor visitor) {
- visitor.visitHistoricalFeatureOps(this);
+ visitor.visitHistoricalAttributionOps(this);
final int opCount = getOpCount();
for (int i = 0; i < opCount; i++) {
getOpAt(i).accept(visitor);
@@ -5608,46 +5643,46 @@
/**
- * Creates a new HistoricalFeatureOps.
+ * Creates a new HistoricalAttributionOps.
*
- * @param featureId
- * Id of the {@link Context#createFeatureContext feature} in the package
+ * @param tag
+ * {@link Context#createAttributionContext attribution} tag
* @param historicalOps
- * Ops for this feature
+ * Ops for this attribution
* @hide
*/
@DataClass.Generated.Member
- public HistoricalFeatureOps(
- @Nullable String featureId,
+ public AttributedHistoricalOps(
+ @Nullable String tag,
@Nullable ArrayMap<String,HistoricalOp> historicalOps) {
- this.mFeatureId = featureId;
+ this.mTag = tag;
this.mHistoricalOps = historicalOps;
// onConstructed(); // You can define this method to get a callback
}
/**
- * Id of the {@link Context#createFeatureContext feature} in the package
+ * {@link Context#createAttributionContext attribution} tag
*/
@DataClass.Generated.Member
- public @Nullable String getFeatureId() {
- return mFeatureId;
+ public @Nullable String getTag() {
+ return mTag;
}
@Override
@DataClass.Generated.Member
public boolean equals(@Nullable Object o) {
// You can override field equality logic by defining either of the methods like:
- // boolean fieldNameEquals(HistoricalFeatureOps other) { ... }
+ // boolean fieldNameEquals(HistoricalAttributionOps other) { ... }
// boolean fieldNameEquals(FieldType otherValue) { ... }
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
@SuppressWarnings("unchecked")
- HistoricalFeatureOps that = (HistoricalFeatureOps) o;
+ AttributedHistoricalOps that = (AttributedHistoricalOps) o;
//noinspection PointlessBooleanExpression
return true
- && Objects.equals(mFeatureId, that.mFeatureId)
+ && Objects.equals(mTag, that.mTag)
&& Objects.equals(mHistoricalOps, that.mHistoricalOps);
}
@@ -5658,7 +5693,7 @@
// int fieldNameHashCode() { ... }
int _hash = 1;
- _hash = 31 * _hash + Objects.hashCode(mFeatureId);
+ _hash = 31 * _hash + Objects.hashCode(mTag);
_hash = 31 * _hash + Objects.hashCode(mHistoricalOps);
return _hash;
}
@@ -5670,10 +5705,10 @@
// void parcelFieldName(Parcel dest, int flags) { ... }
byte flg = 0;
- if (mFeatureId != null) flg |= 0x1;
+ if (mTag != null) flg |= 0x1;
if (mHistoricalOps != null) flg |= 0x2;
dest.writeByte(flg);
- if (mFeatureId != null) dest.writeString(mFeatureId);
+ if (mTag != null) dest.writeString(mTag);
if (mHistoricalOps != null) dest.writeMap(mHistoricalOps);
}
@@ -5684,35 +5719,35 @@
/** @hide */
@SuppressWarnings({"unchecked", "RedundantCast"})
@DataClass.Generated.Member
- /* package-private */ HistoricalFeatureOps(@NonNull Parcel in) {
+ /* package-private */ AttributedHistoricalOps(@NonNull Parcel in) {
// You can override field unparcelling by defining methods like:
// static FieldType unparcelFieldName(Parcel in) { ... }
byte flg = in.readByte();
- String featureId = (flg & 0x1) == 0 ? null : in.readString();
+ String attributionTag = (flg & 0x1) == 0 ? null : in.readString();
ArrayMap<String,HistoricalOp> historicalOps = null;
if ((flg & 0x2) != 0) {
historicalOps = new ArrayMap();
in.readMap(historicalOps, HistoricalOp.class.getClassLoader());
}
- this.mFeatureId = featureId;
+ this.mTag = attributionTag;
this.mHistoricalOps = historicalOps;
// onConstructed(); // You can define this method to get a callback
}
@DataClass.Generated.Member
- public static final @NonNull Parcelable.Creator<HistoricalFeatureOps> CREATOR
- = new Parcelable.Creator<HistoricalFeatureOps>() {
+ public static final @NonNull Parcelable.Creator<AttributedHistoricalOps> CREATOR
+ = new Parcelable.Creator<AttributedHistoricalOps>() {
@Override
- public HistoricalFeatureOps[] newArray(int size) {
- return new HistoricalFeatureOps[size];
+ public AttributedHistoricalOps[] newArray(int size) {
+ return new AttributedHistoricalOps[size];
}
@Override
- public HistoricalFeatureOps createFromParcel(@NonNull Parcel in) {
- return new HistoricalFeatureOps(in);
+ public AttributedHistoricalOps createFromParcel(@NonNull Parcel in) {
+ return new AttributedHistoricalOps(in);
}
};
@@ -5721,7 +5756,7 @@
time = 1578113234821L,
codegenVersion = "1.0.14",
sourceFile = "frameworks/base/core/java/android/app/AppOpsManager.java",
- inputSignatures = "private final @android.annotation.Nullable java.lang.String mFeatureId\nprivate @android.annotation.Nullable android.util.ArrayMap<java.lang.String,android.app.HistoricalOp> mHistoricalOps\nprivate @android.annotation.Nullable android.app.HistoricalFeatureOps splice(double)\nprivate void merge(android.app.HistoricalFeatureOps)\nprivate void filter(java.lang.String[],int,double)\nprivate boolean isEmpty()\nprivate void increaseAccessCount(int,int,int,long)\nprivate void increaseRejectCount(int,int,int,long)\nprivate void increaseAccessDuration(int,int,int,long)\npublic @android.annotation.IntRange(from=0L) int getOpCount()\npublic @android.annotation.NonNull android.app.HistoricalOp getOpAt(int)\npublic @android.annotation.Nullable android.app.HistoricalOp getOp(java.lang.String)\nprivate void accept(android.app.HistoricalOpsVisitor)\nprivate @android.annotation.NonNull android.app.HistoricalOp getOrCreateHistoricalOp(int)\nclass HistoricalFeatureOps extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true, genEqualsHashCode=true, genHiddenCopyConstructor=true)")
+ inputSignatures = "private final @android.annotation.Nullable java.lang.String mAttributionTag\nprivate @android.annotation.Nullable android.util.ArrayMap<java.lang.String,android.app.HistoricalOp> mHistoricalOps\nprivate @android.annotation.Nullable android.app.HistoricalAttributionOps splice(double)\nprivate void merge(android.app.HistoricalAttributionOps)\nprivate void filter(java.lang.String[],int,double)\nprivate boolean isEmpty()\nprivate void increaseAccessCount(int,int,int,long)\nprivate void increaseRejectCount(int,int,int,long)\nprivate void increaseAccessDuration(int,int,int,long)\npublic @android.annotation.IntRange(from=0L) int getOpCount()\npublic @android.annotation.NonNull android.app.HistoricalOp getOpAt(int)\npublic @android.annotation.Nullable android.app.HistoricalOp getOp(java.lang.String)\nprivate void accept(android.app.HistoricalOpsVisitor)\nprivate @android.annotation.NonNull android.app.HistoricalOp getOrCreateHistoricalOp(int)\nclass HistoricalAttributionOps extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genHiddenConstructor=true, genEqualsHashCode=true, genHiddenCopyConstructor=true)")
@Deprecated
private void __metadata() {}
*/
@@ -6397,7 +6432,7 @@
Objects.requireNonNull(executor, "executor cannot be null");
Objects.requireNonNull(callback, "callback cannot be null");
try {
- mService.getHistoricalOps(request.mUid, request.mPackageName, request.mFeatureId,
+ mService.getHistoricalOps(request.mUid, request.mPackageName, request.mAttributionTag,
request.mOpNames, request.mFilter, request.mBeginTimeMillis,
request.mEndTimeMillis, request.mFlags, new RemoteCallback((result) -> {
final HistoricalOps ops = result.getParcelable(KEY_HISTORICAL_OPS);
@@ -6437,8 +6472,9 @@
Objects.requireNonNull(callback, "callback cannot be null");
try {
mService.getHistoricalOpsFromDiskRaw(request.mUid, request.mPackageName,
- request.mFeatureId, request.mOpNames, request.mFilter, request.mBeginTimeMillis,
- request.mEndTimeMillis, request.mFlags, new RemoteCallback((result) -> {
+ request.mAttributionTag, request.mOpNames, request.mFilter,
+ request.mBeginTimeMillis, request.mEndTimeMillis, request.mFlags,
+ new RemoteCallback((result) -> {
final HistoricalOps ops = result.getParcelable(KEY_HISTORICAL_OPS);
final long identity = Binder.clearCallingIdentity();
try {
@@ -6689,6 +6725,13 @@
};
mModeWatchers.put(callback, cb);
}
+
+ // See CALL_BACK_ON_CHANGED_LISTENER_WITH_SWITCHED_OP_CHANGE
+ if (!Compatibility.isChangeEnabled(
+ CALL_BACK_ON_CHANGED_LISTENER_WITH_SWITCHED_OP_CHANGE)) {
+ flags |= CALL_BACK_ON_SWITCHED_OP;
+ }
+
try {
mService.startWatchingModeWithFlags(op, packageName, flags, cb);
} catch (RemoteException e) {
@@ -7021,8 +7064,8 @@
* @param op The operation to note. One of the OPSTR_* constants.
* @param uid The user id of the application attempting to perform the operation.
* @param packageName The name of the application attempting to perform the operation.
- * @param featureId The {@link Context#createFeatureContext feature} in the package or {@code
- * null} for default feature
+ * @param attributionTag The {@link Context#createAttributionContext attribution tag} or {@code
+ * null} for default attribution
* @param message A message describing the reason the op was noted
*
* @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
@@ -7032,8 +7075,8 @@
* @throws SecurityException If the app has been configured to crash on this op.
*/
public int noteOp(@NonNull String op, int uid, @Nullable String packageName,
- @Nullable String featureId, @Nullable String message) {
- return noteOp(strOpToOp(op), uid, packageName, featureId, message);
+ @Nullable String attributionTag, @Nullable String message) {
+ return noteOp(strOpToOp(op), uid, packageName, attributionTag, message);
}
/**
@@ -7049,7 +7092,8 @@
* @param op The operation to note. One of the OP_* constants.
* @param uid The user id of the application attempting to perform the operation.
* @param packageName The name of the application attempting to perform the operation.
- * @param featureId The feature in the app or {@code null} for default feature
+ * @param attributionTag The {@link Context#createAttributionContext attribution tag} or {@code
+ * null} for default attribution
* @param message A message describing the reason the op was noted
*
* @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
@@ -7060,9 +7104,9 @@
*
* @hide
*/
- public int noteOp(int op, int uid, @Nullable String packageName, @Nullable String featureId,
- @Nullable String message) {
- final int mode = noteOpNoThrow(op, uid, packageName, featureId, message);
+ public int noteOp(int op, int uid, @Nullable String packageName,
+ @Nullable String attributionTag, @Nullable String message) {
+ final int mode = noteOpNoThrow(op, uid, packageName, attributionTag, message);
if (mode == MODE_ERRORED) {
throw new SecurityException(buildSecurityExceptionMsg(op, uid, packageName));
}
@@ -7097,8 +7141,8 @@
* @param op The operation to note. One of the OPSTR_* constants.
* @param uid The user id of the application attempting to perform the operation.
* @param packageName The name of the application attempting to perform the operation.
- * @param featureId The {@link Context#createFeatureContext feature} in the package or {@code
- * null} for default feature
+ * @param attributionTag The {@link Context#createAttributionContext attribution tag} or {@code
+ * null} for default attribution
* @param message A message describing the reason the op was noted
*
* @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
@@ -7106,8 +7150,8 @@
* causing the app to crash).
*/
public int noteOpNoThrow(@NonNull String op, int uid, @NonNull String packageName,
- @Nullable String featureId, @Nullable String message) {
- return noteOpNoThrow(strOpToOp(op), uid, packageName, featureId, message);
+ @Nullable String attributionTag, @Nullable String message) {
+ return noteOpNoThrow(strOpToOp(op), uid, packageName, attributionTag, message);
}
/**
@@ -7117,7 +7161,8 @@
* @param op The operation to note. One of the OP_* constants.
* @param uid The user id of the application attempting to perform the operation.
* @param packageName The name of the application attempting to perform the operation.
- * @param featureId The feature in the app or {@code null} for default feature
+ * @param attributionTag The {@link Context#createAttributionContext attribution tag} or {@code
+ * null} for default attribution
* @param message A message describing the reason the op was noted
*
* @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
@@ -7127,7 +7172,7 @@
* @hide
*/
public int noteOpNoThrow(int op, int uid, @Nullable String packageName,
- @Nullable String featureId, @Nullable String message) {
+ @Nullable String attributionTag, @Nullable String message) {
try {
collectNoteOpCallsForValidation(op);
int collectionMode = getNotedOpCollectionMode(uid, packageName, op);
@@ -7138,14 +7183,14 @@
}
}
- int mode = mService.noteOperation(op, uid, packageName, featureId,
+ int mode = mService.noteOperation(op, uid, packageName, attributionTag,
collectionMode == COLLECT_ASYNC, message);
if (mode == MODE_ALLOWED) {
if (collectionMode == COLLECT_SELF) {
- collectNotedOpForSelf(op, featureId);
+ collectNotedOpForSelf(op, attributionTag);
} else if (collectionMode == COLLECT_SYNC) {
- collectNotedOpSync(op, featureId);
+ collectNotedOpSync(op, attributionTag);
}
}
@@ -7185,8 +7230,8 @@
* @param op The operation to note. One of the OP_* constants.
* @param proxiedPackageName The name of the application calling into the proxy application.
* @param proxiedUid The uid of the proxied application
- * @param proxiedFeatureId The feature in the proxied app or {@code null} for default
- * feature
+ * @param proxiedAttributionTag The proxied {@link Context#createAttributionContext
+ * attribution tag} or {@code null} for default attribution
* @param message A message describing the reason the op was noted
*
* @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or {@link #MODE_IGNORED}
@@ -7198,8 +7243,8 @@
* @hide
*/
public int noteProxyOp(int op, @Nullable String proxiedPackageName, int proxiedUid,
- @Nullable String proxiedFeatureId, @Nullable String message) {
- int mode = noteProxyOpNoThrow(op, proxiedPackageName, proxiedUid, proxiedFeatureId,
+ @Nullable String proxiedAttributionTag, @Nullable String message) {
+ int mode = noteProxyOpNoThrow(op, proxiedPackageName, proxiedUid, proxiedAttributionTag,
message);
if (mode == MODE_ERRORED) {
throw new SecurityException("Proxy package " + mContext.getOpPackageName()
@@ -7218,8 +7263,8 @@
* @param op The operation to note. One of the OPSTR_* constants.
* @param proxiedPackageName The name of the application calling into the proxy application.
* @param proxiedUid The uid of the proxied application
- * @param proxiedFeatureId The feature in the proxied app or {@code null} for default
- * feature
+ * @param proxiedAttributionTag The proxied {@link Context#createAttributionContext
+ * attribution tag} or {@code null} for default attribution
* @param message A message describing the reason the op was noted
*
* @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or {@link #MODE_IGNORED}
@@ -7229,8 +7274,8 @@
* op.
*/
public int noteProxyOp(@NonNull String op, @Nullable String proxiedPackageName, int proxiedUid,
- @Nullable String proxiedFeatureId, @Nullable String message) {
- return noteProxyOp(strOpToOp(op), proxiedPackageName, proxiedUid, proxiedFeatureId,
+ @Nullable String proxiedAttributionTag, @Nullable String message) {
+ return noteProxyOp(strOpToOp(op), proxiedPackageName, proxiedUid, proxiedAttributionTag,
message);
}
@@ -7261,14 +7306,14 @@
* @param op The op to note
* @param proxiedPackageName The package to note the op for
* @param proxiedUid The uid the package belongs to
- * @param proxiedFeatureId The feature in the proxied app or {@code null} for default
- * feature
+ * @param proxiedAttributionTag The proxied {@link Context#createAttributionContext
+ * attribution tag} or {@code null} for default attribution
* @param message A message describing the reason the op was noted
*/
public int noteProxyOpNoThrow(@NonNull String op, @Nullable String proxiedPackageName,
- int proxiedUid, @Nullable String proxiedFeatureId, @Nullable String message) {
+ int proxiedUid, @Nullable String proxiedAttributionTag, @Nullable String message) {
return noteProxyOpNoThrow(strOpToOp(op), proxiedPackageName, proxiedUid,
- proxiedFeatureId, message);
+ proxiedAttributionTag, message);
}
/**
@@ -7279,14 +7324,14 @@
* @param proxiedPackageName The package to note the op for or {@code null} if the op should be
* noted for the "android" package
* @param proxiedUid The uid the package belongs to
- * @param proxiedFeatureId The feature in the proxied app or {@code null} for default
- * feature
+ * @param proxiedAttributionTag The proxied {@link Context#createAttributionContext
+ * attribution tag} or {@code null} for default attribution
* @param message A message describing the reason the op was noted
*
* @hide
*/
public int noteProxyOpNoThrow(int op, @Nullable String proxiedPackageName, int proxiedUid,
- @Nullable String proxiedFeatureId, @Nullable String message) {
+ @Nullable String proxiedAttributionTag, @Nullable String message) {
int myUid = Process.myUid();
try {
@@ -7300,17 +7345,17 @@
}
int mode = mService.noteProxyOperation(op, proxiedUid, proxiedPackageName,
- proxiedFeatureId, myUid, mContext.getOpPackageName(),
- mContext.getFeatureId(), collectionMode == COLLECT_ASYNC, message);
+ proxiedAttributionTag, myUid, mContext.getOpPackageName(),
+ mContext.getAttributionTag(), collectionMode == COLLECT_ASYNC, message);
if (mode == MODE_ALLOWED) {
if (collectionMode == COLLECT_SELF) {
- collectNotedOpForSelf(op, proxiedFeatureId);
+ collectNotedOpForSelf(op, proxiedAttributionTag);
} else if (collectionMode == COLLECT_SYNC
// Only collect app-ops when the proxy is trusted
&& mContext.checkPermission(Manifest.permission.UPDATE_APP_OPS_STATS, -1,
myUid) == PackageManager.PERMISSION_GRANTED) {
- collectNotedOpSync(op, proxiedFeatureId);
+ collectNotedOpSync(op, proxiedAttributionTag);
}
}
@@ -7499,8 +7544,8 @@
* @param op The operation to start. One of the OPSTR_* constants.
* @param uid The user id of the application attempting to perform the operation.
* @param packageName The name of the application attempting to perform the operation.
- * @param featureId The {@link Context#createFeatureContext feature} in the package or {@code
- * null} for default feature
+ * @param attributionTag The {@link Context#createAttributionContext attribution tag} or
+ * {@code null} for default attribution
* @param message Description why op was started
*
* @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
@@ -7511,8 +7556,8 @@
* the package is not in the passed in UID.
*/
public int startOp(@NonNull String op, int uid, @Nullable String packageName,
- @Nullable String featureId, @Nullable String message) {
- return startOp(strOpToOp(op), uid, packageName, false, featureId, message);
+ @Nullable String attributionTag, @Nullable String message) {
+ return startOp(strOpToOp(op), uid, packageName, false, attributionTag, message);
}
/**
@@ -7521,7 +7566,8 @@
* @param op The operation to start. One of the OP_* constants.
* @param uid The user id of the application attempting to perform the operation.
* @param packageName The name of the application attempting to perform the operation.
- * @param featureId The feature in the app or {@code null} for default feature
+ * @param attributionTag The {@link Context#createAttributionContext attribution tag} or
+ * {@code null} for default attribution
* @param startIfModeDefault Whether to start if mode is {@link #MODE_DEFAULT}.
* @param message Description why op was started
*
@@ -7535,8 +7581,8 @@
* @hide
*/
public int startOp(int op, int uid, @Nullable String packageName, boolean startIfModeDefault,
- @Nullable String featureId, @Nullable String message) {
- final int mode = startOpNoThrow(op, uid, packageName, startIfModeDefault, featureId,
+ @Nullable String attributionTag, @Nullable String message) {
+ final int mode = startOpNoThrow(op, uid, packageName, startIfModeDefault, attributionTag,
message);
if (mode == MODE_ERRORED) {
throw new SecurityException(buildSecurityExceptionMsg(op, uid, packageName));
@@ -7579,7 +7625,8 @@
* @param op The operation to start. One of the OP_* constants.
* @param uid The user id of the application attempting to perform the operation.
* @param packageName The name of the application attempting to perform the operation.
- * @param featureId The feature in the app or {@code null} for default feature
+ * @param attributionTag The {@link Context#createAttributionContext attribution tag} or
+ * {@code null} for default attribution
* @param message Description why op was started
*
* @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or
@@ -7587,8 +7634,8 @@
* causing the app to crash).
*/
public int startOpNoThrow(@NonNull String op, int uid, @NonNull String packageName,
- @NonNull String featureId, @Nullable String message) {
- return startOpNoThrow(strOpToOp(op), uid, packageName, false, featureId, message);
+ @NonNull String attributionTag, @Nullable String message) {
+ return startOpNoThrow(strOpToOp(op), uid, packageName, false, attributionTag, message);
}
/**
@@ -7598,7 +7645,8 @@
* @param op The operation to start. One of the OP_* constants.
* @param uid The user id of the application attempting to perform the operation.
* @param packageName The name of the application attempting to perform the operation.
- * @param featureId The feature in the app or {@code null} for default feature
+ * @param attributionTag The {@link Context#createAttributionContext attribution tag} or
+ * {@code null} for default attribution
* @param startIfModeDefault Whether to start if mode is {@link #MODE_DEFAULT}.
* @param message Description why op was started
*
@@ -7609,7 +7657,7 @@
* @hide
*/
public int startOpNoThrow(int op, int uid, @NonNull String packageName,
- boolean startIfModeDefault, @Nullable String featureId, @Nullable String message) {
+ boolean startIfModeDefault, @Nullable String attributionTag, @Nullable String message) {
try {
collectNoteOpCallsForValidation(op);
int collectionMode = getNotedOpCollectionMode(uid, packageName, op);
@@ -7621,13 +7669,13 @@
}
int mode = mService.startOperation(getClientId(), op, uid, packageName,
- featureId, startIfModeDefault, collectionMode == COLLECT_ASYNC, message);
+ attributionTag, startIfModeDefault, collectionMode == COLLECT_ASYNC, message);
if (mode == MODE_ALLOWED) {
if (collectionMode == COLLECT_SELF) {
- collectNotedOpForSelf(op, featureId);
+ collectNotedOpForSelf(op, attributionTag);
} else if (collectionMode == COLLECT_SYNC) {
- collectNotedOpSync(op, featureId);
+ collectNotedOpSync(op, attributionTag);
}
}
@@ -7661,8 +7709,8 @@
* previously passed in when starting the operation.
*/
public void finishOp(@NonNull String op, int uid, @NonNull String packageName,
- @Nullable String featureId) {
- finishOp(strOpToOp(op), uid, packageName, featureId);
+ @Nullable String attributionTag) {
+ finishOp(strOpToOp(op), uid, packageName, attributionTag);
}
/**
@@ -7683,9 +7731,9 @@
* @hide
*/
public void finishOp(int op, int uid, @NonNull String packageName,
- @Nullable String featureId) {
+ @Nullable String attributionTag) {
try {
- mService.finishOperation(getClientId(), op, uid, packageName, featureId);
+ mService.finishOperation(getClientId(), op, uid, packageName, attributionTag);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -7796,15 +7844,15 @@
* Collect a noted op for the current process.
*
* @param op The noted op
- * @param featureId The feature the op is noted for
+ * @param attributionTag The attribution tag the op is noted for
*/
- private void collectNotedOpForSelf(int op, @Nullable String featureId) {
+ private void collectNotedOpForSelf(int op, @Nullable String attributionTag) {
synchronized (sLock) {
if (sOnOpNotedCallback != null) {
- sOnOpNotedCallback.onSelfNoted(new SyncNotedAppOp(op, featureId));
+ sOnOpNotedCallback.onSelfNoted(new SyncNotedAppOp(op, attributionTag));
}
}
- sMessageCollector.onSelfNoted(new SyncNotedAppOp(op, featureId));
+ sMessageCollector.onSelfNoted(new SyncNotedAppOp(op, attributionTag));
}
/**
@@ -7813,9 +7861,9 @@
* <p> Delivered to caller via {@link #prefixParcelWithAppOpsIfNeeded}
*
* @param op The noted op
- * @param featureId The feature the op is noted for
+ * @param attributionTag The attribution tag the op is noted for
*/
- private void collectNotedOpSync(int op, @Nullable String featureId) {
+ private void collectNotedOpSync(int op, @Nullable String attributionTag) {
// If this is inside of a two-way binder call:
// We are inside of a two-way binder call. Delivered to caller via
// {@link #prefixParcelWithAppOpsIfNeeded}
@@ -7825,16 +7873,16 @@
sAppOpsNotedInThisBinderTransaction.set(appOpsNoted);
}
- long[] appOpsNotedForFeature = appOpsNoted.get(featureId);
- if (appOpsNotedForFeature == null) {
- appOpsNotedForFeature = new long[2];
- appOpsNoted.put(featureId, appOpsNotedForFeature);
+ long[] appOpsNotedForAttribution = appOpsNoted.get(attributionTag);
+ if (appOpsNotedForAttribution == null) {
+ appOpsNotedForAttribution = new long[2];
+ appOpsNoted.put(attributionTag, appOpsNotedForAttribution);
}
if (op < 64) {
- appOpsNotedForFeature[0] |= 1L << op;
+ appOpsNotedForAttribution[0] |= 1L << op;
} else {
- appOpsNotedForFeature[1] |= 1L << (op - 64);
+ appOpsNotedForAttribution[1] |= 1L << (op - 64);
}
}
@@ -7915,10 +7963,10 @@
p.writeInt(Parcel.EX_HAS_NOTED_APPOPS_REPLY_HEADER);
- int numFeatureWithNotesAppOps = notedAppOps.size();
- p.writeInt(numFeatureWithNotesAppOps);
+ int numAttributionWithNotesAppOps = notedAppOps.size();
+ p.writeInt(numAttributionWithNotesAppOps);
- for (int i = 0; i < numFeatureWithNotesAppOps; i++) {
+ for (int i = 0; i < numAttributionWithNotesAppOps; i++) {
p.writeString(notedAppOps.keyAt(i));
p.writeLong(notedAppOps.valueAt(i)[0]);
p.writeLong(notedAppOps.valueAt(i)[1]);
@@ -7936,10 +7984,10 @@
* @hide
*/
public static void readAndLogNotedAppops(@NonNull Parcel p) {
- int numFeaturesWithNotedAppOps = p.readInt();
+ int numAttributionsWithNotedAppOps = p.readInt();
- for (int i = 0; i < numFeaturesWithNotedAppOps; i++) {
- String featureId = p.readString();
+ for (int i = 0; i < numAttributionsWithNotedAppOps; i++) {
+ String attributionTag = p.readString();
long[] rawNotedAppOps = new long[2];
rawNotedAppOps[0] = p.readLong();
rawNotedAppOps[1] = p.readLong();
@@ -7951,13 +7999,13 @@
for (int code = notedAppOps.nextSetBit(0); code != -1;
code = notedAppOps.nextSetBit(code + 1)) {
if (sOnOpNotedCallback != null) {
- sOnOpNotedCallback.onNoted(new SyncNotedAppOp(code, featureId));
+ sOnOpNotedCallback.onNoted(new SyncNotedAppOp(code, attributionTag));
}
}
}
for (int code = notedAppOps.nextSetBit(0); code != -1;
code = notedAppOps.nextSetBit(code + 1)) {
- sMessageCollector.onNoted(new SyncNotedAppOp(code, featureId));
+ sMessageCollector.onNoted(new SyncNotedAppOp(code, attributionTag));
}
}
}
diff --git a/core/java/android/app/AsyncNotedAppOp.java b/core/java/android/app/AsyncNotedAppOp.java
index 4d955db..b0c2762c 100644
--- a/core/java/android/app/AsyncNotedAppOp.java
+++ b/core/java/android/app/AsyncNotedAppOp.java
@@ -48,8 +48,8 @@
/** Uid that noted the op */
private final @IntRange(from = 0) int mNotingUid;
- /** {@link android.content.Context#createFeatureContext Feature} in the app */
- private final @Nullable String mFeatureId;
+ /** {@link android.content.Context#createAttributionContext attribution tag} */
+ private final @Nullable String mAttributionTag;
/** Message associated with the noteOp. This message is set by the app noting the op */
private final @NonNull String mMessage;
@@ -92,8 +92,8 @@
* Op that was noted
* @param notingUid
* Uid that noted the op
- * @param featureId
- * {@link android.content.Context#createFeatureContext Feature} in the app
+ * @param attributionTag
+ * {@link android.content.Context#createAttributionContext attribution tag}
* @param message
* Message associated with the noteOp. This message is set by the app noting the op
* @param time
@@ -104,7 +104,7 @@
public AsyncNotedAppOp(
@IntRange(from = 0) int opCode,
@IntRange(from = 0) int notingUid,
- @Nullable String featureId,
+ @Nullable String attributionTag,
@NonNull String message,
@CurrentTimeMillisLong long time) {
this.mOpCode = opCode;
@@ -115,7 +115,7 @@
com.android.internal.util.AnnotationValidations.validate(
IntRange.class, null, mNotingUid,
"from", 0);
- this.mFeatureId = featureId;
+ this.mAttributionTag = attributionTag;
this.mMessage = message;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mMessage);
@@ -135,11 +135,11 @@
}
/**
- * {@link android.content.Context#createFeatureContext Feature} in the app
+ * {@link android.content.Context#createAttributionContext attribution tag}
*/
@DataClass.Generated.Member
- public @Nullable String getFeatureId() {
- return mFeatureId;
+ public @Nullable String getAttributionTag() {
+ return mAttributionTag;
}
/**
@@ -173,7 +173,7 @@
return true
&& mOpCode == that.mOpCode
&& mNotingUid == that.mNotingUid
- && java.util.Objects.equals(mFeatureId, that.mFeatureId)
+ && java.util.Objects.equals(mAttributionTag, that.mAttributionTag)
&& java.util.Objects.equals(mMessage, that.mMessage)
&& mTime == that.mTime;
}
@@ -187,7 +187,7 @@
int _hash = 1;
_hash = 31 * _hash + mOpCode;
_hash = 31 * _hash + mNotingUid;
- _hash = 31 * _hash + java.util.Objects.hashCode(mFeatureId);
+ _hash = 31 * _hash + java.util.Objects.hashCode(mAttributionTag);
_hash = 31 * _hash + java.util.Objects.hashCode(mMessage);
_hash = 31 * _hash + Long.hashCode(mTime);
return _hash;
@@ -200,11 +200,11 @@
// void parcelFieldName(Parcel dest, int flags) { ... }
byte flg = 0;
- if (mFeatureId != null) flg |= 0x4;
+ if (mAttributionTag != null) flg |= 0x4;
dest.writeByte(flg);
dest.writeInt(mOpCode);
dest.writeInt(mNotingUid);
- if (mFeatureId != null) dest.writeString(mFeatureId);
+ if (mAttributionTag != null) dest.writeString(mAttributionTag);
dest.writeString(mMessage);
dest.writeLong(mTime);
}
@@ -223,7 +223,7 @@
byte flg = in.readByte();
int opCode = in.readInt();
int notingUid = in.readInt();
- String featureId = (flg & 0x4) == 0 ? null : in.readString();
+ String attributionTag = (flg & 0x4) == 0 ? null : in.readString();
String message = in.readString();
long time = in.readLong();
@@ -235,7 +235,7 @@
com.android.internal.util.AnnotationValidations.validate(
IntRange.class, null, mNotingUid,
"from", 0);
- this.mFeatureId = featureId;
+ this.mAttributionTag = attributionTag;
this.mMessage = message;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mMessage);
@@ -261,10 +261,10 @@
};
@DataClass.Generated(
- time = 1583866178330L,
+ time = 1583866239013L,
codegenVersion = "1.0.15",
sourceFile = "frameworks/base/core/java/android/app/AsyncNotedAppOp.java",
- inputSignatures = "private final @android.annotation.IntRange(from=0L) int mOpCode\nprivate final @android.annotation.IntRange(from=0L) int mNotingUid\nprivate final @android.annotation.Nullable java.lang.String mFeatureId\nprivate final @android.annotation.NonNull java.lang.String mMessage\nprivate final @android.annotation.CurrentTimeMillisLong long mTime\npublic @android.annotation.NonNull java.lang.String getOp()\nprivate void onConstructed()\nclass AsyncNotedAppOp extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genAidl=true, genHiddenConstructor=true)")
+ inputSignatures = "private final @android.annotation.IntRange(from=0L) int mOpCode\nprivate final @android.annotation.IntRange(from=0L) int mNotingUid\nprivate final @android.annotation.Nullable java.lang.String mAttributionTag\nprivate final @android.annotation.NonNull java.lang.String mMessage\nprivate final @android.annotation.CurrentTimeMillisLong long mTime\npublic @android.annotation.NonNull java.lang.String getOp()\nprivate void onConstructed()\nclass AsyncNotedAppOp extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genAidl=true, genHiddenConstructor=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 2873b10..56e6aee 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -219,8 +219,8 @@
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private final String mOpPackageName;
- /** If of feature this context is for */
- private final @Nullable String mFeatureId;
+ /** Attribution tag of this context */
+ private final @Nullable String mAttributionTag;
private final @NonNull ResourcesManager mResourcesManager;
@UnsupportedAppUsage
@@ -421,8 +421,8 @@
/** @hide */
@Override
- public @Nullable String getFeatureId() {
- return mFeatureId;
+ public @Nullable String getAttributionTag() {
+ return mAttributionTag;
}
@Override
@@ -1026,10 +1026,10 @@
public void startActivityAsUser(Intent intent, Bundle options, UserHandle user) {
try {
ActivityTaskManager.getService().startActivityAsUser(
- mMainThread.getApplicationThread(), getBasePackageName(), getFeatureId(), intent,
- intent.resolveTypeIfNeeded(getContentResolver()),
- null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, options,
- user.getIdentifier());
+ mMainThread.getApplicationThread(), getBasePackageName(), getAttributionTag(),
+ intent, intent.resolveTypeIfNeeded(getContentResolver()),
+ null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, options,
+ user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1109,9 +1109,9 @@
try {
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntentWithFeature(
- mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, null,
- Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
- getUserId());
+ mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
+ null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false,
+ false, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1126,9 +1126,9 @@
try {
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntentWithFeature(
- mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, null,
- Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
- null, false, false, getUserId());
+ mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
+ null, Activity.RESULT_OK, null, null, receiverPermissions,
+ AppOpsManager.OP_NONE, null, false, false, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1141,9 +1141,9 @@
try {
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntentWithFeature(
- mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, null,
- Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
- null, false, false, getUserId());
+ mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
+ null, Activity.RESULT_OK, null, null, receiverPermissions,
+ AppOpsManager.OP_NONE, null, false, false, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1156,9 +1156,9 @@
try {
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntentWithFeature(
- mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, null,
- Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
- null, false, false, user.getIdentifier());
+ mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
+ null, Activity.RESULT_OK, null, null, receiverPermissions,
+ AppOpsManager.OP_NONE, null, false, false, user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1173,9 +1173,9 @@
try {
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntentWithFeature(
- mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, null,
- Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
- options, false, false, getUserId());
+ mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
+ null, Activity.RESULT_OK, null, null, receiverPermissions,
+ AppOpsManager.OP_NONE, options, false, false, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1190,9 +1190,9 @@
try {
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntentWithFeature(
- mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, null,
- Activity.RESULT_OK, null, null, receiverPermissions, appOp, null, false, false,
- getUserId());
+ mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
+ null, Activity.RESULT_OK, null, null, receiverPermissions, appOp, null, false,
+ false, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1207,9 +1207,9 @@
try {
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntentWithFeature(
- mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, null,
- Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
- null, true, false, getUserId());
+ mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
+ null, Activity.RESULT_OK, null, null, receiverPermissions,
+ AppOpsManager.OP_NONE, null, true, false, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1270,8 +1270,8 @@
try {
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntentWithFeature(
- mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, rd,
- initialCode, initialData, initialExtras, receiverPermissions, appOp,
+ mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
+ rd, initialCode, initialData, initialExtras, receiverPermissions, appOp,
options, true, false, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1284,9 +1284,9 @@
try {
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntentWithFeature(
- mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, null,
- Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
- user.getIdentifier());
+ mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
+ null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false,
+ false, user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1307,9 +1307,9 @@
try {
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntentWithFeature(
- mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, null,
- Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
- options, false, false, user.getIdentifier());
+ mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
+ null, Activity.RESULT_OK, null, null, receiverPermissions,
+ AppOpsManager.OP_NONE, options, false, false, user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1324,9 +1324,9 @@
try {
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntentWithFeature(
- mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, null,
- Activity.RESULT_OK, null, null, receiverPermissions, appOp, null, false, false,
- user.getIdentifier());
+ mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
+ null, Activity.RESULT_OK, null, null, receiverPermissions, appOp, null, false,
+ false, user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1375,9 +1375,9 @@
try {
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntentWithFeature(
- mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, rd,
- initialCode, initialData, initialExtras, receiverPermissions,
- appOp, options, true, false, user.getIdentifier());
+ mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
+ rd, initialCode, initialData, initialExtras, receiverPermissions, appOp,
+ options, true, false, user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1416,9 +1416,9 @@
try {
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntentWithFeature(
- mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, null,
- Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, true,
- getUserId());
+ mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
+ null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false,
+ true, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1452,9 +1452,9 @@
try {
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntentWithFeature(
- mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, rd,
- initialCode, initialData, initialExtras, null,
- AppOpsManager.OP_NONE, null, true, true, getUserId());
+ mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
+ rd, initialCode, initialData, initialExtras, null, AppOpsManager.OP_NONE, null,
+ true, true, getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1484,9 +1484,9 @@
try {
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntentWithFeature(
- mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, null,
- Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, true,
- user.getIdentifier());
+ mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
+ null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false,
+ true, user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1499,9 +1499,9 @@
try {
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntentWithFeature(
- mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, null,
- Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, options, false, true,
- user.getIdentifier());
+ mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
+ null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, options,
+ false, true, user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1534,9 +1534,9 @@
try {
intent.prepareToLeaveProcess(this);
ActivityManager.getService().broadcastIntentWithFeature(
- mMainThread.getApplicationThread(), getFeatureId(), intent, resolvedType, rd,
- initialCode, initialData, initialExtras, null,
- AppOpsManager.OP_NONE, null, true, true, user.getIdentifier());
+ mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
+ rd, initialCode, initialData, initialExtras, null, AppOpsManager.OP_NONE, null,
+ true, true, user.getIdentifier());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1620,7 +1620,7 @@
}
try {
final Intent intent = ActivityManager.getService().registerReceiverWithFeature(
- mMainThread.getApplicationThread(), mBasePackageName, getFeatureId(), rd,
+ mMainThread.getApplicationThread(), mBasePackageName, getAttributionTag(), rd,
filter, broadcastPermission, userId, flags);
if (intent != null) {
intent.setExtrasClassLoader(getClassLoader());
@@ -1696,7 +1696,7 @@
ComponentName cn = ActivityManager.getService().startService(
mMainThread.getApplicationThread(), service,
service.resolveTypeIfNeeded(getContentResolver()), requireForeground,
- getOpPackageName(), getFeatureId(), user.getIdentifier());
+ getOpPackageName(), getAttributionTag(), user.getIdentifier());
if (cn != null) {
if (cn.getPackageName().equals("!")) {
throw new SecurityException(
@@ -2285,14 +2285,14 @@
if (packageName.equals("system") || packageName.equals("android")) {
// The system resources are loaded in every application, so we can safely copy
// the context without reloading Resources.
- return new ContextImpl(this, mMainThread, mPackageInfo, mFeatureId, null,
+ return new ContextImpl(this, mMainThread, mPackageInfo, mAttributionTag, null,
mToken, user, flags, null, null);
}
LoadedApk pi = mMainThread.getPackageInfo(packageName, mResources.getCompatibilityInfo(),
flags | CONTEXT_REGISTER_PACKAGE, user.getIdentifier());
if (pi != null) {
- ContextImpl c = new ContextImpl(this, mMainThread, pi, mFeatureId, null,
+ ContextImpl c = new ContextImpl(this, mMainThread, pi, mAttributionTag, null,
mToken, user, flags, null, null);
final int displayId = getDisplayId();
@@ -2329,7 +2329,7 @@
final String[] paths = mPackageInfo.getSplitPaths(splitName);
final ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo,
- mFeatureId, splitName, mToken, mUser, mFlags, classLoader, null);
+ mAttributionTag, splitName, mToken, mUser, mFlags, classLoader, null);
final int displayId = getDisplayId();
@@ -2353,7 +2353,7 @@
throw new IllegalArgumentException("overrideConfiguration must not be null");
}
- ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mFeatureId,
+ ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mAttributionTag,
mSplitName, mToken, mUser, mFlags, mClassLoader, null);
final int displayId = getDisplayId();
@@ -2370,7 +2370,7 @@
throw new IllegalArgumentException("display must not be null");
}
- ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mFeatureId,
+ ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mAttributionTag,
mSplitName, mToken, mUser, mFlags, mClassLoader, null);
final int displayId = display.getDisplayId();
@@ -2394,7 +2394,7 @@
}
ContextImpl createBaseWindowContext(IBinder token) {
- ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mFeatureId,
+ ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mAttributionTag,
mSplitName, token, mUser, mFlags, mClassLoader, null);
context.mIsUiContext = true;
@@ -2420,8 +2420,8 @@
}
@Override
- public @NonNull Context createFeatureContext(@Nullable String featureId) {
- return new ContextImpl(this, mMainThread, mPackageInfo, featureId, mSplitName,
+ public @NonNull Context createAttributionContext(@Nullable String attributionTag) {
+ return new ContextImpl(this, mMainThread, mPackageInfo, attributionTag, mSplitName,
mToken, mUser, mFlags, mClassLoader, null);
}
@@ -2429,7 +2429,7 @@
public Context createDeviceProtectedStorageContext() {
final int flags = (mFlags & ~Context.CONTEXT_CREDENTIAL_PROTECTED_STORAGE)
| Context.CONTEXT_DEVICE_PROTECTED_STORAGE;
- return new ContextImpl(this, mMainThread, mPackageInfo, mFeatureId, mSplitName,
+ return new ContextImpl(this, mMainThread, mPackageInfo, mAttributionTag, mSplitName,
mToken, mUser, flags, mClassLoader, null);
}
@@ -2437,7 +2437,7 @@
public Context createCredentialProtectedStorageContext() {
final int flags = (mFlags & ~Context.CONTEXT_DEVICE_PROTECTED_STORAGE)
| Context.CONTEXT_CREDENTIAL_PROTECTED_STORAGE;
- return new ContextImpl(this, mMainThread, mPackageInfo, mFeatureId, mSplitName,
+ return new ContextImpl(this, mMainThread, mPackageInfo, mAttributionTag, mSplitName,
mToken, mUser, flags, mClassLoader, null);
}
@@ -2700,7 +2700,7 @@
}
private ContextImpl(@Nullable ContextImpl container, @NonNull ActivityThread mainThread,
- @NonNull LoadedApk packageInfo, @Nullable String featureId,
+ @NonNull LoadedApk packageInfo, @Nullable String attributionTag,
@Nullable String splitName, @Nullable IBinder activityToken, @Nullable UserHandle user,
int flags, @Nullable ClassLoader classLoader, @Nullable String overrideOpPackageName) {
mOuterContext = this;
@@ -2754,7 +2754,7 @@
}
mOpPackageName = overrideOpPackageName != null ? overrideOpPackageName : opPackageName;
- mFeatureId = featureId;
+ mAttributionTag = attributionTag;
mContentResolver = new ApplicationContentResolver(this, mainThread);
}
diff --git a/core/java/android/app/ITaskStackListener.aidl b/core/java/android/app/ITaskStackListener.aidl
index 28b28da..145d513 100644
--- a/core/java/android/app/ITaskStackListener.aidl
+++ b/core/java/android/app/ITaskStackListener.aidl
@@ -37,13 +37,15 @@
/**
* Called whenever IActivityManager.startActivity is called on an activity that is already
- * running in the pinned stack and the activity is not actually started, but the task is either
- * brought to the front or a new Intent is delivered to it.
+ * running, but the task is either brought to the front or a new Intent is delivered to it.
*
+ * @param task information about the task the activity was relaunched into
+ * @param homeVisible whether or not the home task is visible
* @param clearedTask whether or not the launch activity also cleared the task as a part of
* starting
*/
- void onPinnedActivityRestartAttempt(boolean clearedTask);
+ void onActivityRestartAttempt(in ActivityManager.RunningTaskInfo task, boolean homeTaskVisible,
+ boolean clearedTask);
/**
* Called when we launched an activity that we forced to be resizable.
diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl
index 34684c4..4cb8d93 100644
--- a/core/java/android/app/IWallpaperManager.aidl
+++ b/core/java/android/app/IWallpaperManager.aidl
@@ -175,11 +175,4 @@
* Called from SystemUI when it shows the AoD UI.
*/
oneway void setInAmbientMode(boolean inAmbientMode, long animationDuration);
-
- /**
- * Called when the wallpaper needs to zoom out.
- * The zoom value goes from 0 to 1 (inclusive) where 1 means fully zoomed out,
- * 0 means fully zoomed in
- */
- oneway void setWallpaperZoomOut(float zoom, String callingPackage, int displayId);
}
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 18932c6..818a121 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1720,11 +1720,10 @@
try {
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(who);
- int result = ActivityTaskManager.getService()
- .startActivity(whoThread, who.getBasePackageName(), who.getFeatureId(), intent,
- intent.resolveTypeIfNeeded(who.getContentResolver()),
- token, target != null ? target.mEmbeddedID : null,
- requestCode, 0, null, options);
+ int result = ActivityTaskManager.getService().startActivity(whoThread,
+ who.getBasePackageName(), who.getAttributionTag(), intent,
+ intent.resolveTypeIfNeeded(who.getContentResolver()), token,
+ target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
@@ -1793,9 +1792,9 @@
intents[i].prepareToLeaveProcess(who);
resolvedTypes[i] = intents[i].resolveTypeIfNeeded(who.getContentResolver());
}
- int result = ActivityTaskManager.getService()
- .startActivities(whoThread, who.getBasePackageName(), who.getFeatureId(), intents,
- resolvedTypes, token, options, userId);
+ int result = ActivityTaskManager.getService().startActivities(whoThread,
+ who.getBasePackageName(), who.getAttributionTag(), intents, resolvedTypes,
+ token, options, userId);
checkStartActivityResult(result, intents[0]);
return result;
} catch (RemoteException e) {
@@ -1860,10 +1859,10 @@
try {
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(who);
- int result = ActivityTaskManager.getService()
- .startActivity(whoThread, who.getBasePackageName(), who.getFeatureId(), intent,
- intent.resolveTypeIfNeeded(who.getContentResolver()),
- token, target, requestCode, 0, null, options);
+ int result = ActivityTaskManager.getService().startActivity(whoThread,
+ who.getBasePackageName(), who.getAttributionTag(), intent,
+ intent.resolveTypeIfNeeded(who.getContentResolver()), token, target,
+ requestCode, 0, null, options);
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
@@ -1927,11 +1926,10 @@
try {
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(who);
- int result = ActivityTaskManager.getService()
- .startActivityAsUser(whoThread, who.getBasePackageName(), who.getFeatureId(),
- intent, intent.resolveTypeIfNeeded(who.getContentResolver()),
- token, resultWho,
- requestCode, 0, null, options, user.getIdentifier());
+ int result = ActivityTaskManager.getService().startActivityAsUser(whoThread,
+ who.getBasePackageName(), who.getAttributionTag(), intent,
+ intent.resolveTypeIfNeeded(who.getContentResolver()), token, resultWho,
+ requestCode, 0, null, options, user.getIdentifier());
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
throw new RuntimeException("Failure from system", e);
@@ -2022,7 +2020,7 @@
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(who);
int result = appTask.startActivity(whoThread.asBinder(), who.getBasePackageName(),
- who.getFeatureId(), intent,
+ who.getAttributionTag(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()), options);
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index b54adbb..061e5ff 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -6225,6 +6225,17 @@
}
return loadHeaderAppName();
}
+
+ /**
+ * @return if this builder uses a template
+ *
+ * @hide
+ */
+ public boolean usesTemplate() {
+ return (mN.contentView == null && mN.headsUpContentView == null
+ && mN.bigContentView == null)
+ || (mStyle != null && mStyle.displayCustomViewInline());
+ }
}
/**
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index 3f2ec44..94b237c 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -134,6 +134,7 @@
* @hide
*/
@SystemApi
+ @TestApi
public static final int USER_LOCKED_SOUND = 0x00000020;
/**
@@ -331,6 +332,7 @@
/**
* @hide
*/
+ @TestApi
public void lockFields(int field) {
mUserLockedFields |= field;
}
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index f68c929..792f840 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -355,8 +355,8 @@
intent.prepareToLeaveProcess(context);
IIntentSender target =
ActivityManager.getService().getIntentSenderWithFeature(
- ActivityManager.INTENT_SENDER_ACTIVITY, packageName, context.getFeatureId(),
- null, null, requestCode, new Intent[] { intent },
+ ActivityManager.INTENT_SENDER_ACTIVITY, packageName,
+ context.getAttributionTag(), null, null, requestCode, new Intent[] { intent },
resolvedType != null ? new String[] { resolvedType } : null,
flags, options, context.getUserId());
return target != null ? new PendingIntent(target) : null;
@@ -381,8 +381,8 @@
intent.prepareToLeaveProcess(context);
IIntentSender target =
ActivityManager.getService().getIntentSenderWithFeature(
- ActivityManager.INTENT_SENDER_ACTIVITY, packageName, context.getFeatureId(),
- null, null, requestCode, new Intent[] { intent },
+ ActivityManager.INTENT_SENDER_ACTIVITY, packageName,
+ context.getAttributionTag(), null, null, requestCode, new Intent[] { intent },
resolvedType != null ? new String[] { resolvedType } : null,
flags, options, user.getIdentifier());
return target != null ? new PendingIntent(target) : null;
@@ -498,9 +498,9 @@
try {
IIntentSender target =
ActivityManager.getService().getIntentSenderWithFeature(
- ActivityManager.INTENT_SENDER_ACTIVITY, packageName, context.getFeatureId(),
- null, null, requestCode, intents, resolvedTypes, flags, options,
- context.getUserId());
+ ActivityManager.INTENT_SENDER_ACTIVITY, packageName,
+ context.getAttributionTag(), null, null, requestCode, intents, resolvedTypes,
+ flags, options, context.getUserId());
return target != null ? new PendingIntent(target) : null;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -524,8 +524,8 @@
try {
IIntentSender target =
ActivityManager.getService().getIntentSenderWithFeature(
- ActivityManager.INTENT_SENDER_ACTIVITY, packageName, context.getFeatureId(),
- null, null, requestCode, intents, resolvedTypes,
+ ActivityManager.INTENT_SENDER_ACTIVITY, packageName,
+ context.getAttributionTag(), null, null, requestCode, intents, resolvedTypes,
flags, options, user.getIdentifier());
return target != null ? new PendingIntent(target) : null;
} catch (RemoteException e) {
@@ -576,8 +576,8 @@
intent.prepareToLeaveProcess(context);
IIntentSender target =
ActivityManager.getService().getIntentSenderWithFeature(
- ActivityManager.INTENT_SENDER_BROADCAST, packageName, context.getFeatureId(),
- null, null, requestCode, new Intent[] { intent },
+ ActivityManager.INTENT_SENDER_BROADCAST, packageName,
+ context.getAttributionTag(), null, null, requestCode, new Intent[] { intent },
resolvedType != null ? new String[] { resolvedType } : null,
flags, null, userHandle.getIdentifier());
return target != null ? new PendingIntent(target) : null;
@@ -655,7 +655,7 @@
intent.prepareToLeaveProcess(context);
IIntentSender target =
ActivityManager.getService().getIntentSenderWithFeature(
- serviceKind, packageName, context.getFeatureId(),
+ serviceKind, packageName, context.getAttributionTag(),
null, null, requestCode, new Intent[] { intent },
resolvedType != null ? new String[] { resolvedType } : null,
flags, null, context.getUserId());
diff --git a/core/java/android/app/RuntimeAppOpAccessMessage.java b/core/java/android/app/RuntimeAppOpAccessMessage.java
index a81b8e7..a19f815 100644
--- a/core/java/android/app/RuntimeAppOpAccessMessage.java
+++ b/core/java/android/app/RuntimeAppOpAccessMessage.java
@@ -44,7 +44,7 @@
/** Name of package for which runtime app op access message was collected */
private final @NonNull String mPackageName;
/** Feature of package for which runtime app op access message was collected */
- private final @Nullable String mFeatureId;
+ private final @Nullable String mAttributionTag;
/** Message collected (including stacktrace for synchronous ops) */
private final @NonNull String mMessage;
/** Sampling strategy used to collect this message. */
@@ -63,8 +63,8 @@
* Op code of operation access which was collected
* @param packageName
* Name of package for which runtime app op access message was collected
- * @param featureId
- * Feature of package for which runtime app op access message was collected
+ * @param attributionTag
+ * Attribution tag for which runtime app op access message was collected
* @param message
* Message collected (including stacktrace for synchronous ops)
* @param samplingStrategy
@@ -75,7 +75,7 @@
@IntRange(from = 0L) int uid,
@IntRange(from = 0L) int opCode,
@NonNull String packageName,
- @Nullable String featureId,
+ @Nullable String attributionTag,
@NonNull String message,
@AppOpsManager.SamplingStrategy int samplingStrategy) {
this.mUid = uid;
@@ -90,7 +90,7 @@
this.mPackageName = packageName;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mPackageName);
- this.mFeatureId = featureId;
+ this.mAttributionTag = attributionTag;
this.mMessage = message;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mMessage);
@@ -134,11 +134,11 @@
}
/**
- * Feature of package for which runtime app op access message was collected
+ * Attribution tag for which runtime app op access message was collected
*/
@DataClass.Generated.Member
- public @Nullable String getFeatureId() {
- return mFeatureId;
+ public @Nullable String getAttributionTag() {
+ return mAttributionTag;
}
/**
@@ -164,12 +164,12 @@
// void parcelFieldName(Parcel dest, int flags) { ... }
byte flg = 0;
- if (mFeatureId != null) flg |= 0x8;
+ if (mAttributionTag != null) flg |= 0x8;
dest.writeByte(flg);
dest.writeInt(mUid);
dest.writeInt(mOpCode);
dest.writeString(mPackageName);
- if (mFeatureId != null) dest.writeString(mFeatureId);
+ if (mAttributionTag != null) dest.writeString(mAttributionTag);
dest.writeString(mMessage);
dest.writeInt(mSamplingStrategy);
}
@@ -189,7 +189,7 @@
int uid = in.readInt();
int opCode = in.readInt();
String packageName = in.readString();
- String featureId = (flg & 0x8) == 0 ? null : in.readString();
+ String attributionTag = (flg & 0x8) == 0 ? null : in.readString();
String message = in.readString();
int samplingStrategy = in.readInt();
@@ -205,7 +205,7 @@
this.mPackageName = packageName;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mPackageName);
- this.mFeatureId = featureId;
+ this.mAttributionTag = attributionTag;
this.mMessage = message;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mMessage);
@@ -234,7 +234,7 @@
time = 1581517099127L,
codegenVersion = "1.0.14",
sourceFile = "frameworks/base/core/java/android/app/RuntimeAppOpAccessMessage.java",
- inputSignatures = "private final @android.annotation.IntRange(from=0L) int mUid\nprivate final @android.annotation.IntRange(from=0L, to=AppOpsManager._NUM_OP - 1) int mOpCode\nprivate final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.Nullable java.lang.String mFeatureId\nprivate final @android.annotation.NonNull java.lang.String mMessage\nprivate final @android.app.AppOpsManager.SamplingStrategy int mSamplingStrategy\npublic @android.annotation.NonNull java.lang.String getOp()\nclass RuntimeAppOpAccessMessage extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false)")*/
+ inputSignatures = "private final @android.annotation.IntRange(from=0L) int mUid\nprivate final @android.annotation.IntRange(from=0L, to=AppOpsManager._NUM_OP - 1) int mOpCode\nprivate final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.Nullable java.lang.String mAttributionTag\nprivate final @android.annotation.NonNull java.lang.String mMessage\nprivate final @android.app.AppOpsManager.SamplingStrategy int mSamplingStrategy\npublic @android.annotation.NonNull java.lang.String getOp()\nclass RuntimeAppOpAccessMessage extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false)")*/
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/app/SyncNotedAppOp.java b/core/java/android/app/SyncNotedAppOp.java
index 13b90ca..0a880dc 100644
--- a/core/java/android/app/SyncNotedAppOp.java
+++ b/core/java/android/app/SyncNotedAppOp.java
@@ -43,24 +43,24 @@
/** op code of synchronous appop noted */
private final @IntRange(from = 0L, to = AppOpsManager._NUM_OP - 1) int mOpCode;
- /** featureId of synchronous appop noted */
- private final @Nullable String mFeatureId;
+ /** attributionTag of synchronous appop noted */
+ private final @Nullable String mAttributionTag;
/**
* Creates a new SyncNotedAppOp.
*
* @param opCode
* op code of synchronous appop noted
- * @param featureId
- * featureId of synchronous appop noted
+ * @param attributionTag
+ * attributionTag of synchronous appop noted
*/
- public SyncNotedAppOp(@IntRange(from = 0L) int opCode, @Nullable String featureId) {
+ public SyncNotedAppOp(@IntRange(from = 0L) int opCode, @Nullable String attributionTag) {
this.mOpCode = opCode;
com.android.internal.util.AnnotationValidations.validate(
IntRange.class, null, mOpCode,
"from", 0,
"to", AppOpsManager._NUM_OP - 1);
- this.mFeatureId = featureId;
+ this.mAttributionTag = attributionTag;
}
/**
@@ -84,11 +84,11 @@
/**
- * featureId of synchronous appop noted
+ * attributionTag of synchronous appop noted
*/
@DataClass.Generated.Member
- public @Nullable String getFeatureId() {
- return mFeatureId;
+ public @Nullable String getAttributionTag() {
+ return mAttributionTag;
}
@Override
@@ -105,7 +105,7 @@
//noinspection PointlessBooleanExpression
return true
&& mOpCode == that.mOpCode
- && java.util.Objects.equals(mFeatureId, that.mFeatureId);
+ && java.util.Objects.equals(mAttributionTag, that.mAttributionTag);
}
@Override
@@ -116,7 +116,7 @@
int _hash = 1;
_hash = 31 * _hash + mOpCode;
- _hash = 31 * _hash + java.util.Objects.hashCode(mFeatureId);
+ _hash = 31 * _hash + java.util.Objects.hashCode(mAttributionTag);
return _hash;
}
@@ -127,10 +127,10 @@
// void parcelFieldName(Parcel dest, int flags) { ... }
byte flg = 0;
- if (mFeatureId != null) flg |= 0x2;
+ if (mAttributionTag != null) flg |= 0x2;
dest.writeByte(flg);
dest.writeInt(mOpCode);
- if (mFeatureId != null) dest.writeString(mFeatureId);
+ if (mAttributionTag != null) dest.writeString(mAttributionTag);
}
@Override
@@ -146,14 +146,14 @@
byte flg = in.readByte();
int opCode = in.readInt();
- String featureId = (flg & 0x2) == 0 ? null : in.readString();
+ String attributionTag = (flg & 0x2) == 0 ? null : in.readString();
this.mOpCode = opCode;
com.android.internal.util.AnnotationValidations.validate(
IntRange.class, null, mOpCode,
"from", 0,
"to", AppOpsManager._NUM_OP - 1);
- this.mFeatureId = featureId;
+ this.mAttributionTag = attributionTag;
// onConstructed(); // You can define this method to get a callback
}
@@ -176,7 +176,7 @@
time = 1579188889960L,
codegenVersion = "1.0.14",
sourceFile = "frameworks/base/core/java/android/app/SyncNotedAppOp.java",
- inputSignatures = "private final @android.annotation.IntRange(from=0L, to=AppOpsManager._NUM_OP - 1) int mOpCode\nprivate final @android.annotation.Nullable java.lang.String mFeatureId\npublic @android.annotation.NonNull java.lang.String getOp()\npublic @android.annotation.SystemApi int getOpCode()\nclass SyncNotedAppOp extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genConstructor=false)")*/
+ inputSignatures = "private final @android.annotation.IntRange(from=0L, to=AppOpsManager._NUM_OP - 1) int mOpCode\nprivate final @android.annotation.Nullable java.lang.String mAttributionTag\npublic @android.annotation.NonNull java.lang.String getOp()\npublic @android.annotation.SystemApi int getOpCode()\nclass SyncNotedAppOp extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genConstructor=false)")*/
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/app/TaskStackListener.java b/core/java/android/app/TaskStackListener.java
index b892b8e..93772de 100644
--- a/core/java/android/app/TaskStackListener.java
+++ b/core/java/android/app/TaskStackListener.java
@@ -16,6 +16,7 @@
package android.app;
+import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityManager.TaskSnapshot;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
@@ -53,7 +54,8 @@
@Override
@UnsupportedAppUsage
- public void onPinnedActivityRestartAttempt(boolean clearedTask) throws RemoteException {
+ public void onActivityRestartAttempt(RunningTaskInfo task, boolean homeTaskVisible,
+ boolean clearedTask) throws RemoteException {
}
@Override
@@ -68,14 +70,14 @@
}
@Override
- public void onActivityLaunchOnSecondaryDisplayFailed(ActivityManager.RunningTaskInfo taskInfo,
+ public void onActivityLaunchOnSecondaryDisplayFailed(RunningTaskInfo taskInfo,
int requestedDisplayId) throws RemoteException {
onActivityLaunchOnSecondaryDisplayFailed();
}
/**
* @deprecated see {@link
- * #onActivityLaunchOnSecondaryDisplayFailed(ActivityManager.RunningTaskInfo, int)}
+ * #onActivityLaunchOnSecondaryDisplayFailed(RunningTaskInfo, int)}
*/
@Deprecated
@UnsupportedAppUsage
@@ -84,7 +86,7 @@
@Override
@UnsupportedAppUsage
- public void onActivityLaunchOnSecondaryDisplayRerouted(ActivityManager.RunningTaskInfo taskInfo,
+ public void onActivityLaunchOnSecondaryDisplayRerouted(RunningTaskInfo taskInfo,
int requestedDisplayId) throws RemoteException {
}
@@ -98,13 +100,13 @@
}
@Override
- public void onTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo)
+ public void onTaskMovedToFront(RunningTaskInfo taskInfo)
throws RemoteException {
onTaskMovedToFront(taskInfo.taskId);
}
/**
- * @deprecated see {@link #onTaskMovedToFront(ActivityManager.RunningTaskInfo)}
+ * @deprecated see {@link #onTaskMovedToFront(RunningTaskInfo)}
*/
@Deprecated
@UnsupportedAppUsage
@@ -112,26 +114,26 @@
}
@Override
- public void onTaskRemovalStarted(ActivityManager.RunningTaskInfo taskInfo)
+ public void onTaskRemovalStarted(RunningTaskInfo taskInfo)
throws RemoteException {
onTaskRemovalStarted(taskInfo.taskId);
}
/**
- * @deprecated see {@link #onTaskRemovalStarted(ActivityManager.RunningTaskInfo)}
+ * @deprecated see {@link #onTaskRemovalStarted(RunningTaskInfo)}
*/
@Deprecated
public void onTaskRemovalStarted(int taskId) throws RemoteException {
}
@Override
- public void onTaskDescriptionChanged(ActivityManager.RunningTaskInfo taskInfo)
+ public void onTaskDescriptionChanged(RunningTaskInfo taskInfo)
throws RemoteException {
onTaskDescriptionChanged(taskInfo.taskId, taskInfo.taskDescription);
}
/**
- * @deprecated see {@link #onTaskDescriptionChanged(ActivityManager.RunningTaskInfo)}
+ * @deprecated see {@link #onTaskDescriptionChanged(RunningTaskInfo)}
*/
@Deprecated
public void onTaskDescriptionChanged(int taskId, ActivityManager.TaskDescription td)
@@ -166,7 +168,7 @@
}
@Override
- public void onBackPressedOnTaskRoot(ActivityManager.RunningTaskInfo taskInfo)
+ public void onBackPressedOnTaskRoot(RunningTaskInfo taskInfo)
throws RemoteException {
}
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index d9405e1..1b1568a 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -478,7 +478,7 @@
try {
Bundle params = new Bundle();
ParcelFileDescriptor pfd = mService.getWallpaperWithFeature(
- context.getOpPackageName(), context.getFeatureId(), this, FLAG_SYSTEM,
+ context.getOpPackageName(), context.getAttributionTag(), this, FLAG_SYSTEM,
params, userId);
if (pfd != null) {
@@ -1069,7 +1069,7 @@
try {
Bundle outParams = new Bundle();
return sGlobals.mService.getWallpaperWithFeature(mContext.getOpPackageName(),
- mContext.getFeatureId(), null, which, outParams, userId);
+ mContext.getAttributionTag(), null, which, outParams, userId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
} catch (SecurityException e) {
@@ -1858,13 +1858,12 @@
*
* @hide
*/
- public void setWallpaperZoomOut(float zoom) {
+ public void setWallpaperZoomOut(IBinder windowToken, float zoom) {
if (zoom < 0 || zoom > 1f) {
throw new IllegalArgumentException("zoom must be between 0 and one: " + zoom);
}
try {
- sGlobals.mService.setWallpaperZoomOut(zoom, mContext.getOpPackageName(),
- mContext.getDisplayId());
+ WindowManagerGlobal.getWindowSession().setWallpaperZoomOut(windowToken, zoom);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index c532279..347648a 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -6001,7 +6001,7 @@
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param required Whether auto time is set required or not.
* @throws SecurityException if {@code admin} is not a device owner.
- * @deprecated From {@link android.os.Build.VERSION_CODES#R}. Use {@link #setAutoTime}
+ * @deprecated From {@link android.os.Build.VERSION_CODES#R}. Use {@link #setAutoTimeEnabled}
* to turn auto time on or off and use {@link UserManager#DISALLOW_CONFIG_DATE_TIME}
* to prevent the user from changing this setting.
*/
@@ -6019,7 +6019,7 @@
/**
* @return true if auto time is required.
- * @deprecated From {@link android.os.Build.VERSION_CODES#R}. Use {@link #getAutoTime}
+ * @deprecated From {@link android.os.Build.VERSION_CODES#R}. Use {@link #getAutoTimeEnabled}
*/
@Deprecated
public boolean getAutoTimeRequired() {
@@ -6049,10 +6049,10 @@
* @throws SecurityException if caller is not a device owner, a profile owner for the
* primary user, or a profile owner of an organization-owned managed profile.
*/
- public void setAutoTime(@NonNull ComponentName admin, boolean enabled) {
+ public void setAutoTimeEnabled(@NonNull ComponentName admin, boolean enabled) {
if (mService != null) {
try {
- mService.setAutoTime(admin, enabled);
+ mService.setAutoTimeEnabled(admin, enabled);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -6064,10 +6064,10 @@
* @throws SecurityException if caller is not a device owner, a profile owner for the
* primary user, or a profile owner of an organization-owned managed profile.
*/
- public boolean getAutoTime(@NonNull ComponentName admin) {
+ public boolean getAutoTimeEnabled(@NonNull ComponentName admin) {
if (mService != null) {
try {
- return mService.getAutoTime(admin);
+ return mService.getAutoTimeEnabled(admin);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -6090,11 +6090,11 @@
* @throws SecurityException if caller is not a device owner, a profile owner for the
* primary user, or a profile owner of an organization-owned managed profile.
*/
- public void setAutoTimeZone(@NonNull ComponentName admin, boolean enabled) {
+ public void setAutoTimeZoneEnabled(@NonNull ComponentName admin, boolean enabled) {
throwIfParentInstance("setAutoTimeZone");
if (mService != null) {
try {
- mService.setAutoTimeZone(admin, enabled);
+ mService.setAutoTimeZoneEnabled(admin, enabled);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -6106,11 +6106,11 @@
* @throws SecurityException if caller is not a device owner, a profile owner for the
* primary user, or a profile owner of an organization-owned managed profile.
*/
- public boolean getAutoTimeZone(@NonNull ComponentName admin) {
+ public boolean getAutoTimeZoneEnabled(@NonNull ComponentName admin) {
throwIfParentInstance("getAutoTimeZone");
if (mService != null) {
try {
- return mService.getAutoTimeZone(admin);
+ return mService.getAutoTimeZoneEnabled(admin);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -8804,10 +8804,11 @@
* <p>
* The following settings used to be supported, but can be controlled in other ways:
* <ul>
- * <li>{@link android.provider.Settings.Global#AUTO_TIME} : Use {@link #setAutoTime} and
+ * <li>{@link android.provider.Settings.Global#AUTO_TIME} : Use {@link #setAutoTimeEnabled} and
* {@link UserManager#DISALLOW_CONFIG_DATE_TIME} instead.</li>
- * <li>{@link android.provider.Settings.Global#AUTO_TIME_ZONE} : Use {@link #setAutoTimeZone}
- * and {@link UserManager#DISALLOW_CONFIG_DATE_TIME} instead.</li>
+ * <li>{@link android.provider.Settings.Global#AUTO_TIME_ZONE} : Use
+ * {@link #setAutoTimeZoneEnabled} and {@link UserManager#DISALLOW_CONFIG_DATE_TIME}
+ * instead.</li>
* <li>{@link android.provider.Settings.Global#DATA_ROAMING} : Use
* {@link UserManager#DISALLOW_DATA_ROAMING} instead.</li>
* </ul>
@@ -11984,17 +11985,17 @@
* must handle this intent.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with
- * @param timeoutMs Maximum time the profile is allowed to be off in milliseconds or 0 if
+ * @param timeoutMillis Maximum time the profile is allowed to be off in milliseconds or 0 if
* not limited.
* @throws IllegalStateException if the profile owner doesn't have an activity that handles
* {@link #ACTION_CHECK_POLICY_COMPLIANCE}
* @see #setPersonalAppsSuspended
*/
- public void setManagedProfileMaximumTimeOff(@NonNull ComponentName admin, long timeoutMs) {
+ public void setManagedProfileMaximumTimeOff(@NonNull ComponentName admin, long timeoutMillis) {
throwIfParentInstance("setManagedProfileMaximumTimeOff");
if (mService != null) {
try {
- mService.setManagedProfileMaximumTimeOff(admin, timeoutMs);
+ mService.setManagedProfileMaximumTimeOff(admin, timeoutMillis);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index da48663..f071239 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -308,11 +308,11 @@
void setAutoTimeRequired(in ComponentName who, boolean required);
boolean getAutoTimeRequired();
- void setAutoTime(in ComponentName who, boolean enabled);
- boolean getAutoTime(in ComponentName who);
+ void setAutoTimeEnabled(in ComponentName who, boolean enabled);
+ boolean getAutoTimeEnabled(in ComponentName who);
- void setAutoTimeZone(in ComponentName who, boolean enabled);
- boolean getAutoTimeZone(in ComponentName who);
+ void setAutoTimeZoneEnabled(in ComponentName who, boolean enabled);
+ boolean getAutoTimeZoneEnabled(in ComponentName who);
void setForceEphemeralUsers(in ComponentName who, boolean forceEpehemeralUsers);
boolean getForceEphemeralUsers(in ComponentName who);
diff --git a/core/java/android/app/role/RoleManager.java b/core/java/android/app/role/RoleManager.java
index db4f1de..917eeb8 100644
--- a/core/java/android/app/role/RoleManager.java
+++ b/core/java/android/app/role/RoleManager.java
@@ -636,7 +636,6 @@
* @hide
*/
@Nullable
- @SystemApi
public String getDefaultSmsPackage(@UserIdInt int userId) {
try {
return mService.getDefaultSmsPackage(userId);
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index ccd8199..0d461f5 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -174,7 +174,7 @@
public static final String ACTION_APPWIDGET_CONFIGURE = "android.appwidget.action.APPWIDGET_CONFIGURE";
/**
- * An intent extra that contains one appWidgetId.
+ * An intent extra (int) that contains one appWidgetId.
* <p>
* The value will be an int that can be retrieved like this:
* {@sample frameworks/base/tests/appwidgets/AppWidgetHostTest/src/com/android/tests/appwidgethost/AppWidgetHostActivity.java getExtra_EXTRA_APPWIDGET_ID}
@@ -182,7 +182,7 @@
public static final String EXTRA_APPWIDGET_ID = "appWidgetId";
/**
- * A bundle extra that contains whether or not an app has finished restoring a widget.
+ * A bundle extra (boolean) that contains whether or not an app has finished restoring a widget.
* <p> After restore, the app should set OPTION_APPWIDGET_RESTORE_COMPLETED to true on its
* widgets followed by calling {@link #updateAppWidget} to update the views.
*
@@ -192,22 +192,26 @@
/**
- * A bundle extra that contains the lower bound on the current width, in dips, of a widget instance.
+ * A bundle extra (int) that contains the lower bound on the current width, in dips, of a
+ * widget instance.
*/
public static final String OPTION_APPWIDGET_MIN_WIDTH = "appWidgetMinWidth";
/**
- * A bundle extra that contains the lower bound on the current height, in dips, of a widget instance.
+ * A bundle extra (int) that contains the lower bound on the current height, in dips, of a
+ * widget instance.
*/
public static final String OPTION_APPWIDGET_MIN_HEIGHT = "appWidgetMinHeight";
/**
- * A bundle extra that contains the upper bound on the current width, in dips, of a widget instance.
+ * A bundle extra (int) that contains the upper bound on the current width, in dips, of a
+ * widget instance.
*/
public static final String OPTION_APPWIDGET_MAX_WIDTH = "appWidgetMaxWidth";
/**
- * A bundle extra that contains the upper bound on the current width, in dips, of a widget instance.
+ * A bundle extra (int) that contains the upper bound on the current width, in dips, of a
+ * widget instance.
*/
public static final String OPTION_APPWIDGET_MAX_HEIGHT = "appWidgetMaxHeight";
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 6ae68fc..608b563 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -849,7 +849,7 @@
synchronized (mLock) {
if (sBluetoothLeScanner == null) {
sBluetoothLeScanner = new BluetoothLeScanner(mManagerService, getOpPackageName(),
- getFeatureId());
+ getAttributionTag());
}
}
return sBluetoothLeScanner;
@@ -1663,11 +1663,11 @@
return ActivityThread.currentOpPackageName();
}
- private String getFeatureId() {
+ private String getAttributionTag() {
// Workaround for legacy API for getting a BluetoothAdapter not
// passing a context
if (mContext != null) {
- return mContext.getFeatureId();
+ return mContext.getAttributionTag();
}
return null;
}
@@ -1709,7 +1709,7 @@
try {
mServiceLock.readLock().lock();
if (mService != null) {
- return mService.startDiscovery(getOpPackageName(), getFeatureId());
+ return mService.startDiscovery(getOpPackageName(), getAttributionTag());
}
} catch (RemoteException e) {
Log.e(TAG, "", e);
diff --git a/core/java/android/bluetooth/BluetoothManager.java b/core/java/android/bluetooth/BluetoothManager.java
index 7ff6466..3b4fe0a 100644
--- a/core/java/android/bluetooth/BluetoothManager.java
+++ b/core/java/android/bluetooth/BluetoothManager.java
@@ -62,7 +62,7 @@
* @hide
*/
public BluetoothManager(Context context) {
- if (context.getFeatureId() == null) {
+ if (context.getAttributionTag() == null) {
context = context.getApplicationContext();
if (context == null) {
throw new IllegalArgumentException(
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index bd3298c7..d8e8b27 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -230,12 +230,12 @@
}
@Override
- public Cursor query(String callingPkg, @Nullable String featureId, Uri uri,
+ public Cursor query(String callingPkg, @Nullable String attributionTag, Uri uri,
@Nullable String[] projection, @Nullable Bundle queryArgs,
@Nullable ICancellationSignal cancellationSignal) {
uri = validateIncomingUri(uri);
uri = maybeGetUriWithoutUserId(uri);
- if (enforceReadPermission(callingPkg, featureId, uri, null)
+ if (enforceReadPermission(callingPkg, attributionTag, uri, null)
!= AppOpsManager.MODE_ALLOWED) {
// The caller has no access to the data, so return an empty cursor with
// the columns in the requested order. The caller may ask for an invalid
@@ -253,7 +253,7 @@
// columns. We then use the column names to return an empty cursor.
Cursor cursor;
final Pair<String, String> original = setCallingPackage(
- new Pair<>(callingPkg, featureId));
+ new Pair<>(callingPkg, attributionTag));
try {
cursor = mInterface.query(
uri, projection, queryArgs,
@@ -272,7 +272,7 @@
}
Trace.traceBegin(TRACE_TAG_DATABASE, "query");
final Pair<String, String> original = setCallingPackage(
- new Pair<>(callingPkg, featureId));
+ new Pair<>(callingPkg, attributionTag));
try {
return mInterface.query(
uri, projection, queryArgs,
@@ -308,15 +308,15 @@
}
@Override
- public Uri insert(String callingPkg, @Nullable String featureId, Uri uri,
+ public Uri insert(String callingPkg, @Nullable String attributionTag, Uri uri,
ContentValues initialValues, Bundle extras) {
uri = validateIncomingUri(uri);
int userId = getUserIdFromUri(uri);
uri = maybeGetUriWithoutUserId(uri);
- if (enforceWritePermission(callingPkg, featureId, uri, null)
+ if (enforceWritePermission(callingPkg, attributionTag, uri, null)
!= AppOpsManager.MODE_ALLOWED) {
final Pair<String, String> original = setCallingPackage(
- new Pair<>(callingPkg, featureId));
+ new Pair<>(callingPkg, attributionTag));
try {
return rejectInsert(uri, initialValues);
} finally {
@@ -325,7 +325,7 @@
}
Trace.traceBegin(TRACE_TAG_DATABASE, "insert");
final Pair<String, String> original = setCallingPackage(
- new Pair<>(callingPkg, featureId));
+ new Pair<>(callingPkg, attributionTag));
try {
return maybeAddUserId(mInterface.insert(uri, initialValues, extras), userId);
} catch (RemoteException e) {
@@ -337,17 +337,17 @@
}
@Override
- public int bulkInsert(String callingPkg, @Nullable String featureId, Uri uri,
+ public int bulkInsert(String callingPkg, @Nullable String attributionTag, Uri uri,
ContentValues[] initialValues) {
uri = validateIncomingUri(uri);
uri = maybeGetUriWithoutUserId(uri);
- if (enforceWritePermission(callingPkg, featureId, uri, null)
+ if (enforceWritePermission(callingPkg, attributionTag, uri, null)
!= AppOpsManager.MODE_ALLOWED) {
return 0;
}
Trace.traceBegin(TRACE_TAG_DATABASE, "bulkInsert");
final Pair<String, String> original = setCallingPackage(
- new Pair<>(callingPkg, featureId));
+ new Pair<>(callingPkg, attributionTag));
try {
return mInterface.bulkInsert(uri, initialValues);
} catch (RemoteException e) {
@@ -359,8 +359,9 @@
}
@Override
- public ContentProviderResult[] applyBatch(String callingPkg, @Nullable String featureId,
- String authority, ArrayList<ContentProviderOperation> operations)
+ public ContentProviderResult[] applyBatch(String callingPkg,
+ @Nullable String attributionTag, String authority,
+ ArrayList<ContentProviderOperation> operations)
throws OperationApplicationException {
validateIncomingAuthority(authority);
int numOperations = operations.size();
@@ -377,13 +378,13 @@
operations.set(i, operation);
}
if (operation.isReadOperation()) {
- if (enforceReadPermission(callingPkg, featureId, uri, null)
+ if (enforceReadPermission(callingPkg, attributionTag, uri, null)
!= AppOpsManager.MODE_ALLOWED) {
throw new OperationApplicationException("App op not allowed", 0);
}
}
if (operation.isWriteOperation()) {
- if (enforceWritePermission(callingPkg, featureId, uri, null)
+ if (enforceWritePermission(callingPkg, attributionTag, uri, null)
!= AppOpsManager.MODE_ALLOWED) {
throw new OperationApplicationException("App op not allowed", 0);
}
@@ -391,7 +392,7 @@
}
Trace.traceBegin(TRACE_TAG_DATABASE, "applyBatch");
final Pair<String, String> original = setCallingPackage(
- new Pair<>(callingPkg, featureId));
+ new Pair<>(callingPkg, attributionTag));
try {
ContentProviderResult[] results = mInterface.applyBatch(authority,
operations);
@@ -413,16 +414,17 @@
}
@Override
- public int delete(String callingPkg, @Nullable String featureId, Uri uri, Bundle extras) {
+ public int delete(String callingPkg, @Nullable String attributionTag, Uri uri,
+ Bundle extras) {
uri = validateIncomingUri(uri);
uri = maybeGetUriWithoutUserId(uri);
- if (enforceWritePermission(callingPkg, featureId, uri, null)
+ if (enforceWritePermission(callingPkg, attributionTag, uri, null)
!= AppOpsManager.MODE_ALLOWED) {
return 0;
}
Trace.traceBegin(TRACE_TAG_DATABASE, "delete");
final Pair<String, String> original = setCallingPackage(
- new Pair<>(callingPkg, featureId));
+ new Pair<>(callingPkg, attributionTag));
try {
return mInterface.delete(uri, extras);
} catch (RemoteException e) {
@@ -434,17 +436,17 @@
}
@Override
- public int update(String callingPkg, @Nullable String featureId, Uri uri,
+ public int update(String callingPkg, @Nullable String attributionTag, Uri uri,
ContentValues values, Bundle extras) {
uri = validateIncomingUri(uri);
uri = maybeGetUriWithoutUserId(uri);
- if (enforceWritePermission(callingPkg, featureId, uri, null)
+ if (enforceWritePermission(callingPkg, attributionTag, uri, null)
!= AppOpsManager.MODE_ALLOWED) {
return 0;
}
Trace.traceBegin(TRACE_TAG_DATABASE, "update");
final Pair<String, String> original = setCallingPackage(
- new Pair<>(callingPkg, featureId));
+ new Pair<>(callingPkg, attributionTag));
try {
return mInterface.update(uri, values, extras);
} catch (RemoteException e) {
@@ -456,15 +458,15 @@
}
@Override
- public ParcelFileDescriptor openFile(String callingPkg, @Nullable String featureId,
+ public ParcelFileDescriptor openFile(String callingPkg, @Nullable String attributionTag,
Uri uri, String mode, ICancellationSignal cancellationSignal, IBinder callerToken)
throws FileNotFoundException {
uri = validateIncomingUri(uri);
uri = maybeGetUriWithoutUserId(uri);
- enforceFilePermission(callingPkg, featureId, uri, mode, callerToken);
+ enforceFilePermission(callingPkg, attributionTag, uri, mode, callerToken);
Trace.traceBegin(TRACE_TAG_DATABASE, "openFile");
final Pair<String, String> original = setCallingPackage(
- new Pair<>(callingPkg, featureId));
+ new Pair<>(callingPkg, attributionTag));
try {
return mInterface.openFile(
uri, mode, CancellationSignal.fromTransport(cancellationSignal));
@@ -477,15 +479,15 @@
}
@Override
- public AssetFileDescriptor openAssetFile(String callingPkg, @Nullable String featureId,
+ public AssetFileDescriptor openAssetFile(String callingPkg, @Nullable String attributionTag,
Uri uri, String mode, ICancellationSignal cancellationSignal)
throws FileNotFoundException {
uri = validateIncomingUri(uri);
uri = maybeGetUriWithoutUserId(uri);
- enforceFilePermission(callingPkg, featureId, uri, mode, null);
+ enforceFilePermission(callingPkg, attributionTag, uri, mode, null);
Trace.traceBegin(TRACE_TAG_DATABASE, "openAssetFile");
final Pair<String, String> original = setCallingPackage(
- new Pair<>(callingPkg, featureId));
+ new Pair<>(callingPkg, attributionTag));
try {
return mInterface.openAssetFile(
uri, mode, CancellationSignal.fromTransport(cancellationSignal));
@@ -498,13 +500,13 @@
}
@Override
- public Bundle call(String callingPkg, @Nullable String featureId, String authority,
+ public Bundle call(String callingPkg, @Nullable String attributionTag, String authority,
String method, @Nullable String arg, @Nullable Bundle extras) {
validateIncomingAuthority(authority);
Bundle.setDefusable(extras, true);
Trace.traceBegin(TRACE_TAG_DATABASE, "call");
final Pair<String, String> original = setCallingPackage(
- new Pair<>(callingPkg, featureId));
+ new Pair<>(callingPkg, attributionTag));
try {
return mInterface.call(authority, method, arg, extras);
} catch (RemoteException e) {
@@ -532,15 +534,15 @@
@Override
public AssetFileDescriptor openTypedAssetFile(String callingPkg,
- @Nullable String featureId, Uri uri, String mimeType, Bundle opts,
+ @Nullable String attributionTag, Uri uri, String mimeType, Bundle opts,
ICancellationSignal cancellationSignal) throws FileNotFoundException {
Bundle.setDefusable(opts, true);
uri = validateIncomingUri(uri);
uri = maybeGetUriWithoutUserId(uri);
- enforceFilePermission(callingPkg, featureId, uri, "r", null);
+ enforceFilePermission(callingPkg, attributionTag, uri, "r", null);
Trace.traceBegin(TRACE_TAG_DATABASE, "openTypedAssetFile");
final Pair<String, String> original = setCallingPackage(
- new Pair<>(callingPkg, featureId));
+ new Pair<>(callingPkg, attributionTag));
try {
return mInterface.openTypedAssetFile(
uri, mimeType, opts, CancellationSignal.fromTransport(cancellationSignal));
@@ -558,17 +560,17 @@
}
@Override
- public Uri canonicalize(String callingPkg, @Nullable String featureId, Uri uri) {
+ public Uri canonicalize(String callingPkg, @Nullable String attributionTag, Uri uri) {
uri = validateIncomingUri(uri);
int userId = getUserIdFromUri(uri);
uri = getUriWithoutUserId(uri);
- if (enforceReadPermission(callingPkg, featureId, uri, null)
+ if (enforceReadPermission(callingPkg, attributionTag, uri, null)
!= AppOpsManager.MODE_ALLOWED) {
return null;
}
Trace.traceBegin(TRACE_TAG_DATABASE, "canonicalize");
final Pair<String, String> original = setCallingPackage(
- new Pair<>(callingPkg, featureId));
+ new Pair<>(callingPkg, attributionTag));
try {
return maybeAddUserId(mInterface.canonicalize(uri), userId);
} catch (RemoteException e) {
@@ -580,26 +582,26 @@
}
@Override
- public void canonicalizeAsync(String callingPkg, @Nullable String featureId, Uri uri,
+ public void canonicalizeAsync(String callingPkg, @Nullable String attributionTag, Uri uri,
RemoteCallback callback) {
final Bundle result = new Bundle();
result.putParcelable(ContentResolver.REMOTE_CALLBACK_RESULT,
- canonicalize(callingPkg, featureId, uri));
+ canonicalize(callingPkg, attributionTag, uri));
callback.sendResult(result);
}
@Override
- public Uri uncanonicalize(String callingPkg, String featureId, Uri uri) {
+ public Uri uncanonicalize(String callingPkg, String attributionTag, Uri uri) {
uri = validateIncomingUri(uri);
int userId = getUserIdFromUri(uri);
uri = getUriWithoutUserId(uri);
- if (enforceReadPermission(callingPkg, featureId, uri, null)
+ if (enforceReadPermission(callingPkg, attributionTag, uri, null)
!= AppOpsManager.MODE_ALLOWED) {
return null;
}
Trace.traceBegin(TRACE_TAG_DATABASE, "uncanonicalize");
final Pair<String, String> original = setCallingPackage(
- new Pair<>(callingPkg, featureId));
+ new Pair<>(callingPkg, attributionTag));
try {
return maybeAddUserId(mInterface.uncanonicalize(uri), userId);
} catch (RemoteException e) {
@@ -611,17 +613,17 @@
}
@Override
- public boolean refresh(String callingPkg, String featureId, Uri uri, Bundle extras,
+ public boolean refresh(String callingPkg, String attributionTag, Uri uri, Bundle extras,
ICancellationSignal cancellationSignal) throws RemoteException {
uri = validateIncomingUri(uri);
uri = getUriWithoutUserId(uri);
- if (enforceReadPermission(callingPkg, featureId, uri, null)
+ if (enforceReadPermission(callingPkg, attributionTag, uri, null)
!= AppOpsManager.MODE_ALLOWED) {
return false;
}
Trace.traceBegin(TRACE_TAG_DATABASE, "refresh");
final Pair<String, String> original = setCallingPackage(
- new Pair<>(callingPkg, featureId));
+ new Pair<>(callingPkg, attributionTag));
try {
return mInterface.refresh(uri, extras,
CancellationSignal.fromTransport(cancellationSignal));
@@ -632,13 +634,13 @@
}
@Override
- public int checkUriPermission(String callingPkg, @Nullable String featureId, Uri uri,
+ public int checkUriPermission(String callingPkg, @Nullable String attributionTag, Uri uri,
int uid, int modeFlags) {
uri = validateIncomingUri(uri);
uri = maybeGetUriWithoutUserId(uri);
Trace.traceBegin(TRACE_TAG_DATABASE, "checkUriPermission");
final Pair<String, String> original = setCallingPackage(
- new Pair<>(callingPkg, featureId));
+ new Pair<>(callingPkg, attributionTag));
try {
return mInterface.checkUriPermission(uri, uid, modeFlags);
} catch (RemoteException e) {
@@ -649,47 +651,50 @@
}
}
- private void enforceFilePermission(String callingPkg, @Nullable String featureId, Uri uri,
- String mode, IBinder callerToken) throws FileNotFoundException, SecurityException {
+ private void enforceFilePermission(String callingPkg, @Nullable String attributionTag,
+ Uri uri, String mode, IBinder callerToken)
+ throws FileNotFoundException, SecurityException {
if (mode != null && mode.indexOf('w') != -1) {
- if (enforceWritePermission(callingPkg, featureId, uri, callerToken)
+ if (enforceWritePermission(callingPkg, attributionTag, uri, callerToken)
!= AppOpsManager.MODE_ALLOWED) {
throw new FileNotFoundException("App op not allowed");
}
} else {
- if (enforceReadPermission(callingPkg, featureId, uri, callerToken)
+ if (enforceReadPermission(callingPkg, attributionTag, uri, callerToken)
!= AppOpsManager.MODE_ALLOWED) {
throw new FileNotFoundException("App op not allowed");
}
}
}
- private int enforceReadPermission(String callingPkg, @Nullable String featureId, Uri uri,
- IBinder callerToken)
+ private int enforceReadPermission(String callingPkg, @Nullable String attributionTag,
+ Uri uri, IBinder callerToken)
throws SecurityException {
- final int mode = enforceReadPermissionInner(uri, callingPkg, featureId, callerToken);
+ final int mode = enforceReadPermissionInner(uri, callingPkg, attributionTag,
+ callerToken);
if (mode != MODE_ALLOWED) {
return mode;
}
- return noteProxyOp(callingPkg, featureId, mReadOp);
+ return noteProxyOp(callingPkg, attributionTag, mReadOp);
}
- private int enforceWritePermission(String callingPkg, String featureId, Uri uri,
+ private int enforceWritePermission(String callingPkg, String attributionTag, Uri uri,
IBinder callerToken)
throws SecurityException {
- final int mode = enforceWritePermissionInner(uri, callingPkg, featureId, callerToken);
+ final int mode = enforceWritePermissionInner(uri, callingPkg, attributionTag,
+ callerToken);
if (mode != MODE_ALLOWED) {
return mode;
}
- return noteProxyOp(callingPkg, featureId, mWriteOp);
+ return noteProxyOp(callingPkg, attributionTag, mWriteOp);
}
- private int noteProxyOp(String callingPkg, String featureId, int op) {
+ private int noteProxyOp(String callingPkg, String attributionTag, int op) {
if (op != AppOpsManager.OP_NONE) {
int mode = mAppOpsManager.noteProxyOp(op, callingPkg, Binder.getCallingUid(),
- featureId, null);
+ attributionTag, null);
return mode == MODE_DEFAULT ? MODE_IGNORED : mode;
}
@@ -711,19 +716,19 @@
* associated with that permission.
*/
private int checkPermissionAndAppOp(String permission, String callingPkg,
- @Nullable String featureId, IBinder callerToken) {
+ @Nullable String attributionTag, IBinder callerToken) {
if (getContext().checkPermission(permission, Binder.getCallingPid(), Binder.getCallingUid(),
callerToken) != PERMISSION_GRANTED) {
return MODE_ERRORED;
}
- return mTransport.noteProxyOp(callingPkg, featureId,
+ return mTransport.noteProxyOp(callingPkg, attributionTag,
AppOpsManager.permissionToOpCode(permission));
}
/** {@hide} */
protected int enforceReadPermissionInner(Uri uri, String callingPkg,
- @Nullable String featureId, IBinder callerToken) throws SecurityException {
+ @Nullable String attributionTag, IBinder callerToken) throws SecurityException {
final Context context = getContext();
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
@@ -737,7 +742,7 @@
if (mExported && checkUser(pid, uid, context)) {
final String componentPerm = getReadPermission();
if (componentPerm != null) {
- final int mode = checkPermissionAndAppOp(componentPerm, callingPkg, featureId,
+ final int mode = checkPermissionAndAppOp(componentPerm, callingPkg, attributionTag,
callerToken);
if (mode == MODE_ALLOWED) {
return MODE_ALLOWED;
@@ -757,8 +762,8 @@
for (PathPermission pp : pps) {
final String pathPerm = pp.getReadPermission();
if (pathPerm != null && pp.match(path)) {
- final int mode = checkPermissionAndAppOp(pathPerm, callingPkg, featureId,
- callerToken);
+ final int mode = checkPermissionAndAppOp(pathPerm, callingPkg,
+ attributionTag, callerToken);
if (mode == MODE_ALLOWED) {
return MODE_ALLOWED;
} else {
@@ -807,7 +812,7 @@
/** {@hide} */
protected int enforceWritePermissionInner(Uri uri, String callingPkg,
- @Nullable String featureId, IBinder callerToken) throws SecurityException {
+ @Nullable String attributionTag, IBinder callerToken) throws SecurityException {
final Context context = getContext();
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
@@ -821,8 +826,8 @@
if (mExported && checkUser(pid, uid, context)) {
final String componentPerm = getWritePermission();
if (componentPerm != null) {
- final int mode = checkPermissionAndAppOp(componentPerm, callingPkg, featureId,
- callerToken);
+ final int mode = checkPermissionAndAppOp(componentPerm, callingPkg,
+ attributionTag, callerToken);
if (mode == MODE_ALLOWED) {
return MODE_ALLOWED;
} else {
@@ -841,8 +846,8 @@
for (PathPermission pp : pps) {
final String pathPerm = pp.getWritePermission();
if (pathPerm != null && pp.match(path)) {
- final int mode = checkPermissionAndAppOp(pathPerm, callingPkg, featureId,
- callerToken);
+ final int mode = checkPermissionAndAppOp(pathPerm, callingPkg,
+ attributionTag, callerToken);
if (mode == MODE_ALLOWED) {
return MODE_ALLOWED;
} else {
@@ -943,16 +948,16 @@
}
/**
- * Return the feature in the package of the caller that initiated the request being
+ * Return the attribution tag of the caller that initiated the request being
* processed on the current thread. Returns {@code null} if not currently processing
- * a request of the request is for the default feature.
+ * a request of the request is for the default attribution.
* <p>
* This will always return {@code null} when processing
* {@link #getType(Uri)} or {@link #getStreamTypes(Uri, String)} requests.
*
* @see #getCallingPackage
*/
- public final @Nullable String getCallingFeatureId() {
+ public final @Nullable String getCallingAttributionTag() {
final Pair<String, String> pkg = mCallingPackage.get();
if (pkg != null) {
return pkg.second;
@@ -962,6 +967,14 @@
}
/**
+ * @removed
+ */
+ @Deprecated
+ public final @Nullable String getCallingFeatureId() {
+ return getCallingAttributionTag();
+ }
+
+ /**
* Return the package name of the caller that initiated the request being
* processed on the current thread. The returned package will have
* <em>not</em> been verified to belong to the calling UID. Returns
diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java
index a9b7862..d0f5ec4 100644
--- a/core/java/android/content/ContentProviderClient.java
+++ b/core/java/android/content/ContentProviderClient.java
@@ -80,7 +80,7 @@
private final IContentProvider mContentProvider;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private final String mPackageName;
- private final @Nullable String mFeatureId;
+ private final @Nullable String mAttributionTag;
private final String mAuthority;
private final boolean mStable;
@@ -104,7 +104,7 @@
mContentResolver = contentResolver;
mContentProvider = contentProvider;
mPackageName = contentResolver.mPackageName;
- mFeatureId = contentResolver.mFeatureId;
+ mAttributionTag = contentResolver.mAttributionTag;
mAuthority = authority;
mStable = stable;
@@ -195,7 +195,8 @@
cancellationSignal.setRemote(remoteCancellationSignal);
}
final Cursor cursor = mContentProvider.query(
- mPackageName, mFeatureId, uri, projection, queryArgs, remoteCancellationSignal);
+ mPackageName, mAttributionTag, uri, projection, queryArgs,
+ remoteCancellationSignal);
if (cursor == null) {
return null;
}
@@ -255,7 +256,7 @@
beforeRemote();
try {
- return mContentProvider.canonicalize(mPackageName, mFeatureId, url);
+ return mContentProvider.canonicalize(mPackageName, mAttributionTag, url);
} catch (DeadObjectException e) {
if (!mStable) {
mContentResolver.unstableProviderDied(mContentProvider);
@@ -273,7 +274,7 @@
beforeRemote();
try {
- return mContentProvider.uncanonicalize(mPackageName, mFeatureId, url);
+ return mContentProvider.uncanonicalize(mPackageName, mAttributionTag, url);
} catch (DeadObjectException e) {
if (!mStable) {
mContentResolver.unstableProviderDied(mContentProvider);
@@ -298,7 +299,7 @@
remoteCancellationSignal = mContentProvider.createCancellationSignal();
cancellationSignal.setRemote(remoteCancellationSignal);
}
- return mContentProvider.refresh(mPackageName, mFeatureId, url, extras,
+ return mContentProvider.refresh(mPackageName, mAttributionTag, url, extras,
remoteCancellationSignal);
} catch (DeadObjectException e) {
if (!mStable) {
@@ -318,7 +319,7 @@
beforeRemote();
try {
- return mContentProvider.checkUriPermission(mPackageName, mFeatureId, uri, uid,
+ return mContentProvider.checkUriPermission(mPackageName, mAttributionTag, uri, uid,
modeFlags);
} catch (DeadObjectException e) {
if (!mStable) {
@@ -344,7 +345,8 @@
beforeRemote();
try {
- return mContentProvider.insert(mPackageName, mFeatureId, url, initialValues, extras);
+ return mContentProvider.insert(mPackageName, mAttributionTag, url, initialValues,
+ extras);
} catch (DeadObjectException e) {
if (!mStable) {
mContentResolver.unstableProviderDied(mContentProvider);
@@ -364,7 +366,7 @@
beforeRemote();
try {
- return mContentProvider.bulkInsert(mPackageName, mFeatureId, url, initialValues);
+ return mContentProvider.bulkInsert(mPackageName, mAttributionTag, url, initialValues);
} catch (DeadObjectException e) {
if (!mStable) {
mContentResolver.unstableProviderDied(mContentProvider);
@@ -388,7 +390,7 @@
beforeRemote();
try {
- return mContentProvider.delete(mPackageName, mFeatureId, url, extras);
+ return mContentProvider.delete(mPackageName, mAttributionTag, url, extras);
} catch (DeadObjectException e) {
if (!mStable) {
mContentResolver.unstableProviderDied(mContentProvider);
@@ -413,7 +415,7 @@
beforeRemote();
try {
- return mContentProvider.update(mPackageName, mFeatureId, url, values, extras);
+ return mContentProvider.update(mPackageName, mAttributionTag, url, values, extras);
} catch (DeadObjectException e) {
if (!mStable) {
mContentResolver.unstableProviderDied(mContentProvider);
@@ -457,8 +459,8 @@
remoteSignal = mContentProvider.createCancellationSignal();
signal.setRemote(remoteSignal);
}
- return mContentProvider.openFile(mPackageName, mFeatureId, url, mode, remoteSignal,
- null);
+ return mContentProvider.openFile(mPackageName, mAttributionTag, url, mode,
+ remoteSignal, null);
} catch (DeadObjectException e) {
if (!mStable) {
mContentResolver.unstableProviderDied(mContentProvider);
@@ -502,7 +504,7 @@
remoteSignal = mContentProvider.createCancellationSignal();
signal.setRemote(remoteSignal);
}
- return mContentProvider.openAssetFile(mPackageName, mFeatureId, url, mode,
+ return mContentProvider.openAssetFile(mPackageName, mAttributionTag, url, mode,
remoteSignal);
} catch (DeadObjectException e) {
if (!mStable) {
@@ -544,7 +546,7 @@
signal.setRemote(remoteSignal);
}
return mContentProvider.openTypedAssetFile(
- mPackageName, mFeatureId, uri, mimeTypeFilter, opts, remoteSignal);
+ mPackageName, mAttributionTag, uri, mimeTypeFilter, opts, remoteSignal);
} catch (DeadObjectException e) {
if (!mStable) {
mContentResolver.unstableProviderDied(mContentProvider);
@@ -571,7 +573,8 @@
beforeRemote();
try {
- return mContentProvider.applyBatch(mPackageName, mFeatureId, authority, operations);
+ return mContentProvider.applyBatch(mPackageName, mAttributionTag, authority,
+ operations);
} catch (DeadObjectException e) {
if (!mStable) {
mContentResolver.unstableProviderDied(mContentProvider);
@@ -597,7 +600,8 @@
beforeRemote();
try {
- return mContentProvider.call(mPackageName, mFeatureId, authority, method, arg, extras);
+ return mContentProvider.call(mPackageName, mAttributionTag, authority, method, arg,
+ extras);
} catch (DeadObjectException e) {
if (!mStable) {
mContentResolver.unstableProviderDied(mContentProvider);
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 31e1fc8..b134c37 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -767,7 +767,7 @@
public ContentResolver(@Nullable Context context, @Nullable ContentInterface wrapped) {
mContext = context != null ? context : ActivityThread.currentApplication();
mPackageName = mContext.getOpPackageName();
- mFeatureId = mContext.getFeatureId();
+ mAttributionTag = mContext.getAttributionTag();
mTargetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
mWrapped = wrapped;
}
@@ -1144,7 +1144,7 @@
cancellationSignal.setRemote(remoteCancellationSignal);
}
try {
- qCursor = unstableProvider.query(mPackageName, mFeatureId, uri, projection,
+ qCursor = unstableProvider.query(mPackageName, mAttributionTag, uri, projection,
queryArgs, remoteCancellationSignal);
} catch (DeadObjectException e) {
// The remote process has died... but we only hold an unstable
@@ -1155,7 +1155,7 @@
if (stableProvider == null) {
return null;
}
- qCursor = stableProvider.query(mPackageName, mFeatureId, uri, projection,
+ qCursor = stableProvider.query(mPackageName, mAttributionTag, uri, projection,
queryArgs, remoteCancellationSignal);
}
if (qCursor == null) {
@@ -1247,7 +1247,7 @@
try {
final UriResultListener resultListener = new UriResultListener();
- provider.canonicalizeAsync(mPackageName, mFeatureId, url,
+ provider.canonicalizeAsync(mPackageName, mAttributionTag, url,
new RemoteCallback(resultListener));
resultListener.waitForResult(CONTENT_PROVIDER_TIMEOUT_MILLIS);
return resultListener.result;
@@ -1294,7 +1294,7 @@
}
try {
- return provider.uncanonicalize(mPackageName, mFeatureId, url);
+ return provider.uncanonicalize(mPackageName, mAttributionTag, url);
} catch (RemoteException e) {
// Arbitrary and not worth documenting, as Activity
// Manager will kill this process shortly anyway.
@@ -1346,7 +1346,7 @@
remoteCancellationSignal = provider.createCancellationSignal();
cancellationSignal.setRemote(remoteCancellationSignal);
}
- return provider.refresh(mPackageName, mFeatureId, url, extras,
+ return provider.refresh(mPackageName, mAttributionTag, url, extras,
remoteCancellationSignal);
} catch (RemoteException e) {
// Arbitrary and not worth documenting, as Activity
@@ -1748,7 +1748,8 @@
try {
fd = unstableProvider.openAssetFile(
- mPackageName, mFeatureId, uri, mode, remoteCancellationSignal);
+ mPackageName, mAttributionTag, uri, mode,
+ remoteCancellationSignal);
if (fd == null) {
// The provider will be released by the finally{} clause
return null;
@@ -1763,7 +1764,7 @@
throw new FileNotFoundException("No content provider: " + uri);
}
fd = stableProvider.openAssetFile(
- mPackageName, mFeatureId, uri, mode, remoteCancellationSignal);
+ mPackageName, mAttributionTag, uri, mode, remoteCancellationSignal);
if (fd == null) {
// The provider will be released by the finally{} clause
return null;
@@ -1914,7 +1915,8 @@
try {
fd = unstableProvider.openTypedAssetFile(
- mPackageName, mFeatureId, uri, mimeType, opts, remoteCancellationSignal);
+ mPackageName, mAttributionTag, uri, mimeType, opts,
+ remoteCancellationSignal);
if (fd == null) {
// The provider will be released by the finally{} clause
return null;
@@ -1929,7 +1931,8 @@
throw new FileNotFoundException("No content provider: " + uri);
}
fd = stableProvider.openTypedAssetFile(
- mPackageName, mFeatureId, uri, mimeType, opts, remoteCancellationSignal);
+ mPackageName, mAttributionTag, uri, mimeType, opts,
+ remoteCancellationSignal);
if (fd == null) {
// The provider will be released by the finally{} clause
return null;
@@ -2077,7 +2080,7 @@
}
try {
long startTime = SystemClock.uptimeMillis();
- Uri createdRow = provider.insert(mPackageName, mFeatureId, url, values, extras);
+ Uri createdRow = provider.insert(mPackageName, mAttributionTag, url, values, extras);
long durationMillis = SystemClock.uptimeMillis() - startTime;
maybeLogUpdateToEventLog(durationMillis, url, "insert", null /* where */);
return createdRow;
@@ -2158,7 +2161,7 @@
}
try {
long startTime = SystemClock.uptimeMillis();
- int rowsCreated = provider.bulkInsert(mPackageName, mFeatureId, url, values);
+ int rowsCreated = provider.bulkInsert(mPackageName, mAttributionTag, url, values);
long durationMillis = SystemClock.uptimeMillis() - startTime;
maybeLogUpdateToEventLog(durationMillis, url, "bulkinsert", null /* where */);
return rowsCreated;
@@ -2217,7 +2220,7 @@
}
try {
long startTime = SystemClock.uptimeMillis();
- int rowsDeleted = provider.delete(mPackageName, mFeatureId, url, extras);
+ int rowsDeleted = provider.delete(mPackageName, mAttributionTag, url, extras);
long durationMillis = SystemClock.uptimeMillis() - startTime;
maybeLogUpdateToEventLog(durationMillis, url, "delete", null);
return rowsDeleted;
@@ -2284,7 +2287,7 @@
}
try {
long startTime = SystemClock.uptimeMillis();
- int rowsUpdated = provider.update(mPackageName, mFeatureId, uri, values, extras);
+ int rowsUpdated = provider.update(mPackageName, mAttributionTag, uri, values, extras);
long durationMillis = SystemClock.uptimeMillis() - startTime;
maybeLogUpdateToEventLog(durationMillis, uri, "update", null);
return rowsUpdated;
@@ -2333,7 +2336,7 @@
throw new IllegalArgumentException("Unknown authority " + authority);
}
try {
- final Bundle res = provider.call(mPackageName, mFeatureId, authority, method, arg,
+ final Bundle res = provider.call(mPackageName, mAttributionTag, authority, method, arg,
extras);
Bundle.setDefusable(res, true);
return res;
@@ -3746,8 +3749,8 @@
}
/** @hide */
- public @Nullable String getFeatureId() {
- return mFeatureId;
+ public @Nullable String getAttributionTag() {
+ return mAttributionTag;
}
@UnsupportedAppUsage
@@ -3757,7 +3760,7 @@
@UnsupportedAppUsage
final String mPackageName;
- final @Nullable String mFeatureId;
+ final @Nullable String mAttributionTag;
final int mTargetSdkVersion;
final ContentInterface mWrapped;
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 6cba327..318ae11 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -71,6 +71,7 @@
import android.view.View;
import android.view.ViewDebug;
import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams.WindowType;
import android.view.autofill.AutofillManager.AutofillClient;
import android.view.contentcapture.ContentCaptureManager.ContentCaptureClient;
import android.view.textclassifier.TextClassificationManager;
@@ -814,16 +815,25 @@
}
/**
- * <p>Features are used in complex apps to logically separate parts of the app. E.g. a
- * blogging app might also have a instant messaging app built in.
+ * <p>Attribution can be used in complex apps to logically separate parts of the app. E.g. a
+ * blogging app might also have a instant messaging app built in. In this case two separate tags
+ * can for used each sub-feature.
*
- * @return the feature id this context is for or {@code null} if this is the default
- * feature.
+ * @return the attribution tag this context is for or {@code null} if this is the default.
*/
- public @Nullable String getFeatureId() {
+ public @Nullable String getAttributionTag() {
return null;
}
+ // TODO moltmann: Remove
+ /**
+ * @removed
+ */
+ @Deprecated
+ public @Nullable String getFeatureId() {
+ return getAttributionTag();
+ }
+
/** Return the full application info for this context's package. */
public abstract ApplicationInfo getApplicationInfo();
@@ -5820,24 +5830,34 @@
* @see #WALLPAPER_SERVICE
* @throws IllegalArgumentException if token is invalid
*/
- public @NonNull Context createWindowContext(int type, @Nullable Bundle options) {
+ public @NonNull Context createWindowContext(@WindowType int type, @Nullable Bundle options) {
throw new RuntimeException("Not implemented. Must override in a subclass.");
}
/**
- * Return a new Context object for the current Context but for a different feature in the app.
- * Features can be used by complex apps to separate logical parts.
+ * Return a new Context object for the current Context but attribute to a different tag.
+ * In complex apps attribution tagging can be used to distinguish between separate logical
+ * parts.
*
- * @param featureId The feature id or {@code null} to create a context for the default feature.
+ * @param attributionTag The tag or {@code null} to create a context for the default.
*
- * @return A {@link Context} for the feature
+ * @return A {@link Context} that is tagged for the new attribution
*
- * @see #getFeatureId()
+ * @see #getAttributionTag()
*/
- public @NonNull Context createFeatureContext(@Nullable String featureId) {
+ public @NonNull Context createAttributionContext(@Nullable String attributionTag) {
throw new RuntimeException("Not implemented. Must override in a subclass.");
}
+ // TODO moltmann: remove
+ /**
+ * @removed
+ */
+ @Deprecated
+ public @NonNull Context createFeatureContext(@Nullable String featureId) {
+ return createAttributionContext(featureId);
+ }
+
/**
* Return a new Context object for the current Context but whose storage
* APIs are backed by device-protected storage.
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 91d214b..d389d2a 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -42,6 +42,7 @@
import android.os.UserHandle;
import android.view.Display;
import android.view.DisplayAdjustments;
+import android.view.WindowManager.LayoutParams.WindowType;
import android.view.autofill.AutofillManager.AutofillClient;
import java.io.File;
@@ -163,8 +164,8 @@
/** @hide */
@Override
- public @Nullable String getFeatureId() {
- return mBase.getFeatureId();
+ public @Nullable String getAttributionTag() {
+ return mBase.getAttributionTag();
}
@Override
@@ -978,13 +979,13 @@
@Override
@NonNull
- public Context createWindowContext(int type, @Nullable Bundle options) {
+ public Context createWindowContext(@WindowType int type, @Nullable Bundle options) {
return mBase.createWindowContext(type, options);
}
@Override
- public @NonNull Context createFeatureContext(@Nullable String featureId) {
- return mBase.createFeatureContext(featureId);
+ public @NonNull Context createAttributionContext(@Nullable String attributionTag) {
+ return mBase.createAttributionContext(attributionTag);
}
@Override
diff --git a/core/java/android/content/IContentProvider.java b/core/java/android/content/IContentProvider.java
index 37643da..84b0f0e 100644
--- a/core/java/android/content/IContentProvider.java
+++ b/core/java/android/content/IContentProvider.java
@@ -38,7 +38,7 @@
* @hide
*/
public interface IContentProvider extends IInterface {
- public Cursor query(String callingPkg, @Nullable String featureId, Uri url,
+ public Cursor query(String callingPkg, @Nullable String attributionTag, Uri url,
@Nullable String[] projection,
@Nullable Bundle queryArgs, @Nullable ICancellationSignal cancellationSignal)
throws RemoteException;
@@ -59,8 +59,8 @@
throws RemoteException {
return insert(callingPkg, null, url, initialValues, null);
}
- public Uri insert(String callingPkg, String featureId, Uri url, ContentValues initialValues,
- Bundle extras) throws RemoteException;
+ public Uri insert(String callingPkg, String attributionTag, Uri url,
+ ContentValues initialValues, Bundle extras) throws RemoteException;
@Deprecated
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "Use {@link "
+ "ContentProviderClient#bulkInsert(android.net.Uri, android.content.ContentValues[])"
@@ -69,7 +69,7 @@
throws RemoteException {
return bulkInsert(callingPkg, null, url, initialValues);
}
- public int bulkInsert(String callingPkg, String featureId, Uri url,
+ public int bulkInsert(String callingPkg, String attributionTag, Uri url,
ContentValues[] initialValues) throws RemoteException;
@Deprecated
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "Use {@link "
@@ -80,7 +80,7 @@
return delete(callingPkg, null, url,
ContentResolver.createSqlQueryBundle(selection, selectionArgs));
}
- public int delete(String callingPkg, String featureId, Uri url, Bundle extras)
+ public int delete(String callingPkg, String attributionTag, Uri url, Bundle extras)
throws RemoteException;
@Deprecated
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, publicAlternatives = "Use {@link "
@@ -91,18 +91,18 @@
return update(callingPkg, null, url, values,
ContentResolver.createSqlQueryBundle(selection, selectionArgs));
}
- public int update(String callingPkg, String featureId, Uri url, ContentValues values,
+ public int update(String callingPkg, String attributionTag, Uri url, ContentValues values,
Bundle extras) throws RemoteException;
- public ParcelFileDescriptor openFile(String callingPkg, @Nullable String featureId, Uri url,
- String mode, ICancellationSignal signal, IBinder callerToken)
+ public ParcelFileDescriptor openFile(String callingPkg, @Nullable String attributionTag,
+ Uri url, String mode, ICancellationSignal signal, IBinder callerToken)
throws RemoteException, FileNotFoundException;
- public AssetFileDescriptor openAssetFile(String callingPkg, @Nullable String featureId,
+ public AssetFileDescriptor openAssetFile(String callingPkg, @Nullable String attributionTag,
Uri url, String mode, ICancellationSignal signal)
throws RemoteException, FileNotFoundException;
- public ContentProviderResult[] applyBatch(String callingPkg, @Nullable String featureId,
+ public ContentProviderResult[] applyBatch(String callingPkg, @Nullable String attributionTag,
String authority, ArrayList<ContentProviderOperation> operations)
throws RemoteException, OperationApplicationException;
@@ -115,15 +115,15 @@
return call(callingPkg, null, "unknown", method, arg, extras);
}
- public Bundle call(String callingPkg, @Nullable String featureId, String authority,
+ public Bundle call(String callingPkg, @Nullable String attributionTag, String authority,
String method, @Nullable String arg, @Nullable Bundle extras) throws RemoteException;
- public int checkUriPermission(String callingPkg, @Nullable String featureId, Uri uri, int uid,
- int modeFlags) throws RemoteException;
+ public int checkUriPermission(String callingPkg, @Nullable String attributionTag, Uri uri,
+ int uid, int modeFlags) throws RemoteException;
public ICancellationSignal createCancellationSignal() throws RemoteException;
- public Uri canonicalize(String callingPkg, @Nullable String featureId, Uri uri)
+ public Uri canonicalize(String callingPkg, @Nullable String attributionTag, Uri uri)
throws RemoteException;
/**
@@ -131,20 +131,21 @@
* call returns immediately, and the resulting type is returned when available via
* a binder callback.
*/
- void canonicalizeAsync(String callingPkg, @Nullable String featureId, Uri uri,
+ void canonicalizeAsync(String callingPkg, @Nullable String attributionTag, Uri uri,
RemoteCallback callback) throws RemoteException;
- public Uri uncanonicalize(String callingPkg, @Nullable String featureId, Uri uri)
+ public Uri uncanonicalize(String callingPkg, @Nullable String attributionTag, Uri uri)
throws RemoteException;
- public boolean refresh(String callingPkg, @Nullable String featureId, Uri url,
+ public boolean refresh(String callingPkg, @Nullable String attributionTag, Uri url,
@Nullable Bundle extras, ICancellationSignal cancellationSignal) throws RemoteException;
// Data interchange.
public String[] getStreamTypes(Uri url, String mimeTypeFilter) throws RemoteException;
- public AssetFileDescriptor openTypedAssetFile(String callingPkg, @Nullable String featureId,
- Uri url, String mimeType, Bundle opts, ICancellationSignal signal)
+ public AssetFileDescriptor openTypedAssetFile(String callingPkg,
+ @Nullable String attributionTag, Uri url, String mimeType, Bundle opts,
+ ICancellationSignal signal)
throws RemoteException, FileNotFoundException;
/* IPC constants */
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 4bb7346d..38c1890 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -26,6 +26,7 @@
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.app.AppGlobals;
@@ -86,6 +87,7 @@
import java.util.Locale;
import java.util.Objects;
import java.util.Set;
+import java.util.TimeZone;
/**
* An intent is an abstract description of an operation to be performed. It
@@ -2312,7 +2314,8 @@
/**
* Broadcast Action: The timezone has changed. The intent will have the following extra values:</p>
* <ul>
- * <li><em>time-zone</em> - The java.util.TimeZone.getID() value identifying the new time zone.</li>
+ * <li>{@link #EXTRA_TIMEZONE} - The java.util.TimeZone.getID() value identifying the new
+ * time zone.</li>
* </ul>
*
* <p class="note">This is a protected intent that can only be sent
@@ -5785,6 +5788,14 @@
public static final String EXTRA_TIME = "android.intent.extra.TIME";
/**
+ * Extra sent with {@link #ACTION_TIMEZONE_CHANGED} specifying the new time zone of the device.
+ *
+ * <p>Type: String, the same as returned by {@link TimeZone#getID()} to identify time zones.
+ */
+ @SuppressLint("ActionValue")
+ public static final String EXTRA_TIMEZONE = "time-zone";
+
+ /**
* Optional int extra for {@link #ACTION_TIME_CHANGED} that indicates the
* user has set their time format preference. See {@link #EXTRA_TIME_PREF_VALUE_USE_12_HOUR},
* {@link #EXTRA_TIME_PREF_VALUE_USE_24_HOUR} and
diff --git a/core/java/android/content/PermissionChecker.java b/core/java/android/content/PermissionChecker.java
index 33bd839..052c920 100644
--- a/core/java/android/content/PermissionChecker.java
+++ b/core/java/android/content/PermissionChecker.java
@@ -123,7 +123,7 @@
* @param uid The uid for which to check.
* @param packageName The package name for which to check. If null the
* the first package for the calling UID will be used.
- * @param featureId Feature in the package
+ * @param attributionTag attribution tag
* @return The permission check result which is either {@link #PERMISSION_GRANTED}
* or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}.
* @param message A message describing the reason the permission was checked
@@ -133,9 +133,9 @@
@PermissionResult
public static int checkPermissionForDataDelivery(@NonNull Context context,
@NonNull String permission, int pid, int uid, @Nullable String packageName,
- @Nullable String featureId, @Nullable String message) {
- return checkPermissionCommon(context, permission, pid, uid, packageName, featureId, message,
- true /*forDataDelivery*/);
+ @Nullable String attributionTag, @Nullable String message) {
+ return checkPermissionCommon(context, permission, pid, uid, packageName, attributionTag,
+ message, true /*forDataDelivery*/);
}
/**
@@ -171,8 +171,8 @@
@PermissionResult
public static int checkPermissionForPreflight(@NonNull Context context,
@NonNull String permission, int pid, int uid, @Nullable String packageName) {
- return checkPermissionCommon(context, permission, pid, uid, packageName, null /*featureId*/,
- null /*message*/, false /*forDataDelivery*/);
+ return checkPermissionCommon(context, permission, pid, uid, packageName,
+ null /*attributionTag*/, null /*message*/, false /*forDataDelivery*/);
}
/**
@@ -207,7 +207,7 @@
public static int checkSelfPermissionForDataDelivery(@NonNull Context context,
@NonNull String permission, @Nullable String message) {
return checkPermissionForDataDelivery(context, permission, Process.myPid(),
- Process.myUid(), context.getPackageName(), context.getFeatureId(), message);
+ Process.myUid(), context.getPackageName(), context.getAttributionTag(), message);
}
/**
@@ -266,7 +266,7 @@
* @param permission The permission to check.
* @param packageName The package name making the IPC. If null the
* the first package for the calling UID will be used.
- * @param featureId The feature inside of the app
+ * @param attributionTag attribution tag
* @return The permission check result which is either {@link #PERMISSION_GRANTED}
* or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}.
* @param message A message describing the reason the permission was checked
@@ -276,12 +276,12 @@
@PermissionResult
public static int checkCallingPermissionForDataDelivery(@NonNull Context context,
@NonNull String permission, @Nullable String packageName,
- @Nullable String featureId, @Nullable String message) {
+ @Nullable String attributionTag, @Nullable String message) {
if (Binder.getCallingPid() == Process.myPid()) {
return PERMISSION_HARD_DENIED;
}
return checkPermissionForDataDelivery(context, permission, Binder.getCallingPid(),
- Binder.getCallingUid(), packageName, featureId, message);
+ Binder.getCallingUid(), packageName, attributionTag, message);
}
/**
@@ -343,20 +343,20 @@
* @param permission The permission to check.
* @return The permission check result which is either {@link #PERMISSION_GRANTED}
* or {@link #PERMISSION_SOFT_DENIED} or {@link #PERMISSION_HARD_DENIED}.
- * @param featureId feature Id of caller (if not self)
+ * @param attributionTag attribution tag of caller (if not self)
* @param message A message describing the reason the permission was checked
*
* @see #checkCallingOrSelfPermissionForPreflight(Context, String)
*/
@PermissionResult
public static int checkCallingOrSelfPermissionForDataDelivery(@NonNull Context context,
- @NonNull String permission, @Nullable String featureId, @Nullable String message) {
+ @NonNull String permission, @Nullable String attributionTag, @Nullable String message) {
String packageName = (Binder.getCallingPid() == Process.myPid())
? context.getPackageName() : null;
- featureId = (Binder.getCallingPid() == Process.myPid())
- ? context.getFeatureId() : featureId;
+ attributionTag = (Binder.getCallingPid() == Process.myPid())
+ ? context.getAttributionTag() : attributionTag;
return checkPermissionForDataDelivery(context, permission, Binder.getCallingPid(),
- Binder.getCallingUid(), packageName, featureId, message);
+ Binder.getCallingUid(), packageName, attributionTag, message);
}
/**
@@ -395,7 +395,7 @@
}
static int checkPermissionCommon(@NonNull Context context, @NonNull String permission,
- int pid, int uid, @Nullable String packageName, @Nullable String featureId,
+ int pid, int uid, @Nullable String packageName, @Nullable String attributionTag,
@Nullable String message, boolean forDataDelivery) {
final PermissionInfo permissionInfo;
try {
@@ -414,18 +414,18 @@
}
if (permissionInfo.isAppOp()) {
- return checkAppOpPermission(context, permission, pid, uid, packageName, featureId,
+ return checkAppOpPermission(context, permission, pid, uid, packageName, attributionTag,
message, forDataDelivery);
}
if (permissionInfo.isRuntime()) {
- return checkRuntimePermission(context, permission, pid, uid, packageName, featureId,
- message, forDataDelivery);
+ return checkRuntimePermission(context, permission, pid, uid, packageName,
+ attributionTag, message, forDataDelivery);
}
return context.checkPermission(permission, pid, uid);
}
private static int checkAppOpPermission(@NonNull Context context, @NonNull String permission,
- int pid, int uid, @Nullable String packageName, @Nullable String featureId,
+ int pid, int uid, @Nullable String packageName, @Nullable String attributionTag,
@Nullable String message, boolean forDataDelivery) {
final String op = AppOpsManager.permissionToOp(permission);
if (op == null || packageName == null) {
@@ -434,7 +434,7 @@
final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);
final int opMode = (forDataDelivery)
- ? appOpsManager.noteProxyOpNoThrow(op, packageName, uid, featureId, message)
+ ? appOpsManager.noteProxyOpNoThrow(op, packageName, uid, attributionTag, message)
: appOpsManager.unsafeCheckOpNoThrow(op, uid, packageName);
switch (opMode) {
@@ -453,7 +453,7 @@
}
private static int checkRuntimePermission(@NonNull Context context, @NonNull String permission,
- int pid, int uid, @Nullable String packageName, @Nullable String featureId,
+ int pid, int uid, @Nullable String packageName, @Nullable String attributionTag,
@Nullable String message, boolean forDataDelivery) {
if (context.checkPermission(permission, pid, uid) == PackageManager.PERMISSION_DENIED) {
return PERMISSION_HARD_DENIED;
@@ -466,7 +466,7 @@
final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);
final int opMode = (forDataDelivery)
- ? appOpsManager.noteProxyOpNoThrow(op, packageName, uid, featureId, message)
+ ? appOpsManager.noteProxyOpNoThrow(op, packageName, uid, attributionTag, message)
: appOpsManager.unsafeCheckOpNoThrow(op, uid, packageName);
if (opMode == AppOpsManager.MODE_ALLOWED) {
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 0b2b5b1..f25ce76 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -1222,13 +1222,7 @@
dest.writeInt(lockTaskLaunchMode);
if (windowLayout != null) {
dest.writeInt(1);
- dest.writeInt(windowLayout.width);
- dest.writeFloat(windowLayout.widthFraction);
- dest.writeInt(windowLayout.height);
- dest.writeFloat(windowLayout.heightFraction);
- dest.writeInt(windowLayout.gravity);
- dest.writeInt(windowLayout.minWidth);
- dest.writeInt(windowLayout.minHeight);
+ windowLayout.writeToParcel(dest);
} else {
dest.writeInt(0);
}
@@ -1372,8 +1366,8 @@
* @attr ref android.R.styleable#AndroidManifestLayout_minHeight
*/
public static final class WindowLayout {
- public WindowLayout(int width, float widthFraction, int height, float heightFraction, int gravity,
- int minWidth, int minHeight) {
+ public WindowLayout(int width, float widthFraction, int height, float heightFraction,
+ int gravity, int minWidth, int minHeight) {
this.width = width;
this.widthFraction = widthFraction;
this.height = height;
@@ -1392,6 +1386,7 @@
gravity = source.readInt();
minWidth = source.readInt();
minHeight = source.readInt();
+ windowLayoutAffinity = source.readString();
}
/**
@@ -1458,11 +1453,30 @@
public final int minHeight;
/**
+ * Affinity of window layout parameters. Activities with the same UID and window layout
+ * affinity will share the same window dimension record.
+ * @hide
+ */
+ public String windowLayoutAffinity;
+
+ /**
* Returns if this {@link WindowLayout} has specified bounds.
* @hide
*/
public boolean hasSpecifiedSize() {
return width >= 0 || height >= 0 || widthFraction >= 0 || heightFraction >= 0;
}
+
+ /** @hide */
+ public void writeToParcel(Parcel dest) {
+ dest.writeInt(width);
+ dest.writeFloat(widthFraction);
+ dest.writeInt(height);
+ dest.writeFloat(heightFraction);
+ dest.writeInt(gravity);
+ dest.writeInt(minWidth);
+ dest.writeInt(minHeight);
+ dest.writeString(windowLayoutAffinity);
+ }
}
}
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index a15afe0..c82fffa 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -25,6 +25,7 @@
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ProcessInfo;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.Build;
@@ -38,6 +39,8 @@
import android.util.proto.ProtoOutputStream;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.Parcelling;
+import com.android.internal.util.Parcelling.BuiltIn.ForBoolean;
import com.android.server.SystemConfig;
import java.lang.annotation.Retention;
@@ -56,7 +59,8 @@
* <application> tag.
*/
public class ApplicationInfo extends PackageItemInfo implements Parcelable {
-
+ private static ForBoolean sForBoolean = Parcelling.Cache.getOrCreate(ForBoolean.class);
+
/**
* Default task affinity of all activities in this application. See
* {@link ActivityInfo#taskAffinity} for more information. This comes
@@ -1273,6 +1277,14 @@
public String zygotePreloadName;
/**
+ * Indicates if the application has requested GWP-ASan to be enabled, disabled, or left
+ * unspecified. Processes can override this setting.
+ * @hide
+ */
+ @Nullable
+ public Boolean enableGwpAsan;
+
+ /**
* Represents the default policy. The actual policy used will depend on other properties of
* the application, e.g. the target SDK version.
* @hide
@@ -1413,6 +1425,9 @@
pw.println(prefix + "usesNonSdkApi=" + usesNonSdkApi());
pw.println(prefix + "allowsPlaybackCapture="
+ (isAudioPlaybackCaptureAllowed() ? "true" : "false"));
+ if (enableGwpAsan != null) {
+ pw.println(prefix + "enableGwpAsan=" + enableGwpAsan);
+ }
}
super.dumpBack(pw, prefix);
}
@@ -1511,6 +1526,9 @@
if (category != CATEGORY_UNDEFINED) {
proto.write(ApplicationInfoProto.Detail.CATEGORY, category);
}
+ if (enableGwpAsan != null) {
+ proto.write(ApplicationInfoProto.Detail.ENABLE_GWP_ASAN, enableGwpAsan);
+ }
proto.end(detailToken);
}
proto.end(token);
@@ -1620,6 +1638,7 @@
mHiddenApiPolicy = orig.mHiddenApiPolicy;
hiddenUntilInstalled = orig.hiddenUntilInstalled;
zygotePreloadName = orig.zygotePreloadName;
+ enableGwpAsan = orig.enableGwpAsan;
}
public String toString() {
@@ -1703,6 +1722,7 @@
dest.writeInt(mHiddenApiPolicy);
dest.writeInt(hiddenUntilInstalled ? 1 : 0);
dest.writeString(zygotePreloadName);
+ sForBoolean.parcel(enableGwpAsan, dest, parcelableFlags);
}
public static final @android.annotation.NonNull Parcelable.Creator<ApplicationInfo> CREATOR
@@ -1783,6 +1803,7 @@
mHiddenApiPolicy = source.readInt();
hiddenUntilInstalled = source.readInt() != 0;
zygotePreloadName = source.readString();
+ enableGwpAsan = sForBoolean.unparcel(source);
}
/**
@@ -2161,6 +2182,7 @@
/** {@hide} */ public void setResourcePath(String resourcePath) { scanPublicSourceDir = resourcePath; }
/** {@hide} */ public void setBaseResourcePath(String baseResourcePath) { publicSourceDir = baseResourcePath; }
/** {@hide} */ public void setSplitResourcePaths(String[] splitResourcePaths) { splitPublicSourceDirs = splitResourcePaths; }
+ /** {@hide} */ public void setGwpAsanEnabled(@Nullable Boolean value) { enableGwpAsan = value; }
/** {@hide} */
@UnsupportedAppUsage
@@ -2172,4 +2194,6 @@
@UnsupportedAppUsage
public String getBaseResourcePath() { return publicSourceDir; }
/** {@hide} */ public String[] getSplitResourcePaths() { return splitPublicSourceDirs; }
+ @Nullable
+ public Boolean isGwpAsanEnabled() { return enableGwpAsan; }
}
diff --git a/core/java/android/content/pm/CrossProfileApps.java b/core/java/android/content/pm/CrossProfileApps.java
index 3261cb1..dc3a0297 100644
--- a/core/java/android/content/pm/CrossProfileApps.java
+++ b/core/java/android/content/pm/CrossProfileApps.java
@@ -27,6 +27,7 @@
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.net.Uri;
+import android.os.Bundle;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
@@ -95,7 +96,7 @@
mService.startActivityAsUser(
mContext.getIApplicationThread(),
mContext.getPackageName(),
- mContext.getFeatureId(),
+ mContext.getAttributionTag(),
component,
targetUser.getIdentifier(),
true);
@@ -128,14 +129,44 @@
@NonNull Intent intent,
@NonNull UserHandle targetUser,
@Nullable Activity callingActivity) {
+ startActivity(intent, targetUser, callingActivity, /* options= */ null);
+ }
+
+ /**
+ * Starts the specified activity of the caller package in the specified profile.
+ *
+ * <p>The caller must have the {@link android.Manifest.permission#INTERACT_ACROSS_PROFILES},
+ * {@code android.Manifest.permission#INTERACT_ACROSS_USERS}, or {@code
+ * android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permission. Both the caller and
+ * target user profiles must be in the same profile group. The target user must be a valid user
+ * returned from {@link #getTargetUserProfiles()}.
+ *
+ * @param intent The intent to launch. A component in the caller package must be specified.
+ * @param targetUser The {@link UserHandle} of the profile; must be one of the users returned by
+ * {@link #getTargetUserProfiles()} if different to the calling user, otherwise a
+ * {@link SecurityException} will be thrown.
+ * @param callingActivity The activity to start the new activity from for the purposes of
+ * deciding which task the new activity should belong to. If {@code null}, the activity
+ * will always be started in a new task.
+ * @param options The activity options or {@code null}. See {@link android.app.ActivityOptions}.
+ */
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.INTERACT_ACROSS_PROFILES,
+ android.Manifest.permission.INTERACT_ACROSS_USERS})
+ public void startActivity(
+ @NonNull Intent intent,
+ @NonNull UserHandle targetUser,
+ @Nullable Activity callingActivity,
+ @Nullable Bundle options) {
try {
mService.startActivityAsUserByIntent(
mContext.getIApplicationThread(),
mContext.getPackageName(),
- mContext.getFeatureId(),
+ mContext.getAttributionTag(),
intent,
targetUser.getIdentifier(),
- callingActivity != null ? callingActivity.getActivityToken() : null);
+ callingActivity != null ? callingActivity.getActivityToken() : null,
+ options);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
@@ -159,7 +190,7 @@
public void startActivity(@NonNull ComponentName component, @NonNull UserHandle targetUser) {
try {
mService.startActivityAsUser(mContext.getIApplicationThread(),
- mContext.getPackageName(), mContext.getFeatureId(), component,
+ mContext.getPackageName(), mContext.getAttributionTag(), component,
targetUser.getIdentifier(), false);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
diff --git a/core/java/android/content/pm/ICrossProfileApps.aidl b/core/java/android/content/pm/ICrossProfileApps.aidl
index 5a6e008..4cecb30 100644
--- a/core/java/android/content/pm/ICrossProfileApps.aidl
+++ b/core/java/android/content/pm/ICrossProfileApps.aidl
@@ -31,7 +31,8 @@
in String callingFeatureId, in ComponentName component, int userId,
boolean launchMainActivity);
void startActivityAsUserByIntent(in IApplicationThread caller, in String callingPackage,
- in String callingFeatureId, in Intent intent, int userId, in IBinder callingActivity);
+ in String callingFeatureId, in Intent intent, int userId, in IBinder callingActivity,
+ in Bundle options);
List<UserHandle> getTargetUserProfiles(in String callingPackage);
boolean canInteractAcrossProfiles(in String callingPackage);
boolean canRequestInteractAcrossProfiles(in String callingPackage);
diff --git a/core/java/android/content/pm/InstallSourceInfo.java b/core/java/android/content/pm/InstallSourceInfo.java
index c0fdcc9..a45bf79 100644
--- a/core/java/android/content/pm/InstallSourceInfo.java
+++ b/core/java/android/content/pm/InstallSourceInfo.java
@@ -66,7 +66,18 @@
mInstallingPackageName = source.readString();
}
- /** The name of the package that requested the installation, or null if not available. */
+ /**
+ * The name of the package that requested the installation, or null if not available.
+ *
+ * This is normally the same as the installing package name. If the installing package name
+ * is changed, for example by calling
+ * {@link PackageManager#setInstallerPackageName(String, String)}, the initiating package name
+ * remains unchanged. It continues to identify the actual package that performed the install
+ * or update.
+ * <p>
+ * Null may be returned if the app was not installed by a package (e.g. a system app or an app
+ * installed via adb) or if the initiating package has itself been uninstalled.
+ */
@Nullable
public String getInitiatingPackageName() {
return mInitiatingPackageName;
@@ -100,9 +111,11 @@
/**
* The name of the package responsible for the installation (the installer of record), or null
* if not available.
- * Note that this may differ from the initiating package name and can be modified.
- *
- * @see PackageManager#setInstallerPackageName(String, String)
+ * Note that this may differ from the initiating package name and can be modified via
+ * {@link PackageManager#setInstallerPackageName(String, String)}.
+ * <p>
+ * Null may be returned if the app was not installed by a package (e.g. a system app or an app
+ * installed via adb) or if the installing package has itself been uninstalled.
*/
@Nullable
public String getInstallingPackageName() {
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 86242fd..4e4897f 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -721,7 +721,7 @@
}
try {
mService.startActivityAsUser(mContext.getIApplicationThread(),
- mContext.getPackageName(), mContext.getFeatureId(),
+ mContext.getPackageName(), mContext.getAttributionTag(),
component, sourceBounds, opts, user);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
@@ -739,8 +739,8 @@
@Nullable Rect sourceBounds, @Nullable Bundle opts) {
try {
mService.startSessionDetailsActivityAsUser(mContext.getIApplicationThread(),
- mContext.getPackageName(), mContext.getFeatureId(), sessionInfo, sourceBounds,
- opts, sessionInfo.getUser());
+ mContext.getPackageName(), mContext.getAttributionTag(), sessionInfo,
+ sourceBounds, opts, sessionInfo.getUser());
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
@@ -760,7 +760,7 @@
logErrorForInvalidProfileAccess(user);
try {
mService.showAppDetailsAsUser(mContext.getIApplicationThread(),
- mContext.getPackageName(), mContext.getFeatureId(),
+ mContext.getPackageName(), mContext.getAttributionTag(),
component, sourceBounds, opts, user);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 1f53176..ec3590f 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -2323,6 +2323,7 @@
/**
* Get the value set in {@link SessionParams#setOriginatingUri(Uri)}.
+ * Note: This value will only be non-null for the owner of the session.
*/
public @Nullable Uri getOriginatingUri() {
return originatingUri;
@@ -2337,6 +2338,7 @@
/**
* Get the value set in {@link SessionParams#setReferrerUri(Uri)}
+ * Note: This value will only be non-null for the owner of the session.
*/
public @Nullable Uri getReferrerUri() {
return referrerUri;
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 7600a08..b0964fa 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3411,12 +3411,13 @@
public static final int FLAG_PERMISSION_AUTO_REVOKED = 1 << 17;
/**
- * Permission flags: Reserved for use by the permission controller.
- *
+ * Permission flags: Reserved for use by the permission controller. The platform and any
+ * packages besides the permission controller should not assume any definition about these
+ * flags.
* @hide
*/
@SystemApi
- public static final int FLAGS_PERMISSION_RESERVED_PERMISSIONCONTROLLER = 1 << 28 | 1 << 29
+ public static final int FLAGS_PERMISSION_RESERVED_PERMISSION_CONTROLLER = 1 << 28 | 1 << 29
| 1 << 30 | 1 << 31;
/**
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index c6875a4..18f1343 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -55,7 +55,6 @@
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.pm.parsing.ParsingPackageUtils;
import android.content.pm.permission.SplitPermissionInfoParcelable;
import android.content.pm.split.DefaultSplitAssetLoader;
import android.content.pm.split.SplitAssetDependencyLoader;
@@ -190,7 +189,7 @@
public static final String TAG_OVERLAY = "overlay";
public static final String TAG_PACKAGE = "package";
public static final String TAG_PACKAGE_VERIFIER = "package-verifier";
- public static final String TAG_FEATURE = "feature";
+ public static final String TAG_ATTRIBUTION = "attribution";
public static final String TAG_PERMISSION = "permission";
public static final String TAG_PERMISSION_GROUP = "permission-group";
public static final String TAG_PERMISSION_TREE = "permission-tree";
@@ -209,6 +208,8 @@
public static final String TAG_USES_SPLIT = "uses-split";
public static final String METADATA_MAX_ASPECT_RATIO = "android.max_aspect";
+ public static final String METADATA_ACTIVITY_WINDOW_LAYOUT_AFFINITY =
+ "android.activity_window_layout_affinity";
/**
* Bit mask of all the valid bits that can be set in recreateOnConfigChanges.
@@ -4560,6 +4561,8 @@
}
}
+ resolveWindowLayout(a);
+
if (!setExported) {
a.info.exported = a.intents.size() > 0;
}
@@ -4726,6 +4729,35 @@
height, heightFraction, gravity, minWidth, minHeight);
}
+ /**
+ * Resolves values in {@link ActivityInfo.WindowLayout}.
+ *
+ * <p>{@link ActivityInfo.WindowLayout#windowLayoutAffinity} has a fallback metadata used in
+ * Android R and some variants of pre-R.
+ */
+ private void resolveWindowLayout(Activity activity) {
+ // There isn't a metadata for us to fall back. Whatever is in layout is correct.
+ if (activity.metaData == null
+ || !activity.metaData.containsKey(METADATA_ACTIVITY_WINDOW_LAYOUT_AFFINITY)) {
+ return;
+ }
+
+ final ActivityInfo aInfo = activity.info;
+ // Layout already specifies a value. We should just use that one.
+ if (aInfo.windowLayout != null && aInfo.windowLayout.windowLayoutAffinity != null) {
+ return;
+ }
+
+ String windowLayoutAffinity = activity.metaData.getString(
+ METADATA_ACTIVITY_WINDOW_LAYOUT_AFFINITY);
+ if (aInfo.windowLayout == null) {
+ aInfo.windowLayout = new ActivityInfo.WindowLayout(-1 /* width */,
+ -1 /* widthFraction */, -1 /* height */, -1 /* heightFraction */,
+ Gravity.NO_GRAVITY, -1 /* minWidth */, -1 /* minHeight */);
+ }
+ aInfo.windowLayout.windowLayoutAffinity = windowLayoutAffinity;
+ }
+
private Activity parseActivityAlias(Package owner, Resources res,
XmlResourceParser parser, int flags, String[] outError,
CachedComponentArgs cachedArgs)
diff --git a/core/java/android/content/pm/ProcessInfo.java b/core/java/android/content/pm/ProcessInfo.java
index c77a267..a373067 100644
--- a/core/java/android/content/pm/ProcessInfo.java
+++ b/core/java/android/content/pm/ProcessInfo.java
@@ -23,66 +23,157 @@
import android.text.TextUtils;
import android.util.ArraySet;
+import com.android.internal.util.DataClass;
+import com.android.internal.util.Parcelling;
+
/**
* Information about a process an app may run. This corresponds to information collected from the
* AndroidManifest.xml's <permission-group> tags.
* @hide
*/
+@DataClass(genGetters = true, genSetters = false, genParcelable = true, genAidl = false,
+ genBuilder = false)
public class ProcessInfo implements Parcelable {
/**
* The name of the process, fully-qualified based on the app's package name.
*/
+ @NonNull
public String name;
/**
* If non-null, these are permissions that are not allowed in this process.
*/
@Nullable
+ @DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringArraySet.class)
public ArraySet<String> deniedPermissions;
- public ProcessInfo(String name, ArraySet<String> deniedPermissions) {
- this.name = name;
- this.deniedPermissions = deniedPermissions;
- }
+ /**
+ * Indicates if the process has requested GWP-ASan to be enabled, disabled, or left unspecified.
+ */
+ @Nullable
+ public Boolean enableGwpAsan;
@Deprecated
public ProcessInfo(@NonNull ProcessInfo orig) {
this.name = orig.name;
this.deniedPermissions = orig.deniedPermissions;
+ this.enableGwpAsan = orig.enableGwpAsan;
}
- public int describeContents() {
- return 0;
+
+
+ // Code below generated by codegen v1.0.15.
+ //
+ // DO NOT MODIFY!
+ // CHECKSTYLE:OFF Generated code
+ //
+ // To regenerate run:
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/ProcessInfo.java
+ //
+ // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+ // Settings > Editor > Code Style > Formatter Control
+ //@formatter:off
+
+
+ /**
+ * Creates a new ProcessInfo.
+ *
+ * @param name
+ * The name of the process, fully-qualified based on the app's package name.
+ * @param deniedPermissions
+ * If non-null, these are permissions that are not allowed in this process.
+ * @param enableGwpAsan
+ * Indicates if the process has requested GWP-ASan to be enabled, disabled, or left unspecified.
+ */
+ @DataClass.Generated.Member
+ public ProcessInfo(
+ @NonNull String name,
+ @Nullable ArraySet<String> deniedPermissions,
+ @Nullable Boolean enableGwpAsan) {
+ this.name = name;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, name);
+ this.deniedPermissions = deniedPermissions;
+ this.enableGwpAsan = enableGwpAsan;
+
+ // onConstructed(); // You can define this method to get a callback
}
- public void writeToParcel(Parcel dest, int parcelableFlags) {
- dest.writeString(this.name);
- final int numDenied = this.deniedPermissions != null
- ? this.deniedPermissions.size() : 0;
- dest.writeInt(numDenied);
- for (int i = 0; i < numDenied; i++) {
- dest.writeString(this.deniedPermissions.valueAt(i));
+ @DataClass.Generated.Member
+ static Parcelling<ArraySet<String>> sParcellingForDeniedPermissions =
+ Parcelling.Cache.get(
+ Parcelling.BuiltIn.ForInternedStringArraySet.class);
+ static {
+ if (sParcellingForDeniedPermissions == null) {
+ sParcellingForDeniedPermissions = Parcelling.Cache.put(
+ new Parcelling.BuiltIn.ForInternedStringArraySet());
}
}
- public static final @NonNull Creator<ProcessInfo> CREATOR =
- new Creator<ProcessInfo>() {
- public ProcessInfo createFromParcel(Parcel source) {
- return new ProcessInfo(source);
- }
- public ProcessInfo[] newArray(int size) {
- return new ProcessInfo[size];
- }
- };
+ @Override
+ @DataClass.Generated.Member
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ // You can override field parcelling by defining methods like:
+ // void parcelFieldName(Parcel dest, int flags) { ... }
- private ProcessInfo(Parcel source) {
- this.name = source.readString();
- final int numDenied = source.readInt();
- if (numDenied > 0) {
- this.deniedPermissions = new ArraySet<>(numDenied);
- for (int i = numDenied - 1; i >= 0; i--) {
- this.deniedPermissions.add(TextUtils.safeIntern(source.readString()));
- }
- }
+ byte flg = 0;
+ if (deniedPermissions != null) flg |= 0x2;
+ if (enableGwpAsan != null) flg |= 0x4;
+ dest.writeByte(flg);
+ dest.writeString(name);
+ sParcellingForDeniedPermissions.parcel(deniedPermissions, dest, flags);
+ if (enableGwpAsan != null) dest.writeBoolean(enableGwpAsan);
}
+
+ @Override
+ @DataClass.Generated.Member
+ public int describeContents() { return 0; }
+
+ /** @hide */
+ @SuppressWarnings({"unchecked", "RedundantCast"})
+ @DataClass.Generated.Member
+ protected ProcessInfo(@NonNull Parcel in) {
+ // You can override field unparcelling by defining methods like:
+ // static FieldType unparcelFieldName(Parcel in) { ... }
+
+ byte flg = in.readByte();
+ String _name = in.readString();
+ ArraySet<String> _deniedPermissions = sParcellingForDeniedPermissions.unparcel(in);
+ Boolean _enableGwpAsan = (flg & 0x4) == 0 ? null : (Boolean) in.readBoolean();
+
+ this.name = _name;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, name);
+ this.deniedPermissions = _deniedPermissions;
+ this.enableGwpAsan = _enableGwpAsan;
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ @DataClass.Generated.Member
+ public static final @NonNull Parcelable.Creator<ProcessInfo> CREATOR
+ = new Parcelable.Creator<ProcessInfo>() {
+ @Override
+ public ProcessInfo[] newArray(int size) {
+ return new ProcessInfo[size];
+ }
+
+ @Override
+ public ProcessInfo createFromParcel(@NonNull Parcel in) {
+ return new ProcessInfo(in);
+ }
+ };
+
+ @DataClass.Generated(
+ time = 1582840056156L,
+ codegenVersion = "1.0.15",
+ sourceFile = "frameworks/base/core/java/android/content/pm/ProcessInfo.java",
+ inputSignatures = "public @android.annotation.NonNull java.lang.String name\npublic @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedStringArraySet.class) android.util.ArraySet<java.lang.String> deniedPermissions\npublic @android.annotation.Nullable java.lang.Boolean enableGwpAsan\nclass ProcessInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=false, genParcelable=true, genAidl=false, genBuilder=false)")
+ @Deprecated
+ private void __metadata() {}
+
+
+ //@formatter:on
+ // End of generated code
+
}
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index 49e8c05..af87578 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -1558,11 +1558,6 @@
* "Rank" of a shortcut, which is a non-negative, sequential value that's unique for each
* {@link #getActivity} for each of the two types of shortcuts (static and dynamic).
*
- * <p>Because static shortcuts and dynamic shortcuts have overlapping ranks,
- * when a launcher app shows shortcuts for an activity, it should first show
- * the static shortcuts, followed by the dynamic shortcuts. Within each of those categories,
- * shortcuts should be sorted by rank in ascending order.
- *
* <p><em>Floating shortcuts</em>, or shortcuts that are neither static nor dynamic, will all
* have rank 0, because they aren't sorted.
*
diff --git a/core/java/android/content/pm/parsing/ParsingPackage.java b/core/java/android/content/pm/parsing/ParsingPackage.java
index aa93d80..1e02a7d 100644
--- a/core/java/android/content/pm/parsing/ParsingPackage.java
+++ b/core/java/android/content/pm/parsing/ParsingPackage.java
@@ -24,7 +24,7 @@
import android.content.pm.FeatureInfo;
import android.content.pm.PackageParser;
import android.content.pm.parsing.component.ParsedActivity;
-import android.content.pm.parsing.component.ParsedFeature;
+import android.content.pm.parsing.component.ParsedAttribution;
import android.content.pm.parsing.component.ParsedInstrumentation;
import android.content.pm.parsing.component.ParsedIntentInfo;
import android.content.pm.parsing.component.ParsedPermission;
@@ -77,7 +77,7 @@
ParsingPackage addProvider(ParsedProvider parsedProvider);
- ParsingPackage addFeature(ParsedFeature permission);
+ ParsingPackage addAttribution(ParsedAttribution attribution);
ParsingPackage addReceiver(ParsedActivity parsedReceiver);
@@ -236,6 +236,8 @@
ParsingPackage setEnabled(boolean enabled);
+ ParsingPackage setGwpAsanEnabled(Boolean enableGwpAsan);
+
ParsingPackage setCrossProfile(boolean crossProfile);
ParsingPackage setFullBackupContent(int fullBackupContent);
diff --git a/core/java/android/content/pm/parsing/ParsingPackageImpl.java b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
index a9b72d0..d7c0dfb 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageImpl.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageImpl.java
@@ -30,9 +30,10 @@
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;
-import android.content.pm.parsing.component.ParsedFeature;
import android.content.pm.parsing.component.ParsedInstrumentation;
import android.content.pm.parsing.component.ParsedIntentInfo;
import android.content.pm.parsing.component.ParsedMainComponent;
@@ -243,7 +244,7 @@
protected List<ParsedProvider> providers = emptyList();
@NonNull
- private List<ParsedFeature> features = emptyList();
+ private List<ParsedAttribution> attributions = emptyList();
@NonNull
protected List<ParsedPermission> permissions = emptyList();
@@ -406,6 +407,10 @@
private boolean allowNativeHeapPointerTagging;
private boolean preserveLegacyExternalStorage;
+ @Nullable
+ @DataClass.ParcelWith(ForBoolean.class)
+ protected Boolean enableGwpAsan = null;
+
// TODO(chiuwinson): Non-null
@Nullable
private ArraySet<String> mimeGroups;
@@ -620,8 +625,8 @@
}
@Override
- public ParsingPackageImpl addFeature(ParsedFeature feature) {
- this.features = CollectionUtils.add(this.features, feature);
+ public ParsingPackageImpl addAttribution(ParsedAttribution attribution) {
+ this.attributions = CollectionUtils.add(this.attributions, attribution);
return this;
}
@@ -904,7 +909,7 @@
appInfo.volumeUuid = volumeUuid;
appInfo.zygotePreloadName = zygotePreloadName;
appInfo.crossProfile = isCrossProfile();
-
+ appInfo.setGwpAsanEnabled(enableGwpAsan);
appInfo.setBaseCodePath(baseCodePath);
appInfo.setBaseResourcePath(baseCodePath);
appInfo.setCodePath(codePath);
@@ -990,7 +995,7 @@
dest.writeTypedList(this.receivers);
dest.writeTypedList(this.services);
dest.writeTypedList(this.providers);
- dest.writeTypedList(this.features);
+ dest.writeTypedList(this.attributions);
dest.writeTypedList(this.permissions);
dest.writeTypedList(this.permissionGroups);
dest.writeTypedList(this.instrumentations);
@@ -1086,6 +1091,7 @@
dest.writeBoolean(this.allowNativeHeapPointerTagging);
dest.writeBoolean(this.preserveLegacyExternalStorage);
dest.writeArraySet(this.mimeGroups);
+ sForBoolean.parcel(this.enableGwpAsan, dest, flags);
}
public ParsingPackageImpl(Parcel in) {
@@ -1149,7 +1155,7 @@
this.receivers = in.createTypedArrayList(ParsedActivity.CREATOR);
this.services = in.createTypedArrayList(ParsedService.CREATOR);
this.providers = in.createTypedArrayList(ParsedProvider.CREATOR);
- this.features = in.createTypedArrayList(ParsedFeature.CREATOR);
+ this.attributions = in.createTypedArrayList(ParsedAttribution.CREATOR);
this.permissions = in.createTypedArrayList(ParsedPermission.CREATOR);
this.permissionGroups = in.createTypedArrayList(ParsedPermissionGroup.CREATOR);
this.instrumentations = in.createTypedArrayList(ParsedInstrumentation.CREATOR);
@@ -1243,6 +1249,7 @@
this.allowNativeHeapPointerTagging = in.readBoolean();
this.preserveLegacyExternalStorage = in.readBoolean();
this.mimeGroups = (ArraySet<String>) in.readArraySet(boot);
+ this.enableGwpAsan = sForBoolean.unparcel(in);
}
public static final Parcelable.Creator<ParsingPackageImpl> CREATOR =
@@ -1509,8 +1516,8 @@
@NonNull
@Override
- public List<ParsedFeature> getFeatures() {
- return features;
+ public List<ParsedAttribution> getAttributions() {
+ return attributions;
}
@NonNull
@@ -1965,6 +1972,12 @@
}
@Override
+ @Nullable
+ public Boolean isGwpAsanEnabled() {
+ return enableGwpAsan;
+ }
+
+ @Override
public boolean isPartiallyDirectBootAware() {
return partiallyDirectBootAware;
}
@@ -2420,6 +2433,12 @@
}
@Override
+ public ParsingPackageImpl setGwpAsanEnabled(@Nullable Boolean value) {
+ enableGwpAsan = value;
+ return this;
+ }
+
+ @Override
public ParsingPackageImpl setPartiallyDirectBootAware(boolean value) {
partiallyDirectBootAware = value;
return this;
diff --git a/core/java/android/content/pm/parsing/ParsingPackageRead.java b/core/java/android/content/pm/parsing/ParsingPackageRead.java
index 048b924..0b673b5 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageRead.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageRead.java
@@ -28,7 +28,7 @@
import android.content.pm.PackageParser;
import android.content.pm.ServiceInfo;
import android.content.pm.parsing.component.ParsedActivity;
-import android.content.pm.parsing.component.ParsedFeature;
+import android.content.pm.parsing.component.ParsedAttribution;
import android.content.pm.parsing.component.ParsedInstrumentation;
import android.content.pm.parsing.component.ParsedIntentInfo;
import android.content.pm.parsing.component.ParsedPermission;
@@ -80,7 +80,7 @@
List<ConfigurationInfo> getConfigPreferences();
@NonNull
- List<ParsedFeature> getFeatures();
+ List<ParsedAttribution> getAttributions();
/**
* @see PackageInfo#featureGroups
@@ -840,6 +840,13 @@
@Nullable
Set<String> getMimeGroups();
+ /**
+ * @see ApplicationInfo#enableGwpAsan
+ * @see R.styleable#AndroidManifest_enableGwpAsan
+ */
+ @Nullable
+ public Boolean isGwpAsanEnabled();
+
// TODO(b/135203078): Hide and enforce going through PackageInfoUtils
ApplicationInfo toAppInfoWithoutState();
}
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
index b4f2159..3ed0fd5 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -40,6 +40,7 @@
import android.content.pm.FeatureGroupInfo;
import android.content.pm.FeatureInfo;
import android.content.pm.PackageInfo;
+import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
import android.content.pm.PackageParser.PackageParserException;
@@ -48,8 +49,8 @@
import android.content.pm.parsing.component.ComponentParseUtils;
import android.content.pm.parsing.component.ParsedActivity;
import android.content.pm.parsing.component.ParsedActivityUtils;
-import android.content.pm.parsing.component.ParsedFeature;
-import android.content.pm.parsing.component.ParsedFeatureUtils;
+import android.content.pm.parsing.component.ParsedAttribution;
+import android.content.pm.parsing.component.ParsedAttributionUtils;
import android.content.pm.parsing.component.ParsedInstrumentation;
import android.content.pm.parsing.component.ParsedInstrumentationUtils;
import android.content.pm.parsing.component.ParsedIntentInfo;
@@ -672,7 +673,7 @@
);
}
- if (!ParsedFeature.isCombinationValid(pkg.getFeatures())) {
+ if (!ParsedAttribution.isCombinationValid(pkg.getAttributions())) {
return input.error(
INSTALL_PARSE_FAILED_BAD_MANIFEST,
"Combination <feature> tags are not valid"
@@ -707,8 +708,9 @@
return parseOverlay(input, pkg, res, parser);
case PackageParser.TAG_KEY_SETS:
return parseKeySets(input, pkg, res, parser);
- case PackageParser.TAG_FEATURE:
- return parseFeature(input, pkg, res, parser);
+ case "feature": // TODO moltmann: Remove
+ case PackageParser.TAG_ATTRIBUTION:
+ return parseAttribution(input, pkg, res, parser);
case PackageParser.TAG_PERMISSION_GROUP:
return parsePermissionGroup(input, pkg, res, parser);
case PackageParser.TAG_PERMISSION:
@@ -917,13 +919,15 @@
return input.success(pkg);
}
- private static ParseResult<ParsingPackage> parseFeature(ParseInput input, ParsingPackage pkg,
- Resources res, XmlResourceParser parser) throws IOException, XmlPullParserException {
- ParseResult<ParsedFeature> result = ParsedFeatureUtils.parseFeature(res, parser, input);
+ private static ParseResult<ParsingPackage> parseAttribution(ParseInput input,
+ ParsingPackage pkg, Resources res, XmlResourceParser parser)
+ throws IOException, XmlPullParserException {
+ ParseResult<ParsedAttribution> result = ParsedAttributionUtils.parseAttribution(res,
+ parser, input);
if (result.isError()) {
return input.error(result);
}
- return input.success(pkg.addFeature(result.getResult()));
+ return input.success(pkg.addAttribution(result.getResult()));
}
private static ParseResult<ParsingPackage> parsePermissionGroup(ParseInput input,
@@ -1660,6 +1664,11 @@
&& !ClassLoaderFactory.isValidClassLoaderName(classLoaderName)) {
return input.error("Invalid class loader name: " + classLoaderName);
}
+
+ if (sa.hasValue(R.styleable.AndroidManifestApplication_enableGwpAsan)) {
+ pkg.setGwpAsanEnabled(
+ sa.getBoolean(R.styleable.AndroidManifestApplication_enableGwpAsan, false));
+ }
} finally {
sa.recycle();
}
diff --git a/core/java/android/content/pm/parsing/component/ParsedActivity.java b/core/java/android/content/pm/parsing/component/ParsedActivity.java
index d32171d..4c93d09 100644
--- a/core/java/android/content/pm/parsing/component/ParsedActivity.java
+++ b/core/java/android/content/pm/parsing/component/ParsedActivity.java
@@ -285,14 +285,8 @@
dest.writeBundle(this.metaData);
if (windowLayout != null) {
- dest.writeBoolean(true);
- dest.writeInt(windowLayout.width);
- dest.writeFloat(windowLayout.widthFraction);
- dest.writeInt(windowLayout.height);
- dest.writeFloat(windowLayout.heightFraction);
- dest.writeInt(windowLayout.gravity);
- dest.writeInt(windowLayout.minWidth);
- dest.writeInt(windowLayout.minHeight);
+ dest.writeInt(1);
+ windowLayout.writeToParcel(dest);
} else {
dest.writeBoolean(false);
}
diff --git a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
index 1dcf262..6e5c51a 100644
--- a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
@@ -17,16 +17,17 @@
package android.content.pm.parsing.component;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-
import static android.content.pm.parsing.component.ComponentParseUtils.flag;
import android.annotation.NonNull;
import android.app.ActivityTaskManager;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageParser;
-
import android.content.pm.parsing.ParsingPackage;
+import android.content.pm.parsing.ParsingPackageUtils;
import android.content.pm.parsing.ParsingUtils;
+import android.content.pm.parsing.result.ParseInput;
+import android.content.pm.parsing.result.ParseResult;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -42,9 +43,6 @@
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
-import android.content.pm.parsing.ParsingPackageUtils;
-import android.content.pm.parsing.result.ParseInput;
-import android.content.pm.parsing.result.ParseResult;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -379,6 +377,12 @@
}
}
+ ParseResult<ActivityInfo.WindowLayout> layoutResult = resolveWindowLayout(activity, input);
+ if (layoutResult.isError()) {
+ return input.error(layoutResult);
+ }
+ activity.windowLayout = layoutResult.getResult();
+
if (!setExported) {
activity.exported = activity.getIntents().size() > 0;
}
@@ -481,4 +485,35 @@
sw.recycle();
}
}
+
+ /**
+ * Resolves values in {@link ActivityInfo.WindowLayout}.
+ *
+ * <p>{@link ActivityInfo.WindowLayout#windowLayoutAffinity} has a fallback metadata used in
+ * Android R and some variants of pre-R.
+ */
+ private static ParseResult<ActivityInfo.WindowLayout> resolveWindowLayout(
+ ParsedActivity activity, ParseInput input) {
+ // There isn't a metadata for us to fall back. Whatever is in layout is correct.
+ if (activity.metaData == null || !activity.metaData.containsKey(
+ PackageParser.METADATA_ACTIVITY_WINDOW_LAYOUT_AFFINITY)) {
+ return input.success(activity.windowLayout);
+ }
+
+ // Layout already specifies a value. We should just use that one.
+ if (activity.windowLayout != null && activity.windowLayout.windowLayoutAffinity != null) {
+ return input.success(activity.windowLayout);
+ }
+
+ String windowLayoutAffinity = activity.metaData.getString(
+ PackageParser.METADATA_ACTIVITY_WINDOW_LAYOUT_AFFINITY);
+ ActivityInfo.WindowLayout layout = activity.windowLayout;
+ if (layout == null) {
+ layout = new ActivityInfo.WindowLayout(-1 /* width */, -1 /* widthFraction */,
+ -1 /* height */, -1 /* heightFraction */, Gravity.NO_GRAVITY,
+ -1 /* minWidth */, -1 /* minHeight */);
+ }
+ layout.windowLayoutAffinity = windowLayoutAffinity;
+ return input.success(layout);
+ }
}
diff --git a/core/java/android/content/pm/parsing/component/ParsedAttribution.java b/core/java/android/content/pm/parsing/component/ParsedAttribution.java
new file mode 100644
index 0000000..02b3c7d
--- /dev/null
+++ b/core/java/android/content/pm/parsing/component/ParsedAttribution.java
@@ -0,0 +1,229 @@
+/*
+ * 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 android.content.pm.parsing.component;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StringRes;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.ArraySet;
+
+import com.android.internal.util.DataClass;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A {@link android.R.styleable#AndroidManifestAttribution <attribution>} tag parsed from the
+ * manifest.
+ *
+ * @hide
+ */
+@DataClass(genAidl = false)
+public class ParsedAttribution implements Parcelable {
+ /** Maximum length of attribution tag */
+ public static final int MAX_ATTRIBUTION_TAG_LEN = 50;
+
+ /** Maximum amount of attributions per package */
+ private static final int MAX_NUM_ATTRIBUTIONS = 1000;
+
+ /** Tag of the attribution */
+ public final @NonNull String tag;
+
+ /** User visible label fo the attribution */
+ public final @StringRes int label;
+
+ /** Ids of previously declared attributions this attribution inherits from */
+ public final @NonNull List<String> inheritFrom;
+
+ /**
+ * @return Is this set of attributions a valid combination for a single package?
+ */
+ public static boolean isCombinationValid(@Nullable List<ParsedAttribution> attributions) {
+ if (attributions == null) {
+ return true;
+ }
+
+ ArraySet<String> attributionTags = new ArraySet<>(attributions.size());
+ ArraySet<String> inheritFromAttributionTags = new ArraySet<>();
+
+ int numAttributions = attributions.size();
+ if (numAttributions > MAX_NUM_ATTRIBUTIONS) {
+ return false;
+ }
+
+ for (int attributionNum = 0; attributionNum < numAttributions; attributionNum++) {
+ boolean wasAdded = attributionTags.add(attributions.get(attributionNum).tag);
+ if (!wasAdded) {
+ // feature id is not unique
+ return false;
+ }
+ }
+
+ for (int attributionNum = 0; attributionNum < numAttributions; attributionNum++) {
+ ParsedAttribution feature = attributions.get(attributionNum);
+
+ int numInheritFrom = feature.inheritFrom.size();
+ for (int inheritFromNum = 0; inheritFromNum < numInheritFrom; inheritFromNum++) {
+ String inheritFrom = feature.inheritFrom.get(inheritFromNum);
+
+ if (attributionTags.contains(inheritFrom)) {
+ // Cannot inherit from a attribution that is still defined
+ return false;
+ }
+
+ boolean wasAdded = inheritFromAttributionTags.add(inheritFrom);
+ if (!wasAdded) {
+ // inheritFrom is not unique
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+
+
+ // Code below generated by codegen v1.0.14.
+ //
+ // DO NOT MODIFY!
+ // CHECKSTYLE:OFF Generated code
+ //
+ // To regenerate run:
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedAttribution.java
+ //
+ // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+ // Settings > Editor > Code Style > Formatter Control
+ //@formatter:off
+
+
+ @android.annotation.IntDef(prefix = "MAX_", value = {
+ MAX_ATTRIBUTION_TAG_LEN,
+ MAX_NUM_ATTRIBUTIONS
+ })
+ @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE)
+ @DataClass.Generated.Member
+ public @interface Max {}
+
+ @DataClass.Generated.Member
+ public static String maxToString(@Max int value) {
+ switch (value) {
+ case MAX_ATTRIBUTION_TAG_LEN:
+ return "MAX_ATTRIBUTION_TAG_LEN";
+ case MAX_NUM_ATTRIBUTIONS:
+ return "MAX_NUM_ATTRIBUTIONS";
+ default: return Integer.toHexString(value);
+ }
+ }
+
+ /**
+ * Creates a new ParsedAttribution.
+ *
+ * @param tag
+ * Tag of the attribution
+ * @param label
+ * User visible label fo the attribution
+ * @param inheritFrom
+ * Ids of previously declared attributions this attribution inherits from
+ */
+ @DataClass.Generated.Member
+ public ParsedAttribution(
+ @NonNull String tag,
+ @StringRes int label,
+ @NonNull List<String> inheritFrom) {
+ this.tag = tag;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, tag);
+ this.label = label;
+ com.android.internal.util.AnnotationValidations.validate(
+ StringRes.class, null, label);
+ this.inheritFrom = inheritFrom;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, inheritFrom);
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ // You can override field parcelling by defining methods like:
+ // void parcelFieldName(Parcel dest, int flags) { ... }
+
+ dest.writeString(tag);
+ dest.writeInt(label);
+ dest.writeStringList(inheritFrom);
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public int describeContents() { return 0; }
+
+ /** @hide */
+ @SuppressWarnings({"unchecked", "RedundantCast"})
+ @DataClass.Generated.Member
+ protected ParsedAttribution(@NonNull Parcel in) {
+ // You can override field unparcelling by defining methods like:
+ // static FieldType unparcelFieldName(Parcel in) { ... }
+
+ String _tag = in.readString();
+ int _label = in.readInt();
+ List<String> _inheritFrom = new ArrayList<>();
+ in.readStringList(_inheritFrom);
+
+ this.tag = _tag;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, tag);
+ this.label = _label;
+ com.android.internal.util.AnnotationValidations.validate(
+ StringRes.class, null, label);
+ this.inheritFrom = _inheritFrom;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, inheritFrom);
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ @DataClass.Generated.Member
+ public static final @NonNull Parcelable.Creator<ParsedAttribution> CREATOR
+ = new Parcelable.Creator<ParsedAttribution>() {
+ @Override
+ public ParsedAttribution[] newArray(int size) {
+ return new ParsedAttribution[size];
+ }
+
+ @Override
+ public ParsedAttribution createFromParcel(@NonNull Parcel in) {
+ return new ParsedAttribution(in);
+ }
+ };
+
+ @DataClass.Generated(
+ time = 1583436566499L,
+ codegenVersion = "1.0.14",
+ sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedAttribution.java",
+ inputSignatures = "public static final int MAX_ATTRIBUTION_TAG_LEN\nprivate static final int MAX_NUM_ATTRIBUTIONS\npublic final @android.annotation.NonNull java.lang.String tag\npublic final @android.annotation.StringRes int label\npublic final @android.annotation.NonNull java.util.List<java.lang.String> inheritFrom\npublic static boolean isCombinationValid(java.util.List<android.content.pm.parsing.component.ParsedAttribution>)\nclass ParsedAttribution extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=false)")
+ @Deprecated
+ private void __metadata() {}
+
+
+ //@formatter:on
+ // End of generated code
+
+}
diff --git a/core/java/android/content/pm/parsing/component/ParsedFeatureUtils.java b/core/java/android/content/pm/parsing/component/ParsedAttributionUtils.java
similarity index 63%
rename from core/java/android/content/pm/parsing/component/ParsedFeatureUtils.java
rename to core/java/android/content/pm/parsing/component/ParsedAttributionUtils.java
index fb52801..c4b1a0e 100644
--- a/core/java/android/content/pm/parsing/component/ParsedFeatureUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedAttributionUtils.java
@@ -34,34 +34,40 @@
import java.util.List;
/** @hide */
-public class ParsedFeatureUtils {
+public class ParsedAttributionUtils {
@NonNull
- public static ParseResult<ParsedFeature> parseFeature(Resources res, XmlResourceParser parser,
- ParseInput input) throws IOException, XmlPullParserException {
- String featureId;
+ public static ParseResult<ParsedAttribution> parseAttribution(Resources res,
+ XmlResourceParser parser, ParseInput input)
+ throws IOException, XmlPullParserException {
+ String attributionTag;
int label;
List<String> inheritFrom = null;
- TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestFeature);
+ TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestAttribution);
if (sa == null) {
- return input.error("<feature> could not be parsed");
+ return input.error("<attribution> could not be parsed");
}
try {
- featureId = sa.getNonConfigurationString(R.styleable.AndroidManifestFeature_featureId,
- 0);
- if (featureId == null) {
- return input.error("<featureId> does not specify android:featureId");
+ attributionTag = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestAttribution_tag, 0);
+ if (attributionTag == null) {
+ // TODO moltmann: Remove handling of featureId
+ attributionTag = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestAttribution_featureId, 0);
+ if (attributionTag == null) {
+ return input.error("<attribution> does not specify android:tag");
+ }
}
- if (featureId.length() > ParsedFeature.MAX_FEATURE_ID_LEN) {
- return input.error("<featureId> is too long. Max length is "
- + ParsedFeature.MAX_FEATURE_ID_LEN);
+ if (attributionTag.length() > ParsedAttribution.MAX_ATTRIBUTION_TAG_LEN) {
+ return input.error("android:tag is too long. Max length is "
+ + ParsedAttribution.MAX_ATTRIBUTION_TAG_LEN);
}
- label = sa.getResourceId(R.styleable.AndroidManifestFeature_label, 0);
+ label = sa.getResourceId(R.styleable.AndroidManifestAttribution_label, 0);
if (label == Resources.ID_NULL) {
- return input.error("<featureId> does not specify android:label");
+ return input.error("<attribution> does not specify android:label");
}
} finally {
sa.recycle();
@@ -77,14 +83,15 @@
String tagName = parser.getName();
if (tagName.equals("inherit-from")) {
- sa = res.obtainAttributes(parser, R.styleable.AndroidManifestFeatureInheritFrom);
+ sa = res.obtainAttributes(parser,
+ R.styleable.AndroidManifestAttributionInheritFrom);
if (sa == null) {
return input.error("<inherit-from> could not be parsed");
}
try {
String inheritFromId = sa.getNonConfigurationString(
- R.styleable.AndroidManifestFeatureInheritFrom_featureId,0);
+ R.styleable.AndroidManifestAttributionInheritFrom_tag, 0);
if (inheritFrom == null) {
inheritFrom = new ArrayList<>();
@@ -94,7 +101,7 @@
sa.recycle();
}
} else {
- return input.error("Bad element under <feature>: " + tagName);
+ return input.error("Bad element under <attribution>: " + tagName);
}
}
@@ -104,6 +111,6 @@
((ArrayList) inheritFrom).trimToSize();
}
- return input.success(new ParsedFeature(featureId, label, inheritFrom));
+ return input.success(new ParsedAttribution(attributionTag, label, inheritFrom));
}
}
diff --git a/core/java/android/content/pm/parsing/component/ParsedFeature.java b/core/java/android/content/pm/parsing/component/ParsedFeature.java
deleted file mode 100644
index b8a9098..0000000
--- a/core/java/android/content/pm/parsing/component/ParsedFeature.java
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.content.pm.parsing.component;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.StringRes;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.util.ArraySet;
-
-import com.android.internal.util.DataClass;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * A {@link android.R.styleable#AndroidManifestFeature <feature>} tag parsed from the
- * manifest.
- *
- * @hide
- */
-@DataClass(genAidl = false)
-public class ParsedFeature implements Parcelable {
- /** Maximum length of featureId */
- public static final int MAX_FEATURE_ID_LEN = 50;
-
- /** Maximum amount of features per package */
- private static final int MAX_NUM_FEATURES = 1000;
-
- /** Id of the feature */
- public final @NonNull String id;
-
- /** User visible label fo the feature */
- public final @StringRes int label;
-
- /** Ids of previously declared features this feature inherits from */
- public final @NonNull List<String> inheritFrom;
-
- /**
- * @return Is this set of features a valid combination for a single package?
- */
- public static boolean isCombinationValid(@Nullable List<ParsedFeature> features) {
- if (features == null) {
- return true;
- }
-
- ArraySet<String> featureIds = new ArraySet<>(features.size());
- ArraySet<String> inheritFromFeatureIds = new ArraySet<>();
-
- int numFeatures = features.size();
- if (numFeatures > MAX_NUM_FEATURES) {
- return false;
- }
-
- for (int featureNum = 0; featureNum < numFeatures; featureNum++) {
- boolean wasAdded = featureIds.add(features.get(featureNum).id);
- if (!wasAdded) {
- // feature id is not unique
- return false;
- }
- }
-
- for (int featureNum = 0; featureNum < numFeatures; featureNum++) {
- ParsedFeature feature = features.get(featureNum);
-
- int numInheritFrom = feature.inheritFrom.size();
- for (int inheritFromNum = 0; inheritFromNum < numInheritFrom; inheritFromNum++) {
- String inheritFrom = feature.inheritFrom.get(inheritFromNum);
-
- if (featureIds.contains(inheritFrom)) {
- // Cannot inherit from a feature that is still defined
- return false;
- }
-
- boolean wasAdded = inheritFromFeatureIds.add(inheritFrom);
- if (!wasAdded) {
- // inheritFrom is not unique
- return false;
- }
- }
- }
-
- return true;
- }
-
-
-
- // Code below generated by codegen v1.0.14.
- //
- // DO NOT MODIFY!
- // CHECKSTYLE:OFF Generated code
- //
- // To regenerate run:
- // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedFeature.java
- //
- // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
- // Settings > Editor > Code Style > Formatter Control
- //@formatter:off
-
-
- @android.annotation.IntDef(prefix = "MAX_", value = {
- MAX_FEATURE_ID_LEN,
- MAX_NUM_FEATURES
- })
- @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE)
- @DataClass.Generated.Member
- public @interface Max {}
-
- @DataClass.Generated.Member
- public static String maxToString(@Max int value) {
- switch (value) {
- case MAX_FEATURE_ID_LEN:
- return "MAX_FEATURE_ID_LEN";
- case MAX_NUM_FEATURES:
- return "MAX_NUM_FEATURES";
- default: return Integer.toHexString(value);
- }
- }
-
- /**
- * Creates a new ParsedFeature.
- *
- * @param id
- * Id of the feature
- * @param label
- * User visible label fo the feature
- * @param inheritFrom
- * Ids of previously declared features this feature inherits from
- */
- @DataClass.Generated.Member
- public ParsedFeature(
- @NonNull String id,
- @StringRes int label,
- @NonNull List<String> inheritFrom) {
- this.id = id;
- com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, id);
- this.label = label;
- com.android.internal.util.AnnotationValidations.validate(
- StringRes.class, null, label);
- this.inheritFrom = inheritFrom;
- com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, inheritFrom);
-
- // onConstructed(); // You can define this method to get a callback
- }
-
- @Override
- @DataClass.Generated.Member
- public void writeToParcel(@NonNull Parcel dest, int flags) {
- // You can override field parcelling by defining methods like:
- // void parcelFieldName(Parcel dest, int flags) { ... }
-
- dest.writeString(id);
- dest.writeInt(label);
- dest.writeStringList(inheritFrom);
- }
-
- @Override
- @DataClass.Generated.Member
- public int describeContents() { return 0; }
-
- /** @hide */
- @SuppressWarnings({"unchecked", "RedundantCast"})
- @DataClass.Generated.Member
- protected ParsedFeature(@NonNull Parcel in) {
- // You can override field unparcelling by defining methods like:
- // static FieldType unparcelFieldName(Parcel in) { ... }
-
- String _id = in.readString();
- int _label = in.readInt();
- List<String> _inheritFrom = new ArrayList<>();
- in.readStringList(_inheritFrom);
-
- this.id = _id;
- com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, id);
- this.label = _label;
- com.android.internal.util.AnnotationValidations.validate(
- StringRes.class, null, label);
- this.inheritFrom = _inheritFrom;
- com.android.internal.util.AnnotationValidations.validate(
- NonNull.class, null, inheritFrom);
-
- // onConstructed(); // You can define this method to get a callback
- }
-
- @DataClass.Generated.Member
- public static final @NonNull Parcelable.Creator<ParsedFeature> CREATOR
- = new Parcelable.Creator<ParsedFeature>() {
- @Override
- public ParsedFeature[] newArray(int size) {
- return new ParsedFeature[size];
- }
-
- @Override
- public ParsedFeature createFromParcel(@NonNull Parcel in) {
- return new ParsedFeature(in);
- }
- };
-
- @DataClass.Generated(
- time = 1581379861853L,
- codegenVersion = "1.0.14",
- sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedFeature.java",
- inputSignatures = "public static final int MAX_FEATURE_ID_LEN\nprivate static final int MAX_NUM_FEATURES\npublic final @android.annotation.NonNull java.lang.String id\npublic final @android.annotation.StringRes int label\npublic final @android.annotation.NonNull java.util.List<java.lang.String> inheritFrom\npublic static boolean isCombinationValid(java.util.List<android.content.pm.parsing.component.ParsedFeature>)\nclass ParsedFeature extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genAidl=false)")
- @Deprecated
- private void __metadata() {}
-
-
- //@formatter:on
- // End of generated code
-
-}
diff --git a/core/java/android/content/pm/parsing/component/ParsedProcess.java b/core/java/android/content/pm/parsing/component/ParsedProcess.java
index da7bf98..3b6020a 100644
--- a/core/java/android/content/pm/parsing/component/ParsedProcess.java
+++ b/core/java/android/content/pm/parsing/component/ParsedProcess.java
@@ -41,6 +41,9 @@
@DataClass.ParcelWith(Parcelling.BuiltIn.ForInternedStringSet.class)
protected Set<String> deniedPermissions = emptySet();
+ @Nullable
+ protected Boolean enableGwpAsan = null;
+
public ParsedProcess() {
}
@@ -71,13 +74,15 @@
@DataClass.Generated.Member
public ParsedProcess(
@NonNull String name,
- @NonNull Set<String> deniedPermissions) {
+ @NonNull Set<String> deniedPermissions,
+ @Nullable Boolean enableGwpAsan) {
this.name = name;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, name);
this.deniedPermissions = deniedPermissions;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, deniedPermissions);
+ this.enableGwpAsan = enableGwpAsan;
// onConstructed(); // You can define this method to get a callback
}
@@ -93,6 +98,11 @@
}
@DataClass.Generated.Member
+ public @Nullable Boolean getEnableGwpAsan() {
+ return enableGwpAsan;
+ }
+
+ @DataClass.Generated.Member
static Parcelling<Set<String>> sParcellingForDeniedPermissions =
Parcelling.Cache.get(
Parcelling.BuiltIn.ForInternedStringSet.class);
@@ -109,8 +119,12 @@
// You can override field parcelling by defining methods like:
// void parcelFieldName(Parcel dest, int flags) { ... }
+ byte flg = 0;
+ if (enableGwpAsan != null) flg |= 0x4;
+ dest.writeByte(flg);
dest.writeString(name);
sParcellingForDeniedPermissions.parcel(deniedPermissions, dest, flags);
+ if (enableGwpAsan != null) dest.writeBoolean(enableGwpAsan);
}
@Override
@@ -124,8 +138,10 @@
// You can override field unparcelling by defining methods like:
// static FieldType unparcelFieldName(Parcel in) { ... }
+ byte flg = in.readByte();
String _name = in.readString();
Set<String> _deniedPermissions = sParcellingForDeniedPermissions.unparcel(in);
+ Boolean _enableGwpAsan = (flg & 0x4) == 0 ? null : (Boolean) in.readBoolean();
this.name = _name;
com.android.internal.util.AnnotationValidations.validate(
@@ -133,6 +149,7 @@
this.deniedPermissions = _deniedPermissions;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, deniedPermissions);
+ this.enableGwpAsan = _enableGwpAsan;
// onConstructed(); // You can define this method to get a callback
}
@@ -152,10 +169,10 @@
};
@DataClass.Generated(
- time = 1581452315946L,
+ time = 1582589960479L,
codegenVersion = "1.0.14",
sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedProcess.java",
- inputSignatures = "protected @android.annotation.NonNull java.lang.String name\nprotected @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedStringSet.class) java.util.Set<java.lang.String> deniedPermissions\npublic void addStateFrom(android.content.pm.parsing.component.ParsedProcess)\nclass ParsedProcess extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=false, genParcelable=true, genAidl=false, genBuilder=false)")
+ inputSignatures = "protected @android.annotation.NonNull java.lang.String name\nprotected @android.annotation.NonNull @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedStringSet.class) java.util.Set<java.lang.String> deniedPermissions\nprotected @android.annotation.Nullable java.lang.Boolean enableGwpAsan\npublic void addStateFrom(android.content.pm.parsing.component.ParsedProcess)\nclass ParsedProcess extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=false, genParcelable=true, genAidl=false, genBuilder=false)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/content/pm/parsing/component/ParsedProcessUtils.java b/core/java/android/content/pm/parsing/component/ParsedProcessUtils.java
index 4825066..3820790 100644
--- a/core/java/android/content/pm/parsing/component/ParsedProcessUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedProcessUtils.java
@@ -103,6 +103,11 @@
if (proc.name == null || proc.name.length() <= 0) {
return input.error("<process> does not specify android:process");
}
+
+ if (sa.hasValue(R.styleable.AndroidManifestProcess_enableGwpAsan)) {
+ proc.enableGwpAsan =
+ sa.getBoolean(R.styleable.AndroidManifestProcess_enableGwpAsan, false);
+ }
} finally {
sa.recycle();
}
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index a091f84..972b0f55 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -486,7 +486,7 @@
"Camera service is currently unavailable");
}
cameraUser = cameraService.connectDevice(callbacks, cameraId,
- mContext.getOpPackageName(), mContext.getFeatureId(), uid);
+ mContext.getOpPackageName(), mContext.getAttributionTag(), uid);
} else {
// Use legacy camera implementation for HAL1 devices
int id;
diff --git a/core/java/android/hardware/lights/Light.java b/core/java/android/hardware/lights/Light.java
index c5cb803..e90b57c 100644
--- a/core/java/android/hardware/lights/Light.java
+++ b/core/java/android/hardware/lights/Light.java
@@ -37,7 +37,8 @@
/**
* Creates a new light with the given data.
*
- * @hide */
+ * @hide
+ */
public Light(int id, int ordinal, int type) {
mId = id;
mOrdinal = ordinal;
@@ -76,8 +77,24 @@
}
};
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof Light) {
+ Light light = (Light) obj;
+ return mId == light.mId && mOrdinal == light.mOrdinal && mType == light.mType;
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return mId;
+ }
+
/**
* Returns the id of the light.
+ *
+ * <p>This is an opaque value used as a unique identifier for the light.
*/
public int getId() {
return mId;
@@ -86,11 +103,9 @@
/**
* Returns the ordinal of the light.
*
- * <p>This represents the physical order of the lights on the device. The exact values are
- * device-dependent, but for example, if there are lights in a row, sorting the Light objects
- * by ordinal should match the order in which they appear on the device. If the device has
- * 4 lights, the ordinals could be [1, 2, 3, 4] or [0, 10, 20, 30] or any other values that
- * have the same sort order.
+ * <p>This is a sort key that represents the physical order of lights on the device with the
+ * same type. In the case of multiple lights arranged in a line, for example, the ordinals
+ * could be [1, 2, 3, 4], or [0, 10, 20, 30], or any other values that have the same sort order.
*/
public int getOrdinal() {
return mOrdinal;
diff --git a/core/java/android/hardware/lights/LightsManager.java b/core/java/android/hardware/lights/LightsManager.java
index 1bc051b..8cd2312 100644
--- a/core/java/android/hardware/lights/LightsManager.java
+++ b/core/java/android/hardware/lights/LightsManager.java
@@ -161,7 +161,7 @@
* @param request the settings for lights that should change
*/
@RequiresPermission(Manifest.permission.CONTROL_DEVICE_LIGHTS)
- public void setLights(@NonNull LightsRequest request) {
+ public void requestLights(@NonNull LightsRequest request) {
Preconditions.checkNotNull(request);
if (!mClosed) {
try {
diff --git a/core/java/android/hardware/lights/LightsRequest.java b/core/java/android/hardware/lights/LightsRequest.java
index a36da4c..5c4fc67 100644
--- a/core/java/android/hardware/lights/LightsRequest.java
+++ b/core/java/android/hardware/lights/LightsRequest.java
@@ -86,7 +86,7 @@
* Create a LightsRequest object used to override lights on the device.
*
* <p>The generated {@link LightsRequest} should be used in
- * {@link LightsManager.Session#setLights(LightsLightsRequest).
+ * {@link LightsManager.Session#requestLights(LightsLightsRequest).
*/
public @NonNull LightsRequest build() {
return new LightsRequest(mChanges);
diff --git a/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java b/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java
index bf641d7..1aeb76a3 100644
--- a/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java
+++ b/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java
@@ -28,7 +28,6 @@
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.AttributeSet;
-import android.util.Log;
import android.util.Slog;
import android.util.Xml;
@@ -231,15 +230,7 @@
com.android.internal.R.styleable.VoiceEnrollmentApplication);
keyphraseMetadata = getKeyphraseFromTypedArray(array, packageName, parseErrors);
array.recycle();
- } catch (XmlPullParserException e) {
- String error = "Error parsing keyphrase enrollment meta-data for " + packageName;
- parseErrors.add(error + ": " + e);
- Slog.w(TAG, error, e);
- } catch (IOException e) {
- String error = "Error parsing keyphrase enrollment meta-data for " + packageName;
- parseErrors.add(error + ": " + e);
- Slog.w(TAG, error, e);
- } catch (PackageManager.NameNotFoundException e) {
+ } catch (XmlPullParserException | PackageManager.NameNotFoundException | IOException e) {
String error = "Error parsing keyphrase enrollment meta-data for " + packageName;
parseErrors.add(error + ": " + e);
Slog.w(TAG, error, e);
@@ -390,7 +381,6 @@
* False if not.
*/
public boolean isUidSupportedEnrollmentApplication(int uid) {
- Log.d(TAG, "isUidSupportedEnrollmentApplication: " + toString());
return mEnrollmentApplicationUids.contains(uid);
}
diff --git a/core/java/android/inputmethodservice/SoftInputWindow.java b/core/java/android/inputmethodservice/SoftInputWindow.java
index 0513fee..6efd03c 100644
--- a/core/java/android/inputmethodservice/SoftInputWindow.java
+++ b/core/java/android/inputmethodservice/SoftInputWindow.java
@@ -28,6 +28,7 @@
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.MotionEvent;
+import android.view.View;
import android.view.WindowManager;
import java.lang.annotation.Retention;
@@ -94,6 +95,13 @@
lp.token = token;
getWindow().setAttributes(lp);
updateWindowState(SoftInputWindowState.TOKEN_SET);
+
+ // As soon as we have a token, make sure the window is added (but not shown) by
+ // setting visibility to INVISIBLE and calling show() on Dialog. Note that
+ // WindowInsetsController.OnControllableInsetsChangedListener relies on the window
+ // being added to function.
+ getWindow().getDecorView().setVisibility(View.INVISIBLE);
+ show();
return;
case SoftInputWindowState.TOKEN_SET:
case SoftInputWindowState.SHOWN_AT_LEAST_ONCE:
diff --git a/core/java/android/os/ConfigUpdate.java b/core/java/android/os/ConfigUpdate.java
index 9c999b2..590fbb3 100644
--- a/core/java/android/os/ConfigUpdate.java
+++ b/core/java/android/os/ConfigUpdate.java
@@ -16,6 +16,7 @@
package android.os;
+import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
/**
@@ -114,20 +115,36 @@
= "android.os.action.UPDATE_CARRIER_ID_DB";
/**
- * Broadcast intent action indicating that the updated emergency number database is available.
- * <p>Extra: "VERSION" the numeric version of the new data. Devices should only install if the
- * update version is newer than the current one.
- * <p>Extra: "REQUIRED_HASH" the hash of the current update data.
- * <p>Input: {@link android.content.Intent#getData} is URI of downloaded emergency number file.
- * Devices should pick up the downloaded file and persist to the database
- * {@code com.android.internal.telephony.emergency.EmergencyNumberTracker}.
+ * Update the emergency number database into the devices.
+ * <p>Extra: {@link #EXTRA_VERSION} the numeric version of the database.
+ * <p>Extra: {@link #EXTRA_REQUIRED_HASH} the hash of the database.
+ * <p>Input: {@link android.content.Intent#getData} the URI to download emergency number
+ * database.
*
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.UPDATE_CONFIG)
public static final String ACTION_UPDATE_EMERGENCY_NUMBER_DB =
"android.os.action.UPDATE_EMERGENCY_NUMBER_DB";
+ /**
+ * An integer to indicate the numeric version of the new data. Devices should only install
+ * if the update version is newer than the current one.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_VERSION = "android.os.extra.VERSION";
+
+ /**
+ * A string to indicate the hash of the data.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_REQUIRED_HASH = "android.os.extra.REQUIRED_HASH";
+
private ConfigUpdate() {
}
}
diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java
index b478dbe..a7e3263 100644
--- a/core/java/android/os/Looper.java
+++ b/core/java/android/os/Looper.java
@@ -77,6 +77,7 @@
@UnsupportedAppUsage
final MessageQueue mQueue;
final Thread mThread;
+ private boolean mInLoop;
@UnsupportedAppUsage
private Printer mLogging;
@@ -155,6 +156,12 @@
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
+ if (me.mInLoop) {
+ Slog.w(TAG, "Loop again would have the queued messages be executed"
+ + " before this one completed.");
+ }
+
+ me.mInLoop = true;
final MessageQueue queue = me.mQueue;
// Make sure the identity of this thread is that of the local process,
diff --git a/core/java/android/os/Users.md b/core/java/android/os/Users.md
new file mode 100644
index 0000000..3bbbe54
--- /dev/null
+++ b/core/java/android/os/Users.md
@@ -0,0 +1,109 @@
+<!--
+ 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
+ -->
+
+# Users for system developers
+
+## Concepts
+
+### User
+
+A user of a device e.g. usually a human being. Each user has its own home screen.
+
+#### User Profile
+
+A user can have multiple profiles. E.g. one for the private life and one for work. Each profile
+has a different set of apps and accounts but they share one home screen. All profiles of a
+profile group can be active at the same time.
+
+Each profile has a separate [`userId`](#int-userid). Unless needed user profiles are treated as
+completely separate users.
+
+#### Profile Group
+
+All user profiles that share a home screen. You can list the profiles of a user via
+`UserManager#getEnabledProfiles` (you usually don't deal with disabled profiles)
+
+#### Foreground user vs background user
+
+Only a single user profile group can be in the foreground. This is the user profile the user
+currently interacts with.
+
+#### Parent user (profile)
+
+The main profile of a profile group, usually the personal (as opposed to work) profile. Get this via
+`UserManager#getProfileParent` (returns `null` if the user does not have profiles)
+
+#### Managed user (profile)
+
+The other profiles of a profile group. The name comes from the fact that these profiles are usually
+managed by a device policy controller app. You can create a managed profile from within the device
+policy controller app on your phone.
+
+#### Account
+
+An account of a user profile with a (usually internet based) service. E.g. aname@gmail.com or
+aname@yahoo.com. Each profile can have multiple accounts. A profile does not have to have a
+account.
+
+## Data types
+
+### int userId
+
+... usually marked as `@UserIdInt`
+
+The id of a user profile. List all users via `adb shell dumpsys user`. There is no data type for a
+user, all you can do is using the user id of the parent profile as a proxy for the user.
+
+### int uid
+
+Identity of an app. This is the same as a Linux uid, but in Android there is one uid per package,
+per user.
+
+It is highly discouraged, but uids can be shared between multiple packages using the
+`android:sharedUserId` manifest attribute.
+
+### class UserHandle
+
+A wrapper for userId. Used esp. in public APIs instead of `int userId` as it clearly distinguishes
+from uid.
+
+## Security model
+
+Multiple packages can share an uid by using `android:sharedUserId` manifest attribute. If packages
+share a uid they can run in the same process via `android:process` manifest attribute. Further file
+level access is also tracked by uid. Hence any security or privacy mechanism needs to be built on
+a uid granularity.
+
+On the other hand apps belonging to the same user cannot see each others files. They can only
+interact via activity launches, broadcasts, providers, and service bindings. All of them can be be
+protected by [permissions](../permission/Permissions.md). Hence any new general communication
+mechanism should be access controlled by permissions.
+
+## Lifecycle
+
+A system service should deal with users being started and stopped by overriding
+`SystemService.onSwitchUser` and `SystemService.onStopUser`.
+
+If users profiles become inactive the system should stop all apps of this profile from interacting
+with other apps or the system.
+
+Another important lifecycle event is `onUnlockUser`. Only for unlocked user profiles you can access
+all data, e.g. which packages are installed.
+
+You only want to deal with user profiles that
+
+- are in the profile group of the foreground user
+- the user profile is unlocked and not yet stopped
diff --git a/core/java/android/permission/IPermissionController.aidl b/core/java/android/permission/IPermissionController.aidl
index 0483514..f011395 100644
--- a/core/java/android/permission/IPermissionController.aidl
+++ b/core/java/android/permission/IPermissionController.aidl
@@ -42,6 +42,6 @@
void setRuntimePermissionGrantStateByDeviceAdmin(String callerPackageName, String packageName,
String permission, int grantState, in AndroidFuture callback);
void grantOrUpgradeDefaultRuntimePermissions(in AndroidFuture callback);
- void updateUserSensitive(in AndroidFuture callback);
void notifyOneTimePermissionSessionTimeout(String packageName);
+ void updateUserSensitiveForApp(int uid, in AndroidFuture callback);
}
diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java
index 2a1857f..f08e3d25 100644
--- a/core/java/android/permission/PermissionControllerManager.java
+++ b/core/java/android/permission/PermissionControllerManager.java
@@ -46,6 +46,7 @@
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
+import android.os.Process;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.Log;
@@ -626,14 +627,26 @@
}
/**
- * @see PermissionControllerService#onUpdateUserSensitive()
+ * @see PermissionControllerManager#updateUserSensitiveForApp
* @hide
*/
public void updateUserSensitive() {
+ updateUserSensitiveForApp(Process.INVALID_UID);
+ }
+
+ /**
+ * @see PermissionControllerService#onUpdateUserSensitiveForApp
+ * @hide
+ */
+ public void updateUserSensitiveForApp(int uid) {
mRemoteService.postAsync(service -> {
AndroidFuture<Void> future = new AndroidFuture<>();
- service.updateUserSensitive(future);
+ service.updateUserSensitiveForApp(uid, future);
return future;
+ }).whenComplete((res, err) -> {
+ if (err != null) {
+ Log.e(TAG, "Error updating user_sensitive flags for uid " + uid, err);
+ }
});
}
diff --git a/core/java/android/permission/PermissionControllerService.java b/core/java/android/permission/PermissionControllerService.java
index 263b2c7..4a42230 100644
--- a/core/java/android/permission/PermissionControllerService.java
+++ b/core/java/android/permission/PermissionControllerService.java
@@ -218,11 +218,14 @@
* Called by system to update the
* {@link PackageManager}{@code .FLAG_PERMISSION_USER_SENSITIVE_WHEN_*} flags for permissions.
* <p>
- * This is typically when creating a new user or upgrading either system or
- * permission controller package.
+ *
+ * If uid is -1, updates the permission flags for all packages.
+ *
+ * Typically called by the system when a new app is installed or updated or when creating a
+ * new user or upgrading either system or permission controller package.
*/
@BinderThread
- public void onUpdateUserSensitivePermissionFlags() {
+ public void onUpdateUserSensitivePermissionFlags(int uid, @NonNull Runnable callback) {
throw new AbstractMethodError("Must be overridden in implementing class");
}
@@ -459,11 +462,14 @@
}
@Override
- public void updateUserSensitive(AndroidFuture callback) {
+ public void updateUserSensitiveForApp(int uid, @NonNull AndroidFuture callback) {
Preconditions.checkNotNull(callback, "callback cannot be null");
- onUpdateUserSensitivePermissionFlags();
- callback.complete(null);
+ try {
+ onUpdateUserSensitivePermissionFlags(uid, () -> callback.complete(null));
+ } catch (Exception e) {
+ callback.completeExceptionally(e);
+ }
}
@Override
diff --git a/core/java/android/permission/Permissions.md b/core/java/android/permission/Permissions.md
new file mode 100644
index 0000000..e62bd0a
--- /dev/null
+++ b/core/java/android/permission/Permissions.md
@@ -0,0 +1,832 @@
+<!--
+ 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
+ -->
+
+# Android permissions for system developers
+
+This document targets system developers. App developers should refer to the [public
+ documentation](https://developer.android.com/guide/topics/permissions/overview).
+
+## Definitions
+
+Each app (often called package) has a unique name called package name. Each package has a manifest
+file describing properties of the package. The android system server is in a special package named
+"android".
+
+When a package gets installed the package is (usually) assigned a unique identifier called [uid
+](../os/Users.md#int-uid).
+This is the same as a uid in Linux, but this often leads to confusion. It is easiest to see a uid
+as a unique identifier for a package.
+
+Usually an app is running in a container called a process. Each process has a unique id called
+pid, but unlike the uid the pid changes each time the process is restarted and app that are not
+currently running don't have a pid. The process container makes sure that other apps cannot
+negatively interact with an app. Processes can only interact via controlled interactions called
+remote procedure calls (RPCs). Android’s RPC mechanism is called _Binder_.
+
+As no app code can be trusted the permission need to be checked on the receiving side of the
+Binder call.
+
+For more details please take a look at [Android's security model](../os/Users.md#security-model).
+
+## Permissions for regular apps
+
+### Install time permissions
+
+The purpose of install time permissions is to control access to APIs where it does not makes sense
+to involve the user. This can be either because the API is not sensitive, or because additional
+checks exist.
+
+#### Defining a permission
+
+Any package can define a permission. For that it simply adds an entry in the manifest file
+`<permission android:name="com.example.myapp.myfirstpermission" />`
+
+Any package can do this, including the system package. When talking about [permissions for system
+ apps](#permissions-for-system-apps) we will see that it is important which package defines a
+permission.
+
+It is common good practice to prefix the permission name with the package name to avoid collisions.
+
+#### Requesting a permission
+
+Any app can request any permission via adding an entry in the manifest file like
+`<uses-permission android:name="com.example.myapp.myfirstpermission" />`
+
+A requested permission does not necessarily mean that the permission is granted. When and how a
+permission is granted depends on the protection level of the permission. If no protection level is
+set, the permission will always be granted. Such "normal" permissions can still be useful as it
+will be easy to find apps using a certain functionality on app stores and by checking `dumpsys
+package`.
+
+#### Checking a permission
+
+`Context.checkPermission(permission, pid, uid)` returns if the pid/uid has the permission. By far
+the most common case is to check the permission on the receiving end of a binder call. In this case
+the pid can be read as `Binder.callingPid()` and the uid as `Binder.callingUid()`. The uid is a
+mandatory argument as permissions are maintained per uid. The pid can be set to -1
+if not pid is available. The context class contains handy wrappers for `checkPermission`, such as
+`enforeCallingPermission` which calls checkPermission with `Binder.callingPid`/`Binder.callingUid`
+and throws a SecurityException when the permission is not granted.
+
+#### Verifying an app has an install time permission
+
+In `dumpsys package my.package.name` there are two sections. In requested permissions all
+permissions of the `uses-permission` tags are listed. In install permission the permissions with
+their grant state are listed. If an install time permission is not listed here, it is not granted.
+
+```
+Packages:
+ Package [com.android.packageinstaller] (2eb7062):
+ userId=10071
+ [...]
+ requested permissions:
+ android.permission.MANAGE_USERS
+ android.permission.INSTALL_PACKAGES
+ android.permission.DELETE_PACKAGES
+ android.permission.READ_INSTALL_SESSIONS
+ android.permission.RECEIVE_BOOT_COMPLETED
+ android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS
+ android.permission.USE_RESERVED_DISK
+ android.permission.UPDATE_APP_OPS_STATS
+ android.permission.MANAGE_APP_OPS_MODES
+ android.permission.INTERACT_ACROSS_USERS_FULL
+ android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME
+ android.permission.PACKAGE_USAGE_STATS
+ install permissions:
+ android.permission.USE_RESERVED_DISK: granted=true
+ android.permission.INSTALL_PACKAGES: granted=true
+ android.permission.RECEIVE_BOOT_COMPLETED: granted=true
+ android.permission.INTERACT_ACROSS_USERS_FULL: granted=true
+ android.permission.PACKAGE_USAGE_STATS: granted=true
+ android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME: granted=true
+ android.permission.READ_INSTALL_SESSIONS: granted=true
+ android.permission.MANAGE_USERS: granted=true
+ android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS: granted=true
+ android.permission.MANAGE_APP_OPS_MODES: granted=true
+ android.permission.UPDATE_APP_OPS_STATS: granted=true
+ android.permission.DELETE_PACKAGES: granted=true
+```
+
+#### End-to-end: Protecting an RPC call via a permission
+
+##### Service Manifest
+
+```xml
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.example.myservice">
+ <!-- Define a permission -->
+ <permission android:name="com.android.example.myservice.MY_PERMISSION" />
+ <application>
+ <service android:name=".MyService" android:exported="true" />
+ </application>
+</manifest>
+```
+
+##### Service code
+
+```kotlin
+class MyService : Service() {
+ override fun onBind(intent: Intent?): IBinder? {
+ return object : IMyService.Stub() {
+ override fun doSomething() {
+ // Verify that calling UID has the permission
+ enforceCallingPermission(
+ "com.android.example.myservice.MY_PERMISSION",
+ "Need to hold permission"
+ )
+ // do something
+ }
+ }.asBinder()
+ }
+}
+```
+
+##### Caller Manifest
+
+```xml
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.example.myapp">
+ <!-- request a permission -->
+ <uses-permission android:name="com.android.example.myservice.MY_PERMISSION" />
+ <application />
+</manifest>
+```
+
+### Runtime permissions
+
+Runtime permission must be granted by the user during runtime. This is needed if the API protects
+data or functionality that is sensitive for the user. E.g. the users current location is protected
+by a runtime permission.
+
+Users want a system that is secure and privacy focused by default. User can also often not make a
+good choice when asked at the wrong time without enough context. Hence in general runtime
+permissions should be avoided and the API should be built in a way where no private data needs to be
+leaked.
+
+#### Defining a runtime permission
+
+Runtime permissions are defined in the same way as install time permissions. To tag them as runtime
+permissions the `protectionLevel` needs to be set to dangerous. Dangerous is a synonym for
+runtime permissions in the Android platform.
+
+```xml
+<uses-permission android:name="com.example.myapp.myfirstruntimepermission"
+ android:protectionLevel="dangerous" />
+```
+
+#### Requesting a runtime permission
+
+Similar to install time permissions any app can request a runtime permission by adding the
+`<uses-permission android:name="com.example.myapp.myfirstruntimepermission" />`
+to the manifest.
+
+By default runtime permissions are not granted. The app needs to call `Activity.requestPermissions`
+during runtime to ask the user for the permission. The user might then grant or deny and once the
+decision is made the activity is called by via `Activity.onPermissionGranted`.
+
+During development and testing a runtime permission can be granted via the `pm` shell command or by
+using the `UiAutomator.grantRuntimePermission` API call. Please note that this does _not_ grant the
+[app-op](#runtime-permissions-and-app-ops) synchronously. Unless the app needs to test the actual
+permission grant flow it is recommended to grant the runtime permissions during install using
+`adb install -g /my/package.apk`.
+
+#### Checking a runtime permission
+
+For runtime permissions defined by a 3rd party apps it is fine to check a runtime
+permission like an install time permission. For system defined permissions you need to check all
+runtime permissions by using the `PermissionChecker` utility. It is good practice to use the tool
+anywhere possible.
+
+The permission checker might return `PERMISSION_DENIED_APP_OP` which should lead to a silent
+failure. This can only happen for system defined runtime permissions.
+
+##### Runtime permissions and app-ops
+
+> See [App-ops](../app/AppOps.md).
+
+The PermissionChecker code fundamentally looks like this:
+
+```kotlin
+class PermissionChecker {
+ fun checkCallingPermission(context: Context, permission: String) {
+ if (isRuntimePermission(permission)) {
+ if (context.checkPermission(uid, permission) == DENIED) {
+ return PERMISSION_DENIED
+ }
+
+ val appOpOfPermission = AppOpsManager.permissionToOp(permission)
+ if (appOpOfPermission == null) {
+ // not platform defined
+ return PERMISSION_GRANTED
+ }
+
+ val appOpMode = appOpsManager.noteOp(appOpOfPermission)
+ if (appOpMode == AppOpsManager.MODE_ALLOWED) {
+ return PERMISSION_GRANTED
+ } else {
+ return PERMISSION_DENIED_APP_OP
+ }
+ } else {
+ return PERMISSION_DENIED
+ }
+ }
+}
+```
+
+For each platform defined runtime permission there is a matching app-op. When calling
+`AppOpsManager.noteOp` this returns either `MODE_ALLOWED` or `MODE_IGNORED`.
+
+This value is then used to decide between `PERMISSION_DENIED_APP_OP` and `PERMISSION_GRANTED`.
+
+The primary purpose of the special `PERMISSION_DENIED_APP_OP` state was to support apps targeting an
+SDK lower than 23. These apps do not understand the concept of denied runtime permissions. Hence
+they would crash when getting a `SecurityException`. To protect the users' privacy while still not
+crashing the app the special `PERMISSION_DENIED_APP_OP` mandates that the API should somehow
+silently fail.
+
+A secondary use case of the `AppOpsManager.noteOp` calls is to
+[track](../app/AppOps.md#Appops-for-tracking) which apps perform what runtime protected actions.
+
+#### Verifying an app has a runtime time permission
+
+In `dumpsys package my.package.name` the runtime permissions are listed per uid. I.e. different
+users might have different runtime permission grants and shared uids share a grant-set. If a runtime
+permission is listed as requested but not in the runtime permission section it is in it’s initial
+state, i.e. not granted.
+
+```
+Packages:
+ Package [com.google.android.GoogleCamera] (ccb6af):
+ userId=10181
+ [...]
+ requested permissions:
+ android.permission.ACCESS_COARSE_LOCATION
+ android.permission.ACCESS_FINE_LOCATION
+ android.permission.ACCESS_NETWORK_STATE
+ android.permission.ACCESS_NOTIFICATION_POLICY
+ android.permission.ACCESS_WIFI_STATE
+ android.permission.BIND_WALLPAPER
+ android.permission.CAMERA
+ android.permission.CHANGE_WIFI_STATE
+ android.permission.INTERNET
+ android.permission.GET_PACKAGE_SIZE
+ android.permission.NFC
+ android.permission.READ_SYNC_SETTINGS
+ android.permission.RECEIVE_BOOT_COMPLETED
+ android.permission.RECORD_AUDIO
+ android.permission.SET_WALLPAPER
+ android.permission.USE_CREDENTIALS
+ android.permission.VIBRATE
+ android.permission.WAKE_LOCK
+ android.permission.WRITE_EXTERNAL_STORAGE [ ... ]
+ android.permission.WRITE_SETTINGS
+ android.permission.WRITE_SYNC_SETTINGS
+ com.google.android.elmyra.permission.CONFIGURE_ASSIST_GESTURE
+ com.google.android.providers.gsf.permission.READ_GSERVICES
+ android.permission.FOREGROUND_SERVICE
+ com.google.android.googlequicksearchbox.permission.LENSVIEW_BROADCAST
+ android.permission.READ_EXTERNAL_STORAGE [ ... ]
+ [...]
+ User 0: [ ... ]
+ overlay paths:
+ runtime permissions:
+ android.permission.ACCESS_FINE_LOCATION: granted=false [ ... ]
+ android.permission.READ_EXTERNAL_STORAGE: granted=true [ ... ]
+ android.permission.ACCESS_COARSE_LOCATION: granted=false [ ... ]
+ android.permission.CAMERA: granted=true [ ... ]
+ android.permission.WRITE_EXTERNAL_STORAGE: granted=true [ ... ]
+ android.permission.RECORD_AUDIO: granted=true[ ... ]
+```
+
+#### End-to-end: Protecting an RPC call via a runtime permission
+
+##### Service Manifest
+
+```xml
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.example.myservice">
+ <!-- Define a runtime permission -->
+ <permission android:name="com.android.example.myservice.MY_RUNTIME_PERMISSION"
+ android:protectionLevel="dangerous" />
+ <application>
+ <service android:name=".MyService" android:exported="true" />
+ </application>
+</manifest>
+```
+
+##### Service code
+
+```kotlin
+class MyService : Service() {
+ override fun onBind(intent: Intent?): IBinder? {
+ return object : IMyService.Stub() {
+ override fun doSomething(callingPackage: String?, callingFeatureId: String?) {
+ Objects.requireNonNull(callingPackageName)
+
+ // Verify that calling UID has the permission
+ when (run {
+ PermissionChecker.checkCallingPermission(
+ this@MyService,
+ "com.android.example.myservice.MY_RUNTIME_PERMISSION",
+ callingPackageName,
+ callingFeatureId,
+ "Did something"
+ )
+ }) {
+ PERMISSION_GRANTED -> /* do something */
+ PERMISSION_DENIED_APP_OP -> /* silent failure, do nothing */
+ else -> throw SecurityException(
+ "Cannot do something as caller is missing "
+ + "com.android.example.myservice.MY_RUNTIME_PERMISSION"
+ )
+ }
+ }
+ }.asBinder()
+ }
+}
+```
+
+##### Caller Manifest
+
+```xml
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.example.myapp">
+ <!-- request a permission -->
+ <uses-permission android:name="com.android.example.myservice.MY_RUNTIME_PERMISSION" />
+ <application />
+</manifest>
+```
+
+##### Caller code
+
+```kotlin
+class MyActivity : Activity {
+ fun callDoSomething() {
+ if (checkSelfPermission("com.android.example.myservice.MY_RUNTIME_PERMISSION") == PERMISSION_DENIED) {
+ // Interrupt operation and request permission
+ requestPermissions(arrayOf("com.android.example.myservice.MY_RUNTIME_PERMISSION"), 23)
+ } else {
+ myService.doSomething(this@MyActivity.opPackageName, this@MyActivity.featureId)
+ }
+ }
+
+ override fun onRequestPermissionsResult(
+ requestCode: Int,
+ permissions: Array<String>,
+ grantResults: IntArray
+ ) {
+ if (requestCode == 23 && grantResults[0] == PERMISSION_GRANTED) {
+ // Finish operation
+ callDoSomething()
+ }
+ }
+}
+```
+
+#### Restricted permissions
+
+Some runtime permissions are restricted. They are annotated in the platforms `AndroidManifest.xml`
+has `hardRestricted` or `softRestricted`.
+
+Restricted permissions behave uncommon when not whitelisted. When whitelisted the permissions
+behave normally. What uncommon means depends on the whether they are hard or soft restricted.
+
+They can either be whitelisted during upgrade P->Q, but the system or need to be whitelisted by the
+installer via `PackageInstaller.SessionParams.setWhitelistedRestrictedPermissions`. If this method
+is not used all permissions will be whitelisted.
+
+Afterwards the app that originally installed the app can change the whitelisting state via
+`PackageManager.addWhitelistedRestrictedPermission` and
+`PackageManager.removeWhitelistedRestrictedPermission`.
+
+The system tracks the source of the whitelisting by having three different flags
+ `RESTRICTION_SYSTEM_EXEMPT`, `RESTRICTION_UPGRADE_EXEMPT`, and `RESTRICTION_INSTALLER_EXEMPT`,
+
+The flags can be checked in `dumpsys package my.package.name`
+
+```
+User 0:
+ [...]
+ runtime permissions:
+ android.permission.READ_EXTERNAL_STORAGE: granted=false, flags=[ RESTRICTION_UPGRADE_EXEMPT ]
+ android.permission.ACCESS_FINE_LOCATION: granted=true, flags=[ RESTRICTION_SYSTEM_EXEMPT|RESTRICTION_UPGRADE_EXEMPT ]
+```
+
+##### Hard restricted
+
+Hard restricted permissions need to be whitelisted to be grant-able.
+
+##### Soft restricted
+
+The behavior of non-whitelisted soft restricted permissions is not uniform. The behavior is
+defined in the `SoftRestrictedPermissionPolicy`.
+
+#### System fixed permission
+
+Some runtime permissions are required for normal operation of the device. In this case the system
+can grant the permission as `SYSTEM_FIXED`. In this case the permission can be seen in the
+[permission management settings](#settings) but cannot be revoked by the user.
+
+The flag can be checked in `dumpsys package my.package.name`
+```
+User 0:
+ [...]
+ runtime permissions:
+ android.permission.READ_EXTERNAL_STORAGE: granted=true, flags=[ SYSTEM_FIXED|GRANTED_BY_DEFAULT ]
+```
+
+#### Background access
+
+Whether the app is currently visible to the user is reflected in the `ActivityManager`'s proc state.
+There is a lot of granularity to this, but runtime permissions are using the [app-ops services'
+](../app/AppOps.md) definition of foreground and background.
+
+Most runtime permissions are not affected by foreground/background-ness. Microphone and Camera are
+foreground-only while Location is usually foreground-only, but background access can be added by
+granting the `ACCESS_BACKGROUND_LOCATION` modifier runtime permission.
+
+##### Microphone and Camera
+
+Currently these only allow access while in the app is in foreground. There is a manual whitelist
+for e.g. the voice interaction service.
+
+This is currently (Mar 2020) reworked and will behave like [location](#location) soon.
+
+##### Location
+
+As described [above](#runtime-permissions-and-app-ops) the app-op mode for granted permissions is
+`MODE_ALLOWED` to allow access or `MODE_IGNORED` to suppress access.
+
+The important case is the case where the permission is granted and the app-op is `MODE_IGNORED`. In
+the case of location this state causes the `LocationManagerService` to stop delivering locations to
+the app. This is not a breaking behavior as the same scenarios happens if e.g. no satellites
+could be found.
+
+This behavior is used to implement the foregound/background behavior for location. If the app is
+in the foreground the app-op mode is `MODE_ALLOWED` and works normally. If the app goes into
+background the app-op mode changes to `MODE_IGNORED`. This means that locations are delivered while
+the app is in foreground and while the app is background, the app won't get any locations.
+
+The automatic switching between `MODE_ALLOWED` and `MODE_IGNORED` is done inside of
+ [`AppOpsManager`](../app/AppOps.md#foreground).
+
+Background access can be enabled by also granting the `ACCESS_BACKGROUND_LOCATION` to the app. In
+this case the app-op mode will always be `MODE_ALLOWED`.
+
+#### UI
+
+##### Granting
+
+An app following the best practices does not ask for any runtime permissions until absolutely
+needed. Once needed the request should be made in context. I.e. the user should understand from the
+current state of the app and the user's action why the request is made. E.g. if the user presses
+a "show me the next ATM"-button the user is most likely expecting a request for the location
+permission.
+
+This is central premise to the runtime permission UI. It is the app's responsibility to avoid
+showing permission requests dialogs to the user which might get denied. These dialogs are not
+meant to be user-choices, they are meant to be user-confirmations.
+
+Hence any denied permission dialog is probably due to the app asking for permissions the user
+does not expect. If too many permission requests get denied the app is apparently trying to get
+more than the user wants to give to the app. In this case the permission gets permanently denied
+and all future requests will be denied automatically without showing a UI.
+
+`Context.requestPermission` calls for more than one permission are allowed and might result in
+multiple dialogs in sequence. This might make sense for e.g. getting microphone and camera
+permission when starting a video call.
+
+Each time the the user makes a choice (either to grant or the deny) a permission request the
+permission is marked as `USER_SET`. If a permission gets permanently denied the permission is marked
+as `USER_FIXED`.
+
+This can be found in `dumpsys package my.package.name`
+```
+User 0:
+ [...]
+ runtime permissions:
+ android.permission.READ_EXTERNAL_STORAGE: granted=false, flags=[ USER_SET|USER_FIXED ]
+ android.permission.ACCESS_FINE_LOCATION: granted=true, flags=[ USER_SET ]
+```
+
+##### Settings
+
+By far most interactions with the permission system are via the [permission grant flow](#granting).
+The main purpose of the permission settings is to show the user the previous choices and allow
+the user to revisit previous choices. In reality few users do that.
+
+##### Grouping
+
+There are too many runtime permissions for the user to individually manage. Hence the UI bundles the
+permissions into groups. **Apps should never assume the grouping**. The grouping might change
+with SDK updates, but also at any other time. Certain form factors or locales might use other
+permission models and sometimes some of the permissions of a group cannot be granted for various
+reasons. The grouping is defined inside the permission controller app.
+
+If two permissions belong to a group and the first permission is already granted the second one
+will be granted on request of the app without user interaction. For that reason a permission
+group with at least one individual permission granted will show up as granted in the UI.
+
+##### Alternate permission management
+
+It is not allowed to build alternate permission management UIs. While restricting innovation is not
+a good choice this is a required one to enforce a consistent, predictable, but flexible permission
+model for users and app developers.
+
+Further some data needed for permission management (e.g. the grouping) is not available outside
+the permission controller app.
+
+Hence all permission management UI needs to be integrated with AOSP.
+
+#### Pre granting
+
+Runtime permissions protect user private data. It is a violation of user trust to give the data
+to an app without explicit user consent (i.e. the user [granting](#granting) the permission
+). Still the user expects certain functionality (e.g. receiving a phone call) to work out of the
+box.
+
+Hence the `DefaultPermissionGrantPolicy` and roles allow to grant permission without the user
+. The default permission grant policy grants permissions for three categories of apps
+- Apps running in well defined [uids](../os/Users.md#int-uid) as they are considered as part of
+ the platform
+- Apps that are in certain predefined categories, e.g. the browser and the SMS app. This is
+ meant for the most basic phone functionality, not for all pre-installed apps.
+- Apps that are explicitly mentioned as a pre-grant-exceptions. This is meant to be used for setup
+ and other highly critical use cases, not to improve the user experience. The exceptions are listed
+ in xml files in `etc/` and follow the following syntax
+```xml
+<exceptions>
+ <exception package="my.package.name">
+ <permission name="android.permission.ACCESS_FINE_LOCATION" fixed="false"/>
+ </exception>
+</exceptions>
+```
+
+Pre-granted runtime permissions can still be revoked by the user in [settings](#settings) unless
+they are granted as `SYSTEM_FIXED`.
+
+Whether a permission was granted by the default can be checked in the permission flags of
+`dumpsys package my.package.name`
+
+```
+User 0:
+ [...]
+ runtime permissions:
+ android.permission.ACCESS_FINE_LOCATION: granted=true, flags=[ GRANTED_BY_DEFAULT ]
+```
+
+### Permission restricted components
+
+As [publicly documented](https://developer.android.com/guide/topics/permissions/overview#permission_enforcement)
+it is possible to restrict starting an activity/binding to a service by using permission. It is
+a common pattern to
+
+- define a permission in the platform as `signature`
+- protect a service in an app by this permission using the `android:permission` attribute of the
+ `<service>` tag
+
+Then it is guaranteed that only the system can bind to such service. This is used for services
+that provide extensions to platform functionality, such as auto-fill services, print services, and
+accessibility services.
+
+This does not work for app-op or runtime permissions as the way to check these permissions is
+more complex than install time permissions.
+
+## Permissions for system apps
+
+System apps need to integrate deeper with the system than regular apps. Hence they need to be
+able to call APIs not available to other apps. This is implemented by granting permissions to
+these system apps and then enforcing the permissions in the API similar to other [install time
+permissions](#checking-a-permission).
+
+System apps are not different from regular apps, but the protection levels (e.g.
+[privileged](#privileged-permissions), [preinstalled](#preinstalled-permissions)) mentioned in this
+section are more commonly used by system apps.
+
+### Multiple permission levels
+
+It is possible to assign multiple protection levels to a permission. Very common combinations are
+for example adding `signature` to all permissions to make sure the platform signed apps can be
+granted the permission, e.g. `privileged|signature`.
+
+The permission will be granted if the app qualifies for _any_ of the permission levels.
+
+### App-op permissions
+
+> See [App-ops](../app/AppOps.md).
+
+App-op permissions are user-switchable permissions that are not runtime permissions. This should
+be used for permissions that are really only meant to be ever granted to a very small amount of
+apps. Traditionally granting these permissions is intentionally very heavy weight so that the
+user really needs to understand the use case. For example one use case is the
+`INTERACT_ACROSS_PROFILES` permission that allows apps of different
+[user profiles](../os/Users.md#user-profile) to interact. Of course this is breaking a very basic
+security container and hence should only every be granted with a lot of care.
+
+**Warning:** Most app-op permissions follow this logic, but most of them also have exceptions
+and special behavior. Hence this section is a guideline, not a rule.
+
+#### Defining an app-op permission
+
+Only the platform can reasonably define an app-op permission. The permission is defined in the
+platforms manifest using the `appop` protection level
+
+```xml
+<manifest package="android">
+ <permission android:name="android.permission.MY_APPOP_PERMISSION"
+ android:protectionLevel="appop|signature" />
+</manifest>
+```
+
+Almost always the protection level is app-op | something else, like
+[signature](#signature-permissions) (in the case above) or [privileged](#privileged-permissions).
+
+#### Checking a app-op permission
+
+The `PermissionChecker` utility can check app-op permissions with the [same syntax as runtime
+permissions](#checking-a-runtime-permission).
+
+The permission checker internally follows this flow
+
+```kotlin
+class PermissionChecker {
+ fun checkCallingPermission(context: Context, permission: String) {
+ if (isAppOpPermission(permission)) {
+ val appopOfPermission = AppOpsManager.permissionToOp(permission)
+ if (appopOfPermission == null) {
+ // not platform defined
+ return PERMISSION_DENIED
+ }
+
+ val appopMode = appOpsManager.noteOp(appopOfPermission)
+ when (appopMode) {
+ AppOpsManager.MODE_ALLOWED -> return PERMISSION_GRANTED
+ AppOpsManager.MODE_IGNORED -> return PERMISSION_DENIED
+ AppOpsManager.MODE_DEFAULT -> {
+ if (context.checkPermission(uid, permission) == GRANTED) {
+ return PERMISSION_GRANTED
+ } else {
+ return PERMISSION_DENIED
+ }
+ }
+ }
+ } else {
+ return PERMISSION_DENIED
+ }
+ }
+}
+```
+
+#### Granting a app-op permission
+
+The permission's grant state is only considered if the app-op's mode is `MODE_DEFAULT`. This
+allows to have default grants while still being overridden by the app-op.
+
+The permission is then granted by setting the app-op mode. This is usually done via dedicated APIs
+for each use cases. Similarly whether and how an app can request the permission is different for
+each app-op permission.
+
+When implementing a new app-op permission, make sure to set the app-op mode using `AppOpsManager
+.setUidMode` to make sure the permission is granted on the uid as this is the security domain.
+
+During development app-ops can be grated to app via the `appops set` shell command. E.g.
+
+```
+adb shell appops set 10187 INTERACT_ACROSS_PROFILES allow
+```
+
+sets the `INTERACT_ACROSS_PROFILES` app-op for uid 10187 to allow thereby granting apps in this
+uid the ability to interact across profiles.
+
+##### UI
+
+Most UIs for app-op permissions are in the "Special app access" section of the settings app.
+
+In most cases the permission should only be granted with the user's explicit agreement, usually by
+allowing the app to directly open the "Special app access" page for this permission and app.
+
+To repeat: this is a guideline for app-op permissions and there are many exceptions.
+
+### Signature permissions
+
+Only apps signed with the defining app's certificate will be granted the permission. This is
+used to restrict APIs to apps of the same developer.
+
+This is frequently used to restrict permissions defined by the platform to apps also signed with
+the platform's certificate. As this is a very tight restriction this is recommended for
+permissions that are only used by apps built out of AOSP which are signed with the platform
+certificate.
+
+Please note that OEMs sign their platform them self. I.e. OEMs can implement new apps using these
+permissions. It is unlikely that 3rd party apps will be able to use APIs protected by signature
+permissions as they are usually not signed with the platform certificate.
+
+Such permissions are defined and checked like an install time permission.
+
+### Preinstalled permissions
+
+This means that the app has to be pre-installed. There is no restriction what apps are pre-installed
+on a particular device install there. Hence it can be really any app including 3rd party apps.
+
+Hence this permission level is discouraged unless there are
+[further restrictions](#restricted-by-tests).
+
+Such permissions are defined and checked like an install time permission.
+
+### Privileged permissions
+
+This means that the app has to be pre-installed and in the `system/priv` directory in the
+filesystem. There is no restriction what apps are in this directory on a particular device
+install there. Hence it can be really any app including 3rd party apps.
+
+An app is only ever granted privileged permissions requested by the pre-installed apk. I.e.
+privileged permissions added in updates will never be granted.
+
+Hence this permission level is discouraged unless there are
+[further restrictions](#restricted-by-tests).
+
+Such permissions are defined and checked like an install time permission.
+
+#### Restricted by tests
+
+As all apps that might get preinstalled or privilidged permissions need to be pre-installed and new
+images need to pass compliance tests it is possible to use a test to whitelist the apps that can
+request the permission.
+
+Example of such a test:
+```kotlin
+/* Add new whitelisted packages to this list */
+private val whitelistedPkgs = listOf("my.whitelisted.package")
+
+@Test
+fun onlySomeAppsAreAllowedToHavePermissionGranted() {
+ assertThat(whitelistedPkgs).containsAllIn(
+ context.packageManager.getInstalledPackages(MATCH_ALL)
+ .filter { pkg ->
+ context.checkPermission(android.Manifest.permission.MY_PRIVILEGED_PERMISSION, -1,
+ pkg.applicationInfo.uid) == PERMISSION_GRANTED
+ /* The permission is defined by the system and hence granted to it */
+ }.filter { pkg -> pkg.applicationInfo.uid != SYSTEM_UID }
+ .map { it.packageName }
+ )
+}
+```
+
+#### Whitelist
+
+As mentioned above it is not suggested, but still common practice to install 3rd party apps as
+privilidged. To verify and restrict which privilidged permissions those apps get granted all
+privilidged permissions need to be explicitly whitelisted in a file `/etc`.
+
+```xml
+<permissions>
+ <privapp-permissions package="my.privileged.package">
+ <!-- allow the app to request a permission -->
+ <permission name="android.permission.MY_PRIVILEGED_PERMISSION"/>
+
+ <!-- Even though the app requests the permission, do not grant it -->
+ <deny-permission name="android.permission.MY_OTHER_PRIVILEGED_PERMISSION"/>
+ </privapp-permissions>
+</permissions>
+```
+
+If the pre-installed apk of app requests a privileged permission that is not mentioned in any
+whitelist or that is not denied the system will refuse to boot. As mentioned above privileged
+permissions added in updates to the pre-installed app will never be granted.
+
+### Limited permissions
+
+E.g. installer, wellbeing, documenter, etc... This allows the system to restrict the permission to a
+well defined app or set of apps. It is possible to add new types in `PackageManagerService`.
+
+Which apps qualify for such a permission level is flexible and custom for each such level. Usually
+they refer to a single or small set of apps, usually - but not always - apps defined in AOSP.
+
+These permissions are defined and checked like an install time permission.
+
+### Development permissions
+
+> Not recommended
+
+By adding the `development` protection level to any permissions the permission can be granted via
+the `pm grant` shell command. This appears to be useful for development and testing, but it is very
+highly discouraged. Any user can grant them permanently via adb, hence adding this tag removes
+all guarantees the permission might otherwise provide.
+
+### Other protection levels
+
+There are other levels (such as `runtime`) but they are for special purposes on should not be
+used by platform developers.
diff --git a/core/java/android/provider/BlockedNumberContract.java b/core/java/android/provider/BlockedNumberContract.java
index 1eb7664..dd2ea81 100644
--- a/core/java/android/provider/BlockedNumberContract.java
+++ b/core/java/android/provider/BlockedNumberContract.java
@@ -16,7 +16,6 @@
package android.provider;
import android.annotation.IntDef;
-import android.annotation.SystemApi;
import android.annotation.WorkerThread;
import android.content.Context;
import android.net.Uri;
@@ -240,7 +239,6 @@
* blocked.
* @hide
*/
- @SystemApi
public static final int STATUS_NOT_BLOCKED = 0;
/**
@@ -248,7 +246,6 @@
* because it is in the list of blocked numbers maintained by the provider.
* @hide
*/
- @SystemApi
public static final int STATUS_BLOCKED_IN_LIST = 1;
/**
@@ -256,7 +253,6 @@
* because it is from a restricted number.
* @hide
*/
- @SystemApi
public static final int STATUS_BLOCKED_RESTRICTED = 2;
/**
@@ -264,7 +260,6 @@
* because it is from an unknown number.
* @hide
*/
- @SystemApi
public static final int STATUS_BLOCKED_UNKNOWN_NUMBER = 3;
/**
@@ -272,7 +267,6 @@
* because it is from a pay phone.
* @hide
*/
- @SystemApi
public static final int STATUS_BLOCKED_PAYPHONE = 4;
/**
@@ -280,14 +274,12 @@
* because it is from a number not in the users contacts.
* @hide
*/
- @SystemApi
public static final int STATUS_BLOCKED_NOT_IN_CONTACTS = 5;
/**
* Integer reason indicating whether a call was blocked, and if so why.
* @hide
*/
- @SystemApi
public static final String RES_BLOCK_STATUS = "block_status";
/** @hide */
@@ -298,31 +290,6 @@
"can_current_user_block_numbers";
/** @hide */
- @SystemApi
- public static final String METHOD_NOTIFY_EMERGENCY_CONTACT = "notify_emergency_contact";
-
- /** @hide */
- public static final String METHOD_END_BLOCK_SUPPRESSION = "end_block_suppression";
-
- /** @hide */
- @SystemApi
- public static final String METHOD_SHOULD_SYSTEM_BLOCK_NUMBER = "should_system_block_number";
-
- /** @hide */
- public static final String METHOD_GET_BLOCK_SUPPRESSION_STATUS =
- "get_block_suppression_status";
-
- /** @hide */
- public static final String METHOD_SHOULD_SHOW_EMERGENCY_CALL_NOTIFICATION =
- "should_show_emergency_call_notification";
-
- /** @hide */
- public static final String METHOD_GET_ENHANCED_BLOCK_SETTING = "get_enhanced_block_setting";
-
- /** @hide */
- public static final String METHOD_SET_ENHANCED_BLOCK_SETTING = "set_enhanced_block_setting";
-
- /** @hide */
public static final String RES_CAN_BLOCK_NUMBERS = "can_block";
/** @hide */
@@ -439,11 +406,26 @@
public static final String ACTION_BLOCK_SUPPRESSION_STATE_CHANGED =
"android.provider.action.BLOCK_SUPPRESSION_STATE_CHANGED";
+ public static final String METHOD_NOTIFY_EMERGENCY_CONTACT = "notify_emergency_contact";
+
+ public static final String METHOD_END_BLOCK_SUPPRESSION = "end_block_suppression";
+
+ public static final String METHOD_SHOULD_SYSTEM_BLOCK_NUMBER = "should_system_block_number";
+
+ public static final String METHOD_GET_BLOCK_SUPPRESSION_STATUS =
+ "get_block_suppression_status";
+
+ public static final String METHOD_SHOULD_SHOW_EMERGENCY_CALL_NOTIFICATION =
+ "should_show_emergency_call_notification";
+
public static final String RES_IS_BLOCKING_SUPPRESSED = "blocking_suppressed";
public static final String RES_BLOCKING_SUPPRESSED_UNTIL_TIMESTAMP =
"blocking_suppressed_until_timestamp";
+ public static final String METHOD_GET_ENHANCED_BLOCK_SETTING = "get_enhanced_block_setting";
+ public static final String METHOD_SET_ENHANCED_BLOCK_SETTING = "set_enhanced_block_setting";
+
/* Preference key of block numbers not in contacts setting. */
public static final String ENHANCED_SETTING_KEY_BLOCK_UNREGISTERED =
"block_numbers_not_in_contacts_setting";
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index aa511cc..fb81d67 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -399,6 +399,13 @@
public static final String NAMESPACE_CONNECTIVITY_THERMAL_POWER_MANAGER =
"connectivity_thermal_power_manager";
+ /**
+ * Namespace for configuration related features.
+ *
+ * @hide
+ */
+ public static final String NAMESPACE_CONFIGURATION = "configuration";
+
private static final Object sLock = new Object();
@GuardedBy("sLock")
private static ArrayMap<OnPropertiesChangedListener, Pair<String, Executor>> sListeners =
diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java
index a80153d..327bca2 100644
--- a/core/java/android/provider/DocumentsProvider.java
+++ b/core/java/android/provider/DocumentsProvider.java
@@ -1081,7 +1081,7 @@
// signed with platform signature can hold MANAGE_DOCUMENTS, we are going to check for
// MANAGE_DOCUMENTS or associated URI permission here instead
final Uri rootUri = extras.getParcelable(DocumentsContract.EXTRA_URI);
- enforceWritePermissionInner(rootUri, getCallingPackage(), getCallingFeatureId(),
+ enforceWritePermissionInner(rootUri, getCallingPackage(), getCallingAttributionTag(),
null);
final String rootId = DocumentsContract.getRootId(rootUri);
@@ -1103,8 +1103,8 @@
enforceTree(documentUri);
if (METHOD_IS_CHILD_DOCUMENT.equals(method)) {
- enforceReadPermissionInner(documentUri, getCallingPackage(), getCallingFeatureId(),
- null);
+ enforceReadPermissionInner(documentUri, getCallingPackage(),
+ getCallingAttributionTag(), null);
final Uri childUri = extras.getParcelable(DocumentsContract.EXTRA_TARGET_URI);
final String childAuthority = childUri.getAuthority();
@@ -1116,8 +1116,8 @@
&& isChildDocument(documentId, childId));
} else if (METHOD_CREATE_DOCUMENT.equals(method)) {
- enforceWritePermissionInner(documentUri, getCallingPackage(), getCallingFeatureId(),
- null);
+ enforceWritePermissionInner(documentUri, getCallingPackage(),
+ getCallingAttributionTag(), null);
final String mimeType = extras.getString(Document.COLUMN_MIME_TYPE);
final String displayName = extras.getString(Document.COLUMN_DISPLAY_NAME);
@@ -1131,8 +1131,8 @@
out.putParcelable(DocumentsContract.EXTRA_URI, newDocumentUri);
} else if (METHOD_CREATE_WEB_LINK_INTENT.equals(method)) {
- enforceWritePermissionInner(documentUri, getCallingPackage(), getCallingFeatureId(),
- null);
+ enforceWritePermissionInner(documentUri, getCallingPackage(),
+ getCallingAttributionTag(), null);
final Bundle options = extras.getBundle(DocumentsContract.EXTRA_OPTIONS);
final IntentSender intentSender = createWebLinkIntent(documentId, options);
@@ -1140,8 +1140,8 @@
out.putParcelable(DocumentsContract.EXTRA_RESULT, intentSender);
} else if (METHOD_RENAME_DOCUMENT.equals(method)) {
- enforceWritePermissionInner(documentUri, getCallingPackage(), getCallingFeatureId(),
- null);
+ enforceWritePermissionInner(documentUri, getCallingPackage(),
+ getCallingAttributionTag(), null);
final String displayName = extras.getString(Document.COLUMN_DISPLAY_NAME);
final String newDocumentId = renameDocument(documentId, displayName);
@@ -1165,8 +1165,8 @@
}
} else if (METHOD_DELETE_DOCUMENT.equals(method)) {
- enforceWritePermissionInner(documentUri, getCallingPackage(), getCallingFeatureId(),
- null);
+ enforceWritePermissionInner(documentUri, getCallingPackage(),
+ getCallingAttributionTag(), null);
deleteDocument(documentId);
// Document no longer exists, clean up any grants.
@@ -1176,9 +1176,9 @@
final Uri targetUri = extras.getParcelable(DocumentsContract.EXTRA_TARGET_URI);
final String targetId = DocumentsContract.getDocumentId(targetUri);
- enforceReadPermissionInner(documentUri, getCallingPackage(), getCallingFeatureId(),
- null);
- enforceWritePermissionInner(targetUri, getCallingPackage(), getCallingFeatureId(),
+ enforceReadPermissionInner(documentUri, getCallingPackage(),
+ getCallingAttributionTag(), null);
+ enforceWritePermissionInner(targetUri, getCallingPackage(), getCallingAttributionTag(),
null);
final String newDocumentId = copyDocument(documentId, targetId);
@@ -1202,11 +1202,11 @@
final Uri targetUri = extras.getParcelable(DocumentsContract.EXTRA_TARGET_URI);
final String targetId = DocumentsContract.getDocumentId(targetUri);
- enforceWritePermissionInner(documentUri, getCallingPackage(), getCallingFeatureId(),
- null);
- enforceReadPermissionInner(parentSourceUri, getCallingPackage(), getCallingFeatureId(),
- null);
- enforceWritePermissionInner(targetUri, getCallingPackage(), getCallingFeatureId(),
+ enforceWritePermissionInner(documentUri, getCallingPackage(),
+ getCallingAttributionTag(), null);
+ enforceReadPermissionInner(parentSourceUri, getCallingPackage(),
+ getCallingAttributionTag(), null);
+ enforceWritePermissionInner(targetUri, getCallingPackage(), getCallingAttributionTag(),
null);
final String newDocumentId = moveDocument(documentId, parentSourceId, targetId);
@@ -1228,10 +1228,10 @@
final Uri parentSourceUri = extras.getParcelable(DocumentsContract.EXTRA_PARENT_URI);
final String parentSourceId = DocumentsContract.getDocumentId(parentSourceUri);
- enforceReadPermissionInner(parentSourceUri, getCallingPackage(), getCallingFeatureId(),
- null);
- enforceWritePermissionInner(documentUri, getCallingPackage(), getCallingFeatureId(),
- null);
+ enforceReadPermissionInner(parentSourceUri, getCallingPackage(),
+ getCallingAttributionTag(), null);
+ enforceWritePermissionInner(documentUri, getCallingPackage(),
+ getCallingAttributionTag(), null);
removeDocument(documentId, parentSourceId);
// It's responsibility of the provider to revoke any grants, as the document may be
@@ -1240,8 +1240,8 @@
final boolean isTreeUri = isTreeUri(documentUri);
if (isTreeUri) {
- enforceReadPermissionInner(documentUri, getCallingPackage(), getCallingFeatureId(),
- null);
+ enforceReadPermissionInner(documentUri, getCallingPackage(),
+ getCallingAttributionTag(), null);
} else {
getContext().enforceCallingPermission(Manifest.permission.MANAGE_DOCUMENTS, null);
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 641de4a..ce9b449 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -98,7 +98,8 @@
* The Settings provider contains global system-level device preferences.
*/
public final class Settings {
- private static final boolean DEFAULT_OVERRIDEABLE_BY_RESTORE = false;
+ /** @hide */
+ public static final boolean DEFAULT_OVERRIDEABLE_BY_RESTORE = false;
// Intent actions for Settings
@@ -709,10 +710,7 @@
* If not specified, the default behavior is
* {@link android.hardware.biometrics.BiometricManager.Authenticators#BIOMETRIC_WEAK}.
* <p>
- * Output: Returns {@link android.app.Activity#RESULT_CANCELED} if the user already has an
- * authenticator that meets the requirements, or if the device cannot fulfill the request
- * (e.g. does not have biometric hardware). Returns {@link android.app.Activity#RESULT_OK}
- * otherwise. Note that callers should still check
+ * Output: Nothing. Note that callers should still check
* {@link android.hardware.biometrics.BiometricManager#canAuthenticate(int)}
* afterwards to ensure that the user actually completed enrollment.
*/
@@ -2626,7 +2624,7 @@
arg.putBoolean(CALL_METHOD_OVERRIDEABLE_BY_RESTORE_KEY, true);
}
IContentProvider cp = mProviderHolder.getProvider(cr);
- cp.call(cr.getPackageName(), cr.getFeatureId(),
+ cp.call(cr.getPackageName(), cr.getAttributionTag(),
mProviderHolder.mUri.getAuthority(), mCallSetCommand, name, arg);
} catch (RemoteException e) {
Log.w(TAG, "Can't set key " + name + " in " + mUri, e);
@@ -2646,7 +2644,7 @@
args.putString(CALL_METHOD_PREFIX_KEY, prefix);
args.putSerializable(CALL_METHOD_FLAGS_KEY, keyValues);
IContentProvider cp = mProviderHolder.getProvider(cr);
- Bundle bundle = cp.call(cr.getPackageName(), cr.getFeatureId(),
+ Bundle bundle = cp.call(cr.getPackageName(), cr.getAttributionTag(),
mProviderHolder.mUri.getAuthority(),
mCallSetAllCommand, null, args);
return bundle.getBoolean(KEY_CONFIG_SET_RETURN);
@@ -2721,14 +2719,14 @@
if (Settings.isInSystemServer() && Binder.getCallingUid() != Process.myUid()) {
final long token = Binder.clearCallingIdentity();
try {
- b = cp.call(cr.getPackageName(), cr.getFeatureId(),
+ b = cp.call(cr.getPackageName(), cr.getAttributionTag(),
mProviderHolder.mUri.getAuthority(), mCallGetCommand, name,
args);
} finally {
Binder.restoreCallingIdentity(token);
}
} else {
- b = cp.call(cr.getPackageName(), cr.getFeatureId(),
+ b = cp.call(cr.getPackageName(), cr.getAttributionTag(),
mProviderHolder.mUri.getAuthority(), mCallGetCommand, name, args);
}
if (b != null) {
@@ -2798,13 +2796,13 @@
if (Settings.isInSystemServer() && Binder.getCallingUid() != Process.myUid()) {
final long token = Binder.clearCallingIdentity();
try {
- c = cp.query(cr.getPackageName(), cr.getFeatureId(), mUri,
+ c = cp.query(cr.getPackageName(), cr.getAttributionTag(), mUri,
SELECT_VALUE_PROJECTION, queryArgs, null);
} finally {
Binder.restoreCallingIdentity(token);
}
} else {
- c = cp.query(cr.getPackageName(), cr.getFeatureId(), mUri,
+ c = cp.query(cr.getPackageName(), cr.getAttributionTag(), mUri,
SELECT_VALUE_PROJECTION, queryArgs, null);
}
if (c == null) {
@@ -2897,7 +2895,7 @@
}
// Fetch all flags for the namespace at once for caching purposes
- Bundle b = cp.call(cr.getPackageName(), cr.getFeatureId(),
+ Bundle b = cp.call(cr.getPackageName(), cr.getAttributionTag(),
mProviderHolder.mUri.getAuthority(), mCallListCommand, null, args);
if (b == null) {
// Invalid response, return an empty map
@@ -5542,7 +5540,7 @@
}
arg.putInt(CALL_METHOD_RESET_MODE_KEY, mode);
IContentProvider cp = sProviderHolder.getProvider(resolver);
- cp.call(resolver.getPackageName(), resolver.getFeatureId(),
+ cp.call(resolver.getPackageName(), resolver.getAttributionTag(),
sProviderHolder.mUri.getAuthority(), CALL_METHOD_RESET_SECURE, null, arg);
} catch (RemoteException e) {
Log.w(TAG, "Can't reset do defaults for " + CONTENT_URI, e);
@@ -6092,10 +6090,7 @@
* device is removed from this mode.
* <p>
* Type: int (0 for false, 1 for true)
- *
- * @hide
*/
- @SystemApi
public static final String SECURE_FRP_MODE = "secure_frp_mode";
/**
@@ -13388,7 +13383,7 @@
}
arg.putInt(CALL_METHOD_RESET_MODE_KEY, mode);
IContentProvider cp = sProviderHolder.getProvider(resolver);
- cp.call(resolver.getPackageName(), resolver.getFeatureId(),
+ cp.call(resolver.getPackageName(), resolver.getAttributionTag(),
sProviderHolder.mUri.getAuthority(), CALL_METHOD_RESET_GLOBAL, null, arg);
} catch (RemoteException e) {
Log.w(TAG, "Can't reset do defaults for " + CONTENT_URI, e);
@@ -14363,7 +14358,7 @@
arg.putString(Settings.CALL_METHOD_PREFIX_KEY, createPrefix(namespace));
}
IContentProvider cp = sProviderHolder.getProvider(resolver);
- cp.call(resolver.getPackageName(), resolver.getFeatureId(),
+ cp.call(resolver.getPackageName(), resolver.getAttributionTag(),
sProviderHolder.mUri.getAuthority(), CALL_METHOD_RESET_CONFIG, null, arg);
} catch (RemoteException e) {
Log.w(TAG, "Can't reset to defaults for " + DeviceConfig.CONTENT_URI, e);
@@ -14392,7 +14387,7 @@
arg.putInt(CALL_METHOD_USER_KEY, userHandle);
arg.putParcelable(CALL_METHOD_MONITOR_CALLBACK_KEY, callback);
IContentProvider cp = sProviderHolder.getProvider(resolver);
- cp.call(resolver.getPackageName(), resolver.getFeatureId(),
+ cp.call(resolver.getPackageName(), resolver.getAttributionTag(),
sProviderHolder.mUri.getAuthority(),
CALL_METHOD_REGISTER_MONITOR_CALLBACK_CONFIG, null, arg);
} catch (RemoteException e) {
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 629dc8b..e7b360d 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -3551,7 +3551,6 @@
* can manage DPC-owned APNs.
* @hide
*/
- @SystemApi
public static final @NonNull Uri DPC_URI = Uri.parse("content://telephony/carriers/dpc");
/**
@@ -3735,7 +3734,6 @@
* @deprecated this column is no longer supported, use {@link #NETWORK_TYPE_BITMASK} instead
*/
@Deprecated
- @SystemApi
public static final String BEARER_BITMASK = "bearer_bitmask";
/**
@@ -3785,7 +3783,6 @@
* <p>Type: INTEGER</p>
*@hide
*/
- @SystemApi
public static final String PROFILE_ID = "profile_id";
/**
@@ -3866,7 +3863,6 @@
* Integer value denoting an invalid APN id
* @hide
*/
- @SystemApi
public static final int INVALID_APN_ID = -1;
/**
@@ -3986,7 +3982,6 @@
*
* @hide
*/
- @SystemApi
public static final String SKIP_464XLAT = "skip_464xlat";
/**
@@ -3995,7 +3990,6 @@
*
* @hide
*/
- @SystemApi
public static final int SKIP_464XLAT_DEFAULT = -1;
/**
@@ -4004,7 +3998,6 @@
*
* @hide
*/
- @SystemApi
public static final int SKIP_464XLAT_DISABLE = 0;
/**
@@ -4013,7 +4006,6 @@
*
* @hide
*/
- @SystemApi
public static final int SKIP_464XLAT_ENABLE = 1;
@@ -4392,6 +4384,7 @@
* Indicates that whether the message has been broadcasted to the application.
* <P>Type: BOOLEAN</P>
*/
+ // TODO: deprecate this in S.
public static final String MESSAGE_BROADCASTED = "message_broadcasted";
/**
diff --git a/core/java/android/service/autofill/Dataset.java b/core/java/android/service/autofill/Dataset.java
index 886b433..08aa534 100644
--- a/core/java/android/service/autofill/Dataset.java
+++ b/core/java/android/service/autofill/Dataset.java
@@ -232,22 +232,6 @@
* Creates a new builder.
*
* @param presentation The presentation used to visualize this dataset.
- * @param inlinePresentation The {@link InlinePresentation} used to visualize this dataset
- * as inline suggestions. If the dataset supports inline suggestions,
- * this should not be null.
- */
- public Builder(@NonNull RemoteViews presentation,
- @NonNull InlinePresentation inlinePresentation) {
- Preconditions.checkNotNull(presentation, "presentation must be non-null");
- Preconditions.checkNotNull(inlinePresentation, "inlinePresentation must be non-null");
- mPresentation = presentation;
- mInlinePresentation = inlinePresentation;
- }
-
- /**
- * Creates a new builder.
- *
- * @param presentation The presentation used to visualize this dataset.
*/
public Builder(@NonNull RemoteViews presentation) {
Preconditions.checkNotNull(presentation, "presentation must be non-null");
@@ -282,6 +266,22 @@
}
/**
+ * Sets the {@link InlinePresentation} used to visualize this dataset as inline suggestions.
+ * If the dataset supports inline suggestions this should not be null.
+ *
+ * @throws IllegalStateException if {@link #build()} was already called.
+ *
+ * @return this builder.
+ */
+ public @NonNull Builder setInlinePresentation(
+ @NonNull InlinePresentation inlinePresentation) {
+ throwIfDestroyed();
+ Preconditions.checkNotNull(inlinePresentation, "inlinePresentation must be non-null");
+ mInlinePresentation = inlinePresentation;
+ return this;
+ }
+
+ /**
* Triggers a custom UI before before autofilling the screen with the contents of this
* dataset.
*
@@ -600,7 +600,7 @@
*/
@SystemApi
@TestApi
- public @NonNull Builder setInlinePresentation(@NonNull AutofillId id,
+ public @NonNull Builder setFieldInlinePresentation(@NonNull AutofillId id,
@Nullable AutofillValue value, @Nullable Pattern filter,
@NonNull InlinePresentation inlinePresentation) {
throwIfDestroyed();
@@ -700,7 +700,7 @@
final Builder builder = presentation != null
? inlinePresentation == null
? new Builder(presentation)
- : new Builder(presentation, inlinePresentation)
+ : new Builder(presentation).setInlinePresentation(inlinePresentation)
: inlinePresentation == null
? new Builder()
: new Builder(inlinePresentation);
diff --git a/core/java/android/service/autofill/FillRequest.java b/core/java/android/service/autofill/FillRequest.java
index 72e9ad0..8f858d5 100644
--- a/core/java/android/service/autofill/FillRequest.java
+++ b/core/java/android/service/autofill/FillRequest.java
@@ -77,6 +77,15 @@
*/
public static final @RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST = 0x2;
+ /**
+ * Indicates the request came from a password field.
+ *
+ * (TODO: b/141703197) Temporary fix for augmented autofill showing passwords.
+ *
+ * @hide
+ */
+ public static final @RequestFlags int FLAG_PASSWORD_INPUT_TYPE = 0x4;
+
/** @hide */
public static final int INVALID_REQUEST_ID = Integer.MIN_VALUE;
@@ -149,7 +158,8 @@
/** @hide */
@IntDef(flag = true, prefix = "FLAG_", value = {
FLAG_MANUAL_REQUEST,
- FLAG_COMPATIBILITY_MODE_REQUEST
+ FLAG_COMPATIBILITY_MODE_REQUEST,
+ FLAG_PASSWORD_INPUT_TYPE
})
@Retention(RetentionPolicy.SOURCE)
@DataClass.Generated.Member
@@ -169,6 +179,8 @@
return "FLAG_MANUAL_REQUEST";
case FLAG_COMPATIBILITY_MODE_REQUEST:
return "FLAG_COMPATIBILITY_MODE_REQUEST";
+ case FLAG_PASSWORD_INPUT_TYPE:
+ return "FLAG_PASSWORD_INPUT_TYPE";
default: return Integer.toHexString(value);
}
}
@@ -223,7 +235,8 @@
Preconditions.checkFlagsArgument(
mFlags,
FLAG_MANUAL_REQUEST
- | FLAG_COMPATIBILITY_MODE_REQUEST);
+ | FLAG_COMPATIBILITY_MODE_REQUEST
+ | FLAG_PASSWORD_INPUT_TYPE);
this.mInlineSuggestionsRequest = inlineSuggestionsRequest;
onConstructed();
@@ -352,7 +365,8 @@
Preconditions.checkFlagsArgument(
mFlags,
FLAG_MANUAL_REQUEST
- | FLAG_COMPATIBILITY_MODE_REQUEST);
+ | FLAG_COMPATIBILITY_MODE_REQUEST
+ | FLAG_PASSWORD_INPUT_TYPE);
this.mInlineSuggestionsRequest = inlineSuggestionsRequest;
onConstructed();
@@ -373,10 +387,10 @@
};
@DataClass.Generated(
- time = 1575928271155L,
+ time = 1583196707026L,
codegenVersion = "1.0.14",
sourceFile = "frameworks/base/core/java/android/service/autofill/FillRequest.java",
- inputSignatures = "public static final @android.service.autofill.FillRequest.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final int INVALID_REQUEST_ID\nprivate final int mId\nprivate final @android.annotation.NonNull java.util.List<android.service.autofill.FillContext> mFillContexts\nprivate final @android.annotation.Nullable android.os.Bundle mClientState\nprivate final @android.service.autofill.FillRequest.RequestFlags int mFlags\nprivate final @android.annotation.Nullable android.view.inputmethod.InlineSuggestionsRequest mInlineSuggestionsRequest\nprivate void onConstructed()\nclass FillRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
+ inputSignatures = "public static final @android.service.autofill.FillRequest.RequestFlags int FLAG_MANUAL_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_COMPATIBILITY_MODE_REQUEST\npublic static final @android.service.autofill.FillRequest.RequestFlags int FLAG_PASSWORD_INPUT_TYPE\npublic static final int INVALID_REQUEST_ID\nprivate final int mId\nprivate final @android.annotation.NonNull java.util.List<android.service.autofill.FillContext> mFillContexts\nprivate final @android.annotation.Nullable android.os.Bundle mClientState\nprivate final @android.service.autofill.FillRequest.RequestFlags int mFlags\nprivate final @android.annotation.Nullable android.view.inputmethod.InlineSuggestionsRequest mInlineSuggestionsRequest\nprivate void onConstructed()\nclass FillRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genHiddenConstructor=true, genHiddenConstDefs=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/service/autofill/IInlineSuggestionUiCallback.aidl b/core/java/android/service/autofill/IInlineSuggestionUiCallback.aidl
index 1011651..1bcc76b 100644
--- a/core/java/android/service/autofill/IInlineSuggestionUiCallback.aidl
+++ b/core/java/android/service/autofill/IInlineSuggestionUiCallback.aidl
@@ -25,7 +25,8 @@
* @hide
*/
oneway interface IInlineSuggestionUiCallback {
- void onAutofill();
+ void onClick();
+ void onLongClick();
void onContent(in SurfaceControlViewHost.SurfacePackage surface);
void onError();
void onTransferTouchFocusToImeWindow(in IBinder sourceInputToken, int displayId);
diff --git a/core/java/android/service/autofill/InlineSuggestionRenderService.java b/core/java/android/service/autofill/InlineSuggestionRenderService.java
index ee152837..b6cc62d 100644
--- a/core/java/android/service/autofill/InlineSuggestionRenderService.java
+++ b/core/java/android/service/autofill/InlineSuggestionRenderService.java
@@ -97,12 +97,21 @@
host.addView(suggestionRoot, lp);
suggestionRoot.setOnClickListener((v) -> {
try {
- callback.onAutofill();
+ callback.onClick();
} catch (RemoteException e) {
- Log.w(TAG, "RemoteException calling onAutofill()");
+ Log.w(TAG, "RemoteException calling onClick()");
}
});
+ suggestionRoot.setOnLongClickListener((v) -> {
+ try {
+ callback.onLongClick();
+ } catch (RemoteException e) {
+ Log.w(TAG, "RemoteException calling onLongClick()");
+ }
+ return true;
+ });
+
sendResult(callback, host.getSurfacePackage());
} finally {
updateDisplay(Display.DEFAULT_DISPLAY);
diff --git a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
index ed27dd5..5b08ae20 100644
--- a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
+++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
@@ -488,7 +488,8 @@
ids.add(pair.first);
values.add(pair.second);
}
- mClient.autofill(mSessionId, ids, values);
+ final boolean hideHighlight = size == 1 && ids.get(0).equals(mFocusedId);
+ mClient.autofill(mSessionId, ids, values, hideHighlight);
}
public void setFillWindow(@NonNull FillWindow fillWindow) {
diff --git a/core/java/android/service/dataloader/DataLoaderService.java b/core/java/android/service/dataloader/DataLoaderService.java
index 0b9a8af..d4db79e 100644
--- a/core/java/android/service/dataloader/DataLoaderService.java
+++ b/core/java/android/service/dataloader/DataLoaderService.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.app.Service;
import android.content.Intent;
@@ -206,6 +207,7 @@
* @throws IOException if trouble opening the file for writing, such as lack of disk space
* or unavailable media.
*/
+ @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES)
public void writeData(@NonNull String name, long offsetBytes, long lengthBytes,
@NonNull ParcelFileDescriptor incomingFd) throws IOException {
try {
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 002d4b8..e70311f 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -609,9 +609,7 @@
*
* @hide
*
- * TODO: Remove @UnsupportedAppUsage.
*/
- @UnsupportedAppUsage
public void setWindowless(boolean windowless) {
mWindowless = windowless;
}
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index 8e6f77b..4a0dd87 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -1314,7 +1314,8 @@
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(mContext);
int res = mSystemService.startVoiceActivity(mToken, intent,
- intent.resolveType(mContext.getContentResolver()), mContext.getFeatureId());
+ intent.resolveType(mContext.getContentResolver()),
+ mContext.getAttributionTag());
Instrumentation.checkStartActivityResult(res, intent);
} catch (RemoteException e) {
}
@@ -1342,7 +1343,8 @@
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(mContext);
int res = mSystemService.startAssistantActivity(mToken, intent,
- intent.resolveType(mContext.getContentResolver()), mContext.getFeatureId());
+ intent.resolveType(mContext.getContentResolver()),
+ mContext.getAttributionTag());
Instrumentation.checkStartActivityResult(res, intent);
} catch (RemoteException e) {
}
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index bf3c088..f531e12 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -124,8 +124,6 @@
private static final int MSG_REQUEST_WALLPAPER_COLORS = 10050;
private static final int MSG_SCALE = 10100;
- private static final float MAX_SCALE = 1.15f;
-
private static final int NOTIFY_COLORS_RATE_LIMIT_MS = 1000;
private final ArrayList<Engine> mActiveEngines
@@ -351,7 +349,7 @@
@Override
public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
- boolean sync) {
+ float zoom, boolean sync) {
synchronized (mLock) {
if (DEBUG) Log.v(TAG, "Dispatch wallpaper offsets: " + x + ", " + y);
mPendingXOffset = x;
@@ -366,6 +364,8 @@
Message msg = mCaller.obtainMessage(MSG_WALLPAPER_OFFSETS);
mCaller.sendMessage(msg);
}
+ Message msg = mCaller.obtainMessageI(MSG_SCALE, Float.floatToIntBits(zoom));
+ mCaller.sendMessage(msg);
}
}
@@ -462,6 +462,18 @@
}
/**
+ * This will be called when the wallpaper is first started. If true is returned, the system
+ * will zoom in the wallpaper by default and zoom it out as the user interacts,
+ * to create depth. Otherwise, zoom will have to be handled manually
+ * in {@link #onZoomChanged(float)}.
+ *
+ * @hide
+ */
+ public boolean shouldZoomOutWallpaper() {
+ return false;
+ }
+
+ /**
* Control whether this wallpaper will receive raw touch events
* from the window manager as the user interacts with the window
* that is currently displaying the wallpaper. By default they
@@ -870,6 +882,7 @@
Log.w(TAG, "Failed to add window while updating wallpaper surface.");
return;
}
+ mSession.setShouldZoomOutWallpaper(mWindow, shouldZoomOutWallpaper());
mCreated = true;
mInputEventReceiver = new WallpaperInputEventReceiver(
@@ -964,7 +977,6 @@
c.surfaceCreated(mSurfaceHolder);
}
}
- onZoomChanged(0f);
}
redrawNeeded |= creating || (relayoutResult
@@ -1125,7 +1137,6 @@
mIsInAmbientMode = inAmbientMode;
if (mCreated) {
onAmbientModeChanged(inAmbientMode, animationDuration);
- setZoom(0);
}
}
}
diff --git a/core/java/android/speech/SpeechRecognizer.java b/core/java/android/speech/SpeechRecognizer.java
index e93ba16..92f3538 100644
--- a/core/java/android/speech/SpeechRecognizer.java
+++ b/core/java/android/speech/SpeechRecognizer.java
@@ -342,7 +342,7 @@
}
try {
mService.startListening(recognizerIntent, mListener, mContext.getOpPackageName(),
- mContext.getFeatureId());
+ mContext.getAttributionTag());
if (DBG) Log.d(TAG, "service start listening command succeded");
} catch (final RemoteException e) {
Log.e(TAG, "startListening() failed", e);
@@ -357,7 +357,7 @@
}
try {
mService.stopListening(mListener, mContext.getOpPackageName(),
- mContext.getFeatureId());
+ mContext.getAttributionTag());
if (DBG) Log.d(TAG, "service stop listening command succeded");
} catch (final RemoteException e) {
Log.e(TAG, "stopListening() failed", e);
@@ -371,7 +371,7 @@
return;
}
try {
- mService.cancel(mListener, mContext.getOpPackageName(), mContext.getFeatureId());
+ mService.cancel(mListener, mContext.getOpPackageName(), mContext.getAttributionTag());
if (DBG) Log.d(TAG, "service cancel command succeded");
} catch (final RemoteException e) {
Log.e(TAG, "cancel() failed", e);
@@ -400,7 +400,8 @@
public void destroy() {
if (mService != null) {
try {
- mService.cancel(mListener, mContext.getOpPackageName(), mContext.getFeatureId());
+ mService.cancel(mListener, mContext.getOpPackageName(),
+ mContext.getAttributionTag());
} catch (final RemoteException e) {
// Not important
}
diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index 7238b12..ab9df56 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -116,7 +116,7 @@
mSubscriptionChangedListenerMap.put(listener, callback);
try {
sRegistry.addOnSubscriptionsChangedListener(mContext.getOpPackageName(),
- mContext.getFeatureId(), callback);
+ mContext.getAttributionTag(), callback);
} catch (RemoteException ex) {
// system server crash
}
@@ -175,7 +175,7 @@
mOpportunisticSubscriptionChangedListenerMap.put(listener, callback);
try {
sRegistry.addOnOpportunisticSubscriptionsChangedListener(mContext.getOpPackageName(),
- mContext.getFeatureId(), callback);
+ mContext.getAttributionTag(), callback);
} catch (RemoteException ex) {
// system server crash
}
diff --git a/core/java/android/text/util/Linkify.java b/core/java/android/text/util/Linkify.java
index 2aca36a..82c7ea7 100644
--- a/core/java/android/text/util/Linkify.java
+++ b/core/java/android/text/util/Linkify.java
@@ -19,6 +19,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.ActivityThread;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.telephony.PhoneNumberUtils;
@@ -663,9 +664,11 @@
private static void gatherTelLinks(ArrayList<LinkSpec> links, Spannable s,
@Nullable Context context) {
PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
+ final Context ctx = (context != null) ? context : ActivityThread.currentApplication();
+ final String regionCode = (ctx != null) ? ctx.getSystemService(TelephonyManager.class).
+ getSimCountryIso().toUpperCase(Locale.US) : Locale.getDefault().getCountry();
Iterable<PhoneNumberMatch> matches = phoneUtil.findNumbers(s.toString(),
- TelephonyManager.getDefaultSimCountryIso().toUpperCase(Locale.US),
- Leniency.POSSIBLE, Long.MAX_VALUE);
+ regionCode, Leniency.POSSIBLE, Long.MAX_VALUE);
for (PhoneNumberMatch match : matches) {
LinkSpec spec = new LinkSpec();
spec.url = "tel:" + PhoneNumberUtils.normalizeNumber(match.rawString());
diff --git a/core/java/android/util/apk/SourceStampVerifier.java b/core/java/android/util/apk/SourceStampVerifier.java
index 759c864..70e4a51 100644
--- a/core/java/android/util/apk/SourceStampVerifier.java
+++ b/core/java/android/util/apk/SourceStampVerifier.java
@@ -82,25 +82,34 @@
public static SourceStampVerificationResult verify(String apkFile) {
try (RandomAccessFile apk = new RandomAccessFile(apkFile, "r")) {
return verify(apk);
- } catch (Exception e) {
- // Any exception in the SourceStamp verification returns a non-verified SourceStamp
- // outcome without affecting the outcome of any of the other signature schemes.
- return SourceStampVerificationResult.notVerified();
+ } catch (IOException e) {
+ // Any exception in reading the APK returns a non-present SourceStamp outcome
+ // without affecting the outcome of any of the other signature schemes.
+ return SourceStampVerificationResult.notPresent();
}
}
- private static SourceStampVerificationResult verify(RandomAccessFile apk)
- throws IOException, SignatureNotFoundException {
- byte[] sourceStampCertificateDigest = getSourceStampCertificateDigest(apk);
- if (sourceStampCertificateDigest == null) {
- // SourceStamp certificate hash file not found, which means that there is not
- // SourceStamp present.
+ private static SourceStampVerificationResult verify(RandomAccessFile apk) {
+ byte[] sourceStampCertificateDigest;
+ try {
+ sourceStampCertificateDigest = getSourceStampCertificateDigest(apk);
+ if (sourceStampCertificateDigest == null) {
+ // SourceStamp certificate hash file not found, which means that there is not
+ // SourceStamp present.
+ return SourceStampVerificationResult.notPresent();
+ }
+ } catch (IOException e) {
return SourceStampVerificationResult.notPresent();
}
- SignatureInfo signatureInfo =
- ApkSigningBlockUtils.findSignature(apk, SOURCE_STAMP_BLOCK_ID);
- Map<Integer, byte[]> apkContentDigests = getApkContentDigests(apk);
- return verify(signatureInfo, apkContentDigests, sourceStampCertificateDigest);
+
+ try {
+ SignatureInfo signatureInfo =
+ ApkSigningBlockUtils.findSignature(apk, SOURCE_STAMP_BLOCK_ID);
+ Map<Integer, byte[]> apkContentDigests = getApkContentDigests(apk);
+ return verify(signatureInfo, apkContentDigests, sourceStampCertificateDigest);
+ } catch (IOException | SignatureNotFoundException e) {
+ return SourceStampVerificationResult.notVerified();
+ }
}
private static SourceStampVerificationResult verify(
diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl
index 3927ebf..9f2d36d 100644
--- a/core/java/android/view/IWindow.aidl
+++ b/core/java/android/view/IWindow.aidl
@@ -102,9 +102,9 @@
void closeSystemDialogs(String reason);
/**
- * Called for wallpaper windows when their offsets change.
+ * Called for wallpaper windows when their offsets or zoom level change.
*/
- void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep, boolean sync);
+ void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep, float zoom, boolean sync);
void dispatchWallpaperCommand(String action, int x, int y,
int z, in Bundle extras, boolean sync);
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 91000a9..dfe89a3 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -221,6 +221,19 @@
*/
void setWallpaperPosition(IBinder windowToken, float x, float y, float xstep, float ystep);
+ /**
+ * For wallpaper windows, sets the scale of the wallpaper based on
+ * SystemUI behavior.
+ */
+ void setWallpaperZoomOut(IBinder windowToken, float scale);
+
+ /**
+ * For wallpaper windows, sets whether the wallpaper should actually be
+ * scaled when setWallpaperZoomOut is called. If set to false, the WallpaperService will
+ * receive the zoom out value but the surface won't be scaled.
+ */
+ void setShouldZoomOutWallpaper(IBinder windowToken, boolean shouldZoom);
+
@UnsupportedAppUsage
void wallpaperOffsetsComplete(IBinder window);
diff --git a/core/java/android/view/InsetsAnimationControlCallbacks.java b/core/java/android/view/InsetsAnimationControlCallbacks.java
index 5d5edec..4227f78 100644
--- a/core/java/android/view/InsetsAnimationControlCallbacks.java
+++ b/core/java/android/view/InsetsAnimationControlCallbacks.java
@@ -16,7 +16,6 @@
package android.view;
-import android.view.InsetsController.LayoutInsetsDuringAnimation;
import android.view.WindowInsetsAnimation.Bounds;
/**
@@ -37,7 +36,7 @@
void startAnimation(InsetsAnimationControlImpl controller,
WindowInsetsAnimationControlListener listener, int types,
WindowInsetsAnimation animation,
- Bounds bounds, @LayoutInsetsDuringAnimation int layoutDuringAnimation);
+ Bounds bounds);
/**
* Schedule the apply by posting the animation callback.
@@ -46,10 +45,10 @@
/**
* Finish the final steps after the animation.
- * @param controller The controller used to control the animation.
+ * @param runner The runner used to run the animation.
* @param shown {@code true} if the insets are shown.
*/
- void notifyFinished(InsetsAnimationControlImpl controller, boolean shown);
+ void notifyFinished(InsetsAnimationControlRunner runner, boolean shown);
/**
* Apply the new params to the surface.
@@ -57,4 +56,10 @@
* apply.
*/
void applySurfaceParams(SyncRtSurfaceTransactionApplier.SurfaceParams... params);
+
+ /**
+ * Post a message to release the Surface, guaranteed to happen after all
+ * previous calls to applySurfaceParams.
+ */
+ void releaseSurfaceControlFromRt(SurfaceControl sc);
}
diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java
index ae509f3..baee412 100644
--- a/core/java/android/view/InsetsAnimationControlImpl.java
+++ b/core/java/android/view/InsetsAnimationControlImpl.java
@@ -31,9 +31,7 @@
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.util.SparseSetArray;
-import android.view.InsetsController.LayoutInsetsDuringAnimation;
import android.view.InsetsState.InternalInsetsSide;
-import android.view.InsetsState.InternalInsetsType;
import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
import android.view.WindowInsets.Type.InsetsType;
import android.view.WindowInsetsAnimation.Bounds;
@@ -49,7 +47,8 @@
* @hide
*/
@VisibleForTesting
-public class InsetsAnimationControlImpl implements WindowInsetsAnimationController {
+public class InsetsAnimationControlImpl implements WindowInsetsAnimationController,
+ InsetsAnimationControlRunner {
private final Rect mTmpFrame = new Rect();
@@ -84,8 +83,7 @@
InsetsState state, WindowInsetsAnimationControlListener listener,
@InsetsType int types,
InsetsAnimationControlCallbacks controller, long durationMs, Interpolator interpolator,
- boolean fade, @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation,
- @AnimationType int animationType) {
+ boolean fade, @AnimationType int animationType) {
mControls = controls;
mListener = listener;
mTypes = types;
@@ -105,7 +103,7 @@
mAnimation.setAlpha(getCurrentAlpha());
mAnimationType = animationType;
mController.startAnimation(this, listener, types, mAnimation,
- new Bounds(mHiddenInsets, mShownInsets), layoutInsetsDuringAnimation);
+ new Bounds(mHiddenInsets, mShownInsets));
}
@Override
@@ -133,11 +131,8 @@
return mTypes;
}
- boolean controlsInternalType(@InternalInsetsType int type) {
- return InsetsState.toInternalType(mTypes).contains(type);
- }
-
- @AnimationType int getAnimationType() {
+ @Override
+ public @AnimationType int getAnimationType() {
return mAnimationType;
}
@@ -185,10 +180,19 @@
mAnimation.setAlpha(mPendingAlpha);
if (mFinished) {
mController.notifyFinished(this, mShownOnFinish);
+ releaseLeashes();
}
return mFinished;
}
+ private void releaseLeashes() {
+ for (int i = mControls.size() - 1; i >= 0; i--) {
+ final InsetsSourceControl c = mControls.valueAt(i);
+ if (c == null) continue;
+ c.release(mController::releaseSurfaceControlFromRt);
+ }
+ }
+
@Override
public void finish(boolean shown) {
if (mCancelled || mFinished) {
@@ -196,6 +200,7 @@
}
setInsetsAndAlpha(shown ? mShownInsets : mHiddenInsets, 1f /* alpha */, 1f /* fraction */);
mFinished = true;
+
mShownOnFinish = shown;
}
@@ -205,19 +210,23 @@
return mAnimation.getFraction();
}
- public void onCancelled() {
+ @Override
+ public void cancel() {
if (mFinished) {
return;
}
mCancelled = true;
mListener.onCancelled();
+
+ releaseLeashes();
}
public boolean isCancelled() {
return mCancelled;
}
- WindowInsetsAnimation getAnimation() {
+ @Override
+ public WindowInsetsAnimation getAnimation() {
return mAnimation;
}
@@ -225,6 +234,10 @@
return mListener;
}
+ SparseArray<InsetsSourceControl> getControls() {
+ return mControls;
+ }
+
private Insets calculateInsets(InsetsState state, Rect frame,
SparseArray<InsetsSourceControl> controls, boolean shown,
@Nullable @InternalInsetsSide SparseIntArray typeSideMap) {
diff --git a/core/java/android/view/InsetsAnimationControlRunner.java b/core/java/android/view/InsetsAnimationControlRunner.java
new file mode 100644
index 0000000..0711c3e
--- /dev/null
+++ b/core/java/android/view/InsetsAnimationControlRunner.java
@@ -0,0 +1,56 @@
+/*
+ * 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 android.view;
+
+import android.view.InsetsController.AnimationType;
+import android.view.InsetsState.InternalInsetsType;
+import android.view.WindowInsets.Type.InsetsType;
+
+/**
+ * Interface representing a runner for an insets animation.
+ *
+ * @hide
+ */
+public interface InsetsAnimationControlRunner {
+
+ /**
+ * @return The {@link InsetsType} the animation of this runner is controlling.
+ */
+ @InsetsType int getTypes();
+
+ /**
+ * Cancels the animation.
+ */
+ void cancel();
+
+ /**
+ * @return The animation this runner is running.
+ */
+ WindowInsetsAnimation getAnimation();
+
+ /**
+ * @return Whether {@link #getTypes()} maps to a specific {@link InternalInsetsType}.
+ */
+ default boolean controlsInternalType(@InternalInsetsType int type) {
+ return InsetsState.toInternalType(getTypes()).contains(type);
+ }
+
+ /**
+ * @return The animation type this runner is running.
+ */
+ @AnimationType int getAnimationType();
+}
diff --git a/core/java/android/view/InsetsAnimationThread.java b/core/java/android/view/InsetsAnimationThread.java
new file mode 100644
index 0000000..cdf9733
--- /dev/null
+++ b/core/java/android/view/InsetsAnimationThread.java
@@ -0,0 +1,70 @@
+/*
+ * 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 android.view;
+
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Trace;
+
+/**
+ * Thread to be used for inset animations to be running off the main thread.
+ * @hide
+ */
+public class InsetsAnimationThread extends HandlerThread {
+
+ private static InsetsAnimationThread sInstance;
+ private static Handler sHandler;
+
+ private InsetsAnimationThread() {
+ // TODO: Should this use higher priority?
+ super("InsetsAnimations");
+ }
+
+ private static void ensureThreadLocked() {
+ if (sInstance == null) {
+ sInstance = new InsetsAnimationThread();
+ sInstance.start();
+ sInstance.getLooper().setTraceTag(Trace.TRACE_TAG_VIEW);
+ sHandler = new Handler(sInstance.getLooper());
+ }
+ }
+
+ public static void release() {
+ synchronized (InsetsAnimationThread.class) {
+ if (sInstance == null) {
+ return;
+ }
+ sInstance.getLooper().quitSafely();
+ sInstance = null;
+ sHandler = null;
+ }
+ }
+
+ public static InsetsAnimationThread get() {
+ synchronized (InsetsAnimationThread.class) {
+ ensureThreadLocked();
+ return sInstance;
+ }
+ }
+
+ public static Handler getHandler() {
+ synchronized (InsetsAnimationThread.class) {
+ ensureThreadLocked();
+ return sHandler;
+ }
+ }
+}
diff --git a/core/java/android/view/InsetsAnimationThreadControlRunner.java b/core/java/android/view/InsetsAnimationThreadControlRunner.java
new file mode 100644
index 0000000..13b4cd8
--- /dev/null
+++ b/core/java/android/view/InsetsAnimationThreadControlRunner.java
@@ -0,0 +1,136 @@
+/*
+ * 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 android.view;
+
+import static android.view.SyncRtSurfaceTransactionApplier.applyParams;
+
+import android.annotation.UiThread;
+import android.graphics.Rect;
+import android.os.Handler;
+import android.util.SparseArray;
+import android.view.InsetsController.AnimationType;
+import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
+import android.view.WindowInsets.Type.InsetsType;
+import android.view.WindowInsetsAnimation.Bounds;
+import android.view.animation.Interpolator;
+
+/**
+ * Insets animation runner that uses {@link InsetsAnimationThread} to run the animation off from the
+ * main thread.
+ *
+ * @hide
+ */
+public class InsetsAnimationThreadControlRunner implements InsetsAnimationControlRunner {
+
+ private final InsetsAnimationControlImpl mControl;
+ private final InsetsAnimationControlCallbacks mOuterCallbacks;
+ private final Handler mMainThreadHandler;
+ private final InsetsState mState = new InsetsState();
+ private final InsetsAnimationControlCallbacks mCallbacks =
+ new InsetsAnimationControlCallbacks() {
+
+ private final float[] mTmpFloat9 = new float[9];
+
+ @Override
+ @UiThread
+ public void startAnimation(InsetsAnimationControlImpl controller,
+ WindowInsetsAnimationControlListener listener, int types,
+ WindowInsetsAnimation animation, Bounds bounds) {
+ // Animation will be started in constructor already.
+ }
+
+ @Override
+ public void scheduleApplyChangeInsets() {
+ mControl.applyChangeInsets(mState);
+ }
+
+ @Override
+ public void notifyFinished(InsetsAnimationControlRunner runner, boolean shown) {
+ releaseControls(mControl.getControls());
+ mMainThreadHandler.post(() ->
+ mOuterCallbacks.notifyFinished(InsetsAnimationThreadControlRunner.this, shown));
+ }
+
+ @Override
+ public void applySurfaceParams(SurfaceParams... params) {
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ for (int i = params.length - 1; i >= 0; i--) {
+ SyncRtSurfaceTransactionApplier.SurfaceParams surfaceParams = params[i];
+ applyParams(t, surfaceParams, mTmpFloat9);
+ }
+ t.apply();
+ t.close();
+ }
+
+ @Override
+ public void releaseSurfaceControlFromRt(SurfaceControl sc) {
+ // Since we don't push the SurfaceParams to the RT we can release directly
+ sc.release();
+ }
+ };
+
+ @UiThread
+ public InsetsAnimationThreadControlRunner(SparseArray<InsetsSourceControl> controls, Rect frame,
+ InsetsState state, WindowInsetsAnimationControlListener listener,
+ @InsetsType int types,
+ InsetsAnimationControlCallbacks controller, long durationMs, Interpolator interpolator,
+ boolean fade, @AnimationType int animationType, Handler mainThreadHandler) {
+ mMainThreadHandler = mainThreadHandler;
+ mOuterCallbacks = controller;
+ mControl = new InsetsAnimationControlImpl(copyControls(controls), frame, state, listener,
+ types, mCallbacks, durationMs, interpolator, fade, animationType);
+ InsetsAnimationThread.getHandler().post(() -> listener.onReady(mControl, types));
+ }
+
+ private void releaseControls(SparseArray<InsetsSourceControl> controls) {
+ for (int i = controls.size() - 1; i >= 0; i--) {
+ controls.valueAt(i).release(SurfaceControl::release);
+ }
+ }
+
+ private SparseArray<InsetsSourceControl> copyControls(
+ SparseArray<InsetsSourceControl> controls) {
+ SparseArray<InsetsSourceControl> copy = new SparseArray<>(controls.size());
+ for (int i = 0; i < controls.size(); i++) {
+ copy.append(controls.keyAt(i), new InsetsSourceControl(controls.valueAt(i)));
+ }
+ return copy;
+ }
+
+ @Override
+ @UiThread
+ public int getTypes() {
+ return mControl.getTypes();
+ }
+
+ @Override
+ @UiThread
+ public void cancel() {
+ InsetsAnimationThread.getHandler().post(mControl::cancel);
+ }
+
+ @Override
+ @UiThread
+ public WindowInsetsAnimation getAnimation() {
+ return mControl.getAnimation();
+ }
+
+ @Override
+ public int getAnimationType() {
+ return mControl.getAnimationType();
+ }
+}
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 302d4f3..88e7f2e 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -23,6 +23,7 @@
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_APPEARANCE_CONTROLLED;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_BEHAVIOR_CONTROLLED;
+import android.animation.AnimationHandler;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
@@ -52,6 +53,8 @@
import android.view.animation.PathInterpolator;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
+import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -59,6 +62,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Objects;
import java.util.function.BiFunction;
/**
@@ -165,10 +169,22 @@
private WindowInsetsAnimationController mController;
private ObjectAnimator mAnimator;
- protected boolean mShow;
+ private final boolean mShow;
+ private final boolean mUseSfVsync;
- public InternalAnimationControlListener(boolean show) {
+ private ThreadLocal<AnimationHandler> mSfAnimationHandlerThreadLocal =
+ new ThreadLocal<AnimationHandler>() {
+ @Override
+ protected AnimationHandler initialValue() {
+ AnimationHandler handler = new AnimationHandler();
+ handler.setProvider(new SfVsyncFrameCallbackProvider());
+ return handler;
+ }
+ };
+
+ public InternalAnimationControlListener(boolean show, boolean useSfVsync) {
mShow = show;
+ mUseSfVsync = useSfVsync;
}
@Override
@@ -191,6 +207,9 @@
onAnimationFinish();
}
});
+ if (mUseSfVsync) {
+ mAnimator.setAnimationHandler(mSfAnimationHandlerThreadLocal.get());
+ }
mAnimator.start();
}
@@ -226,12 +245,12 @@
*/
private static class RunningAnimation {
- RunningAnimation(InsetsAnimationControlImpl control, int type) {
- this.control = control;
+ RunningAnimation(InsetsAnimationControlRunner runner, int type) {
+ this.runner = runner;
this.type = type;
}
- final InsetsAnimationControlImpl control;
+ final InsetsAnimationControlRunner runner;
final @AnimationType int type;
/**
@@ -250,7 +269,7 @@
PendingControlRequest(@InsetsType int types, WindowInsetsAnimationControlListener listener,
long durationMs, Interpolator interpolator, @AnimationType int animationType,
@LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation,
- CancellationSignal cancellationSignal) {
+ CancellationSignal cancellationSignal, boolean useInsetsAnimationThread) {
this.types = types;
this.listener = listener;
this.durationMs = durationMs;
@@ -258,6 +277,7 @@
this.animationType = animationType;
this.layoutInsetsDuringAnimation = layoutInsetsDuringAnimation;
this.cancellationSignal = cancellationSignal;
+ this.useInsetsAnimationThread = useInsetsAnimationThread;
}
final @InsetsType int types;
@@ -267,6 +287,7 @@
final @AnimationType int animationType;
final @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation;
final CancellationSignal cancellationSignal;
+ final boolean useInsetsAnimationThread;
}
private final String TAG = "InsetsControllerImpl";
@@ -306,6 +327,11 @@
private SyncRtSurfaceTransactionApplier mApplier;
private Runnable mPendingControlTimeout = this::abortPendingImeControlRequest;
+ private final ArrayList<OnControllableInsetsChangedListener> mControllableInsetsChangedListeners
+ = new ArrayList<>();
+
+ /** Set of inset types for which an animation was started since last resetting this field */
+ private @InsetsType int mLastStartedAnimTypes;
public InsetsController(ViewRootImpl viewRoot) {
this(viewRoot, (controller, type) -> {
@@ -340,15 +366,20 @@
InsetsState state = new InsetsState(mState, true /* copySources */);
for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
RunningAnimation runningAnimation = mRunningAnimations.get(i);
- InsetsAnimationControlImpl control = runningAnimation.control;
+ InsetsAnimationControlRunner runner = runningAnimation.runner;
+ if (runner instanceof InsetsAnimationControlImpl) {
+ InsetsAnimationControlImpl control = (InsetsAnimationControlImpl) runner;
- // Keep track of running animation to be dispatched. Aggregate it here such that if
- // it gets finished within applyChangeInsets we still dispatch it to onProgress.
- if (runningAnimation.startDispatched) {
- mTmpRunningAnims.add(control.getAnimation());
- }
- if (control.applyChangeInsets(state)) {
- mTmpFinishedControls.add(control);
+ // Keep track of running animation to be dispatched. Aggregate it here such that
+ // if it gets finished within applyChangeInsets we still dispatch it to
+ // onProgress.
+ if (runningAnimation.startDispatched) {
+ mTmpRunningAnims.add(control.getAnimation());
+ }
+
+ if (control.applyChangeInsets(state)) {
+ mTmpFinishedControls.add(control);
+ }
}
}
@@ -459,6 +490,13 @@
}
mTmpControlArray.clear();
+
+ // Do not override any animations that the app started in the OnControllableInsetsChanged
+ // listeners.
+ int animatingTypes = invokeControllableInsetsChangedListeners();
+ showTypes[0] &= ~animatingTypes;
+ hideTypes[0] &= ~animatingTypes;
+
if (showTypes[0] != 0) {
applyAnimation(showTypes[0], true /* show */, false /* fromIme */);
}
@@ -485,7 +523,8 @@
pendingRequest.listener, mFrame,
true /* fromIme */, pendingRequest.durationMs, pendingRequest.interpolator,
false /* fade */, pendingRequest.animationType,
- pendingRequest.layoutInsetsDuringAnimation);
+ pendingRequest.layoutInsetsDuringAnimation,
+ pendingRequest.useInsetsAnimationThread);
pendingRequest.cancellationSignal.setOnCancelListener(cancellationSignal::cancel);
return;
}
@@ -542,23 +581,30 @@
private CancellationSignal controlWindowInsetsAnimation(@InsetsType int types,
WindowInsetsAnimationControlListener listener, boolean fromIme, long durationMs,
@Nullable Interpolator interpolator, @AnimationType int animationType) {
- // If the frame of our window doesn't span the entire display, the control API makes very
- // little sense, as we don't deal with negative insets. So just cancel immediately.
- if (!mState.getDisplayFrame().equals(mFrame)) {
+ if (!checkDisplayFramesForControlling()) {
listener.onCancelled();
CancellationSignal cancellationSignal = new CancellationSignal();
cancellationSignal.cancel();
return cancellationSignal;
}
return controlAnimationUnchecked(types, listener, mFrame, fromIme, durationMs, interpolator,
- false /* fade */, animationType, getLayoutInsetsDuringAnimationMode(types));
+ false /* fade */, animationType, getLayoutInsetsDuringAnimationMode(types),
+ false /* useInsetsAnimationThread */);
+ }
+
+ private boolean checkDisplayFramesForControlling() {
+
+ // If the frame of our window doesn't span the entire display, the control API makes very
+ // little sense, as we don't deal with negative insets. So just cancel immediately.
+ return mState.getDisplayFrame().equals(mFrame);
}
private CancellationSignal controlAnimationUnchecked(@InsetsType int types,
WindowInsetsAnimationControlListener listener, Rect frame, boolean fromIme,
long durationMs, Interpolator interpolator, boolean fade,
@AnimationType int animationType,
- @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation) {
+ @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation,
+ boolean useInsetsAnimationThread) {
CancellationSignal cancellationSignal = new CancellationSignal();
if (types == 0) {
// nothing to animate.
@@ -567,6 +613,7 @@
return cancellationSignal;
}
cancelExistingControllers(types);
+ mLastStartedAnimTypes |= types;
final ArraySet<Integer> internalTypes = InsetsState.toInternalType(types);
final SparseArray<InsetsSourceControl> controls = new SparseArray<>();
@@ -580,7 +627,8 @@
abortPendingImeControlRequest();
final PendingControlRequest request = new PendingControlRequest(types,
listener, durationMs,
- interpolator, animationType, layoutInsetsDuringAnimation, cancellationSignal);
+ interpolator, animationType, layoutInsetsDuringAnimation, cancellationSignal,
+ useInsetsAnimationThread);
mPendingImeControlRequest = request;
mHandler.postDelayed(mPendingControlTimeout, PENDING_CONTROL_TIMEOUT_MS);
cancellationSignal.setOnCancelListener(() -> {
@@ -597,11 +645,21 @@
return cancellationSignal;
}
- final InsetsAnimationControlImpl controller = new InsetsAnimationControlImpl(controls,
- frame, mState, listener, typesReady, this, durationMs, interpolator, fade,
- layoutInsetsDuringAnimation, animationType);
- mRunningAnimations.add(new RunningAnimation(controller, animationType));
- cancellationSignal.setOnCancelListener(controller::onCancelled);
+
+ final InsetsAnimationControlRunner runner = useInsetsAnimationThread
+ ? new InsetsAnimationThreadControlRunner(controls,
+ frame, mState, listener, typesReady, this, durationMs, interpolator, fade,
+ animationType, mViewRoot.mHandler)
+ : new InsetsAnimationControlImpl(controls,
+ frame, mState, listener, typesReady, this, durationMs, interpolator, fade,
+ animationType);
+ mRunningAnimations.add(new RunningAnimation(runner, animationType));
+ cancellationSignal.setOnCancelListener(runner::cancel);
+ if (layoutInsetsDuringAnimation == LAYOUT_INSETS_DURING_ANIMATION_SHOWN) {
+ showDirectly(types);
+ } else {
+ hideDirectly(types, false /* animationFinished */, animationType);
+ }
return cancellationSignal;
}
@@ -646,7 +704,7 @@
}
final InsetsSourceControl control = consumer.getControl();
if (control != null) {
- controls.put(consumer.getType(), control);
+ controls.put(consumer.getType(), new InsetsSourceControl(control));
typesReady |= toPublicType(consumer.getType());
} else if (animationType == ANIMATION_TYPE_SHOW) {
@@ -685,7 +743,7 @@
private void cancelExistingControllers(@InsetsType int types) {
for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
- InsetsAnimationControlImpl control = mRunningAnimations.get(i).control;
+ InsetsAnimationControlRunner control = mRunningAnimations.get(i).runner;
if ((control.getTypes() & types) != 0) {
cancelAnimation(control, true /* invokeCallback */);
}
@@ -705,13 +763,13 @@
@VisibleForTesting
@Override
- public void notifyFinished(InsetsAnimationControlImpl controller, boolean shown) {
- cancelAnimation(controller, false /* invokeCallback */);
+ public void notifyFinished(InsetsAnimationControlRunner runner, boolean shown) {
+ cancelAnimation(runner, false /* invokeCallback */);
if (shown) {
- showDirectly(controller.getTypes());
+ showDirectly(runner.getTypes());
} else {
- hideDirectly(controller.getTypes(), true /* animationFinished */,
- controller.getAnimationType());
+ hideDirectly(runner.getTypes(), true /* animationFinished */,
+ runner.getAnimationType());
}
}
@@ -736,7 +794,7 @@
void notifyControlRevoked(InsetsSourceConsumer consumer) {
for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
- InsetsAnimationControlImpl control = mRunningAnimations.get(i).control;
+ InsetsAnimationControlRunner control = mRunningAnimations.get(i).runner;
if ((control.getTypes() & toPublicType(consumer.getType())) != 0) {
cancelAnimation(control, true /* invokeCallback */);
}
@@ -746,12 +804,12 @@
}
}
- private void cancelAnimation(InsetsAnimationControlImpl control, boolean invokeCallback) {
+ private void cancelAnimation(InsetsAnimationControlRunner control, boolean invokeCallback) {
if (invokeCallback) {
- control.onCancelled();
+ control.cancel();
}
for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
- if (mRunningAnimations.get(i).control == control) {
+ if (mRunningAnimations.get(i).runner == control) {
mRunningAnimations.remove(i);
break;
}
@@ -824,7 +882,7 @@
@VisibleForTesting
public @AnimationType int getAnimationType(@InternalInsetsType int type) {
for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
- InsetsAnimationControlImpl control = mRunningAnimations.get(i).control;
+ InsetsAnimationControlRunner control = mRunningAnimations.get(i).runner;
if (control.controlsInternalType(type)) {
return mRunningAnimations.get(i).type;
}
@@ -858,15 +916,24 @@
return;
}
+ boolean useInsetsAnimationThread = canUseInsetsAnimationThread();
final InternalAnimationControlListener listener =
- new InternalAnimationControlListener(show);
+ new InternalAnimationControlListener(show, useInsetsAnimationThread);
// Show/hide animations always need to be relative to the display frame, in order that shown
// and hidden state insets are correct.
controlAnimationUnchecked(
types, listener, mState.getDisplayFrame(), fromIme, listener.getDurationMs(),
INTERPOLATOR, true /* fade */, show ? ANIMATION_TYPE_SHOW : ANIMATION_TYPE_HIDE,
show ? LAYOUT_INSETS_DURING_ANIMATION_SHOWN
- : LAYOUT_INSETS_DURING_ANIMATION_HIDDEN);
+ : LAYOUT_INSETS_DURING_ANIMATION_HIDDEN,
+ useInsetsAnimationThread);
+ }
+
+ private boolean canUseInsetsAnimationThread() {
+ if (mViewRoot.mView == null) {
+ return true;
+ }
+ return !mViewRoot.mView.hasWindowInsetsAnimationCallback();
}
private void hideDirectly(
@@ -901,13 +968,7 @@
@Override
public void startAnimation(InsetsAnimationControlImpl controller,
WindowInsetsAnimationControlListener listener, int types,
- WindowInsetsAnimation animation, Bounds bounds, int layoutDuringAnimation) {
- if (layoutDuringAnimation == LAYOUT_INSETS_DURING_ANIMATION_SHOWN) {
- showDirectly(types);
- } else {
- hideDirectly(types, false /* animationFinished */, controller.getAnimationType());
- }
-
+ WindowInsetsAnimation animation, Bounds bounds) {
if (mViewRoot.mView == null) {
return;
}
@@ -921,7 +982,7 @@
}
for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
RunningAnimation runningAnimation = mRunningAnimations.get(i);
- if (runningAnimation.control == controller) {
+ if (runningAnimation.runner == controller) {
runningAnimation.startDispatched = true;
}
}
@@ -994,6 +1055,48 @@
return mViewRoot.mWindowAttributes.insetsFlags.behavior;
}
+ private @InsetsType int calculateControllableTypes() {
+ if (!checkDisplayFramesForControlling()) {
+ return 0;
+ }
+ @InsetsType int result = 0;
+ for (int i = mSourceConsumers.size() - 1; i >= 0; i--) {
+ InsetsSourceConsumer consumer = mSourceConsumers.valueAt(i);
+ if (consumer.getControl() != null) {
+ result |= toPublicType(consumer.mType);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * @return The types that are now animating due to a listener invoking control/show/hide
+ */
+ private @InsetsType int invokeControllableInsetsChangedListeners() {
+ mLastStartedAnimTypes = 0;
+ @InsetsType int types = calculateControllableTypes();
+ int size = mControllableInsetsChangedListeners.size();
+ for (int i = 0; i < size; i++) {
+ mControllableInsetsChangedListeners.get(i).onControllableInsetsChanged(this, types);
+ }
+ return mLastStartedAnimTypes;
+ }
+
+ @Override
+ public void addOnControllableInsetsChangedListener(
+ OnControllableInsetsChangedListener listener) {
+ Objects.requireNonNull(listener);
+ mControllableInsetsChangedListeners.add(listener);
+ listener.onControllableInsetsChanged(this, calculateControllableTypes());
+ }
+
+ @Override
+ public void removeOnControllableInsetsChangedListener(
+ OnControllableInsetsChangedListener listener) {
+ Objects.requireNonNull(listener);
+ mControllableInsetsChangedListeners.remove(listener);
+ }
+
/**
* At the time we receive new leashes (e.g. InsetsSourceConsumer is processing
* setControl) we need to release the old leash. But we may have already scheduled
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index 252fc0c..3325734 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -117,7 +117,7 @@
}
}
if (lastControl != null) {
- lastControl.release(mController);
+ lastControl.release(mController::releaseSurfaceControlFromRt);
}
}
diff --git a/core/java/android/view/InsetsSourceControl.java b/core/java/android/view/InsetsSourceControl.java
index 75f6eab..f3ec65f 100644
--- a/core/java/android/view/InsetsSourceControl.java
+++ b/core/java/android/view/InsetsSourceControl.java
@@ -22,6 +22,8 @@
import android.os.Parcelable;
import android.view.InsetsState.InternalInsetsType;
+import java.util.function.Consumer;
+
/**
* Represents a parcelable object to allow controlling a single {@link InsetsSource}.
* @hide
@@ -94,9 +96,9 @@
dest.writeParcelable(mSurfacePosition, 0 /* flags*/);
}
- public void release(InsetsController controller) {
+ public void release(Consumer<SurfaceControl> surfaceReleaseConsumer) {
if (mLeash != null) {
- controller.releaseSurfaceControlFromRt(mLeash);
+ surfaceReleaseConsumer.accept(mLeash);
}
}
diff --git a/core/java/android/view/PendingInsetsController.java b/core/java/android/view/PendingInsetsController.java
index c0ed935..7f36418 100644
--- a/core/java/android/view/PendingInsetsController.java
+++ b/core/java/android/view/PendingInsetsController.java
@@ -38,6 +38,8 @@
private @Behavior int mBehavior = KEEP_BEHAVIOR;
private final InsetsState mDummyState = new InsetsState();
private InsetsController mReplayedInsetsController;
+ private ArrayList<OnControllableInsetsChangedListener> mControllableInsetsChangedListeners
+ = new ArrayList<>();
@Override
public void show(int types) {
@@ -112,6 +114,27 @@
return mDummyState;
}
+ @Override
+ public void addOnControllableInsetsChangedListener(
+ OnControllableInsetsChangedListener listener) {
+ if (mReplayedInsetsController != null) {
+ mReplayedInsetsController.addOnControllableInsetsChangedListener(listener);
+ } else {
+ mControllableInsetsChangedListeners.add(listener);
+ listener.onControllableInsetsChanged(this, 0);
+ }
+ }
+
+ @Override
+ public void removeOnControllableInsetsChangedListener(
+ OnControllableInsetsChangedListener listener) {
+ if (mReplayedInsetsController != null) {
+ mReplayedInsetsController.removeOnControllableInsetsChangedListener(listener);
+ } else {
+ mControllableInsetsChangedListeners.remove(listener);
+ }
+ }
+
/**
* Replays the commands on {@code controller} and attaches it to this instance such that any
* calls will be forwarded to the real instance in the future.
@@ -128,9 +151,15 @@
for (int i = 0; i < size; i++) {
mRequests.get(i).replay(controller);
}
+ size = mControllableInsetsChangedListeners.size();
+ for (int i = 0; i < size; i++) {
+ controller.addOnControllableInsetsChangedListener(
+ mControllableInsetsChangedListeners.get(i));
+ }
// Reset all state so it doesn't get applied twice just in case
mRequests.clear();
+ mControllableInsetsChangedListeners.clear();
mBehavior = KEEP_BEHAVIOR;
mAppearance = 0;
mAppearanceMask = 0;
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 6236e6e..e665f06 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3318,7 +3318,7 @@
* Flag indicating that the view is autofilled
*
* @see #isAutofilled()
- * @see #setAutofilled(boolean)
+ * @see #setAutofilled(boolean, boolean)
*/
private static final int PFLAG3_IS_AUTOFILLED = 0x10000;
@@ -3428,6 +3428,7 @@
* 1 PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE
* 11 PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK
* 1 PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS
+ * 1 PFLAG4_AUTOFILL_HIDE_HIGHLIGHT
* |-------|-------|-------|-------|
*/
@@ -3470,6 +3471,11 @@
*/
static final int PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS = 0x000000100;
+ /**
+ * Flag indicating the field should not have yellow highlight when autofilled.
+ */
+ private static final int PFLAG4_AUTOFILL_HIDE_HIGHLIGHT = 0x100;
+
/* End of masks for mPrivateFlags4 */
/** @hide */
@@ -9170,6 +9176,13 @@
}
/**
+ * @hide
+ */
+ public boolean hideAutofillHighlight() {
+ return (mPrivateFlags4 & PFLAG4_AUTOFILL_HIDE_HIGHLIGHT) != 0;
+ }
+
+ /**
* Gets the {@link View}'s current autofill value.
*
* <p>By default returns {@code null}, but subclasses should override it and return an
@@ -11227,6 +11240,15 @@
}
/**
+ * @return {@code true} if any {@link WindowInsetsAnimation.Callback} is registered on the view
+ * or view tree of the sub-hierarchy {@code false} otherwise.
+ * @hide
+ */
+ public boolean hasWindowInsetsAnimationCallback() {
+ return getListenerInfo().mWindowInsetsAnimationCallback != null;
+ }
+
+ /**
* Dispatches {@link WindowInsetsAnimation.Callback#onPrepare(WindowInsetsAnimation)}
* when Window Insets animation is being prepared.
* @param animation current animation
@@ -11741,7 +11763,7 @@
* @hide
*/
@TestApi
- public void setAutofilled(boolean isAutofilled) {
+ public void setAutofilled(boolean isAutofilled, boolean hideHighlight) {
boolean wasChanged = isAutofilled != isAutofilled();
if (wasChanged) {
@@ -11751,6 +11773,12 @@
mPrivateFlags3 &= ~PFLAG3_IS_AUTOFILLED;
}
+ if (hideHighlight) {
+ mPrivateFlags4 |= PFLAG4_AUTOFILL_HIDE_HIGHLIGHT;
+ } else {
+ mPrivateFlags4 &= ~PFLAG4_AUTOFILL_HIDE_HIGHLIGHT;
+ }
+
invalidate();
}
}
@@ -20569,6 +20597,7 @@
state.mStartActivityRequestWhoSaved = mStartActivityRequestWho;
state.mIsAutofilled = isAutofilled();
+ state.mHideHighlight = hideAutofillHighlight();
state.mAutofillViewId = mAutofillViewId;
return state;
}
@@ -20645,7 +20674,7 @@
mStartActivityRequestWho = baseState.mStartActivityRequestWhoSaved;
}
if ((baseState.mSavedData & BaseSavedState.IS_AUTOFILLED) != 0) {
- setAutofilled(baseState.mIsAutofilled);
+ setAutofilled(baseState.mIsAutofilled, baseState.mHideHighlight);
}
if ((baseState.mSavedData & BaseSavedState.AUTOFILL_ID) != 0) {
// It can happen that views have the same view id and the restoration path will not
@@ -24078,12 +24107,13 @@
}
/**
- * Draw {@link View#isAutofilled()} highlight over view if the view is autofilled.
+ * Draw {@link View#isAutofilled()} highlight over view if the view is autofilled, unless
+ * {@link #PFLAG4_AUTOFILL_HIDE_HIGHLIGHT} is enabled.
*
* @param canvas The canvas to draw on
*/
private void drawAutofilledHighlight(@NonNull Canvas canvas) {
- if (isAutofilled()) {
+ if (isAutofilled() && !hideAutofillHighlight()) {
Drawable autofilledHighlight = getAutofilledDrawable();
if (autofilledHighlight != null) {
@@ -28526,6 +28556,7 @@
int mSavedData;
String mStartActivityRequestWhoSaved;
boolean mIsAutofilled;
+ boolean mHideHighlight;
int mAutofillViewId;
/**
@@ -28549,6 +28580,7 @@
mSavedData = source.readInt();
mStartActivityRequestWhoSaved = source.readString();
mIsAutofilled = source.readBoolean();
+ mHideHighlight = source.readBoolean();
mAutofillViewId = source.readInt();
}
@@ -28568,6 +28600,7 @@
out.writeInt(mSavedData);
out.writeString(mStartActivityRequestWhoSaved);
out.writeBoolean(mIsAutofilled);
+ out.writeBoolean(mHideHighlight);
out.writeInt(mAutofillViewId);
}
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 7d4ec3d..e34e84c 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -7258,6 +7258,34 @@
: DISPATCH_MODE_CONTINUE_ON_SUBTREE;
}
+ /**
+ * @hide
+ */
+ @Override
+ public boolean hasWindowInsetsAnimationCallback() {
+ if (super.hasWindowInsetsAnimationCallback()) {
+ return true;
+ }
+
+ // If we are root-level content view that fits insets, we imitate consuming behavior, so
+ // no child will retrieve window insets animation callback.
+ // See dispatchWindowInsetsAnimationPrepare.
+ boolean isOptionalFitSystemWindows = (mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) != 0
+ || isFrameworkOptionalFitsSystemWindows();
+ if (isOptionalFitSystemWindows && mAttachInfo != null
+ && mAttachInfo.mContentOnApplyWindowInsetsListener != null) {
+ return false;
+ }
+
+ final int count = getChildCount();
+ for (int i = 0; i < count; i++) {
+ if (getChildAt(i).hasWindowInsetsAnimationCallback()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
@Override
public void dispatchWindowInsetsAnimationPrepare(
@NonNull WindowInsetsAnimation animation) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 9228fbd..26ac4fc 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -5699,9 +5699,9 @@
mTranslator.translateEventInScreenToAppWindow(event);
}
- // Enter touch mode if event is coming from a touch screen device.
+ // Enter touch mode on down or scroll from any type of a device.
final int action = event.getAction();
- if (event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN)) {
+ if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_SCROLL) {
ensureTouchMode(true);
}
@@ -9054,7 +9054,7 @@
@Override
public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
- boolean sync) {
+ float zoom, boolean sync) {
if (sync) {
try {
mWindowSession.wallpaperOffsetsComplete(asBinder());
diff --git a/core/java/android/view/WindowContainerTransaction.java b/core/java/android/view/WindowContainerTransaction.java
index e05c374..9c16e13 100644
--- a/core/java/android/view/WindowContainerTransaction.java
+++ b/core/java/android/view/WindowContainerTransaction.java
@@ -131,6 +131,31 @@
}
/**
+ * Set the windowing mode of children of a given root task, without changing
+ * the windowing mode of the Task itself. This can be used during transitions
+ * for example to make the activity render it's fullscreen configuration
+ * while the Task is still in PIP, so you can complete the animation.
+ *
+ * TODO(b/134365562): Can be removed once TaskOrg drives full-screen
+ */
+ public WindowContainerTransaction setActivityWindowingMode(IWindowContainer container,
+ int windowingMode) {
+ Change chg = getOrCreateChange(container.asBinder());
+ chg.mActivityWindowingMode = windowingMode;
+ return this;
+ }
+
+ /**
+ * Sets the windowing mode of the given container.
+ */
+ public WindowContainerTransaction setWindowingMode(IWindowContainer container,
+ int windowingMode) {
+ Change chg = getOrCreateChange(container.asBinder());
+ chg.mWindowingMode = windowingMode;
+ return this;
+ }
+
+ /**
* Sets whether a container or any of its children can be focusable. When {@code false}, no
* child can be focused; however, when {@code true}, it is still possible for children to be
* non-focusable due to WM policy.
@@ -235,6 +260,9 @@
private Rect mPinnedBounds = null;
private SurfaceControl.Transaction mBoundsChangeTransaction = null;
+ private int mActivityWindowingMode = -1;
+ private int mWindowingMode = -1;
+
public Change() {}
protected Change(Parcel in) {
@@ -251,6 +279,17 @@
mBoundsChangeTransaction =
SurfaceControl.Transaction.CREATOR.createFromParcel(in);
}
+
+ mWindowingMode = in.readInt();
+ mActivityWindowingMode = in.readInt();
+ }
+
+ public int getWindowingMode() {
+ return mWindowingMode;
+ }
+
+ public int getActivityWindowingMode() {
+ return mActivityWindowingMode;
}
public Configuration getConfiguration() {
@@ -340,6 +379,9 @@
if (mBoundsChangeTransaction != null) {
mBoundsChangeTransaction.writeToParcel(dest, flags);
}
+
+ dest.writeInt(mWindowingMode);
+ dest.writeInt(mActivityWindowingMode);
}
@Override
diff --git a/core/java/android/view/WindowInsetsController.java b/core/java/android/view/WindowInsetsController.java
index b7ca037..2ad557e 100644
--- a/core/java/android/view/WindowInsetsController.java
+++ b/core/java/android/view/WindowInsetsController.java
@@ -20,7 +20,9 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Insets;
+import android.inputmethodservice.InputMethodService;
import android.os.CancellationSignal;
+import android.view.WindowInsets.Type;
import android.view.WindowInsets.Type.InsetsType;
import android.view.animation.Interpolator;
@@ -212,4 +214,55 @@
* @hide
*/
InsetsState getState();
+
+ /**
+ * Adds a {@link OnControllableInsetsChangedListener} to the window insets controller.
+ *
+ * @param listener The listener to add.
+ *
+ * @see OnControllableInsetsChangedListener
+ * @see #removeOnControllableInsetsChangedListener(OnControllableInsetsChangedListener)
+ */
+ void addOnControllableInsetsChangedListener(
+ @NonNull OnControllableInsetsChangedListener listener);
+
+ /**
+ * Removes a {@link OnControllableInsetsChangedListener} from the window insets controller.
+ *
+ * @param listener The listener to remove.
+ *
+ * @see OnControllableInsetsChangedListener
+ * @see #addOnControllableInsetsChangedListener(OnControllableInsetsChangedListener)
+ */
+ void removeOnControllableInsetsChangedListener(
+ @NonNull OnControllableInsetsChangedListener listener);
+
+ /**
+ * Listener to be notified when the set of controllable {@link InsetsType} controlled by a
+ * {@link WindowInsetsController} changes.
+ * <p>
+ * Once a {@link InsetsType} becomes controllable, the app will be able to control the window
+ * that is causing this type of insets by calling {@link #controlWindowInsetsAnimation}.
+ * <p>
+ * Note: When listening to controllability of the {@link Type#ime},
+ * {@link #controlWindowInsetsAnimation} may still fail in case the {@link InputMethodService}
+ * decides to cancel the show request. This could happen when there is a hardware keyboard
+ * attached.
+ *
+ * @see #addOnControllableInsetsChangedListener(OnControllableInsetsChangedListener)
+ * @see #removeOnControllableInsetsChangedListener(OnControllableInsetsChangedListener)
+ */
+ interface OnControllableInsetsChangedListener {
+
+ /**
+ * Called when the set of controllable {@link InsetsType} changes.
+ *
+ * @param controller The controller for which the set of controllable {@link InsetsType}s
+ * are changing.
+ * @param typeMask Bitwise type-mask of the {@link InsetsType}s the controller is currently
+ * able to control.
+ */
+ void onControllableInsetsChanged(@NonNull WindowInsetsController controller,
+ @InsetsType int typeMask);
+ }
}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 867b648..c5fa3c8 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -805,6 +805,7 @@
@ViewDebug.IntToString(from = TYPE_APPLICATION_OVERLAY,
to = "APPLICATION_OVERLAY")
})
+ @WindowType
public int type;
/**
@@ -1244,13 +1245,47 @@
public static final int INVALID_WINDOW_TYPE = -1;
/**
+ * @hide
+ */
+ @IntDef(prefix = "TYPE_", value = {
+ TYPE_ACCESSIBILITY_OVERLAY,
+ TYPE_APPLICATION,
+ TYPE_APPLICATION_ATTACHED_DIALOG,
+ TYPE_APPLICATION_MEDIA,
+ TYPE_APPLICATION_OVERLAY,
+ TYPE_APPLICATION_PANEL,
+ TYPE_APPLICATION_STARTING,
+ TYPE_APPLICATION_SUB_PANEL,
+ TYPE_BASE_APPLICATION,
+ TYPE_DRAWN_APPLICATION,
+ TYPE_INPUT_METHOD,
+ TYPE_INPUT_METHOD_DIALOG,
+ TYPE_KEYGUARD,
+ TYPE_KEYGUARD_DIALOG,
+ TYPE_PHONE,
+ TYPE_PRIORITY_PHONE,
+ TYPE_PRIVATE_PRESENTATION,
+ TYPE_SEARCH_BAR,
+ TYPE_STATUS_BAR,
+ TYPE_STATUS_BAR_PANEL,
+ TYPE_SYSTEM_ALERT,
+ TYPE_SYSTEM_DIALOG,
+ TYPE_SYSTEM_ERROR,
+ TYPE_SYSTEM_OVERLAY,
+ TYPE_TOAST,
+ TYPE_WALLPAPER,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface WindowType {}
+
+ /**
* Return true if the window type is an alert window.
*
* @param type The window type.
* @return If the window type is an alert window.
* @hide
*/
- public static boolean isSystemAlertWindowType(int type) {
+ public static boolean isSystemAlertWindowType(@WindowType int type) {
switch (type) {
case TYPE_PHONE:
case TYPE_PRIORITY_PHONE:
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index 01a1c77..410d9af 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -504,6 +504,7 @@
}
void doRemoveView(ViewRootImpl root) {
+ boolean allViewsRemoved;
synchronized (mLock) {
final int index = mRoots.indexOf(root);
if (index >= 0) {
@@ -512,10 +513,17 @@
final View view = mViews.remove(index);
mDyingViews.remove(view);
}
+ allViewsRemoved = mRoots.isEmpty();
}
if (ThreadedRenderer.sTrimForeground && ThreadedRenderer.isAvailable()) {
doTrimForeground();
}
+
+ // If we don't have any views anymore in our process, we no longer need the
+ // InsetsAnimationThread to save some resources.
+ if (allViewsRemoved) {
+ InsetsAnimationThread.release();
+ }
}
private int findViewLocked(View view, boolean required) {
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index 87dcba0..144f8e3 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -312,6 +312,14 @@
}
@Override
+ public void setWallpaperZoomOut(android.os.IBinder windowToken, float zoom) {
+ }
+
+ @Override
+ public void setShouldZoomOutWallpaper(android.os.IBinder windowToken, boolean shouldZoom) {
+ }
+
+ @Override
public void wallpaperOffsetsComplete(android.os.IBinder window) {
}
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index ce7cfa7..39a9ed4 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -17,6 +17,7 @@
package android.view.autofill;
import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
+import static android.service.autofill.FillRequest.FLAG_PASSWORD_INPUT_TYPE;
import static android.view.autofill.Helper.sDebug;
import static android.view.autofill.Helper.sVerbose;
import static android.view.autofill.Helper.toList;
@@ -63,6 +64,7 @@
import android.view.accessibility.AccessibilityNodeProvider;
import android.view.accessibility.AccessibilityWindowInfo;
import android.widget.EditText;
+import android.widget.TextView;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.logging.MetricsLogger;
@@ -983,6 +985,10 @@
if (!isClientDisablingEnterExitEvent()) {
final AutofillValue value = view.getAutofillValue();
+ if (view instanceof TextView && ((TextView) view).isAnyPasswordInputType()) {
+ flags |= FLAG_PASSWORD_INPUT_TYPE;
+ }
+
if (!isActiveLocked()) {
// Starts new session.
startSessionLocked(id, null, value, flags);
@@ -1149,6 +1155,10 @@
} else {
// don't notify entered when Activity is already in background
if (!isClientDisablingEnterExitEvent()) {
+ if (view instanceof TextView && ((TextView) view).isAnyPasswordInputType()) {
+ flags |= FLAG_PASSWORD_INPUT_TYPE;
+ }
+
if (!isActiveLocked()) {
// Starts new session.
startSessionLocked(id, bounds, null, flags);
@@ -1226,7 +1236,7 @@
// If the session is gone some fields might still be highlighted, hence we have to
// remove the isAutofilled property even if no sessions are active.
if (mLastAutofilledData == null) {
- view.setAutofilled(false);
+ view.setAutofilled(false, false);
} else {
id = view.getAutofillId();
if (mLastAutofilledData.containsKey(id)) {
@@ -1234,13 +1244,13 @@
valueWasRead = true;
if (Objects.equals(mLastAutofilledData.get(id), value)) {
- view.setAutofilled(true);
+ view.setAutofilled(true, false);
} else {
- view.setAutofilled(false);
+ view.setAutofilled(false, false);
mLastAutofilledData.remove(id);
}
} else {
- view.setAutofilled(false);
+ view.setAutofilled(false, false);
}
}
@@ -2156,7 +2166,8 @@
* @param view The view that is to be autofilled
* @param targetValue The value we want to fill into view
*/
- private void setAutofilledIfValuesIs(@NonNull View view, @Nullable AutofillValue targetValue) {
+ private void setAutofilledIfValuesIs(@NonNull View view, @Nullable AutofillValue targetValue,
+ boolean hideHighlight) {
AutofillValue currentValue = view.getAutofillValue();
if (Objects.equals(currentValue, targetValue)) {
synchronized (mLock) {
@@ -2165,11 +2176,12 @@
}
mLastAutofilledData.put(view.getAutofillId(), targetValue);
}
- view.setAutofilled(true);
+ view.setAutofilled(true, hideHighlight);
}
}
- private void autofill(int sessionId, List<AutofillId> ids, List<AutofillValue> values) {
+ private void autofill(int sessionId, List<AutofillId> ids, List<AutofillValue> values,
+ boolean hideHighlight) {
synchronized (mLock) {
if (sessionId != mSessionId) {
return;
@@ -2228,7 +2240,7 @@
// synchronously.
// If autofill happens async, the view is set to autofilled in
// notifyValueChanged.
- setAutofilledIfValuesIs(view, value);
+ setAutofilledIfValuesIs(view, value, hideHighlight);
numApplied++;
}
@@ -3246,10 +3258,11 @@
}
@Override
- public void autofill(int sessionId, List<AutofillId> ids, List<AutofillValue> values) {
+ public void autofill(int sessionId, List<AutofillId> ids, List<AutofillValue> values,
+ boolean hideHighlight) {
final AutofillManager afm = mAfm.get();
if (afm != null) {
- afm.post(() -> afm.autofill(sessionId, ids, values));
+ afm.post(() -> afm.autofill(sessionId, ids, values, hideHighlight));
}
}
@@ -3387,10 +3400,11 @@
}
@Override
- public void autofill(int sessionId, List<AutofillId> ids, List<AutofillValue> values) {
+ public void autofill(int sessionId, List<AutofillId> ids, List<AutofillValue> values,
+ boolean hideHighlight) {
final AutofillManager afm = mAfm.get();
if (afm != null) {
- afm.post(() -> afm.autofill(sessionId, ids, values));
+ afm.post(() -> afm.autofill(sessionId, ids, values, hideHighlight));
}
}
diff --git a/core/java/android/view/autofill/IAugmentedAutofillManagerClient.aidl b/core/java/android/view/autofill/IAugmentedAutofillManagerClient.aidl
index 03054df..8526c1e 100644
--- a/core/java/android/view/autofill/IAugmentedAutofillManagerClient.aidl
+++ b/core/java/android/view/autofill/IAugmentedAutofillManagerClient.aidl
@@ -38,7 +38,8 @@
/**
* Autofills the activity with the contents of the values.
*/
- void autofill(int sessionId, in List<AutofillId> ids, in List<AutofillValue> values);
+ void autofill(int sessionId, in List<AutofillId> ids, in List<AutofillValue> values,
+ boolean hideHighlight);
/**
* Requests showing the fill UI.
diff --git a/core/java/android/view/autofill/IAutoFillManagerClient.aidl b/core/java/android/view/autofill/IAutoFillManagerClient.aidl
index 3903665..4371b3c 100644
--- a/core/java/android/view/autofill/IAutoFillManagerClient.aidl
+++ b/core/java/android/view/autofill/IAutoFillManagerClient.aidl
@@ -44,7 +44,8 @@
/**
* Autofills the activity with the contents of a dataset.
*/
- void autofill(int sessionId, in List<AutofillId> ids, in List<AutofillValue> values);
+ void autofill(int sessionId, in List<AutofillId> ids, in List<AutofillValue> values,
+ boolean hideHighlight);
/**
* Authenticates a fill response or a data set.
diff --git a/core/java/android/view/inputmethod/InlineSuggestion.java b/core/java/android/view/inputmethod/InlineSuggestion.java
index 6500613..dd1738a 100644
--- a/core/java/android/view/inputmethod/InlineSuggestion.java
+++ b/core/java/android/view/inputmethod/InlineSuggestion.java
@@ -16,6 +16,7 @@
package android.view.inputmethod;
+import android.annotation.BinderThread;
import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -94,19 +95,21 @@
}
-
/**
* Inflates a view with the content of this suggestion at a specific size.
* The size must be between the {@link InlinePresentationSpec#getMinSize() min size}
* and the {@link InlinePresentationSpec#getMaxSize() max size} of the presentation
* spec returned by {@link InlineSuggestionInfo#getPresentationSpec()}.
*
- * @param context Context in which to inflate the view.
- * @param size The size at which to inflate the suggestion.
- * @param callback Callback for receiving the inflated view.
+ * <p> The caller can attach an {@link View.OnClickListener} and/or an
+ * {@link View.OnLongClickListener} to the view in the {@code callback} to receive click and
+ * long click events on the view.
*
+ * @param context Context in which to inflate the view.
+ * @param size The size at which to inflate the suggestion.
+ * @param callback Callback for receiving the inflated view.
* @throws IllegalArgumentException If an invalid argument is passed.
- * @throws IllegalStateException if this method is already called.
+ * @throws IllegalStateException If this method is already called.
*/
public void inflate(@NonNull Context context, @NonNull Size size,
@NonNull @CallbackExecutor Executor callbackExecutor,
@@ -151,12 +154,31 @@
}
@Override
+ @BinderThread
public void onContent(SurfaceControlViewHost.SurfacePackage content) {
final InlineContentCallbackImpl callbackImpl = mCallbackImpl.get();
if (callbackImpl != null) {
callbackImpl.onContent(content);
}
}
+
+ @Override
+ @BinderThread
+ public void onClick() {
+ final InlineContentCallbackImpl callbackImpl = mCallbackImpl.get();
+ if (callbackImpl != null) {
+ callbackImpl.onClick();
+ }
+ }
+
+ @Override
+ @BinderThread
+ public void onLongClick() {
+ final InlineContentCallbackImpl callbackImpl = mCallbackImpl.get();
+ if (callbackImpl != null) {
+ callbackImpl.onLongClick();
+ }
+ }
}
private static final class InlineContentCallbackImpl {
@@ -164,6 +186,7 @@
private final @NonNull Context mContext;
private final @NonNull Executor mCallbackExecutor;
private final @NonNull Consumer<View> mCallback;
+ private @Nullable View mView;
InlineContentCallbackImpl(@NonNull Context context,
@NonNull @CallbackExecutor Executor callbackExecutor,
@@ -173,12 +196,27 @@
mCallback = callback;
}
+ @BinderThread
public void onContent(SurfaceControlViewHost.SurfacePackage content) {
if (content == null) {
mCallbackExecutor.execute(() -> mCallback.accept(/* view */null));
} else {
- mCallbackExecutor.execute(
- () -> mCallback.accept(new InlineContentView(mContext, content)));
+ mView = new InlineContentView(mContext, content);
+ mCallbackExecutor.execute(() -> mCallback.accept(mView));
+ }
+ }
+
+ @BinderThread
+ public void onClick() {
+ if (mView != null && mView.hasOnClickListeners()) {
+ mView.callOnClick();
+ }
+ }
+
+ @BinderThread
+ public void onLongClick() {
+ if (mView != null && mView.hasOnLongClickListeners()) {
+ mView.performLongClick();
}
}
}
@@ -201,7 +239,7 @@
- // Code below generated by codegen v1.0.14.
+ // Code below generated by codegen v1.0.15.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -360,8 +398,8 @@
};
@DataClass.Generated(
- time = 1581929285156L,
- codegenVersion = "1.0.14",
+ time = 1583889058241L,
+ codegenVersion = "1.0.15",
sourceFile = "frameworks/base/core/java/android/view/inputmethod/InlineSuggestion.java",
inputSignatures = "private static final java.lang.String TAG\nprivate final @android.annotation.NonNull android.view.inputmethod.InlineSuggestionInfo mInfo\nprivate final @android.annotation.Nullable com.android.internal.view.inline.IInlineContentProvider mContentProvider\nprivate @com.android.internal.util.DataClass.ParcelWith(android.view.inputmethod.InlineSuggestion.InlineContentCallbackImplParceling.class) @android.annotation.Nullable android.view.inputmethod.InlineSuggestion.InlineContentCallbackImpl mInlineContentCallback\npublic static @android.annotation.TestApi @android.annotation.NonNull android.view.inputmethod.InlineSuggestion newInlineSuggestion(android.view.inputmethod.InlineSuggestionInfo)\npublic void inflate(android.content.Context,android.util.Size,java.util.concurrent.Executor,java.util.function.Consumer<android.view.View>)\nprivate synchronized android.view.inputmethod.InlineSuggestion.InlineContentCallbackImpl getInlineContentCallback(android.content.Context,java.util.concurrent.Executor,java.util.function.Consumer<android.view.View>)\nclass InlineSuggestion extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genHiddenConstDefs=true, genHiddenConstructor=true)")
@Deprecated
diff --git a/core/java/android/view/inputmethod/InlineSuggestionsRequest.java b/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
index e50da40..8e8c7df 100644
--- a/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
+++ b/core/java/android/view/inputmethod/InlineSuggestionsRequest.java
@@ -44,15 +44,15 @@
public static final int SUGGESTION_COUNT_UNLIMITED = Integer.MAX_VALUE;
/**
- * Max number of suggestions expected from the response. Defaults to {@code
- * SUGGESTION_COUNT_UNLIMITED} if not set.
+ * Max number of suggestions expected from the response. It must be a positive value.
+ * Defaults to {@code SUGGESTION_COUNT_UNLIMITED} if not set.
*/
private final int mMaxSuggestionCount;
/**
* The {@link InlinePresentationSpec} for each suggestion in the response. If the max suggestion
* count is larger than the number of specs in the list, then the last spec is used for the
- * remainder of the suggestions.
+ * remainder of the suggestions. The list should not be empty.
*/
private final @NonNull List<InlinePresentationSpec> mPresentationSpecs;
@@ -72,6 +72,7 @@
/**
* The extras state propagated from the IME to pass extra data.
*/
+ @DataClass.MaySetToNull
private @Nullable Bundle mExtras;
/**
@@ -80,6 +81,7 @@
*
* @hide
*/
+ @DataClass.MaySetToNull
private @Nullable IBinder mHostInputToken;
/**
@@ -117,6 +119,7 @@
}
private void onConstructed() {
+ Preconditions.checkState(!mPresentationSpecs.isEmpty());
Preconditions.checkState(mMaxSuggestionCount >= mPresentationSpecs.size());
}
@@ -162,7 +165,7 @@
- // Code below generated by codegen v1.0.14.
+ // Code below generated by codegen v1.0.15.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -202,8 +205,8 @@
}
/**
- * Max number of suggestions expected from the response. Defaults to {@code
- * SUGGESTION_COUNT_UNLIMITED} if not set.
+ * Max number of suggestions expected from the response. It must be a positive value.
+ * Defaults to {@code SUGGESTION_COUNT_UNLIMITED} if not set.
*/
@DataClass.Generated.Member
public int getMaxSuggestionCount() {
@@ -213,7 +216,7 @@
/**
* The {@link InlinePresentationSpec} for each suggestion in the response. If the max suggestion
* count is larger than the number of specs in the list, then the last spec is used for the
- * remainder of the suggestions.
+ * remainder of the suggestions. The list should not be empty.
*/
@DataClass.Generated.Member
public @NonNull List<InlinePresentationSpec> getPresentationSpecs() {
@@ -419,7 +422,7 @@
* @param presentationSpecs
* The {@link InlinePresentationSpec} for each suggestion in the response. If the max suggestion
* count is larger than the number of specs in the list, then the last spec is used for the
- * remainder of the suggestions.
+ * remainder of the suggestions. The list should not be empty.
*/
public Builder(
@NonNull List<InlinePresentationSpec> presentationSpecs) {
@@ -429,8 +432,8 @@
}
/**
- * Max number of suggestions expected from the response. Defaults to {@code
- * SUGGESTION_COUNT_UNLIMITED} if not set.
+ * Max number of suggestions expected from the response. It must be a positive value.
+ * Defaults to {@code SUGGESTION_COUNT_UNLIMITED} if not set.
*/
@DataClass.Generated.Member
public @NonNull Builder setMaxSuggestionCount(int value) {
@@ -443,7 +446,7 @@
/**
* The {@link InlinePresentationSpec} for each suggestion in the response. If the max suggestion
* count is larger than the number of specs in the list, then the last spec is used for the
- * remainder of the suggestions.
+ * remainder of the suggestions. The list should not be empty.
*/
@DataClass.Generated.Member
@Override
@@ -575,10 +578,10 @@
}
@DataClass.Generated(
- time = 1582339908980L,
- codegenVersion = "1.0.14",
+ time = 1583975428858L,
+ codegenVersion = "1.0.15",
sourceFile = "frameworks/base/core/java/android/view/inputmethod/InlineSuggestionsRequest.java",
- inputSignatures = "public static final int SUGGESTION_COUNT_UNLIMITED\nprivate final int mMaxSuggestionCount\nprivate final @android.annotation.NonNull java.util.List<android.view.inline.InlinePresentationSpec> mPresentationSpecs\nprivate @android.annotation.NonNull java.lang.String mHostPackageName\nprivate @android.annotation.NonNull android.os.LocaleList mSupportedLocales\nprivate @android.annotation.Nullable android.os.Bundle mExtras\nprivate @android.annotation.Nullable android.os.IBinder mHostInputToken\nprivate int mHostDisplayId\npublic void setHostInputToken(android.os.IBinder)\nprivate void parcelHostInputToken(android.os.Parcel,int)\nprivate @android.annotation.Nullable android.os.IBinder unparcelHostInputToken(android.os.Parcel)\npublic void setHostDisplayId(int)\nprivate void onConstructed()\nprivate static int defaultMaxSuggestionCount()\nprivate static java.lang.String defaultHostPackageName()\nprivate static android.os.LocaleList defaultSupportedLocales()\nprivate static @android.annotation.Nullable android.os.IBinder defaultHostInputToken()\nprivate static @android.annotation.Nullable int defaultHostDisplayId()\nprivate static @android.annotation.Nullable android.os.Bundle defaultExtras()\nclass InlineSuggestionsRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genBuilder=true)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setPresentationSpecs(java.util.List<android.view.inline.InlinePresentationSpec>)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostPackageName(java.lang.String)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostInputToken(android.os.IBinder)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostDisplayId(int)\nclass BaseBuilder extends java.lang.Object implements []")
+ inputSignatures = "public static final int SUGGESTION_COUNT_UNLIMITED\nprivate final int mMaxSuggestionCount\nprivate final @android.annotation.NonNull java.util.List<android.view.inline.InlinePresentationSpec> mPresentationSpecs\nprivate @android.annotation.NonNull java.lang.String mHostPackageName\nprivate @android.annotation.NonNull android.os.LocaleList mSupportedLocales\nprivate @com.android.internal.util.DataClass.MaySetToNull @android.annotation.Nullable android.os.Bundle mExtras\nprivate @com.android.internal.util.DataClass.MaySetToNull @android.annotation.Nullable android.os.IBinder mHostInputToken\nprivate int mHostDisplayId\npublic void setHostInputToken(android.os.IBinder)\nprivate void parcelHostInputToken(android.os.Parcel,int)\nprivate @android.annotation.Nullable android.os.IBinder unparcelHostInputToken(android.os.Parcel)\npublic void setHostDisplayId(int)\nprivate void onConstructed()\nprivate static int defaultMaxSuggestionCount()\nprivate static java.lang.String defaultHostPackageName()\nprivate static android.os.LocaleList defaultSupportedLocales()\nprivate static @android.annotation.Nullable android.os.IBinder defaultHostInputToken()\nprivate static @android.annotation.Nullable int defaultHostDisplayId()\nprivate static @android.annotation.Nullable android.os.Bundle defaultExtras()\nclass InlineSuggestionsRequest extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genBuilder=true)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setPresentationSpecs(java.util.List<android.view.inline.InlinePresentationSpec>)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostPackageName(java.lang.String)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostInputToken(android.os.IBinder)\nabstract android.view.inputmethod.InlineSuggestionsRequest.Builder setHostDisplayId(int)\nclass BaseBuilder extends java.lang.Object implements []")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/view/textclassifier/ConversationActions.java b/core/java/android/view/textclassifier/ConversationActions.java
index 6246b50..842ba29 100644
--- a/core/java/android/view/textclassifier/ConversationActions.java
+++ b/core/java/android/view/textclassifier/ConversationActions.java
@@ -21,15 +21,12 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringDef;
-import android.annotation.UserIdInt;
import android.app.Person;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
-import android.os.UserHandle;
import android.text.SpannedString;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
@@ -317,13 +314,9 @@
@NonNull
@Hint
private final List<String> mHints;
- @Nullable
- private String mCallingPackageName;
- @UserIdInt
- private int mUserId = UserHandle.USER_NULL;
@NonNull
private Bundle mExtras;
- private boolean mUseDefaultTextClassifier;
+ @Nullable private SystemTextClassifierMetadata mSystemTcMetadata;
private Request(
@NonNull List<Message> conversation,
@@ -345,10 +338,8 @@
int maxSuggestions = in.readInt();
List<String> hints = new ArrayList<>();
in.readStringList(hints);
- String callingPackageName = in.readString();
- int userId = in.readInt();
Bundle extras = in.readBundle();
- boolean useDefaultTextClassifier = in.readBoolean();
+ SystemTextClassifierMetadata systemTcMetadata = in.readParcelable(null);
Request request = new Request(
conversation,
@@ -356,9 +347,7 @@
maxSuggestions,
hints,
extras);
- request.setCallingPackageName(callingPackageName);
- request.setUserId(userId);
- request.setUseDefaultTextClassifier(useDefaultTextClassifier);
+ request.setSystemTextClassifierMetadata(systemTcMetadata);
return request;
}
@@ -368,10 +357,8 @@
parcel.writeParcelable(mTypeConfig, flags);
parcel.writeInt(mMaxSuggestions);
parcel.writeStringList(mHints);
- parcel.writeString(mCallingPackageName);
- parcel.writeInt(mUserId);
parcel.writeBundle(mExtras);
- parcel.writeBoolean(mUseDefaultTextClassifier);
+ parcel.writeParcelable(mSystemTcMetadata, flags);
}
@Override
@@ -421,62 +408,31 @@
}
/**
- * Sets the name of the package that is sending this request.
- * <p>
- * Package-private for SystemTextClassifier's use.
- * @hide
- */
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
- public void setCallingPackageName(@Nullable String callingPackageName) {
- mCallingPackageName = callingPackageName;
- }
-
- /**
* Returns the name of the package that sent this request.
* This returns {@code null} if no calling package name is set.
*/
@Nullable
public String getCallingPackageName() {
- return mCallingPackageName;
+ return mSystemTcMetadata != null ? mSystemTcMetadata.getCallingPackageName() : null;
}
/**
- * Sets the id of the user that sent this request.
- * <p>
- * Package-private for SystemTextClassifier's use.
- * @hide
- */
- void setUserId(@UserIdInt int userId) {
- mUserId = userId;
- }
-
- /**
- * Returns the id of the user that sent this request.
- * @hide
- */
- @UserIdInt
- public int getUserId() {
- return mUserId;
- }
-
- /**
- * Sets whether to use the default text classifier to handle this request.
- * This will be ignored if it is not the system text classifier to handle this request.
+ * Sets the information about the {@link SystemTextClassifier} that sent this request.
*
* @hide
*/
- void setUseDefaultTextClassifier(boolean useDefaultTextClassifier) {
- mUseDefaultTextClassifier = useDefaultTextClassifier;
+ void setSystemTextClassifierMetadata(@Nullable SystemTextClassifierMetadata systemTcData) {
+ mSystemTcMetadata = systemTcData;
}
/**
- * Returns whether to use the default text classifier to handle this request. This
- * will be ignored if it is not the system text classifier to handle this request.
+ * Returns the information about the {@link SystemTextClassifier} that sent this request.
*
* @hide
*/
- public boolean getUseDefaultTextClassifier() {
- return mUseDefaultTextClassifier;
+ @Nullable
+ public SystemTextClassifierMetadata getSystemTextClassifierMetadata() {
+ return mSystemTcMetadata;
}
/**
diff --git a/core/java/android/view/textclassifier/SelectionEvent.java b/core/java/android/view/textclassifier/SelectionEvent.java
index e0f29a9..9a54544 100644
--- a/core/java/android/view/textclassifier/SelectionEvent.java
+++ b/core/java/android/view/textclassifier/SelectionEvent.java
@@ -19,10 +19,8 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.UserIdInt;
import android.os.Parcel;
import android.os.Parcelable;
-import android.os.UserHandle;
import android.view.textclassifier.TextClassifier.EntityType;
import android.view.textclassifier.TextClassifier.WidgetType;
@@ -129,7 +127,6 @@
private String mWidgetType = TextClassifier.WIDGET_TYPE_UNKNOWN;
private @InvocationMethod int mInvocationMethod;
@Nullable private String mWidgetVersion;
- private @UserIdInt int mUserId = UserHandle.USER_NULL;
@Nullable private String mResultId;
private long mEventTime;
private long mDurationSinceSessionStart;
@@ -140,7 +137,7 @@
private int mEnd;
private int mSmartStart;
private int mSmartEnd;
- private boolean mUseDefaultTextClassifier;
+ @Nullable private SystemTextClassifierMetadata mSystemTcMetadata;
SelectionEvent(
int start, int end,
@@ -161,6 +158,7 @@
mEventType = in.readInt();
mEntityType = in.readString();
mWidgetVersion = in.readInt() > 0 ? in.readString() : null;
+ // TODO: remove mPackageName once aiai does not need it
mPackageName = in.readString();
mWidgetType = in.readString();
mInvocationMethod = in.readInt();
@@ -175,8 +173,7 @@
mEnd = in.readInt();
mSmartStart = in.readInt();
mSmartEnd = in.readInt();
- mUserId = in.readInt();
- mUseDefaultTextClassifier = in.readBoolean();
+ mSystemTcMetadata = in.readParcelable(null);
}
@Override
@@ -189,6 +186,7 @@
if (mWidgetVersion != null) {
dest.writeString(mWidgetVersion);
}
+ // TODO: remove mPackageName once aiai does not need it
dest.writeString(mPackageName);
dest.writeString(mWidgetType);
dest.writeInt(mInvocationMethod);
@@ -205,8 +203,7 @@
dest.writeInt(mEnd);
dest.writeInt(mSmartStart);
dest.writeInt(mSmartEnd);
- dest.writeInt(mUserId);
- dest.writeBoolean(mUseDefaultTextClassifier);
+ dest.writeParcelable(mSystemTcMetadata, flags);
}
@Override
@@ -409,45 +406,26 @@
*/
@NonNull
public String getPackageName() {
- return mPackageName;
+ return mSystemTcMetadata != null ? mSystemTcMetadata.getCallingPackageName() : "";
}
/**
- * Sets the id of this event's user.
- * <p>
- * Package-private for SystemTextClassifier's use.
- */
- void setUserId(@UserIdInt int userId) {
- mUserId = userId;
- }
-
- /**
- * Returns the id of this event's user.
- * @hide
- */
- @UserIdInt
- public int getUserId() {
- return mUserId;
- }
-
- /**
- * Sets whether to use the default text classifier to handle this request.
- * This will be ignored if it is not the system text classifier to handle this request.
+ * Sets the information about the {@link SystemTextClassifier} that sent this request.
*
* @hide
*/
- void setUseDefaultTextClassifier(boolean useDefaultTextClassifier) {
- mUseDefaultTextClassifier = useDefaultTextClassifier;
+ void setSystemTextClassifierMetadata(@Nullable SystemTextClassifierMetadata systemTcMetadata) {
+ mSystemTcMetadata = systemTcMetadata;
}
/**
- * Returns whether to use the default text classifier to handle this request. This
- * will be ignored if it is not the system text classifier to handle this request.
+ * Returns the information about the {@link SystemTextClassifier} that sent this request.
*
* @hide
*/
- public boolean getUseDefaultTextClassifier() {
- return mUseDefaultTextClassifier;
+ @Nullable
+ public SystemTextClassifierMetadata getSystemTextClassifierMetadata() {
+ return mSystemTcMetadata;
}
/**
@@ -476,7 +454,7 @@
mPackageName = context.getPackageName();
mWidgetType = context.getWidgetType();
mWidgetVersion = context.getWidgetVersion();
- mUserId = context.getUserId();
+ mSystemTcMetadata = context.getSystemTextClassifierMetadata();
}
/**
@@ -663,10 +641,9 @@
@Override
public int hashCode() {
return Objects.hash(mAbsoluteStart, mAbsoluteEnd, mEventType, mEntityType,
- mWidgetVersion, mPackageName, mUserId, mWidgetType, mInvocationMethod, mResultId,
+ mWidgetVersion, mPackageName, mWidgetType, mInvocationMethod, mResultId,
mEventTime, mDurationSinceSessionStart, mDurationSincePreviousEvent,
- mEventIndex, mSessionId, mStart, mEnd, mSmartStart, mSmartEnd,
- mUseDefaultTextClassifier);
+ mEventIndex, mSessionId, mStart, mEnd, mSmartStart, mSmartEnd, mSystemTcMetadata);
}
@Override
@@ -685,7 +662,6 @@
&& Objects.equals(mEntityType, other.mEntityType)
&& Objects.equals(mWidgetVersion, other.mWidgetVersion)
&& Objects.equals(mPackageName, other.mPackageName)
- && mUserId == other.mUserId
&& Objects.equals(mWidgetType, other.mWidgetType)
&& mInvocationMethod == other.mInvocationMethod
&& Objects.equals(mResultId, other.mResultId)
@@ -698,7 +674,7 @@
&& mEnd == other.mEnd
&& mSmartStart == other.mSmartStart
&& mSmartEnd == other.mSmartEnd
- && mUseDefaultTextClassifier == other.mUseDefaultTextClassifier;
+ && mSystemTcMetadata == other.mSystemTcMetadata;
}
@Override
@@ -706,15 +682,14 @@
return String.format(Locale.US,
"SelectionEvent {absoluteStart=%d, absoluteEnd=%d, eventType=%d, entityType=%s, "
+ "widgetVersion=%s, packageName=%s, widgetType=%s, invocationMethod=%s, "
- + "userId=%d, resultId=%s, eventTime=%d, durationSinceSessionStart=%d, "
+ + "resultId=%s, eventTime=%d, durationSinceSessionStart=%d, "
+ "durationSincePreviousEvent=%d, eventIndex=%d,"
+ "sessionId=%s, start=%d, end=%d, smartStart=%d, smartEnd=%d, "
- + "mUseDefaultTextClassifier=%b}",
+ + "systemTcMetadata=%s}",
mAbsoluteStart, mAbsoluteEnd, mEventType, mEntityType,
mWidgetVersion, mPackageName, mWidgetType, mInvocationMethod,
- mUserId, mResultId, mEventTime, mDurationSinceSessionStart,
- mDurationSincePreviousEvent, mEventIndex,
- mSessionId, mStart, mEnd, mSmartStart, mSmartEnd, mUseDefaultTextClassifier);
+ mResultId, mEventTime, mDurationSinceSessionStart, mDurationSincePreviousEvent,
+ mEventIndex, mSessionId, mStart, mEnd, mSmartStart, mSmartEnd, mSystemTcMetadata);
}
public static final @android.annotation.NonNull Creator<SelectionEvent> CREATOR = new Creator<SelectionEvent>() {
diff --git a/core/java/android/view/textclassifier/SystemTextClassifier.java b/core/java/android/view/textclassifier/SystemTextClassifier.java
index fe5e8d6..86ef4e1 100644
--- a/core/java/android/view/textclassifier/SystemTextClassifier.java
+++ b/core/java/android/view/textclassifier/SystemTextClassifier.java
@@ -18,7 +18,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.UserIdInt;
import android.annotation.WorkerThread;
import android.content.Context;
import android.os.Bundle;
@@ -39,7 +38,8 @@
import java.util.concurrent.TimeUnit;
/**
- * Proxy to the system's default TextClassifier.
+ * proxy to the request to TextClassifierService via the TextClassificationManagerService.
+ *
* @hide
*/
@VisibleForTesting(visibility = Visibility.PACKAGE)
@@ -50,14 +50,19 @@
private final ITextClassifierService mManagerService;
private final TextClassificationConstants mSettings;
private final TextClassifier mFallback;
- private final String mPackageName;
- // NOTE: Always set this before sending a request to the manager service otherwise the manager
- // service will throw a remote exception.
- @UserIdInt
- private final int mUserId;
- private final boolean mUseDefault;
private TextClassificationSessionId mSessionId;
+ // NOTE: Always set this before sending a request to the manager service otherwise the
+ // manager service will throw a remote exception.
+ @NonNull
+ private final SystemTextClassifierMetadata mSystemTcMetadata;
+ /**
+ * Constructor of {@link SystemTextClassifier}
+ *
+ * @param context the context of the request.
+ * @param settings TextClassifier specific settings.
+ * @param useDefault whether to use the default text classifier to handle this request
+ */
public SystemTextClassifier(
Context context,
TextClassificationConstants settings,
@@ -66,9 +71,11 @@
ServiceManager.getServiceOrThrow(Context.TEXT_CLASSIFICATION_SERVICE));
mSettings = Objects.requireNonNull(settings);
mFallback = TextClassifier.NO_OP;
- mPackageName = Objects.requireNonNull(context.getOpPackageName());
- mUserId = context.getUserId();
- mUseDefault = useDefault;
+ // NOTE: Always set this before sending a request to the manager service otherwise the
+ // manager service will throw a remote exception.
+ mSystemTcMetadata = new SystemTextClassifierMetadata(
+ Objects.requireNonNull(context.getOpPackageName()), context.getUserId(),
+ useDefault);
}
/**
@@ -80,9 +87,7 @@
Objects.requireNonNull(request);
Utils.checkMainThread();
try {
- request.setCallingPackageName(mPackageName);
- request.setUserId(mUserId);
- request.setUseDefaultTextClassifier(mUseDefault);
+ request.setSystemTextClassifierMetadata(mSystemTcMetadata);
final BlockingCallback<TextSelection> callback =
new BlockingCallback<>("textselection");
mManagerService.onSuggestSelection(mSessionId, request, callback);
@@ -105,9 +110,7 @@
Objects.requireNonNull(request);
Utils.checkMainThread();
try {
- request.setCallingPackageName(mPackageName);
- request.setUserId(mUserId);
- request.setUseDefaultTextClassifier(mUseDefault);
+ request.setSystemTextClassifierMetadata(mSystemTcMetadata);
final BlockingCallback<TextClassification> callback =
new BlockingCallback<>("textclassification");
mManagerService.onClassifyText(mSessionId, request, callback);
@@ -137,9 +140,7 @@
}
try {
- request.setCallingPackageName(mPackageName);
- request.setUserId(mUserId);
- request.setUseDefaultTextClassifier(mUseDefault);
+ request.setSystemTextClassifierMetadata(mSystemTcMetadata);
final BlockingCallback<TextLinks> callback =
new BlockingCallback<>("textlinks");
mManagerService.onGenerateLinks(mSessionId, request, callback);
@@ -159,8 +160,7 @@
Utils.checkMainThread();
try {
- event.setUserId(mUserId);
- event.setUseDefaultTextClassifier(mUseDefault);
+ event.setSystemTextClassifierMetadata(mSystemTcMetadata);
mManagerService.onSelectionEvent(mSessionId, event);
} catch (RemoteException e) {
Log.e(LOG_TAG, "Error reporting selection event.", e);
@@ -173,12 +173,11 @@
Utils.checkMainThread();
try {
- final TextClassificationContext tcContext = event.getEventContext() == null
- ? new TextClassificationContext.Builder(mPackageName, WIDGET_TYPE_UNKNOWN)
- .build()
- : event.getEventContext();
- tcContext.setUserId(mUserId);
- tcContext.setUseDefaultTextClassifier(mUseDefault);
+ final TextClassificationContext tcContext =
+ event.getEventContext() == null ? new TextClassificationContext.Builder(
+ mSystemTcMetadata.getCallingPackageName(), WIDGET_TYPE_UNKNOWN).build()
+ : event.getEventContext();
+ tcContext.setSystemTextClassifierMetadata(mSystemTcMetadata);
event.setEventContext(tcContext);
mManagerService.onTextClassifierEvent(mSessionId, event);
} catch (RemoteException e) {
@@ -192,9 +191,7 @@
Utils.checkMainThread();
try {
- request.setCallingPackageName(mPackageName);
- request.setUserId(mUserId);
- request.setUseDefaultTextClassifier(mUseDefault);
+ request.setSystemTextClassifierMetadata(mSystemTcMetadata);
final BlockingCallback<TextLanguage> callback =
new BlockingCallback<>("textlanguage");
mManagerService.onDetectLanguage(mSessionId, request, callback);
@@ -214,9 +211,7 @@
Utils.checkMainThread();
try {
- request.setCallingPackageName(mPackageName);
- request.setUserId(mUserId);
- request.setUseDefaultTextClassifier(mUseDefault);
+ request.setSystemTextClassifierMetadata(mSystemTcMetadata);
final BlockingCallback<ConversationActions> callback =
new BlockingCallback<>("conversation-actions");
mManagerService.onSuggestConversationActions(mSessionId, request, callback);
@@ -256,10 +251,8 @@
printWriter.println("SystemTextClassifier:");
printWriter.increaseIndent();
printWriter.printPair("mFallback", mFallback);
- printWriter.printPair("mPackageName", mPackageName);
printWriter.printPair("mSessionId", mSessionId);
- printWriter.printPair("mUserId", mUserId);
- printWriter.printPair("mUseDefault", mUseDefault);
+ printWriter.printPair("mSystemTcMetadata", mSystemTcMetadata);
printWriter.decreaseIndent();
printWriter.println();
}
@@ -275,7 +268,7 @@
@NonNull TextClassificationSessionId sessionId) {
mSessionId = Objects.requireNonNull(sessionId);
try {
- classificationContext.setUserId(mUserId);
+ classificationContext.setSystemTextClassifierMetadata(mSystemTcMetadata);
mManagerService.onCreateTextClassificationSession(classificationContext, mSessionId);
} catch (RemoteException e) {
Log.e(LOG_TAG, "Error starting a new classification session.", e);
diff --git a/core/java/android/view/textclassifier/SystemTextClassifierMetadata.aidl b/core/java/android/view/textclassifier/SystemTextClassifierMetadata.aidl
new file mode 100644
index 0000000..4d4e90a
--- /dev/null
+++ b/core/java/android/view/textclassifier/SystemTextClassifierMetadata.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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 android.view.textclassifier;
+
+parcelable SystemTextClassifierMetadata;
\ No newline at end of file
diff --git a/core/java/android/view/textclassifier/SystemTextClassifierMetadata.java b/core/java/android/view/textclassifier/SystemTextClassifierMetadata.java
new file mode 100644
index 0000000..971e3e2
--- /dev/null
+++ b/core/java/android/view/textclassifier/SystemTextClassifierMetadata.java
@@ -0,0 +1,121 @@
+/*
+ * 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 android.view.textclassifier;
+
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.annotations.VisibleForTesting.Visibility;
+
+import java.util.Locale;
+import java.util.Objects;
+
+/**
+ * SystemTextClassifier specific information.
+ * <p>
+ * This contains information requires for the TextClassificationManagerService to process the
+ * requests from the application, e.g. user id, calling package name and etc. Centrialize the data
+ * into this class helps to extend the scalability if we want to add new fields.
+ * @hide
+ */
+@VisibleForTesting(visibility = Visibility.PACKAGE)
+public final class SystemTextClassifierMetadata implements Parcelable {
+
+ /* The name of the package that sent the TC request. */
+ @NonNull
+ private final String mCallingPackageName;
+ /* The id of the user that sent the TC request. */
+ @UserIdInt
+ private final int mUserId;
+ /* Whether to use the default text classifier to handle the request. */
+ private final boolean mUseDefaultTextClassifier;
+
+ public SystemTextClassifierMetadata(@NonNull String packageName, @UserIdInt int userId,
+ boolean useDefaultTextClassifier) {
+ Objects.requireNonNull(packageName);
+ mCallingPackageName = packageName;
+ mUserId = userId;
+ mUseDefaultTextClassifier = useDefaultTextClassifier;
+ }
+
+ /**
+ * Returns the id of the user that sent the TC request.
+ */
+ @UserIdInt
+ public int getUserId() {
+ return mUserId;
+ }
+
+ /**
+ * Returns the name of the package that sent the TC request.
+ * This returns {@code null} if no calling package name is set.
+ */
+ @NonNull
+ public String getCallingPackageName() {
+ return mCallingPackageName;
+ }
+
+ /**
+ * Returns whether to use the default text classifier to handle TC request.
+ */
+ public boolean useDefaultTextClassifier() {
+ return mUseDefaultTextClassifier;
+ }
+
+ @Override
+ public String toString() {
+ return String.format(Locale.US,
+ "SystemTextClassifierMetadata {callingPackageName=%s, userId=%d, "
+ + "useDefaultTextClassifier=%b}",
+ mCallingPackageName, mUserId, mUseDefaultTextClassifier);
+ }
+
+ private static SystemTextClassifierMetadata readFromParcel(Parcel in) {
+ final String packageName = in.readString();
+ final int userId = in.readInt();
+ final boolean useDefaultTextClassifier = in.readBoolean();
+ return new SystemTextClassifierMetadata(packageName, userId, useDefaultTextClassifier);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mCallingPackageName);
+ dest.writeInt(mUserId);
+ dest.writeBoolean(mUseDefaultTextClassifier);
+ }
+
+ public static final @NonNull Creator<SystemTextClassifierMetadata> CREATOR =
+ new Creator<SystemTextClassifierMetadata>() {
+ @Override
+ public SystemTextClassifierMetadata createFromParcel(Parcel in) {
+ return readFromParcel(in);
+ }
+
+ @Override
+ public SystemTextClassifierMetadata[] newArray(int size) {
+ return new SystemTextClassifierMetadata[size];
+ }
+ };
+}
diff --git a/core/java/android/view/textclassifier/TextClassification.java b/core/java/android/view/textclassifier/TextClassification.java
index 00f762b..8b9d129 100644
--- a/core/java/android/view/textclassifier/TextClassification.java
+++ b/core/java/android/view/textclassifier/TextClassification.java
@@ -21,7 +21,6 @@
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.UserIdInt;
import android.app.PendingIntent;
import android.app.RemoteAction;
import android.content.Context;
@@ -36,7 +35,6 @@
import android.os.LocaleList;
import android.os.Parcel;
import android.os.Parcelable;
-import android.os.UserHandle;
import android.text.SpannedString;
import android.util.ArrayMap;
import android.view.View.OnClickListener;
@@ -552,10 +550,7 @@
@Nullable private final LocaleList mDefaultLocales;
@Nullable private final ZonedDateTime mReferenceTime;
@NonNull private final Bundle mExtras;
- @Nullable private String mCallingPackageName;
- @UserIdInt
- private int mUserId = UserHandle.USER_NULL;
- private boolean mUseDefaultTextClassifier;
+ @Nullable private SystemTextClassifierMetadata mSystemTcMetadata;
private Request(
CharSequence text,
@@ -616,62 +611,33 @@
}
/**
- * Sets the name of the package that is sending this request.
- * <p>
- * For SystemTextClassifier's use.
- * @hide
- */
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
- public void setCallingPackageName(@Nullable String callingPackageName) {
- mCallingPackageName = callingPackageName;
- }
-
- /**
* Returns the name of the package that sent this request.
* This returns {@code null} if no calling package name is set.
*/
@Nullable
public String getCallingPackageName() {
- return mCallingPackageName;
+ return mSystemTcMetadata != null ? mSystemTcMetadata.getCallingPackageName() : null;
}
/**
- * Sets the id of the user that sent this request.
- * <p>
- * Package-private for SystemTextClassifier's use.
- * @hide
- */
- void setUserId(@UserIdInt int userId) {
- mUserId = userId;
- }
-
- /**
- * Returns the id of the user that sent this request.
- * @hide
- */
- @UserIdInt
- public int getUserId() {
- return mUserId;
- }
-
- /**
- * Sets whether to use the default text classifier to handle this request.
- * This will be ignored if it is not the system text classifier to handle this request.
+ * Sets the information about the {@link SystemTextClassifier} that sent this request.
*
* @hide
*/
- void setUseDefaultTextClassifier(boolean useDefaultTextClassifier) {
- mUseDefaultTextClassifier = useDefaultTextClassifier;
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ public void setSystemTextClassifierMetadata(
+ @Nullable SystemTextClassifierMetadata systemTcMetadata) {
+ mSystemTcMetadata = systemTcMetadata;
}
/**
- * Returns whether to use the default text classifier to handle this request. This
- * will be ignored if it is not the system text classifier to handle this request.
+ * Returns the information about the {@link SystemTextClassifier} that sent this request.
*
* @hide
*/
- public boolean getUseDefaultTextClassifier() {
- return mUseDefaultTextClassifier;
+ @Nullable
+ public SystemTextClassifierMetadata getSystemTextClassifierMetadata() {
+ return mSystemTcMetadata;
}
/**
@@ -773,10 +739,8 @@
dest.writeInt(mEndIndex);
dest.writeParcelable(mDefaultLocales, flags);
dest.writeString(mReferenceTime == null ? null : mReferenceTime.toString());
- dest.writeString(mCallingPackageName);
- dest.writeInt(mUserId);
dest.writeBundle(mExtras);
- dest.writeBoolean(mUseDefaultTextClassifier);
+ dest.writeParcelable(mSystemTcMetadata, flags);
}
private static Request readFromParcel(Parcel in) {
@@ -787,16 +751,12 @@
final String referenceTimeString = in.readString();
final ZonedDateTime referenceTime = referenceTimeString == null
? null : ZonedDateTime.parse(referenceTimeString);
- final String callingPackageName = in.readString();
- final int userId = in.readInt();
final Bundle extras = in.readBundle();
- final boolean useDefaultTextClassifier = in.readBoolean();
+ final SystemTextClassifierMetadata systemTcMetadata = in.readParcelable(null);
final Request request = new Request(text, startIndex, endIndex,
defaultLocales, referenceTime, extras);
- request.setCallingPackageName(callingPackageName);
- request.setUserId(userId);
- request.setUseDefaultTextClassifier(useDefaultTextClassifier);
+ request.setSystemTextClassifierMetadata(systemTcMetadata);
return request;
}
diff --git a/core/java/android/view/textclassifier/TextClassificationContext.java b/core/java/android/view/textclassifier/TextClassificationContext.java
index d58d175..f2323c6 100644
--- a/core/java/android/view/textclassifier/TextClassificationContext.java
+++ b/core/java/android/view/textclassifier/TextClassificationContext.java
@@ -18,10 +18,8 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.UserIdInt;
import android.os.Parcel;
import android.os.Parcelable;
-import android.os.UserHandle;
import android.view.textclassifier.TextClassifier.WidgetType;
import java.util.Locale;
@@ -33,12 +31,11 @@
*/
public final class TextClassificationContext implements Parcelable {
- private final String mPackageName;
+ // NOTE: Modify packageName only in the constructor or in setSystemTextClassifierMetadata()
+ private String mPackageName;
private final String mWidgetType;
@Nullable private final String mWidgetVersion;
- @UserIdInt
- private int mUserId = UserHandle.USER_NULL;
- private boolean mUseDefaultTextClassifier;
+ private SystemTextClassifierMetadata mSystemTcMetadata;
private TextClassificationContext(
String packageName,
@@ -58,42 +55,26 @@
}
/**
- * Sets the id of this context's user.
- * <p>
- * Package-private for SystemTextClassifier's use.
+ * Sets the information about the {@link SystemTextClassifier} that sent this request.
+ *
+ * <p><b>NOTE: </b>This will override the value returned in {@link getPackageName()}.
* @hide
*/
- void setUserId(@UserIdInt int userId) {
- mUserId = userId;
+ void setSystemTextClassifierMetadata(@Nullable SystemTextClassifierMetadata systemTcMetadata) {
+ mSystemTcMetadata = systemTcMetadata;
+ if (mSystemTcMetadata != null) {
+ mPackageName = mSystemTcMetadata.getCallingPackageName();
+ }
}
/**
- * Returns the id of this context's user.
- * @hide
- */
- @UserIdInt
- public int getUserId() {
- return mUserId;
- }
-
- /**
- * Sets whether to use the default text classifier to handle this request.
- * This will be ignored if it is not the system text classifier to handle this request.
+ * Returns the information about the {@link SystemTextClassifier} that sent this request.
*
* @hide
*/
- void setUseDefaultTextClassifier(boolean useDefaultTextClassifier) {
- mUseDefaultTextClassifier = useDefaultTextClassifier;
- }
-
- /**
- * Returns whether to use the default text classifier to handle this request. This
- * will be ignored if it is not the system text classifier to handle this request.
- *
- * @hide
- */
- public boolean getUseDefaultTextClassifier() {
- return mUseDefaultTextClassifier;
+ @Nullable
+ public SystemTextClassifierMetadata getSystemTextClassifierMetadata() {
+ return mSystemTcMetadata;
}
/**
@@ -118,8 +99,8 @@
@Override
public String toString() {
return String.format(Locale.US, "TextClassificationContext{"
- + "packageName=%s, widgetType=%s, widgetVersion=%s, userId=%d}",
- mPackageName, mWidgetType, mWidgetVersion, mUserId);
+ + "packageName=%s, widgetType=%s, widgetVersion=%s, systemTcMetadata=%s}",
+ mPackageName, mWidgetType, mWidgetVersion, mSystemTcMetadata);
}
/**
@@ -176,16 +157,14 @@
parcel.writeString(mPackageName);
parcel.writeString(mWidgetType);
parcel.writeString(mWidgetVersion);
- parcel.writeInt(mUserId);
- parcel.writeBoolean(mUseDefaultTextClassifier);
+ parcel.writeParcelable(mSystemTcMetadata, flags);
}
private TextClassificationContext(Parcel in) {
mPackageName = in.readString();
mWidgetType = in.readString();
mWidgetVersion = in.readString();
- mUserId = in.readInt();
- mUseDefaultTextClassifier = in.readBoolean();
+ mSystemTcMetadata = in.readParcelable(null);
}
public static final @android.annotation.NonNull Parcelable.Creator<TextClassificationContext> CREATOR =
diff --git a/core/java/android/view/textclassifier/TextLanguage.java b/core/java/android/view/textclassifier/TextLanguage.java
index 58024dc..1e8253d 100644
--- a/core/java/android/view/textclassifier/TextLanguage.java
+++ b/core/java/android/view/textclassifier/TextLanguage.java
@@ -20,12 +20,10 @@
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.UserIdInt;
import android.icu.util.ULocale;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
-import android.os.UserHandle;
import android.util.ArrayMap;
import com.android.internal.annotations.VisibleForTesting;
@@ -227,10 +225,7 @@
private final CharSequence mText;
private final Bundle mExtra;
- @Nullable private String mCallingPackageName;
- @UserIdInt
- private int mUserId = UserHandle.USER_NULL;
- private boolean mUseDefaultTextClassifier;
+ @Nullable private SystemTextClassifierMetadata mSystemTcMetadata;
private Request(CharSequence text, Bundle bundle) {
mText = text;
@@ -246,61 +241,33 @@
}
/**
- * Sets the name of the package that is sending this request.
- * Package-private for SystemTextClassifier's use.
- * @hide
- */
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
- public void setCallingPackageName(@Nullable String callingPackageName) {
- mCallingPackageName = callingPackageName;
- }
-
- /**
* Returns the name of the package that sent this request.
* This returns null if no calling package name is set.
*/
@Nullable
public String getCallingPackageName() {
- return mCallingPackageName;
+ return mSystemTcMetadata != null ? mSystemTcMetadata.getCallingPackageName() : null;
}
/**
- * Sets the id of the user that sent this request.
- * <p>
- * Package-private for SystemTextClassifier's use.
- * @hide
- */
- void setUserId(@UserIdInt int userId) {
- mUserId = userId;
- }
-
- /**
- * Returns the id of the user that sent this request.
- * @hide
- */
- @UserIdInt
- public int getUserId() {
- return mUserId;
- }
-
- /**
- * Sets whether to use the default text classifier to handle this request.
- * This will be ignored if it is not the system text classifier to handle this request.
+ * Sets the information about the {@link SystemTextClassifier} that sent this request.
*
* @hide
*/
- void setUseDefaultTextClassifier(boolean useDefaultTextClassifier) {
- mUseDefaultTextClassifier = useDefaultTextClassifier;
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ public void setSystemTextClassifierMetadata(
+ @Nullable SystemTextClassifierMetadata systemTcMetadata) {
+ mSystemTcMetadata = systemTcMetadata;
}
/**
- * Returns whether to use the default text classifier to handle this request. This
- * will be ignored if it is not the system text classifier to handle this request.
+ * Returns the information about the {@link SystemTextClassifier} that sent this request.
*
* @hide
*/
- public boolean getUseDefaultTextClassifier() {
- return mUseDefaultTextClassifier;
+ @Nullable
+ public SystemTextClassifierMetadata getSystemTextClassifierMetadata() {
+ return mSystemTcMetadata;
}
/**
@@ -321,23 +288,17 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeCharSequence(mText);
- dest.writeString(mCallingPackageName);
- dest.writeInt(mUserId);
dest.writeBundle(mExtra);
- dest.writeBoolean(mUseDefaultTextClassifier);
+ dest.writeParcelable(mSystemTcMetadata, flags);
}
private static Request readFromParcel(Parcel in) {
final CharSequence text = in.readCharSequence();
- final String callingPackageName = in.readString();
- final int userId = in.readInt();
final Bundle extra = in.readBundle();
- final boolean useDefaultTextClassifier = in.readBoolean();
+ final SystemTextClassifierMetadata systemTcMetadata = in.readParcelable(null);
final Request request = new Request(text, extra);
- request.setCallingPackageName(callingPackageName);
- request.setUserId(userId);
- request.setUseDefaultTextClassifier(useDefaultTextClassifier);
+ request.setSystemTextClassifierMetadata(systemTcMetadata);
return request;
}
diff --git a/core/java/android/view/textclassifier/TextLinks.java b/core/java/android/view/textclassifier/TextLinks.java
index 7430cb3..dea3a90 100644
--- a/core/java/android/view/textclassifier/TextLinks.java
+++ b/core/java/android/view/textclassifier/TextLinks.java
@@ -20,13 +20,11 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.UserIdInt;
import android.content.Context;
import android.os.Bundle;
import android.os.LocaleList;
import android.os.Parcel;
import android.os.Parcelable;
-import android.os.UserHandle;
import android.text.Spannable;
import android.text.method.MovementMethod;
import android.text.style.ClickableSpan;
@@ -340,12 +338,9 @@
@Nullable private final LocaleList mDefaultLocales;
@Nullable private final EntityConfig mEntityConfig;
private final boolean mLegacyFallback;
- @Nullable private String mCallingPackageName;
private final Bundle mExtras;
@Nullable private final ZonedDateTime mReferenceTime;
- @UserIdInt
- private int mUserId = UserHandle.USER_NULL;
- private boolean mUseDefaultTextClassifier;
+ @Nullable private SystemTextClassifierMetadata mSystemTcMetadata;
private Request(
CharSequence text,
@@ -409,62 +404,33 @@
}
/**
- * Sets the name of the package that is sending this request.
- * <p>
- * Package-private for SystemTextClassifier's use.
- * @hide
- */
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
- public void setCallingPackageName(@Nullable String callingPackageName) {
- mCallingPackageName = callingPackageName;
- }
-
- /**
* Returns the name of the package that sent this request.
* This returns {@code null} if no calling package name is set.
*/
@Nullable
public String getCallingPackageName() {
- return mCallingPackageName;
+ return mSystemTcMetadata != null ? mSystemTcMetadata.getCallingPackageName() : null;
}
/**
- * Sets the id of the user that sent this request.
- * <p>
- * Package-private for SystemTextClassifier's use.
- * @hide
- */
- void setUserId(@UserIdInt int userId) {
- mUserId = userId;
- }
-
- /**
- * Returns the id of the user that sent this request.
- * @hide
- */
- @UserIdInt
- public int getUserId() {
- return mUserId;
- }
-
- /**
- * Sets whether to use the default text classifier to handle this request.
- * This will be ignored if it is not the system text classifier to handle this request.
+ * Sets the information about the {@link SystemTextClassifier} that sent this request.
*
* @hide
*/
- void setUseDefaultTextClassifier(boolean useDefaultTextClassifier) {
- mUseDefaultTextClassifier = useDefaultTextClassifier;
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ public void setSystemTextClassifierMetadata(
+ @Nullable SystemTextClassifierMetadata systemTcMetadata) {
+ mSystemTcMetadata = systemTcMetadata;
}
/**
- * Returns whether to use the default text classifier to handle this request. This
- * will be ignored if it is not the system text classifier to handle this request.
+ * Returns the information about the {@link SystemTextClassifier} that sent this request.
*
* @hide
*/
- public boolean getUseDefaultTextClassifier() {
- return mUseDefaultTextClassifier;
+ @Nullable
+ public SystemTextClassifierMetadata getSystemTextClassifierMetadata() {
+ return mSystemTcMetadata;
}
/**
@@ -585,30 +551,24 @@
dest.writeString(mText.toString());
dest.writeParcelable(mDefaultLocales, flags);
dest.writeParcelable(mEntityConfig, flags);
- dest.writeString(mCallingPackageName);
- dest.writeInt(mUserId);
dest.writeBundle(mExtras);
dest.writeString(mReferenceTime == null ? null : mReferenceTime.toString());
- dest.writeBoolean(mUseDefaultTextClassifier);
+ dest.writeParcelable(mSystemTcMetadata, flags);
}
private static Request readFromParcel(Parcel in) {
final String text = in.readString();
final LocaleList defaultLocales = in.readParcelable(null);
final EntityConfig entityConfig = in.readParcelable(null);
- final String callingPackageName = in.readString();
- final int userId = in.readInt();
final Bundle extras = in.readBundle();
final String referenceTimeString = in.readString();
final ZonedDateTime referenceTime = referenceTimeString == null
? null : ZonedDateTime.parse(referenceTimeString);
- final boolean useDefaultTextClassifier = in.readBoolean();
+ final SystemTextClassifierMetadata systemTcMetadata = in.readParcelable(null);
final Request request = new Request(text, defaultLocales, entityConfig,
/* legacyFallback= */ true, referenceTime, extras);
- request.setCallingPackageName(callingPackageName);
- request.setUserId(userId);
- request.setUseDefaultTextClassifier(useDefaultTextClassifier);
+ request.setSystemTextClassifierMetadata(systemTcMetadata);
return request;
}
diff --git a/core/java/android/view/textclassifier/TextSelection.java b/core/java/android/view/textclassifier/TextSelection.java
index 575a072..d8a632d 100644
--- a/core/java/android/view/textclassifier/TextSelection.java
+++ b/core/java/android/view/textclassifier/TextSelection.java
@@ -20,12 +20,10 @@
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.UserIdInt;
import android.os.Bundle;
import android.os.LocaleList;
import android.os.Parcel;
import android.os.Parcelable;
-import android.os.UserHandle;
import android.text.SpannedString;
import android.util.ArrayMap;
import android.view.textclassifier.TextClassifier.EntityType;
@@ -213,10 +211,7 @@
@Nullable private final LocaleList mDefaultLocales;
private final boolean mDarkLaunchAllowed;
private final Bundle mExtras;
- @Nullable private String mCallingPackageName;
- @UserIdInt
- private int mUserId = UserHandle.USER_NULL;
- private boolean mUseDefaultTextClassifier;
+ @Nullable private SystemTextClassifierMetadata mSystemTcMetadata;
private Request(
CharSequence text,
@@ -278,62 +273,33 @@
}
/**
- * Sets the name of the package that is sending this request.
- * <p>
- * Package-private for SystemTextClassifier's use.
- * @hide
- */
- @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
- public void setCallingPackageName(@Nullable String callingPackageName) {
- mCallingPackageName = callingPackageName;
- }
-
- /**
* Returns the name of the package that sent this request.
* This returns {@code null} if no calling package name is set.
*/
@Nullable
public String getCallingPackageName() {
- return mCallingPackageName;
+ return mSystemTcMetadata != null ? mSystemTcMetadata.getCallingPackageName() : null;
}
/**
- * Sets the id of the user that sent this request.
- * <p>
- * Package-private for SystemTextClassifier's use.
- * @hide
- */
- void setUserId(@UserIdInt int userId) {
- mUserId = userId;
- }
-
- /**
- * Returns the id of the user that sent this request.
- * @hide
- */
- @UserIdInt
- public int getUserId() {
- return mUserId;
- }
-
- /**
- * Sets whether to use the default text classifier to handle this request.
- * This will be ignored if it is not the system text classifier to handle this request.
+ * Sets the information about the {@link SystemTextClassifier} that sent this request.
*
* @hide
*/
- void setUseDefaultTextClassifier(boolean useDefaultTextClassifier) {
- mUseDefaultTextClassifier = useDefaultTextClassifier;
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ public void setSystemTextClassifierMetadata(
+ @Nullable SystemTextClassifierMetadata systemTcMetadata) {
+ mSystemTcMetadata = systemTcMetadata;
}
/**
- * Returns whether to use the default text classifier to handle this request. This
- * will be ignored if it is not the system text classifier to handle this request.
+ * Returns the information about the {@link SystemTextClassifier} that sent this request.
*
* @hide
*/
- public boolean getUseDefaultTextClassifier() {
- return mUseDefaultTextClassifier;
+ @Nullable
+ public SystemTextClassifierMetadata getSystemTextClassifierMetadata() {
+ return mSystemTcMetadata;
}
/**
@@ -438,10 +404,8 @@
dest.writeInt(mStartIndex);
dest.writeInt(mEndIndex);
dest.writeParcelable(mDefaultLocales, flags);
- dest.writeString(mCallingPackageName);
- dest.writeInt(mUserId);
dest.writeBundle(mExtras);
- dest.writeBoolean(mUseDefaultTextClassifier);
+ dest.writeParcelable(mSystemTcMetadata, flags);
}
private static Request readFromParcel(Parcel in) {
@@ -449,16 +413,12 @@
final int startIndex = in.readInt();
final int endIndex = in.readInt();
final LocaleList defaultLocales = in.readParcelable(null);
- final String callingPackageName = in.readString();
- final int userId = in.readInt();
final Bundle extras = in.readBundle();
- final boolean systemTextClassifierType = in.readBoolean();
+ final SystemTextClassifierMetadata systemTcMetadata = in.readParcelable(null);
final Request request = new Request(text, startIndex, endIndex, defaultLocales,
/* darkLaunchAllowed= */ false, extras);
- request.setCallingPackageName(callingPackageName);
- request.setUserId(userId);
- request.setUseDefaultTextClassifier(systemTextClassifierType);
+ request.setSystemTextClassifierMetadata(systemTcMetadata);
return request;
}
diff --git a/core/java/android/widget/AnalogClock.java b/core/java/android/widget/AnalogClock.java
index d165bd0..ffdb89d 100644
--- a/core/java/android/widget/AnalogClock.java
+++ b/core/java/android/widget/AnalogClock.java
@@ -261,7 +261,7 @@
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_TIMEZONE_CHANGED)) {
- String tz = intent.getStringExtra("time-zone");
+ String tz = intent.getStringExtra(Intent.EXTRA_TIMEZONE);
mClock = Clock.system(ZoneId.of(tz));
}
diff --git a/core/java/android/widget/TextClock.java b/core/java/android/widget/TextClock.java
index 8565493..6432438 100644
--- a/core/java/android/widget/TextClock.java
+++ b/core/java/android/widget/TextClock.java
@@ -173,7 +173,7 @@
return; // Test disabled the clock ticks
}
if (mTimeZone == null && Intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
- final String timeZone = intent.getStringExtra("time-zone");
+ final String timeZone = intent.getStringExtra(Intent.EXTRA_TIMEZONE);
createTime(timeZone);
} else if (!mShouldRunTicker && (Intent.ACTION_TIME_TICK.equals(intent.getAction())
|| Intent.ACTION_TIME_CHANGED.equals(intent.getAction()))) {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 0d82065..2168018 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -6607,6 +6607,16 @@
return mTransformation instanceof PasswordTransformationMethod;
}
+ /**
+ * Returns true if the current inputType is any type of password.
+ *
+ * @hide
+ */
+ public boolean isAnyPasswordInputType() {
+ final int inputType = getInputType();
+ return isPasswordInputType(inputType) || isVisiblePasswordInputType(inputType);
+ }
+
static boolean isPasswordInputType(int inputType) {
final int variation =
inputType & (EditorInfo.TYPE_MASK_CLASS | EditorInfo.TYPE_MASK_VARIATION);
diff --git a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
index d50826f..fa567f2 100644
--- a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
@@ -452,7 +452,7 @@
mEmptyStateView = rootView.findViewById(R.id.resolver_empty_state);
}
- private ViewGroup getEmptyStateView() {
+ protected ViewGroup getEmptyStateView() {
return mEmptyStateView;
}
}
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index c487e96..5620bff 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -2398,17 +2398,22 @@
}
final int availableWidth = right - left - v.getPaddingLeft() - v.getPaddingRight();
- if (mChooserMultiProfilePagerAdapter.getCurrentUserHandle() != getUser()) {
- gridAdapter.calculateChooserTargetWidth(availableWidth);
- return;
- }
-
- if (gridAdapter.consumeLayoutRequest()
+ boolean isLayoutUpdated = gridAdapter.consumeLayoutRequest()
|| gridAdapter.calculateChooserTargetWidth(availableWidth)
|| recyclerView.getAdapter() == null
- || mLastNumberOfChildren != recyclerView.getChildCount()
- || availableWidth != mCurrAvailableWidth) {
+ || availableWidth != mCurrAvailableWidth;
+ if (isLayoutUpdated
+ || mLastNumberOfChildren != recyclerView.getChildCount()) {
mCurrAvailableWidth = availableWidth;
+ if (isLayoutUpdated
+ && mChooserMultiProfilePagerAdapter.getCurrentUserHandle() != getUser()) {
+ // This fixes b/150936654 - empty work tab in share sheet when swiping
+ mChooserMultiProfilePagerAdapter.getActiveAdapterView()
+ .setAdapter(mChooserMultiProfilePagerAdapter.getCurrentRootAdapter());
+ return;
+ } else if (mChooserMultiProfilePagerAdapter.getCurrentUserHandle() != getUser()) {
+ return;
+ }
getMainThreadHandler().post(() -> {
if (mResolverDrawerLayout == null || gridAdapter == null) {
@@ -2452,39 +2457,46 @@
offset += tabDivider.getHeight();
}
- int directShareHeight = 0;
- rowsToShow = Math.min(4, rowsToShow);
- mLastNumberOfChildren = recyclerView.getChildCount();
- for (int i = 0, childCount = recyclerView.getChildCount();
- i < childCount && rowsToShow > 0; i++) {
- View child = recyclerView.getChildAt(i);
- if (((GridLayoutManager.LayoutParams)
- child.getLayoutParams()).getSpanIndex() != 0) {
- continue;
+ if (recyclerView.getVisibility() == View.VISIBLE) {
+ int directShareHeight = 0;
+ rowsToShow = Math.min(4, rowsToShow);
+ mLastNumberOfChildren = recyclerView.getChildCount();
+ for (int i = 0, childCount = recyclerView.getChildCount();
+ i < childCount && rowsToShow > 0; i++) {
+ View child = recyclerView.getChildAt(i);
+ if (((GridLayoutManager.LayoutParams)
+ child.getLayoutParams()).getSpanIndex() != 0) {
+ continue;
+ }
+ int height = child.getHeight();
+ offset += height;
+
+ if (gridAdapter.getTargetType(
+ recyclerView.getChildAdapterPosition(child))
+ == ChooserListAdapter.TARGET_SERVICE) {
+ directShareHeight = height;
+ }
+ rowsToShow--;
}
- int height = child.getHeight();
- offset += height;
- if (gridAdapter.getTargetType(
- recyclerView.getChildAdapterPosition(child))
- == ChooserListAdapter.TARGET_SERVICE) {
- directShareHeight = height;
+ boolean isExpandable = getResources().getConfiguration().orientation
+ == Configuration.ORIENTATION_PORTRAIT && !isInMultiWindowMode();
+ if (directShareHeight != 0 && isSendAction(getTargetIntent())
+ && isExpandable) {
+ // make sure to leave room for direct share 4->8 expansion
+ int requiredExpansionHeight =
+ (int) (directShareHeight / DIRECT_SHARE_EXPANSION_RATE);
+ int topInset = mSystemWindowInsets != null ? mSystemWindowInsets.top : 0;
+ int minHeight = bottom - top - mResolverDrawerLayout.getAlwaysShowHeight()
+ - requiredExpansionHeight - topInset - bottomInset;
+
+ offset = Math.min(offset, minHeight);
}
- rowsToShow--;
- }
-
- boolean isExpandable = getResources().getConfiguration().orientation
- == Configuration.ORIENTATION_PORTRAIT && !isInMultiWindowMode();
- if (directShareHeight != 0 && isSendAction(getTargetIntent())
- && isExpandable) {
- // make sure to leave room for direct share 4->8 expansion
- int requiredExpansionHeight =
- (int) (directShareHeight / DIRECT_SHARE_EXPANSION_RATE);
- int topInset = mSystemWindowInsets != null ? mSystemWindowInsets.top : 0;
- int minHeight = bottom - top - mResolverDrawerLayout.getAlwaysShowHeight()
- - requiredExpansionHeight - topInset - bottomInset;
-
- offset = Math.min(offset, minHeight);
+ } else {
+ ViewGroup currentEmptyStateView = getCurrentEmptyStateView();
+ if (currentEmptyStateView.getVisibility() == View.VISIBLE) {
+ offset += currentEmptyStateView.getHeight();
+ }
}
mResolverDrawerLayout.setCollapsibleHeightReserved(Math.min(offset, bottom - top));
@@ -2492,6 +2504,11 @@
}
}
+ private ViewGroup getCurrentEmptyStateView() {
+ int currentPage = mChooserMultiProfilePagerAdapter.getCurrentPage();
+ return mChooserMultiProfilePagerAdapter.getItem(currentPage).getEmptyStateView();
+ }
+
static class BaseChooserTargetComparator implements Comparator<ChooserTarget> {
@Override
public int compare(ChooserTarget lhs, ChooserTarget rhs) {
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index 907ea55..9218823 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -34,14 +34,14 @@
// be kept in sync with frameworks/native/libs/binder/include/binder/IAppOpsService.h
// and not be reordered
int checkOperation(int code, int uid, String packageName);
- int noteOperation(int code, int uid, String packageName, @nullable String featureId,
+ int noteOperation(int code, int uid, String packageName, @nullable String attributionTag,
boolean shouldCollectAsyncNotedOp, String message);
int startOperation(IBinder clientId, int code, int uid, String packageName,
- @nullable String featureId, boolean startIfModeDefault,
+ @nullable String attributionTag, boolean startIfModeDefault,
boolean shouldCollectAsyncNotedOp, String message);
@UnsupportedAppUsage
void finishOperation(IBinder clientId, int code, int uid, String packageName,
- @nullable String featureId);
+ @nullable String attributionTag);
void startWatchingMode(int op, String packageName, IAppOpsCallback callback);
void stopWatchingMode(IAppOpsCallback callback);
int permissionToOpCode(String permission);
@@ -52,8 +52,8 @@
// Any new method exposed to native must be added after the last one, do not reorder
int noteProxyOperation(int code, int proxiedUid, String proxiedPackageName,
- String proxiedFeatureId, int proxyUid, String proxyPackageName,
- String proxyFeatureId, boolean shouldCollectAsyncNotedOp, String message);
+ String proxiedAttributionTag, int proxyUid, String proxyPackageName,
+ String proxyAttributionTag, boolean shouldCollectAsyncNotedOp, String message);
// Remaining methods are only used in Java.
int checkPackage(int uid, String packageName);
@@ -64,10 +64,10 @@
List<AppOpsManager.PackageOps> getPackagesForOps(in int[] ops);
@UnsupportedAppUsage
List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName, in int[] ops);
- void getHistoricalOps(int uid, String packageName, String featureId, in List<String> ops,
+ void getHistoricalOps(int uid, String packageName, String attributionTag, in List<String> ops,
int filter, long beginTimeMillis, long endTimeMillis, int flags,
in RemoteCallback callback);
- void getHistoricalOpsFromDiskRaw(int uid, String packageName, String featureId,
+ void getHistoricalOpsFromDiskRaw(int uid, String packageName, String attributionTag,
in List<String> ops, int filter, long beginTimeMillis, long endTimeMillis, int flags,
in RemoteCallback callback);
void offsetHistory(long duration);
diff --git a/core/java/com/android/internal/compat/IPlatformCompat.aidl b/core/java/com/android/internal/compat/IPlatformCompat.aidl
index 4c203d3..523ed6f 100644
--- a/core/java/com/android/internal/compat/IPlatformCompat.aidl
+++ b/core/java/com/android/internal/compat/IPlatformCompat.aidl
@@ -164,6 +164,30 @@
boolean clearOverride(long changeId, String packageName);
/**
+ * Enable all compatibility changes which have enabledAfterTargetSdk ==
+ * {@param targetSdkVersion} for an app, subject to the policy. Kills the app to allow the
+ * changes to take effect.
+ *
+ * @param packageName The package name of the app whose compatibility changes will be enabled.
+ * @param targetSdkVersion The targetSdkVersion for filtering the changes to be enabled.
+ *
+ * @return The number of changes that were enabled.
+ */
+ int enableTargetSdkChanges(in String packageName, int targetSdkVersion);
+
+ /**
+ * Disable all compatibility changes which have enabledAfterTargetSdk ==
+ * {@param targetSdkVersion} for an app, subject to the policy. Kills the app to allow the
+ * changes to take effect.
+ *
+ * @param packageName The package name of the app whose compatibility changes will be disabled.
+ * @param targetSdkVersion The targetSdkVersion for filtering the changes to be disabled.
+ *
+ * @return The number of changes that were disabled.
+ */
+ int disableTargetSdkChanges(in String packageName, int targetSdkVersion);
+
+ /**
* Revert overrides to compatibility changes. Kills the app to allow the changes to take effect.
*
* @param packageName The package name of the app whose overrides will be cleared.
diff --git a/core/java/com/android/internal/content/FileSystemProvider.java b/core/java/com/android/internal/content/FileSystemProvider.java
index 73ef8c6..2f048c9 100644
--- a/core/java/com/android/internal/content/FileSystemProvider.java
+++ b/core/java/com/android/internal/content/FileSystemProvider.java
@@ -430,7 +430,7 @@
if (shouldHide(file)) continue;
if (file.isDirectory()) {
- for (File child : file.listFiles()) {
+ for (File child : FileUtils.listFilesOrEmpty(file)) {
pending.add(child);
}
}
diff --git a/core/java/com/android/internal/notification/SystemNotificationChannels.java b/core/java/com/android/internal/notification/SystemNotificationChannels.java
index 91ef0b5..1296ddc 100644
--- a/core/java/com/android/internal/notification/SystemNotificationChannels.java
+++ b/core/java/com/android/internal/notification/SystemNotificationChannels.java
@@ -116,6 +116,7 @@
NETWORK_STATUS,
context.getString(R.string.notification_channel_network_status),
NotificationManager.IMPORTANCE_LOW);
+ network.setBlockableSystem(true);
channelsList.add(network);
final NotificationChannel networkAlertsChannel = new NotificationChannel(
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 94924a5..633aa2c 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -140,6 +140,33 @@
*/
public static final int MEMORY_TAG_LEVEL_SYNC = 3 << 19;
+ /**
+ * A two-bit field for GWP-ASan level of this process. See the possible values below.
+ */
+ public static final int GWP_ASAN_LEVEL_MASK = (1 << 21) | (1 << 22);
+
+ /**
+ * Disable GWP-ASan in this process.
+ * GWP-ASan is a low-overhead memory bug detector using guard pages on a small
+ * subset of heap allocations.
+ */
+ public static final int GWP_ASAN_LEVEL_NEVER = 0 << 21;
+
+ /**
+ * Enable GWP-ASan in this process with a small sampling rate.
+ * With approx. 1% chance GWP-ASan will be activated and apply its protection
+ * to a small subset of heap allocations.
+ * Otherwise (~99% chance) this process is unaffected.
+ */
+ public static final int GWP_ASAN_LEVEL_LOTTERY = 1 << 21;
+
+ /**
+ * Always enable GWP-ASan in this process.
+ * GWP-ASan is activated unconditionally (but still, only a small subset of
+ * allocations is protected).
+ */
+ public static final int GWP_ASAN_LEVEL_ALWAYS = 2 << 21;
+
/** No external storage should be mounted. */
public static final int MOUNT_EXTERNAL_NONE = IVold.REMOUNT_MODE_NONE;
/** Default external storage should be mounted. */
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 54cf693..0bfd659 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -125,12 +125,6 @@
private static boolean sPreloadComplete;
- /**
- * Cached classloader to use for the system server. Will only be populated in the system
- * server process.
- */
- private static ClassLoader sCachedSystemServerClassLoader = null;
-
static void preload(TimingsTraceLog bootTimingsTraceLog) {
Log.d(TAG, "begin preload");
bootTimingsTraceLog.traceBegin("BeginPreload");
@@ -508,13 +502,7 @@
final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
if (systemServerClasspath != null) {
- if (performSystemServerDexOpt(systemServerClasspath)) {
- // Throw away the cached classloader. If we compiled here, the classloader would
- // not have had AoT-ed artifacts.
- // Note: This only works in a very special environment where selinux enforcement is
- // disabled, e.g., Mac builds.
- sCachedSystemServerClassLoader = null;
- }
+ performSystemServerDexOpt(systemServerClasspath);
// Capturing profiles is only supported for debug or eng builds since selinux normally
// prevents it.
if (shouldProfileSystemServer() && (Build.IS_USERDEBUG || Build.IS_ENG)) {
@@ -546,9 +534,10 @@
throw new IllegalStateException("Unexpected return from WrapperInit.execApplication");
} else {
- createSystemServerClassLoader();
- ClassLoader cl = sCachedSystemServerClassLoader;
- if (cl != null) {
+ ClassLoader cl = null;
+ if (systemServerClasspath != null) {
+ cl = createPathClassLoader(systemServerClasspath, parsedArgs.mTargetSdkVersion);
+
Thread.currentThread().setContextClassLoader(cl);
}
@@ -564,24 +553,6 @@
}
/**
- * Create the classloader for the system server and store it in
- * {@link sCachedSystemServerClassLoader}. This function may be called through JNI in
- * system server startup, when the runtime is in a critically low state. Do not do
- * extended computation etc here.
- */
- private static void createSystemServerClassLoader() {
- if (sCachedSystemServerClassLoader != null) {
- return;
- }
- final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
- // TODO: Should we run optimization here?
- if (systemServerClasspath != null) {
- sCachedSystemServerClassLoader = createPathClassLoader(systemServerClasspath,
- VMRuntime.SDK_VERSION_CUR_DEVELOPMENT);
- }
- }
-
- /**
* Note that preparing the profiles for system server does not require special selinux
* permissions. From the installer perspective the system server is a regular package which can
* capture profile information.
@@ -645,16 +616,15 @@
/**
* Performs dex-opt on the elements of {@code classPath}, if needed. We choose the instruction
- * set of the current runtime. If something was compiled, return true.
+ * set of the current runtime.
*/
- private static boolean performSystemServerDexOpt(String classPath) {
+ private static void performSystemServerDexOpt(String classPath) {
final String[] classPathElements = classPath.split(":");
final IInstalld installd = IInstalld.Stub
.asInterface(ServiceManager.getService("installd"));
final String instructionSet = VMRuntime.getRuntime().vmInstructionSet();
String classPathForElement = "";
- boolean compiledSomething = false;
for (String classPathElement : classPathElements) {
// We default to the verify filter because the compilation will happen on /data and
// system server cannot load executable code outside /system.
@@ -695,7 +665,6 @@
uuid, classLoaderContext, seInfo, false /* downgrade */,
targetSdkVersion, /*profileName*/ null, /*dexMetadataPath*/ null,
"server-dexopt");
- compiledSomething = true;
} catch (RemoteException | ServiceSpecificException e) {
// Ignore (but log), we need this on the classpath for fallback mode.
Log.w(TAG, "Failed compiling classpath element for system server: "
@@ -706,8 +675,6 @@
classPathForElement = encodeSystemServerClassPath(
classPathForElement, classPathElement);
}
-
- return compiledSomething;
}
/**
diff --git a/core/java/com/android/internal/util/Parcelling.java b/core/java/com/android/internal/util/Parcelling.java
index 7f567b9..dd64c40 100644
--- a/core/java/com/android/internal/util/Parcelling.java
+++ b/core/java/com/android/internal/util/Parcelling.java
@@ -221,6 +221,33 @@
}
}
+ class ForInternedStringArraySet implements Parcelling<ArraySet<String>> {
+ @Override
+ public void parcel(ArraySet<String> item, Parcel dest, int parcelFlags) {
+ if (item == null) {
+ dest.writeInt(-1);
+ } else {
+ dest.writeInt(item.size());
+ for (String string : item) {
+ dest.writeString(string);
+ }
+ }
+ }
+
+ @Override
+ public ArraySet<String> unparcel(Parcel source) {
+ final int size = source.readInt();
+ if (size < 0) {
+ return null;
+ }
+ ArraySet<String> set = new ArraySet<>();
+ for (int count = 0; count < size; count++) {
+ set.add(TextUtils.safeIntern(source.readString()));
+ }
+ return set;
+ }
+ }
+
class ForBoolean implements Parcelling<Boolean> {
@Override
public void parcel(@Nullable Boolean item, Parcel dest, int parcelFlags) {
diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java
index 5dd3389b..47f094f 100644
--- a/core/java/com/android/internal/view/BaseIWindow.java
+++ b/core/java/com/android/internal/view/BaseIWindow.java
@@ -116,7 +116,8 @@
}
@Override
- public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep, boolean sync) {
+ public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep, float zoom,
+ boolean sync) {
if (sync) {
try {
mSession.wallpaperOffsetsComplete(asBinder());
diff --git a/core/java/com/android/internal/view/inline/IInlineContentCallback.aidl b/core/java/com/android/internal/view/inline/IInlineContentCallback.aidl
index 29bdf56..feb3f02 100644
--- a/core/java/com/android/internal/view/inline/IInlineContentCallback.aidl
+++ b/core/java/com/android/internal/view/inline/IInlineContentCallback.aidl
@@ -24,4 +24,6 @@
*/
oneway interface IInlineContentCallback {
void onContent(in SurfaceControlViewHost.SurfacePackage content);
+ void onClick();
+ void onLongClick();
}
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 0d0dc3e..f7c6dbd 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -853,8 +853,11 @@
} cfg_state = CONFIG_UNKNOWN;
if (cfg_state == CONFIG_UNKNOWN) {
- const std::map<std::string, std::string> configs =
- vintf::VintfObject::GetInstance()->getRuntimeInfo()->kernelConfigs();
+ auto runtime_info = vintf::VintfObject::GetInstance()
+ ->getRuntimeInfo(false /* skip cache */,
+ vintf::RuntimeInfo::FetchFlag::CONFIG_GZ);
+ CHECK(runtime_info != nullptr) << "Kernel configs cannot be fetched. b/151092221";
+ const std::map<std::string, std::string>& configs = runtime_info->kernelConfigs();
std::map<std::string, std::string>::const_iterator it = configs.find("CONFIG_VMAP_STACK");
cfg_state = (it != configs.end() && it->second == "y") ? CONFIG_SET : CONFIG_UNSET;
}
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 2128f99..dafb377 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -121,16 +121,11 @@
static pid_t gSystemServerPid = 0;
static constexpr const char* kPropFuse = "persist.sys.fuse";
-static constexpr const char* kZygoteClassName = "com/android/internal/os/Zygote";
-
+static const char kZygoteClassName[] = "com/android/internal/os/Zygote";
static jclass gZygoteClass;
static jmethodID gCallPostForkSystemServerHooks;
static jmethodID gCallPostForkChildHooks;
-static constexpr const char* kZygoteInitClassName = "com/android/internal/os/ZygoteInit";
-static jclass gZygoteInitClass;
-static jmethodID gCreateSystemServerClassLoader;
-
static bool gIsSecurityEnforced = true;
/**
@@ -356,10 +351,14 @@
// Must match values in com.android.internal.os.Zygote.
enum RuntimeFlags : uint32_t {
- DEBUG_ENABLE_JDWP = 1,
- PROFILE_FROM_SHELL = 1 << 15,
- MEMORY_TAG_LEVEL_MASK = (1 << 19) | (1 << 20),
- MEMORY_TAG_LEVEL_TBI = 1 << 19,
+ DEBUG_ENABLE_JDWP = 1,
+ PROFILE_FROM_SHELL = 1 << 15,
+ MEMORY_TAG_LEVEL_MASK = (1 << 19) | (1 << 20),
+ MEMORY_TAG_LEVEL_TBI = 1 << 19,
+ GWP_ASAN_LEVEL_MASK = (1 << 21) | (1 << 22),
+ GWP_ASAN_LEVEL_NEVER = 0 << 21,
+ GWP_ASAN_LEVEL_LOTTERY = 1 << 21,
+ GWP_ASAN_LEVEL_ALWAYS = 2 << 21,
};
enum UnsolicitedZygoteMessageTypes : uint32_t {
@@ -1741,6 +1740,18 @@
}
android_mallopt(M_SET_HEAP_TAGGING_LEVEL, &heap_tagging_level, sizeof(heap_tagging_level));
+ bool forceEnableGwpAsan = false;
+ switch (runtime_flags & RuntimeFlags::GWP_ASAN_LEVEL_MASK) {
+ default:
+ case RuntimeFlags::GWP_ASAN_LEVEL_NEVER:
+ break;
+ case RuntimeFlags::GWP_ASAN_LEVEL_ALWAYS:
+ forceEnableGwpAsan = true;
+ [[fallthrough]];
+ case RuntimeFlags::GWP_ASAN_LEVEL_LOTTERY:
+ android_mallopt(M_INITIALIZE_GWP_ASAN, &forceEnableGwpAsan, sizeof(forceEnableGwpAsan));
+ }
+
if (NeedsNoRandomizeWorkaround()) {
// Work around ARM kernel ASLR lossage (http://b/5817320).
int old_personality = personality(0xffffffff);
@@ -1780,15 +1791,6 @@
fail_fn("Error calling post fork system server hooks.");
}
- // Prefetch the classloader for the system server. This is done early to
- // allow a tie-down of the proper system server selinux domain.
- env->CallStaticVoidMethod(gZygoteInitClass, gCreateSystemServerClassLoader);
- if (env->ExceptionCheck()) {
- // Be robust here. The Java code will attempt to create the classloader
- // at a later point (but may not have rights to use AoT artifacts).
- env->ExceptionClear();
- }
-
// TODO(oth): Remove hardcoded label here (b/117874058).
static const char* kSystemServerLabel = "u:r:system_server:s0";
if (selinux_android_setcon(kSystemServerLabel) != 0) {
@@ -2466,13 +2468,6 @@
gCallPostForkChildHooks = GetStaticMethodIDOrDie(env, gZygoteClass, "callPostForkChildHooks",
"(IZZLjava/lang/String;)V");
- gZygoteInitClass = MakeGlobalRefOrDie(env, FindClassOrDie(env, kZygoteInitClassName));
- gCreateSystemServerClassLoader = GetStaticMethodIDOrDie(env, gZygoteInitClass,
- "createSystemServerClassLoader",
- "()V");
-
- RegisterMethodsOrDie(env, "com/android/internal/os/Zygote", gMethods, NELEM(gMethods));
-
- return JNI_OK;
+ return RegisterMethodsOrDie(env, "com/android/internal/os/Zygote", gMethods, NELEM(gMethods));
}
} // namespace android
diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto
index 030483b..ef6eb38 100644
--- a/core/proto/android/app/settings_enums.proto
+++ b/core/proto/android/app/settings_enums.proto
@@ -724,6 +724,16 @@
// CATEGORY: SETTINGS
// OS: R
ACTION_ADB_WIRELESS_OFF = 1735;
+
+ // ACTION: Change Wi-Fi hotspot name
+ // CATEGORY: SETTINGS
+ // OS: R
+ ACTION_SETTINGS_CHANGE_WIFI_HOTSPOT_NAME = 1736;
+
+ // ACTION: Change Wi-Fi hotspot password
+ // CATEGORY: SETTINGS
+ // OS: R
+ ACTION_SETTINGS_CHANGE_WIFI_HOTSPOT_PASSWORD = 1737;
}
/**
diff --git a/core/proto/android/content/package_item_info.proto b/core/proto/android/content/package_item_info.proto
index 4a7d043..e8ae1b3 100644
--- a/core/proto/android/content/package_item_info.proto
+++ b/core/proto/android/content/package_item_info.proto
@@ -109,6 +109,7 @@
}
optional int32 network_security_config_res = 17;
optional int32 category = 18;
+ optional bool enable_gwp_asan = 19;
}
optional Detail detail = 17;
}
diff --git a/core/proto/android/telephony/enums.proto b/core/proto/android/telephony/enums.proto
index 4777169..f14e3ed 100644
--- a/core/proto/android/telephony/enums.proto
+++ b/core/proto/android/telephony/enums.proto
@@ -20,6 +20,43 @@
option java_outer_classname = "TelephonyProtoEnums";
option java_multiple_files = true;
+enum CallBearerEnum {
+ /** Call bearer is unknown or invalid */
+ CALL_BEARER_UNKNOWN = 0;
+
+ /** Call bearer is legacy CS */
+ CALL_BEARER_CS = 1;
+
+ /** Call bearer is IMS */
+ CALL_BEARER_IMS = 2;
+}
+
+enum CallDirectionEnum {
+ /** Call direction: unknown or invalid */
+ CALL_DIRECTION_UNKNOWN = 0;
+
+ /** Call direction: mobile originated (outgoing for this device) */
+ CALL_DIRECTION_MO = 1;
+
+ /** Call direction: mobile terminated (incoming for this device) */
+ CALL_DIRECTION_MT = 2;
+}
+
+// Call setup duration buckets.
+// See com.android.internal.telephony.metrics.VoiceCallSessionStats for definition.
+enum CallSetupDurationEnum {
+ CALL_SETUP_DURATION_UNKNOWN = 0;
+ CALL_SETUP_DURATION_EXTREMELY_FAST = 1;
+ CALL_SETUP_DURATION_ULTRA_FAST = 2;
+ CALL_SETUP_DURATION_VERY_FAST = 3;
+ CALL_SETUP_DURATION_FAST = 4;
+ CALL_SETUP_DURATION_NORMAL = 5;
+ CALL_SETUP_DURATION_SLOW = 6;
+ CALL_SETUP_DURATION_VERY_SLOW = 7;
+ CALL_SETUP_DURATION_ULTRA_SLOW = 8;
+ CALL_SETUP_DURATION_EXTREMELY_SLOW = 9;
+}
+
// Data conn. power states, primarily used by android/telephony/DataConnectionRealTimeInfo.java.
enum DataConnectionPowerStateEnum {
DATA_CONNECTION_POWER_STATE_LOW = 1;
@@ -63,7 +100,6 @@
SIGNAL_STRENGTH_GREAT = 4;
}
-
enum ServiceStateEnum {
/**
* Normal operation condition, the phone is registered
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 5086c7e..4001def 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1187,6 +1187,16 @@
android:description="@string/permdesc_callCompanionApp"
android:protectionLevel="normal" />
+ <!-- Exempt this uid from restrictions to background audio recoding
+ <p>Protection level: signature|privileged
+ @hide
+ @SystemApi
+ -->
+ <permission android:name="android.permission.EXEMPT_FROM_AUDIO_RECORD_RESTRICTIONS"
+ android:label="@string/permlab_exemptFromAudioRecordRestrictions"
+ android:description="@string/permdesc_exemptFromAudioRecordRestrictions"
+ android:protectionLevel="signature|privileged" />
+
<!-- Allows a calling app to continue a call which was started in another app. An example is a
video calling app that wants to continue a voice call on the user's mobile network.<p>
When the handover of a call from one app to another takes place, there are two devices
@@ -3735,7 +3745,8 @@
<permission android:name="android.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY"
android:protectionLevel="signature|installer" />
- <!-- @hide Allows an application to upgrade runtime permissions. -->
+ <!-- @SystemApi @TestApi Allows an application to upgrade runtime permissions.
+ @hide -->
<permission android:name="android.permission.UPGRADE_RUNTIME_PERMISSIONS"
android:protectionLevel="signature" />
@@ -4992,15 +5003,15 @@
<permission android:name="android.permission.ACCESS_LOCUS_ID_USAGE_STATS"
android:protectionLevel="signature|appPredictor" />
- <!-- Feature Id for Country Detector. -->
- <feature android:featureId="CountryDetector" android:label="@string/country_detector"/>
- <!-- Feature Id for Location service. -->
- <feature android:featureId="LocationService" android:label="@string/location_service"/>
- <!-- Feature Id for Sensor Notification service. -->
- <feature android:featureId="SensorNotificationService"
+ <!-- Attribution for Country Detector. -->
+ <attribution android:tag="CountryDetector" android:label="@string/country_detector"/>
+ <!-- Attribution for Location service. -->
+ <attribution android:tag="LocationService" android:label="@string/location_service"/>
+ <!-- Attribution for Sensor Notification service. -->
+ <attribution android:tag="SensorNotificationService"
android:label="@string/sensor_notification_service"/>
<!-- Feature Id for Twilight service. -->
- <feature android:featureId="TwilightService" android:label="@string/twilight_service"/>
+ <attribution android:tag="TwilightService" android:label="@string/twilight_service"/>
<application android:process="system"
android:persistent="true"
@@ -5189,6 +5200,7 @@
<activity android:name="com.android.internal.app.BlockedAppActivity"
android:theme="@style/Theme.Dialog.Confirmation"
android:excludeFromRecents="true"
+ android:lockTaskMode="always"
android:process=":ui">
</activity>
diff --git a/core/res/res/layout-car/car_resolver_different_item_header.xml b/core/res/res/layout-car/car_resolver_different_item_header.xml
deleted file mode 100644
index 222ecc6..0000000
--- a/core/res/res/layout-car/car_resolver_different_item_header.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
- * Copyright 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
--->
-<TextView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alwaysShow="true"
- android:text="@*android:string/use_a_different_app"
- android:minHeight="56dp"
- android:textAppearance="?android:attr/textAppearanceLarge"
- android:gravity="start|center_vertical"
- android:paddingStart="16dp"
- android:paddingEnd="16dp"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
- android:elevation="8dp"
-/>
\ No newline at end of file
diff --git a/core/res/res/layout-car/car_resolver_list.xml b/core/res/res/layout-car/car_resolver_list.xml
index 15a8645..755cbfe 100644
--- a/core/res/res/layout-car/car_resolver_list.xml
+++ b/core/res/res/layout-car/car_resolver_list.xml
@@ -23,90 +23,142 @@
android:id="@id/contentPanel">
<LinearLayout
- android:id="@+id/button_bar"
- android:visibility="gone"
- style="?attr/buttonBarStyle"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_ignoreOffset="true"
- android:layout_alwaysShow="true"
- android:layout_hasNestedScrollIndicator="true"
- android:background="?attr/colorBackgroundFloating"
- android:orientation="horizontal"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
- android:paddingStart="12dp"
+ android:layout_height="match_parent"
android:weightSum="5"
- android:paddingEnd="12dp"
+ android:layout_alwaysShow="true"
+ android:orientation="vertical"
+ android:background="?attr/colorBackgroundFloating"
android:elevation="8dp">
- <TextView
- android:id="@+id/profile_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginEnd="8dp"
- android:paddingStart="8dp"
- android:paddingEnd="8dp"
- android:textSize="40sp"
- android:layout_weight="5"
- android:layout_gravity = "left"
+ <LinearLayout
+ android:id="@+id/button_bar"
android:visibility="gone"
- android:textColor="?attr/colorAccent"
- android:singleLine="true"/>
-
- <TextView
- android:id="@+id/title"
- android:layout_width="wrap_content"
+ style="?attr/buttonBarStyle"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:minHeight="56dp"
- android:layout_gravity = "left"
- android:layout_weight="3"
+ android:layout_ignoreOffset="true"
+ android:layout_alwaysShow="true"
+ android:layout_hasNestedScrollIndicator="true"
+ android:background="?attr/colorBackgroundFloating"
+ android:orientation="horizontal"
android:paddingTop="8dp"
- android:layout_below="@id/profile_button"
- android:paddingBottom="8dp"/>
+ android:paddingStart="12dp"
+ android:weightSum="4"
+ android:paddingEnd="12dp"
+ android:elevation="8dp">
- <Button
- android:id="@+id/button_once"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:enabled="false"
- android:layout_gravity = "right"
- android:text="@string/activity_resolver_use_once"
- android:layout_weight="1"
- android:onClick="onButtonClick"/>
+ <TextView
+ android:id="@+id/profile_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="8dp"
+ android:paddingStart="8dp"
+ android:paddingEnd="8dp"
+ android:textSize="40sp"
+ android:layout_weight="4"
+ android:layout_gravity="left"
+ android:visibility="gone"
+ android:textColor="?attr/colorAccent"
+ android:singleLine="true"/>
- <Button
- android:id="@+id/button_always"
- android:layout_marginLeft="10dp"
- android:layout_width="wrap_content"
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="left"
+ android:layout_weight="3"
+ android:paddingTop="8dp"
+ android:layout_below="@id/profile_button"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:paddingBottom="8dp"/>
+
+ <Button
+ android:id="@+id/button_once"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:enabled="false"
+ android:layout_gravity="right"
+ style="?attr/buttonBarButtonStyle"
+ android:text="@string/activity_resolver_use_once"
+ android:layout_weight="0.5"
+ android:onClick="onButtonClick"/>
+
+ <Button
+ android:id="@+id/button_always"
+ android:layout_marginLeft="2dp"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:enabled="false"
+ android:layout_gravity="right"
+ style="?attr/buttonBarButtonStyle"
+ android:text="@string/activity_resolver_use_always"
+ android:layout_weight="0.5"
+ android:onClick="onButtonClick"/>
+ </LinearLayout>
+
+ <FrameLayout
+ android:id="@+id/stub"
+ android:visibility="gone"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:enabled="false"
- android:layout_gravity = "right"
- android:text="@string/activity_resolver_use_always"
- android:layout_weight="1"
- android:onClick="onButtonClick"/>
+ android:background="?attr/colorBackgroundFloating"/>
+
+ <TabHost
+ android:id="@+id/profile_tabhost"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:layout_centerHorizontal="true"
+ android:background="?attr/colorBackgroundFloating">
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <TabWidget
+ android:id="@android:id/tabs"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:visibility="gone">
+ </TabWidget>
+ <View
+ android:id="@+id/resolver_tab_divider"
+ android:visibility="gone"
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="?attr/colorBackgroundFloating"
+ android:foreground="?attr/dividerVertical"
+ android:layout_marginBottom="8dp"/>
+ <FrameLayout
+ android:id="@android:id/tabcontent"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <com.android.internal.app.ResolverViewPager
+ android:id="@+id/profile_pager"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+ </FrameLayout>
+ </LinearLayout>
+ </TabHost>
+
+ <View
+ android:layout_alwaysShow="true"
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="?attr/colorBackgroundFloating"
+ android:foreground="?attr/dividerVertical"/>
+
+ <TextView android:id="@+id/empty"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="?attr/colorBackgroundFloating"
+ android:elevation="8dp"
+ android:layout_alwaysShow="true"
+ android:text="@string/noApplications"
+ android:padding="32dp"
+ android:gravity="center"
+ android:visibility="gone"/>
+
</LinearLayout>
- <ListView
- android:layout_width="match_parent"
- android:layout_height="500dp"
- android:id="@+id/resolver_list"
- android:clipToPadding="false"
- android:scrollbarStyle="outsideOverlay"
- android:background="?attr/colorBackgroundFloating"
- android:elevation="8dp"
- android:nestedScrollingEnabled="true"
- android:scrollIndicators="top|bottom"/>
-
- <TextView android:id="@+id/empty"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="?attr/colorBackgroundFloating"
- android:elevation="8dp"
- android:layout_alwaysShow="true"
- android:text="@string/noApplications"
- android:padding="32dp"
- android:gravity="center"
- android:visibility="gone"/>
-
</com.android.internal.widget.ResolverDrawerLayout>
diff --git a/core/res/res/layout-car/car_resolver_list_with_default.xml b/core/res/res/layout-car/car_resolver_list_with_default.xml
index 2aed00b..5e450b2 100644
--- a/core/res/res/layout-car/car_resolver_list_with_default.xml
+++ b/core/res/res/layout-car/car_resolver_list_with_default.xml
@@ -40,12 +40,12 @@
<ImageView
android:id="@+id/icon"
- android:layout_width="24dp"
- android:layout_height="24dp"
+ android:layout_width="60dp"
+ android:layout_height="60dp"
android:layout_gravity="start|top"
- android:layout_marginStart="16dp"
- android:layout_marginEnd="16dp"
- android:layout_marginTop="20dp"
+ android:layout_marginStart="10dp"
+ android:layout_marginEnd="5dp"
+ android:layout_marginTop="10dp"
android:src="@drawable/resolver_icon_placeholder"
android:scaleType="fitCenter"/>
@@ -55,7 +55,7 @@
android:layout_weight="1"
android:layout_height="?attr/listPreferredItemHeight"
android:layout_marginStart="16dp"
- android:textAppearance="?attr/textAppearanceMedium"
+ android:textAppearance="?android:attr/textAppearanceLarge"
android:gravity="start|center_vertical"
android:paddingEnd="16dp"/>
@@ -120,7 +120,7 @@
android:layout_width="wrap_content"
android:layout_gravity="start"
android:maxLines="2"
- style="?attr/buttonBarNegativeButtonStyle"
+ style="?attr/buttonBarButtonStyle"
android:minHeight="@dimen/alert_dialog_button_bar_height"
android:layout_height="wrap_content"
android:enabled="false"
@@ -133,29 +133,64 @@
android:layout_gravity="end"
android:maxLines="2"
android:minHeight="@dimen/alert_dialog_button_bar_height"
- style="?attr/buttonBarPositiveButtonStyle"
+ style="?attr/buttonBarButtonStyle"
android:layout_height="wrap_content"
android:enabled="false"
android:text="@string/activity_resolver_use_always"
android:onClick="onButtonClick"/>
</LinearLayout>
+ <FrameLayout
+ android:id="@+id/stub"
+ android:layout_alwaysShow="true"
+ android:visibility="gone"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="?attr/colorBackgroundFloating"/>
+
+ <TabHost
+ android:layout_alwaysShow="true"
+ android:id="@+id/profile_tabhost"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:layout_centerHorizontal="true"
+ android:background="?attr/colorBackgroundFloating">
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <TabWidget
+ android:id="@android:id/tabs"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:visibility="gone">
+ </TabWidget>
+ <View
+ android:id="@+id/resolver_tab_divider"
+ android:visibility="gone"
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="?attr/colorBackgroundFloating"
+ android:foreground="?attr/dividerVertical"
+ android:layout_marginBottom="8dp"/>
+ <FrameLayout
+ android:id="@android:id/tabcontent"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <com.android.internal.app.ResolverViewPager
+ android:id="@+id/profile_pager"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ </com.android.internal.app.ResolverViewPager>
+ </FrameLayout>
+ </LinearLayout>
+ </TabHost>
+
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?attr/dividerVertical"/>
-
- <ListView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:id="@+id/resolver_list"
- android:layout_weight="4"
- android:clipToPadding="false"
- android:scrollbarStyle="outsideOverlay"
- android:background="?attr/colorBackgroundFloating"
- android:elevation="8dp"
- android:nestedScrollingEnabled="true"
- android:divider="@null"/>
</LinearLayout>
</com.android.internal.widget.ResolverDrawerLayout>
diff --git a/core/res/res/layout/resolver_list.xml b/core/res/res/layout/resolver_list.xml
index e17fc8a..b754e0c 100644
--- a/core/res/res/layout/resolver_list.xml
+++ b/core/res/res/layout/resolver_list.xml
@@ -100,8 +100,7 @@
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?attr/colorBackgroundFloating"
- android:foreground="?attr/dividerVertical"
- android:layout_marginBottom="@dimen/resolver_tab_divider_bottom_padding"/>
+ android:foreground="?attr/dividerVertical"/>
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="match_parent"
diff --git a/core/res/res/layout/resolver_list_with_default.xml b/core/res/res/layout/resolver_list_with_default.xml
index 0d4523a..06a7633 100644
--- a/core/res/res/layout/resolver_list_with_default.xml
+++ b/core/res/res/layout/resolver_list_with_default.xml
@@ -183,8 +183,7 @@
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="?attr/colorBackgroundFloating"
- android:foreground="?attr/dividerVertical"
- android:layout_marginBottom="@dimen/resolver_tab_divider_bottom_padding"/>
+ android:foreground="?attr/dividerVertical"/>
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="match_parent"
diff --git a/core/res/res/values-mcc219/config.xml b/core/res/res/values-mcc219/config.xml
deleted file mode 100644
index 7ae82fa..0000000
--- a/core/res/res/values-mcc219/config.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2009, 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
- for different hardware and product builds. -->
-<resources>
- <!-- Do not translate. Defines the slots is Two Digit Number for dialing normally not USSD -->
- <string-array name="config_twoDigitNumberPattern">
- <item>"92"</item>
- <item>"93"</item>
- <item>"94"</item>
- <item>"95"</item>
- <item>"96"</item>
- </string-array>
-
-</resources>
diff --git a/core/res/res/values-mcc220/config.xml b/core/res/res/values-mcc220/config.xml
deleted file mode 100644
index 7ae82fa..0000000
--- a/core/res/res/values-mcc220/config.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2009, 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
- for different hardware and product builds. -->
-<resources>
- <!-- Do not translate. Defines the slots is Two Digit Number for dialing normally not USSD -->
- <string-array name="config_twoDigitNumberPattern">
- <item>"92"</item>
- <item>"93"</item>
- <item>"94"</item>
- <item>"95"</item>
- <item>"96"</item>
- </string-array>
-
-</resources>
diff --git a/core/res/res/values-mcc310-mnc150/config.xml b/core/res/res/values-mcc310-mnc150/config.xml
deleted file mode 100644
index e7d1325..0000000
--- a/core/res/res/values-mcc310-mnc150/config.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2013, 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.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string-array translatable="false" name="config_twoDigitNumberPattern">
- <item>"0"</item>
- <item>"00"</item>
- <item>"*0"</item>
- <item>"*1"</item>
- <item>"*2"</item>
- <item>"*3"</item>
- <item>"*4"</item>
- <item>"*5"</item>
- <item>"*6"</item>
- <item>"*7"</item>
- <item>"*8"</item>
- <item>"*9"</item>
- <item>"#0"</item>
- <item>"#1"</item>
- <item>"#2"</item>
- <item>"#3"</item>
- <item>"#4"</item>
- <item>"#5"</item>
- <item>"#6"</item>
- <item>"#7"</item>
- <item>"#8"</item>
- <item>"#9"</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc310-mnc410/config.xml b/core/res/res/values-mcc310-mnc410/config.xml
index 3fb3f0f..53e4193 100644
--- a/core/res/res/values-mcc310-mnc410/config.xml
+++ b/core/res/res/values-mcc310-mnc410/config.xml
@@ -23,31 +23,6 @@
<!-- Configure mobile network MTU. Carrier specific value is set here.
-->
<integer name="config_mobile_mtu">1410</integer>
- <!-- Do not translate. Defines the slots is Two Digit Number for dialing normally not USSD -->
- <string-array name="config_twoDigitNumberPattern">
- <item>"0"</item>
- <item>"00"</item>
- <item>"*0"</item>
- <item>"*1"</item>
- <item>"*2"</item>
- <item>"*3"</item>
- <item>"*4"</item>
- <item>"*5"</item>
- <item>"*6"</item>
- <item>"*7"</item>
- <item>"*8"</item>
- <item>"*9"</item>
- <item>"#0"</item>
- <item>"#1"</item>
- <item>"#2"</item>
- <item>"#3"</item>
- <item>"#4"</item>
- <item>"#5"</item>
- <item>"#6"</item>
- <item>"#7"</item>
- <item>"#8"</item>
- <item>"#9"</item>
- </string-array>
<!-- Enable 5 bar signal strength icon -->
<bool name="config_inflateSignalStrength">true</bool>
diff --git a/core/res/res/values-mcc313-mnc100/config.xml b/core/res/res/values-mcc313-mnc100/config.xml
deleted file mode 100644
index ccd03f1..0000000
--- a/core/res/res/values-mcc313-mnc100/config.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2019, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string-array translatable="false" name="config_twoDigitNumberPattern">
- <item>"0"</item>
- <item>"00"</item>
- <item>"*0"</item>
- <item>"*1"</item>
- <item>"*2"</item>
- <item>"*3"</item>
- <item>"*4"</item>
- <item>"*5"</item>
- <item>"*6"</item>
- <item>"*7"</item>
- <item>"*8"</item>
- <item>"*9"</item>
- <item>"#0"</item>
- <item>"#1"</item>
- <item>"#2"</item>
- <item>"#3"</item>
- <item>"#4"</item>
- <item>"#5"</item>
- <item>"#6"</item>
- <item>"#7"</item>
- <item>"#8"</item>
- <item>"#9"</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc334-mnc050/config.xml b/core/res/res/values-mcc334-mnc050/config.xml
index 23678f1..2e8c504 100644
--- a/core/res/res/values-mcc334-mnc050/config.xml
+++ b/core/res/res/values-mcc334-mnc050/config.xml
@@ -31,8 +31,4 @@
<item>9</item>
</integer-array>
- <!-- Do not translate. Defines the slots is Two Digit Number for dialing normally not USSD -->
- <string-array translatable="false" name="config_twoDigitNumberPattern">
- <item>"#9"</item>
- </string-array>
</resources>
diff --git a/core/res/res/values-mcc334-mnc090/config.xml b/core/res/res/values-mcc334-mnc090/config.xml
deleted file mode 100644
index 1632a42..0000000
--- a/core/res/res/values-mcc334-mnc090/config.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2017, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
- for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Do not translate. Defines the slots is Two Digit Number for dialing normally not USSD -->
-
- <string-array translatable="false" name="config_twoDigitNumberPattern">
- <item>"#9"</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc704-mnc01/config.xml b/core/res/res/values-mcc704-mnc01/config.xml
deleted file mode 100644
index 10b6470..0000000
--- a/core/res/res/values-mcc704-mnc01/config.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2016, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my 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.
-*/
--->
-
-<resources>
- <!-- Do not translate. Defines the slots is Two Digit Number for dialing normally not USSD -->
- <string-array name="config_twoDigitNumberPattern">
- <item>"*1"</item>
- <item>"*5"</item>
- <item>"*9"</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values-mcc708-mnc001/config.xml b/core/res/res/values-mcc708-mnc001/config.xml
deleted file mode 100755
index 7b7c48d..0000000
--- a/core/res/res/values-mcc708-mnc001/config.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2016, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
- for different hardware and product builds. -->
-<resources>
- <string-array translatable="false" name="config_twoDigitNumberPattern">
- <item>"*1"</item>
- <item>"*5"</item>
- </string-array>
-</resources>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index c245131..cb88aee 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1541,6 +1541,28 @@
<flag name="microphone" value="0x80" />
</attr>
+ <!-- Enable sampled memory bug detection in this process.
+ When enabled, a very small, random subset of native
+ memory allocations are protected with guard pages, providing an
+ ASan-like error report in case of a memory corruption bug.
+
+ GWP-ASan is a recursive acronym. It stands for “GWP-ASan Will Provide Allocation SANity”.
+ See the <a href="http://llvm.org/docs/GwpAsan.html">LLVM documentation</a>
+ for more information about this feature.
+
+ <p>This tag can be applied to any tag that allows
+ {@link android.R.styleable#AndroidManifestProcess process} tag:
+ {@link android.R.styleable#AndroidManifestApplication application} tag (to supply
+ a default setting for all application components), or with the
+ {@link android.R.styleable#AndroidManifestProvider provider},
+ {@link android.R.styleable#AndroidManifestService service},
+ {@link android.R.styleable#AndroidManifestReceiver receiver},
+ {@link android.R.styleable#AndroidManifestActivity activity} tag.
+ When multiple components run in the same process,
+ the first component to start determines the behavior of the entire process.
+
+ The default value is {@code false}. -->
+ <attr name="enableGwpAsan" format="boolean" />
<!-- The <code>manifest</code> tag is the root of an
<code>AndroidManifest.xml</code> file,
@@ -1552,7 +1574,7 @@
<code>com.google.app.<em>appname</em></code>
<p>Inside of the manifest tag, may appear the following tags
- in any order: {@link #AndroidManifestFeature feature},
+ in any order: {@link #AndroidManifestAttribution attribution},
{@link #AndroidManifestPermission permission},
{@link #AndroidManifestPermissionGroup permission-group},
{@link #AndroidManifestPermissionTree permission-tree},
@@ -1806,31 +1828,38 @@
The default value is {@code true}. -->
<attr name="allowNativeHeapPointerTagging" format="boolean" />
+
+ <attr name="enableGwpAsan" />
+
</declare-styleable>
- <!-- The <code>feature</code> tag declares a feature. A feature is a logical part of an app.
- E.g. photo sharing app might include a direct messaging component. To tag certain code as
- belonging to a feature, use a context created via
- {@link android.content.Context#createFeatureContext(String)} for any interaction with the
+ <!-- An attribution is a logical part of an app and is identified by a tag.
+ E.g. a photo sharing app might include a direct messaging component. To tag certain code as
+ belonging to an attribution, use a context created via
+ {@link android.content.Context#createAttributionContext(String)} for any interaction with the
system.
<p>This appears as a child tag of the root {@link #AndroidManifest manifest} tag.
- <p>In case this feature inherits from another feature, this tag can contain one or multiple
- {@link #AndroidManifestFeatureInheritFrom inherit-from} tags. -->
- <declare-styleable name="AndroidManifestFeature" parent="AndroidManifest">
- <!-- Required identifier for a feature. Can be passed to
- {@link android.content.Context#createFeatureContext} to create a context for this feature
- -->
+ <p>In case this attribution inherits from another attribution, this tag can contain one or
+ multiple {@link #AndroidManifestAttributionInheritFrom inherit-from} tags. -->
+ <declare-styleable name="AndroidManifestAttribution" parent="AndroidManifest">
+ <!-- TODO moltmann: Remove -->
<attr name="featureId" format="string" />
- <!-- Required user visible label for a feature. -->
+ <!-- Required identifier for a attribution. Can be passed to
+ {@link android.content.Context#createAttributionContext} to create a context tagged with
+ this attribution
+ -->
+ <attr name="tag" format="string" />
+ <!-- Required user visible label for a attribution. -->
<attr name="label" format="string" />
</declare-styleable>
<!-- Declares previously declared features this feature inherits from. -->
- <declare-styleable name="AndroidManifestFeatureInheritFrom" parent="AndroidManifestFeature">
- <!-- Identifier of the feature this feature inherits from -->
- <attr name="featureId" format="string" />
+ <declare-styleable name="AndroidManifestAttributionInheritFrom"
+ parent="AndroidManifestAttribution">
+ <!-- Identifier of the attribution this attribution inherits from -->
+ <attr name="tag" format="string" />
</declare-styleable>
<!-- The <code>permission</code> tag declares a security permission that can be
@@ -2312,6 +2341,7 @@
<declare-styleable name="AndroidManifestProcess" parent="AndroidManifestProcesses">
<!-- Required name of the process that is allowed -->
<attr name="process" />
+ <attr name="enableGwpAsan" />
</declare-styleable>
<!-- The <code>deny-permission</code> tag specifies that a permission is to be denied
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 0b6e65fe..6f468e0 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2024,7 +2024,10 @@
a keyboard is present. -->
<bool name="config_showMenuShortcutsWhenKeyboardPresent">false</bool>
- <!-- Do not translate. Defines the slots is Two Digit Number for dialing normally not USSD -->
+ <!-- Do not translate. Defines the slots is Two Digit Number for dialing normally not USSD.
+
+ Note: This config is deprecated, please use carrier config which is
+ CarrierConfigManager.KEY_MMI_TWO_DIGIT_NUMBER_PATTERN_STRING_ARRAY instead. -->
<string-array name="config_twoDigitNumberPattern" translatable="false">
</string-array>
@@ -4415,4 +4418,7 @@
<!-- Package name of custom session policy provider class used by MediaSessionService. -->
<string name="config_customSessionPolicyProvider"></string>
+
+ <!-- The max scale for the wallpaper when it's zoomed in -->
+ <item name="config_wallpaperMaxScale" format="float" type="dimen">1</item>
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 8f35360..e3fe982 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -794,7 +794,6 @@
<dimen name="resolver_empty_state_height_with_tabs">268dp</dimen>
<dimen name="resolver_max_collapsed_height">192dp</dimen>
<dimen name="resolver_max_collapsed_height_with_tabs">248dp</dimen>
- <dimen name="resolver_tab_divider_bottom_padding">8dp</dimen>
<dimen name="chooser_action_button_icon_size">18dp</dimen>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 39e8197..96807cc 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3004,6 +3004,7 @@
<public name="animatedImageDrawable"/>
<public name="htmlDescription"/>
<public name="preferMinimalPostProcessing"/>
+ <!-- @removed -->
<public name="featureId" />
<public name="supportsInlineSuggestions" />
<public name="crossProfile" />
@@ -3015,6 +3016,7 @@
<public name="allowNativeHeapPointerTagging" />
<public name="preserveLegacyExternalStorage" />
<public name="mimeGroup" />
+ <public name="enableGwpAsan" />
</public-group>
<public-group type="drawable" first-id="0x010800b5">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index fddca4d..f101f59 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1217,6 +1217,14 @@
device. This includes information such as call numbers for calls and the state of the
calls.</string>
+ <!-- Title of an application permission. When granted the app is exempt from audio record
+ restrictions.
+ [CHAR LIMIT=NONE]-->
+ <string name="permlab_exemptFromAudioRecordRestrictions">exempt from audio record restrictions</string>
+ <!-- Description of an application permission. When granted the app is exempt from audio record
+ restrictions. [CHAR LIMIT=NONE]-->
+ <string name="permdesc_exemptFromAudioRecordRestrictions">Exempt the app from restrictions to record audio.</string>
+
<!-- Title of an application permission. When granted the user is giving access to a third
party app to continue a call which originated in another app. For example, the user
could be in a voice call over their carrier's mobile network, and a third party video
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 73360d5..49a0f17 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3933,7 +3933,6 @@
<java-symbol type="dimen" name="resolver_empty_state_height_with_tabs" />
<java-symbol type="dimen" name="resolver_max_collapsed_height_with_tabs" />
<java-symbol type="bool" name="sharesheet_show_content_preview" />
- <java-symbol type="dimen" name="resolver_tab_divider_bottom_padding" />
<!-- Toast message for background started foreground service while-in-use permission restriction feature -->
<java-symbol type="string" name="allow_while_in_use_permission_in_fgs" />
@@ -3951,4 +3950,6 @@
<java-symbol type="string" name="config_customMediaKeyDispatcher" />
<java-symbol type="string" name="config_customSessionPolicyProvider" />
+ <!-- The max scale for the wallpaper when it's zoomed in -->
+ <java-symbol type="dimen" name="config_wallpaperMaxScale"/>
</resources>
diff --git a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
index 50cd5a3..fe25e79 100644
--- a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
+++ b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
@@ -123,7 +123,7 @@
mController = new InsetsAnimationControlImpl(controls,
new Rect(0, 0, 500, 500), mInsetsState, mMockListener, systemBars(),
mMockController, 10 /* durationMs */, new LinearInterpolator(),
- false /* fade */, LAYOUT_INSETS_DURING_ANIMATION_SHOWN, 0 /* animationType */);
+ false /* fade */, 0 /* animationType */);
}
@Test
@@ -182,7 +182,7 @@
@Test
public void testCancelled() {
- mController.onCancelled();
+ mController.cancel();
try {
mController.setInsetsAndAlpha(Insets.NONE, 1f /*alpha */, 0f /* fraction */);
fail("Expected exception to be thrown");
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index 7737b1a..f1ab8dd 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -31,6 +31,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
@@ -47,8 +48,10 @@
import android.graphics.Rect;
import android.os.CancellationSignal;
import android.platform.test.annotations.Presubmit;
+import android.view.InsetsState.InternalInsetsType;
import android.view.SurfaceControl.Transaction;
import android.view.WindowInsets.Type;
+import android.view.WindowInsetsController.OnControllableInsetsChangedListener;
import android.view.WindowManager.BadTokenException;
import android.view.WindowManager.LayoutParams;
import android.view.animation.LinearInterpolator;
@@ -67,6 +70,8 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
+import org.mockito.Mockito;
import java.util.concurrent.CountDownLatch;
import java.util.function.Supplier;
@@ -166,28 +171,30 @@
@Test
public void testControlsChanged() {
- InsetsSourceControl control =
- new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point());
- mController.onControlsChanged(new InsetsSourceControl[] { control });
- assertEquals(mLeash,
- mController.getSourceConsumer(ITYPE_STATUS_BAR).getControl().getLeash());
+ mController.onControlsChanged(createSingletonControl(ITYPE_STATUS_BAR));
+ assertNotNull(mController.getSourceConsumer(ITYPE_STATUS_BAR).getControl().getLeash());
+ mController.addOnControllableInsetsChangedListener(
+ ((controller, typeMask) -> assertEquals(statusBars(), typeMask)));
}
@Test
public void testControlsRevoked() {
- InsetsSourceControl control =
- new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point());
- mController.onControlsChanged(new InsetsSourceControl[] { control });
+ OnControllableInsetsChangedListener listener
+ = mock(OnControllableInsetsChangedListener.class);
+ mController.addOnControllableInsetsChangedListener(listener);
+ mController.onControlsChanged(createSingletonControl(ITYPE_STATUS_BAR));
mController.onControlsChanged(new InsetsSourceControl[0]);
assertNull(mController.getSourceConsumer(ITYPE_STATUS_BAR).getControl());
+ InOrder inOrder = Mockito.inOrder(listener);
+ inOrder.verify(listener).onControllableInsetsChanged(eq(mController), eq(0));
+ inOrder.verify(listener).onControllableInsetsChanged(eq(mController), eq(statusBars()));
+ inOrder.verify(listener).onControllableInsetsChanged(eq(mController), eq(0));
}
@Test
public void testControlsRevoked_duringAnim() {
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
- InsetsSourceControl control =
- new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point());
- mController.onControlsChanged(new InsetsSourceControl[] { control });
+ mController.onControlsChanged(createSingletonControl(ITYPE_STATUS_BAR));
WindowInsetsAnimationControlListener mockListener =
mock(WindowInsetsAnimationControlListener.class);
@@ -206,10 +213,15 @@
public void testFrameDoesntMatchDisplay() {
mController.onFrameChanged(new Rect(0, 0, 100, 100));
mController.getState().setDisplayFrame(new Rect(0, 0, 200, 200));
+ InsetsSourceControl control =
+ new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point());
+ mController.onControlsChanged(new InsetsSourceControl[] { control });
WindowInsetsAnimationControlListener controlListener =
mock(WindowInsetsAnimationControlListener.class);
mController.controlWindowInsetsAnimation(0, 0 /* durationMs */, new LinearInterpolator(),
controlListener);
+ mController.addOnControllableInsetsChangedListener(
+ (controller, typeMask) -> assertEquals(0, typeMask));
verify(controlListener).onCancelled();
verify(controlListener, never()).onReady(any(), anyInt());
}
@@ -245,11 +257,8 @@
@Test
public void testApplyImeVisibility() {
- final InsetsSourceControl ime = new InsetsSourceControl(ITYPE_IME, mLeash, new Point());
-
- InsetsSourceControl[] controls = new InsetsSourceControl[3];
- controls[0] = ime;
- mController.onControlsChanged(controls);
+ InsetsSourceControl ime = createControl(ITYPE_IME);
+ mController.onControlsChanged(new InsetsSourceControl[] { ime });
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
mController.getSourceConsumer(ITYPE_IME).onWindowFocusGained();
mController.applyImeVisibility(true);
@@ -412,9 +421,7 @@
@Test
public void testRestoreStartsAnimation() {
- InsetsSourceControl control =
- new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point());
- mController.onControlsChanged(new InsetsSourceControl[]{control});
+ mController.onControlsChanged(createSingletonControl(ITYPE_STATUS_BAR));
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
mController.hide(Type.statusBars());
@@ -431,7 +438,7 @@
assertTrue(mController.getState().getSource(ITYPE_STATUS_BAR).isVisible());
// Gaining control
- mController.onControlsChanged(new InsetsSourceControl[]{control});
+ mController.onControlsChanged(createSingletonControl(ITYPE_STATUS_BAR));
assertEquals(ANIMATION_TYPE_HIDE, mController.getAnimationType(ITYPE_STATUS_BAR));
mController.cancelExistingAnimation();
assertFalse(mController.getSourceConsumer(ITYPE_STATUS_BAR).isRequestedVisible());
@@ -442,8 +449,6 @@
@Test
public void testStartImeAnimationAfterGettingControl() {
- InsetsSourceControl control =
- new InsetsSourceControl(ITYPE_IME, mLeash, new Point());
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
@@ -454,7 +459,7 @@
mController.show(ime(), true /* fromIme */);
// Gaining control shortly after
- mController.onControlsChanged(new InsetsSourceControl[]{control});
+ mController.onControlsChanged(createSingletonControl(ITYPE_IME));
assertEquals(ANIMATION_TYPE_SHOW, mController.getAnimationType(ITYPE_IME));
mController.cancelExistingAnimation();
@@ -466,16 +471,13 @@
@Test
public void testStartImeAnimationAfterGettingControl_imeLater() {
- InsetsSourceControl control =
- new InsetsSourceControl(ITYPE_IME, mLeash, new Point());
-
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
mController.show(ime());
assertFalse(mController.getState().getSource(ITYPE_IME).isVisible());
// Gaining control shortly after
- mController.onControlsChanged(new InsetsSourceControl[]{control});
+ mController.onControlsChanged(createSingletonControl(ITYPE_IME));
// Pretend IME is calling
mController.show(ime(), true /* fromIme */);
@@ -490,9 +492,7 @@
@Test
public void testAnimationEndState_controller() throws Exception {
- InsetsSourceControl control =
- new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point());
- mController.onControlsChanged(new InsetsSourceControl[] { control });
+ mController.onControlsChanged(createSingletonControl(ITYPE_STATUS_BAR));
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
WindowInsetsAnimationControlListener mockListener =
@@ -518,9 +518,7 @@
@Test
public void testCancellation_afterGainingControl() throws Exception {
- InsetsSourceControl control =
- new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point());
- mController.onControlsChanged(new InsetsSourceControl[] { control });
+ mController.onControlsChanged(createSingletonControl(ITYPE_STATUS_BAR));
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
WindowInsetsAnimationControlListener mockListener =
@@ -638,12 +636,23 @@
latch.await();
}
+ private InsetsSourceControl createControl(@InternalInsetsType int type) {
+
+ // Simulate binder behavior by copying SurfaceControl. Otherwise, InsetsController will
+ // attempt to release mLeash directly.
+ SurfaceControl copy = new SurfaceControl();
+ copy.copyFrom(mLeash);
+ return new InsetsSourceControl(type, copy, new Point());
+ }
+
+ private InsetsSourceControl[] createSingletonControl(@InternalInsetsType int type) {
+ return new InsetsSourceControl[] { createControl(type) };
+ }
+
private InsetsSourceControl[] prepareControls() {
- final InsetsSourceControl navBar = new InsetsSourceControl(ITYPE_NAVIGATION_BAR, mLeash,
- new Point());
- final InsetsSourceControl statusBar = new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash,
- new Point());
- final InsetsSourceControl ime = new InsetsSourceControl(ITYPE_IME, mLeash, new Point());
+ final InsetsSourceControl navBar = createControl(ITYPE_NAVIGATION_BAR);
+ final InsetsSourceControl statusBar = createControl(ITYPE_STATUS_BAR);
+ final InsetsSourceControl ime = createControl(ITYPE_IME);
InsetsSourceControl[] controls = new InsetsSourceControl[3];
controls[0] = navBar;
diff --git a/core/tests/coretests/src/android/view/PendingInsetsControllerTest.java b/core/tests/coretests/src/android/view/PendingInsetsControllerTest.java
index 9787b77..9797178 100644
--- a/core/tests/coretests/src/android/view/PendingInsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/PendingInsetsControllerTest.java
@@ -25,12 +25,14 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import android.os.CancellationSignal;
import android.platform.test.annotations.Presubmit;
+import android.view.WindowInsetsController.OnControllableInsetsChangedListener;
import android.view.animation.LinearInterpolator;
import org.junit.Before;
@@ -163,11 +165,43 @@
}
@Test
+ public void testAddOnControllableInsetsChangedListener() {
+ OnControllableInsetsChangedListener listener =
+ mock(OnControllableInsetsChangedListener.class);
+ mPendingInsetsController.addOnControllableInsetsChangedListener(listener);
+ mPendingInsetsController.replayAndAttach(mReplayedController);
+ verify(mReplayedController).addOnControllableInsetsChangedListener(eq(listener));
+ verify(listener).onControllableInsetsChanged(eq(mPendingInsetsController), eq(0));
+ }
+
+ @Test
+ public void testAddRemoveControllableInsetsChangedListener() {
+ OnControllableInsetsChangedListener listener =
+ mock(OnControllableInsetsChangedListener.class);
+ mPendingInsetsController.addOnControllableInsetsChangedListener(listener);
+ mPendingInsetsController.removeOnControllableInsetsChangedListener(listener);
+ mPendingInsetsController.replayAndAttach(mReplayedController);
+ verify(mReplayedController, never()).addOnControllableInsetsChangedListener(any());
+ verify(listener).onControllableInsetsChanged(eq(mPendingInsetsController), eq(0));
+ }
+
+ @Test
+ public void testAddOnControllableInsetsChangedListener_direct() {
+ mPendingInsetsController.replayAndAttach(mReplayedController);
+ OnControllableInsetsChangedListener listener =
+ mock(OnControllableInsetsChangedListener.class);
+ mPendingInsetsController.addOnControllableInsetsChangedListener(listener);
+ verify(mReplayedController).addOnControllableInsetsChangedListener(eq(listener));
+ }
+
+ @Test
public void testReplayTwice() {
mPendingInsetsController.show(systemBars());
mPendingInsetsController.setSystemBarsBehavior(BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE);
mPendingInsetsController.setSystemBarsAppearance(APPEARANCE_LIGHT_STATUS_BARS,
APPEARANCE_LIGHT_STATUS_BARS);
+ mPendingInsetsController.addOnControllableInsetsChangedListener(
+ (controller, typeMask) -> {});
mPendingInsetsController.replayAndAttach(mReplayedController);
InsetsController secondController = mock(InsetsController.class);
mPendingInsetsController.replayAndAttach(secondController);
diff --git a/core/tests/coretests/src/android/view/textclassifier/SystemTextClassifierMetadataTest.java b/core/tests/coretests/src/android/view/textclassifier/SystemTextClassifierMetadataTest.java
new file mode 100644
index 0000000..e4cfc53
--- /dev/null
+++ b/core/tests/coretests/src/android/view/textclassifier/SystemTextClassifierMetadataTest.java
@@ -0,0 +1,61 @@
+/*
+ * 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 android.view.textclassifier;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+
+
+import android.os.Parcel;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SystemTextClassifierMetadataTest {
+
+ @Test
+ public void testInvalidPackageNameThrowsException() {
+ assertThrows(NullPointerException.class,
+ () -> new SystemTextClassifierMetadata(/* packageName= */ null, /* userId= */
+ 1, /* useDefaultTextClassifier= */ false));
+ }
+
+ @Test
+ public void testParcel() {
+ SystemTextClassifierMetadata sysTcMetadata = new SystemTextClassifierMetadata(
+ "package", /* userId= */ 1, /* useDefaultTextClassifier= */ false);
+
+ Parcel p = Parcel.obtain();
+ sysTcMetadata.writeToParcel(p, 0);
+ p.setDataPosition(0);
+
+ SystemTextClassifierMetadata targetSysTcMetadata =
+ SystemTextClassifierMetadata.CREATOR.createFromParcel(p);
+
+ assertThat(targetSysTcMetadata.getUserId()).isEqualTo(sysTcMetadata.getUserId());
+ assertThat(targetSysTcMetadata.getCallingPackageName()).isEqualTo(
+ sysTcMetadata.getCallingPackageName());
+ assertThat(targetSysTcMetadata.useDefaultTextClassifier()).isEqualTo(
+ sysTcMetadata.useDefaultTextClassifier());
+ }
+}
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
index d544029..39ededa 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
@@ -17,6 +17,7 @@
package android.view.textclassifier;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
@@ -199,7 +200,9 @@
.setReferenceTime(referenceTime)
.setExtras(BUNDLE)
.build();
- reference.setCallingPackageName(packageName);
+ final SystemTextClassifierMetadata systemTcMetadata =
+ new SystemTextClassifierMetadata(packageName, 1, false);
+ reference.setSystemTextClassifierMetadata(systemTcMetadata);
// Parcel and unparcel.
final Parcel parcel = Parcel.obtain();
@@ -216,5 +219,11 @@
assertEquals(referenceTime, result.getReferenceTime());
assertEquals(BUNDLE_VALUE, result.getExtras().getString(BUNDLE_KEY));
assertEquals(packageName, result.getCallingPackageName());
+ final SystemTextClassifierMetadata resultSystemTcMetadata =
+ result.getSystemTextClassifierMetadata();
+ assertNotNull(resultSystemTcMetadata);
+ assertEquals(packageName, resultSystemTcMetadata.getCallingPackageName());
+ assertEquals(1, resultSystemTcMetadata.getUserId());
+ assertFalse(resultSystemTcMetadata.useDefaultTextClassifier());
}
}
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextLanguageTest.java b/core/tests/coretests/src/android/view/textclassifier/TextLanguageTest.java
index d0d32e3..31f8029 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextLanguageTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextLanguageTest.java
@@ -17,6 +17,8 @@
package android.view.textclassifier;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
import android.icu.util.ULocale;
import android.os.Bundle;
@@ -75,7 +77,9 @@
final TextLanguage.Request reference = new TextLanguage.Request.Builder(text)
.setExtras(bundle)
.build();
- reference.setCallingPackageName(packageName);
+ final SystemTextClassifierMetadata systemTcMetadata =
+ new SystemTextClassifierMetadata(packageName, 1, false);
+ reference.setSystemTextClassifierMetadata(systemTcMetadata);
final Parcel parcel = Parcel.obtain();
reference.writeToParcel(parcel, 0);
@@ -85,5 +89,11 @@
assertEquals(text, result.getText());
assertEquals("bundle", result.getExtras().getString(bundleKey));
assertEquals(packageName, result.getCallingPackageName());
+ final SystemTextClassifierMetadata resultSystemTcMetadata =
+ result.getSystemTextClassifierMetadata();
+ assertNotNull(resultSystemTcMetadata);
+ assertEquals(packageName, resultSystemTcMetadata.getCallingPackageName());
+ assertEquals(1, resultSystemTcMetadata.getUserId());
+ assertFalse(resultSystemTcMetadata.useDefaultTextClassifier());
}
}
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextLinksTest.java b/core/tests/coretests/src/android/view/textclassifier/TextLinksTest.java
index ec5813f..4f0b44b 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextLinksTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextLinksTest.java
@@ -17,6 +17,8 @@
package android.view.textclassifier;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
import android.os.Bundle;
import android.os.LocaleList;
@@ -115,7 +117,9 @@
.setExtras(BUNDLE)
.setReferenceTime(referenceTime)
.build();
- reference.setCallingPackageName(packageName);
+ final SystemTextClassifierMetadata systemTcMetadata =
+ new SystemTextClassifierMetadata(packageName, 1, false);
+ reference.setSystemTextClassifierMetadata(systemTcMetadata);
// Parcel and unparcel.
final Parcel parcel = Parcel.obtain();
@@ -132,5 +136,11 @@
assertEquals(BUNDLE_VALUE, result.getExtras().getString(BUNDLE_KEY));
assertEquals(packageName, result.getCallingPackageName());
assertEquals(referenceTime, result.getReferenceTime());
+ final SystemTextClassifierMetadata resultSystemTcMetadata =
+ result.getSystemTextClassifierMetadata();
+ assertNotNull(resultSystemTcMetadata);
+ assertEquals(packageName, resultSystemTcMetadata.getCallingPackageName());
+ assertEquals(1, resultSystemTcMetadata.getUserId());
+ assertFalse(resultSystemTcMetadata.useDefaultTextClassifier());
}
}
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextSelectionTest.java b/core/tests/coretests/src/android/view/textclassifier/TextSelectionTest.java
index 30cc4e8..82788c8 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextSelectionTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextSelectionTest.java
@@ -17,6 +17,8 @@
package android.view.textclassifier;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
import android.os.Bundle;
import android.os.LocaleList;
@@ -82,7 +84,9 @@
.setDefaultLocales(new LocaleList(Locale.US, Locale.GERMANY))
.setExtras(BUNDLE)
.build();
- reference.setCallingPackageName(packageName);
+ final SystemTextClassifierMetadata systemTcMetadata =
+ new SystemTextClassifierMetadata(packageName, 1, false);
+ reference.setSystemTextClassifierMetadata(systemTcMetadata);
// Parcel and unparcel.
final Parcel parcel = Parcel.obtain();
@@ -96,5 +100,11 @@
assertEquals("en-US,de-DE", result.getDefaultLocales().toLanguageTags());
assertEquals(BUNDLE_VALUE, result.getExtras().getString(BUNDLE_KEY));
assertEquals(packageName, result.getCallingPackageName());
+ final SystemTextClassifierMetadata resultSystemTcMetadata =
+ result.getSystemTextClassifierMetadata();
+ assertNotNull(resultSystemTcMetadata);
+ assertEquals(packageName, resultSystemTcMetadata.getCallingPackageName());
+ assertEquals(1, resultSystemTcMetadata.getUserId());
+ assertFalse(resultSystemTcMetadata.useDefaultTextClassifier());
}
}
diff --git a/data/etc/car/com.google.android.car.kitchensink.xml b/data/etc/car/com.google.android.car.kitchensink.xml
index 61281ee..efe658a 100644
--- a/data/etc/car/com.google.android.car.kitchensink.xml
+++ b/data/etc/car/com.google.android.car.kitchensink.xml
@@ -33,6 +33,7 @@
<permission name="android.permission.MODIFY_AUDIO_ROUTING"/>
<permission name="android.permission.MODIFY_DAY_NIGHT_MODE"/>
<permission name="android.permission.MODIFY_PHONE_STATE"/>
+ <permission name="android.permission.MONITOR_INPUT"/>
<permission name="android.permission.PROVIDE_TRUST_AGENT"/>
<permission name="android.permission.OVERRIDE_WIFI_CONFIG"/>
<permission name="android.permission.REAL_GET_TASKS"/>
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 49edcf7..487a6e9 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -164,6 +164,7 @@
<permission name="android.permission.REBOOT"/>
<permission name="android.permission.REGISTER_CALL_PROVIDER"/>
<permission name="android.permission.REGISTER_SIM_SUBSCRIPTION"/>
+ <permission name="android.permission.REGISTER_STATS_PULL_ATOM"/>
<permission name="android.permission.SEND_RESPOND_VIA_MESSAGE"/>
<permission name="android.permission.SET_TIME_ZONE"/>
<permission name="android.permission.SHUTDOWN"/>
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index d9d2eea..a7d0cb8 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -764,8 +764,9 @@
private @KeyProperties.BlockModeEnum String[] mBlockModes;
private boolean mRandomizedEncryptionRequired = true;
private boolean mUserAuthenticationRequired;
- private int mUserAuthenticationValidityDurationSeconds = -1;
- private @KeyProperties.AuthEnum int mUserAuthenticationType;
+ private int mUserAuthenticationValidityDurationSeconds = 0;
+ private @KeyProperties.AuthEnum int mUserAuthenticationType =
+ KeyProperties.AUTH_BIOMETRIC_STRONG;
private boolean mUserPresenceRequired = false;
private byte[] mAttestationChallenge = null;
private boolean mUniqueIdIncluded = false;
@@ -1240,7 +1241,8 @@
if (seconds == -1) {
return setUserAuthenticationParameters(0, KeyProperties.AUTH_BIOMETRIC_STRONG);
}
- return setUserAuthenticationParameters(seconds, KeyProperties.AUTH_BIOMETRIC_STRONG);
+ return setUserAuthenticationParameters(seconds, KeyProperties.AUTH_DEVICE_CREDENTIAL
+ | KeyProperties.AUTH_BIOMETRIC_STRONG);
}
/**
diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java
index 8120a93..2e793de 100644
--- a/keystore/java/android/security/keystore/KeyProtection.java
+++ b/keystore/java/android/security/keystore/KeyProtection.java
@@ -562,8 +562,9 @@
private @KeyProperties.BlockModeEnum String[] mBlockModes;
private boolean mRandomizedEncryptionRequired = true;
private boolean mUserAuthenticationRequired;
- private @KeyProperties.AuthEnum int mUserAuthenticationType;
- private int mUserAuthenticationValidityDurationSeconds = -1;
+ private int mUserAuthenticationValidityDurationSeconds = 0;
+ private @KeyProperties.AuthEnum int mUserAuthenticationType =
+ KeyProperties.AUTH_BIOMETRIC_STRONG;
private boolean mUserPresenceRequired = false;
private boolean mUserAuthenticationValidWhileOnBody;
private boolean mInvalidatedByBiometricEnrollment = true;
@@ -870,7 +871,8 @@
if (seconds == -1) {
return setUserAuthenticationParameters(0, KeyProperties.AUTH_BIOMETRIC_STRONG);
}
- return setUserAuthenticationParameters(seconds, KeyProperties.AUTH_BIOMETRIC_STRONG);
+ return setUserAuthenticationParameters(seconds, KeyProperties.AUTH_DEVICE_CREDENTIAL
+ | KeyProperties.AUTH_BIOMETRIC_STRONG);
}
/**
diff --git a/keystore/java/android/security/keystore/KeymasterUtils.java b/keystore/java/android/security/keystore/KeymasterUtils.java
index 4ead253..bc933ff 100644
--- a/keystore/java/android/security/keystore/KeymasterUtils.java
+++ b/keystore/java/android/security/keystore/KeymasterUtils.java
@@ -165,8 +165,7 @@
}
args.addUnsignedLong(KeymasterDefs.KM_TAG_USER_SECURE_ID,
KeymasterArguments.toUint64(sid));
- args.addEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE,
- KeymasterDefs.HW_AUTH_PASSWORD | KeymasterDefs.HW_AUTH_BIOMETRIC);
+ args.addEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, spec.getUserAuthenticationType());
args.addUnsignedInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT,
spec.getUserAuthenticationValidityDurationSeconds());
if (spec.isUserAuthenticationValidWhileOnBody()) {
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 550e41f..ff7049e 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -612,7 +612,7 @@
public Location getLastLocation() {
try {
return mService.getLastLocation(null, mContext.getPackageName(),
- mContext.getFeatureId());
+ mContext.getAttributionTag());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -645,7 +645,7 @@
try {
return mService.getLastLocation(request, mContext.getPackageName(),
- mContext.getFeatureId());
+ mContext.getAttributionTag());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -742,7 +742,7 @@
try {
if (mService.getCurrentLocation(currentLocationRequest, remoteCancellationSignal,
- listenerTransport, mContext.getPackageName(), mContext.getFeatureId(),
+ listenerTransport, mContext.getPackageName(), mContext.getAttributionTag(),
getListenerIdentifier(consumer))) {
listenerTransport.register(mContext.getSystemService(AlarmManager.class),
remoteCancellationSignal);
@@ -1189,7 +1189,7 @@
boolean registered = false;
try {
mService.requestLocationUpdates(locationRequest, transport, null,
- mContext.getPackageName(), mContext.getFeatureId(),
+ mContext.getPackageName(), mContext.getAttributionTag(),
getListenerIdentifier(listener));
registered = true;
} catch (RemoteException e) {
@@ -1235,7 +1235,7 @@
try {
mService.requestLocationUpdates(locationRequest, null, pendingIntent,
- mContext.getPackageName(), mContext.getFeatureId(),
+ mContext.getPackageName(), mContext.getAttributionTag(),
getListenerIdentifier(pendingIntent));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1711,7 +1711,7 @@
LocationRequest request = new LocationRequest().setExpireIn(expiration);
try {
mService.requestGeofence(request, fence, intent, mContext.getPackageName(),
- mContext.getFeatureId(), getListenerIdentifier(intent));
+ mContext.getAttributionTag(), getListenerIdentifier(intent));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1798,7 +1798,7 @@
try {
mService.requestGeofence(request, fence, intent, mContext.getPackageName(),
- mContext.getFeatureId(), getListenerIdentifier(intent));
+ mContext.getAttributionTag(), getListenerIdentifier(intent));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2946,7 +2946,7 @@
GnssStatusListener transport = new GnssStatusListener();
if (mService.registerGnssStatusCallback(transport, mContext.getPackageName(),
- mContext.getFeatureId())) {
+ mContext.getAttributionTag())) {
mListenerTransport = transport;
return true;
} else {
@@ -3012,7 +3012,7 @@
GnssMeasurementsListener transport = new GnssMeasurementsListener();
if (mService.addGnssMeasurementsListener(request, transport, mContext.getPackageName(),
- mContext.getFeatureId(), "gnss measurement callback")) {
+ mContext.getAttributionTag(), "gnss measurement callback")) {
mListenerTransport = transport;
return true;
} else {
@@ -3065,7 +3065,7 @@
GnssNavigationMessageListener transport = new GnssNavigationMessageListener();
if (mService.addGnssNavigationMessageListener(transport, mContext.getPackageName(),
- mContext.getFeatureId(), "gnss navigation callback")) {
+ mContext.getAttributionTag(), "gnss navigation callback")) {
mListenerTransport = transport;
return true;
} else {
@@ -3106,7 +3106,7 @@
GnssAntennaInfoListener transport = new GnssAntennaInfoListener();
if (mService.addGnssAntennaInfoListener(transport, mContext.getPackageName(),
- mContext.getFeatureId(), "gnss antenna info callback")) {
+ mContext.getAttributionTag(), "gnss antenna info callback")) {
mListenerTransport = transport;
return true;
} else {
@@ -3143,7 +3143,7 @@
BatchedLocationCallback transport = new BatchedLocationCallback();
if (mService.addGnssBatchingCallback(transport, mContext.getPackageName(),
- mContext.getFeatureId(), "batched location callback")) {
+ mContext.getAttributionTag(), "batched location callback")) {
mListenerTransport = transport;
return true;
} else {
diff --git a/media/java/android/media/tv/tuner/Lnb.java b/media/java/android/media/tv/tuner/Lnb.java
index 7932dcb..ea06632 100644
--- a/media/java/android/media/tv/tuner/Lnb.java
+++ b/media/java/android/media/tv/tuner/Lnb.java
@@ -156,7 +156,7 @@
private long mNativeContext;
- Lnb(int id) {
+ private Lnb(int id) {
mId = id;
}
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index bcbc12b..08a33f1 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -43,7 +43,11 @@
import android.media.tv.tuner.frontend.FrontendStatus.FrontendStatusType;
import android.media.tv.tuner.frontend.OnTuneEventListener;
import android.media.tv.tuner.frontend.ScanCallback;
+import android.media.tv.tunerresourcemanager.ResourceClientProfile;
+import android.media.tv.tunerresourcemanager.TunerLnbRequest;
+import android.media.tv.tunerresourcemanager.TunerResourceManager;
import android.os.Handler;
+import android.os.HandlerExecutor;
import android.os.Looper;
import android.os.Message;
@@ -67,6 +71,7 @@
private static final String TAG = "MediaTvTuner";
private static final boolean DEBUG = false;
+ private static final int MSG_RESOURCE_LOST = 1;
private static final int MSG_ON_FILTER_EVENT = 2;
private static final int MSG_ON_FILTER_STATUS = 3;
private static final int MSG_ON_LNB_EVENT = 4;
@@ -93,6 +98,8 @@
}
private final Context mContext;
+ private final TunerResourceManager mTunerResourceManager;
+ private final int mClientId;
private List<Integer> mFrontendIds;
private Frontend mFrontend;
@@ -102,6 +109,7 @@
private List<Integer> mLnbIds;
private Lnb mLnb;
+ private Integer mLnbId;
@Nullable
private OnTuneEventListener mOnTuneEventListener;
@Nullable
@@ -115,6 +123,15 @@
@Nullable
private Executor mOnResourceLostListenerExecutor;
+
+ private final TunerResourceManager.ResourcesReclaimListener mResourceListener =
+ new TunerResourceManager.ResourcesReclaimListener() {
+ @Override
+ public void onReclaimResources() {
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_RESOURCE_LOST));
+ }
+ };
+
/**
* Constructs a Tuner instance.
*
@@ -127,6 +144,14 @@
@TvInputService.PriorityHintUseCaseType int useCase) {
nativeSetup();
mContext = context;
+ mTunerResourceManager = (TunerResourceManager)
+ context.getSystemService(Context.TV_TUNER_RESOURCE_MGR_SERVICE);
+
+ int[] clientId = new int[1];
+ ResourceClientProfile profile = new ResourceClientProfile(tvInputSessionId, useCase);
+ mTunerResourceManager.registerClientProfile(
+ profile, new HandlerExecutor(mHandler), mResourceListener, clientId);
+ mClientId = clientId[0];
}
/**
@@ -226,6 +251,7 @@
private native List<Integer> nativeGetLnbIds();
private native Lnb nativeOpenLnbById(int id);
+ private native Lnb nativeOpenLnbByName(String name);
private native Descrambler nativeOpenDescrambler();
@@ -275,6 +301,14 @@
}
break;
}
+ case MSG_RESOURCE_LOST: {
+ if (mOnResourceLostListener != null
+ && mOnResourceLostListenerExecutor != null) {
+ mOnResourceLostListenerExecutor.execute(
+ () -> mOnResourceLostListener.onResourceLost(Tuner.this));
+ }
+ break;
+ }
default:
// fall through
}
@@ -698,7 +732,10 @@
Objects.requireNonNull(executor, "executor must not be null");
Objects.requireNonNull(cb, "LnbCallback must not be null");
TunerUtils.checkTunerPermission(mContext);
- return openLnbByName(null, executor, cb);
+ if (mLnbId == null && !requestLnb()) {
+ return null;
+ }
+ return nativeOpenLnbById(mLnbId);
}
/**
@@ -714,11 +751,21 @@
@Nullable
public Lnb openLnbByName(@NonNull String name, @CallbackExecutor @NonNull Executor executor,
@NonNull LnbCallback cb) {
+ Objects.requireNonNull(name, "LNB name must not be null");
Objects.requireNonNull(executor, "executor must not be null");
Objects.requireNonNull(cb, "LnbCallback must not be null");
TunerUtils.checkTunerPermission(mContext);
- // TODO: use resource manager to get LNB ID.
- return new Lnb(0);
+ return nativeOpenLnbByName(name);
+ }
+
+ private boolean requestLnb() {
+ int[] lnbId = new int[1];
+ TunerLnbRequest request = new TunerLnbRequest(mClientId);
+ boolean granted = mTunerResourceManager.requestLnb(request, lnbId);
+ if (granted) {
+ mLnbId = lnbId[0];
+ }
+ return granted;
}
/**
diff --git a/media/java/android/media/tv/tuner/dvr/DvrPlayback.java b/media/java/android/media/tv/tuner/dvr/DvrPlayback.java
index dbd9db4..37a016e 100644
--- a/media/java/android/media/tv/tuner/dvr/DvrPlayback.java
+++ b/media/java/android/media/tv/tuner/dvr/DvrPlayback.java
@@ -69,7 +69,7 @@
*/
public static final int PLAYBACK_STATUS_FULL = Constants.PlaybackStatus.SPACE_FULL;
- long mNativeContext;
+ private long mNativeContext;
private native int nativeAttachFilter(Filter filter);
private native int nativeDetachFilter(Filter filter);
diff --git a/media/java/android/media/tv/tuner/dvr/DvrRecorder.java b/media/java/android/media/tv/tuner/dvr/DvrRecorder.java
index c1c6c62..d06356c 100644
--- a/media/java/android/media/tv/tuner/dvr/DvrRecorder.java
+++ b/media/java/android/media/tv/tuner/dvr/DvrRecorder.java
@@ -30,7 +30,7 @@
*/
@SystemApi
public class DvrRecorder implements AutoCloseable {
- long mNativeContext;
+ private long mNativeContext;
private native int nativeAttachFilter(Filter filter);
private native int nativeDetachFilter(Filter filter);
diff --git a/media/java/android/media/tv/tuner/frontend/DvbtFrontendSettings.java b/media/java/android/media/tv/tuner/frontend/DvbtFrontendSettings.java
index e99fd36f..1510b2d 100644
--- a/media/java/android/media/tv/tuner/frontend/DvbtFrontendSettings.java
+++ b/media/java/android/media/tv/tuner/frontend/DvbtFrontendSettings.java
@@ -125,9 +125,9 @@
/** @hide */
@IntDef(flag = true,
prefix = "CONSTELLATION_",
- value = {CONSTELLATION_UNDEFINED, CONSTELLATION_AUTO, CONSTELLATION_CONSTELLATION_QPSK,
- CONSTELLATION_CONSTELLATION_16QAM, CONSTELLATION_CONSTELLATION_64QAM,
- CONSTELLATION_CONSTELLATION_256QAM})
+ value = {CONSTELLATION_UNDEFINED, CONSTELLATION_AUTO, CONSTELLATION_QPSK,
+ CONSTELLATION_16QAM, CONSTELLATION_64QAM,
+ CONSTELLATION_256QAM})
@Retention(RetentionPolicy.SOURCE)
public @interface Constellation {}
@@ -142,22 +142,22 @@
/**
* QPSK Constellation.
*/
- public static final int CONSTELLATION_CONSTELLATION_QPSK =
+ public static final int CONSTELLATION_QPSK =
Constants.FrontendDvbtConstellation.CONSTELLATION_QPSK;
/**
* 16QAM Constellation.
*/
- public static final int CONSTELLATION_CONSTELLATION_16QAM =
+ public static final int CONSTELLATION_16QAM =
Constants.FrontendDvbtConstellation.CONSTELLATION_16QAM;
/**
* 64QAM Constellation.
*/
- public static final int CONSTELLATION_CONSTELLATION_64QAM =
+ public static final int CONSTELLATION_64QAM =
Constants.FrontendDvbtConstellation.CONSTELLATION_64QAM;
/**
* 256QAM Constellation.
*/
- public static final int CONSTELLATION_CONSTELLATION_256QAM =
+ public static final int CONSTELLATION_256QAM =
Constants.FrontendDvbtConstellation.CONSTELLATION_256QAM;
@@ -275,11 +275,11 @@
@IntDef(flag = true,
prefix = "GUARD_INTERVAL_",
value = {GUARD_INTERVAL_UNDEFINED, GUARD_INTERVAL_AUTO,
- GUARD_INTERVAL_INTERVAL_1_32, GUARD_INTERVAL_INTERVAL_1_16,
- GUARD_INTERVAL_INTERVAL_1_8, GUARD_INTERVAL_INTERVAL_1_4,
- GUARD_INTERVAL_INTERVAL_1_128,
- GUARD_INTERVAL_INTERVAL_19_128,
- GUARD_INTERVAL_INTERVAL_19_256})
+ GUARD_INTERVAL_1_32, GUARD_INTERVAL_1_16,
+ GUARD_INTERVAL_1_8, GUARD_INTERVAL_1_4,
+ GUARD_INTERVAL_1_128,
+ GUARD_INTERVAL_19_128,
+ GUARD_INTERVAL_19_256})
@Retention(RetentionPolicy.SOURCE)
public @interface GuardInterval {}
@@ -295,37 +295,37 @@
/**
* 1/32 Guard Interval.
*/
- public static final int GUARD_INTERVAL_INTERVAL_1_32 =
+ public static final int GUARD_INTERVAL_1_32 =
Constants.FrontendDvbtGuardInterval.INTERVAL_1_32;
/**
* 1/16 Guard Interval.
*/
- public static final int GUARD_INTERVAL_INTERVAL_1_16 =
+ public static final int GUARD_INTERVAL_1_16 =
Constants.FrontendDvbtGuardInterval.INTERVAL_1_16;
/**
* 1/8 Guard Interval.
*/
- public static final int GUARD_INTERVAL_INTERVAL_1_8 =
+ public static final int GUARD_INTERVAL_1_8 =
Constants.FrontendDvbtGuardInterval.INTERVAL_1_8;
/**
* 1/4 Guard Interval.
*/
- public static final int GUARD_INTERVAL_INTERVAL_1_4 =
+ public static final int GUARD_INTERVAL_1_4 =
Constants.FrontendDvbtGuardInterval.INTERVAL_1_4;
/**
* 1/128 Guard Interval.
*/
- public static final int GUARD_INTERVAL_INTERVAL_1_128 =
+ public static final int GUARD_INTERVAL_1_128 =
Constants.FrontendDvbtGuardInterval.INTERVAL_1_128;
/**
* 19/128 Guard Interval.
*/
- public static final int GUARD_INTERVAL_INTERVAL_19_128 =
+ public static final int GUARD_INTERVAL_19_128 =
Constants.FrontendDvbtGuardInterval.INTERVAL_19_128;
/**
* 19/256 Guard Interval.
*/
- public static final int GUARD_INTERVAL_INTERVAL_19_256 =
+ public static final int GUARD_INTERVAL_19_256 =
Constants.FrontendDvbtGuardInterval.INTERVAL_19_256;
/** @hide */
@@ -435,14 +435,14 @@
* Gets Code Rate for High Priority level.
*/
@CodeRate
- public int getHpCodeRate() {
+ public int getHighPriorityCodeRate() {
return mHpCodeRate;
}
/**
* Gets Code Rate for Low Priority level.
*/
@CodeRate
- public int getLpCodeRate() {
+ public int getLowPriorityCodeRate() {
return mLpCodeRate;
}
/**
@@ -560,7 +560,7 @@
* Sets Code Rate for High Priority level.
*/
@NonNull
- public Builder setHpCodeRate(@CodeRate int hpCodeRate) {
+ public Builder setHighPriorityCodeRate(@CodeRate int hpCodeRate) {
mHpCodeRate = hpCodeRate;
return this;
}
@@ -568,7 +568,7 @@
* Sets Code Rate for Low Priority level.
*/
@NonNull
- public Builder setLpCodeRate(@CodeRate int lpCodeRate) {
+ public Builder setLowPriorityCodeRate(@CodeRate int lpCodeRate) {
mLpCodeRate = lpCodeRate;
return this;
}
diff --git a/media/java/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl b/media/java/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl
index 20efaa1..77cac6e 100644
--- a/media/java/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl
+++ b/media/java/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl
@@ -19,6 +19,8 @@
import android.media.tv.tunerresourcemanager.CasSessionRequest;
import android.media.tv.tunerresourcemanager.IResourcesReclaimListener;
import android.media.tv.tunerresourcemanager.ResourceClientProfile;
+import android.media.tv.tunerresourcemanager.TunerDemuxRequest;
+import android.media.tv.tunerresourcemanager.TunerDescramblerRequest;
import android.media.tv.tunerresourcemanager.TunerFrontendInfo;
import android.media.tv.tunerresourcemanager.TunerFrontendRequest;
import android.media.tv.tunerresourcemanager.TunerLnbRequest;
@@ -148,6 +150,53 @@
void shareFrontend(in int selfClientId, in int targetClientId);
/*
+ * This API is used by the Tuner framework to request an available demux from the TunerHAL.
+ *
+ * <p>There are three possible scenarios:
+ * <ul>
+ * <li>If there is demux available, the API would send the handle back.
+ *
+ * <li>If no Demux is available but the current request info can show higher priority than
+ * other uses of demuxes, the API will send
+ * {@link IResourcesReclaimListener#onReclaimResources()} to the {@link Tuner}. Tuner would
+ * handle the resource reclaim on the holder of lower priority and notify the holder of its
+ * resource loss.
+ *
+ * <li>If no demux can be granted, the API would return false.
+ * <ul>
+ *
+ * @param request {@link TunerDemuxRequest} information of the current request.
+ * @param demuxHandle a one-element array to return the granted demux handle.
+ *
+ * @return true if there is demux granted.
+ */
+ boolean requestDemux(in TunerDemuxRequest request, out int[] demuxHandle);
+
+ /*
+ * This API is used by the Tuner framework to request an available descrambler from the
+ * TunerHAL.
+ *
+ * <p>There are three possible scenarios:
+ * <ul>
+ * <li>If there is descrambler available, the API would send the handle back.
+ *
+ * <li>If no Descrambler is available but the current request info can show higher priority than
+ * other uses of Descrambler, the API will send
+ * {@link IResourcesReclaimListener#onReclaimResources()} to the {@link Tuner}. Tuner would
+ * handle the resource reclaim on the holder of lower priority and notify the holder of its
+ * resource loss.
+ *
+ * <li>If no Descrambler can be granted, the API would return false.
+ * <ul>
+ *
+ * @param request {@link TunerDescramblerRequest} information of the current request.
+ * @param descramblerHandle a one-element array to return the granted descrambler handle.
+ *
+ * @return true if there is Descrambler granted.
+ */
+ boolean requestDescrambler(in TunerDescramblerRequest request, out int[] descramblerHandle);
+
+ /*
* This API is used by the Tuner framework to request an available Cas session. This session
* needs to be under the CAS system with the id indicated in the {@code request}.
*
@@ -210,6 +259,24 @@
void releaseFrontend(in int frontendId);
/*
+ * Notifies the TRM that the Demux with the given handle was released.
+ *
+ * <p>Client must call this whenever it releases a demux.
+ *
+ * @param demuxHandle the handle of the released Tuner Demux.
+ */
+ void releaseDemux(in int demuxHandle);
+
+ /*
+ * Notifies the TRM that the Descrambler with the given handle was released.
+ *
+ * <p>Client must call this whenever it releases a descrambler.
+ *
+ * @param demuxHandle the handle of the released Tuner Descrambler.
+ */
+ void releaseDescrambler(in int descramblerHandle);
+
+ /*
* Notifies the TRM that the given Cas session has been released.
*
* <p>Client must call this whenever it releases a Cas session.
diff --git a/media/java/android/media/tv/tunerresourcemanager/TunerDemuxRequest.aidl b/media/java/android/media/tv/tunerresourcemanager/TunerDemuxRequest.aidl
new file mode 100644
index 0000000..919a215
--- /dev/null
+++ b/media/java/android/media/tv/tunerresourcemanager/TunerDemuxRequest.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv.tunerresourcemanager;
+
+/**
+ * Information required to request a Tuner Demux.
+ *
+ * @hide
+ */
+parcelable TunerDemuxRequest;
\ No newline at end of file
diff --git a/media/java/android/media/tv/tunerresourcemanager/TunerDemuxRequest.java b/media/java/android/media/tv/tunerresourcemanager/TunerDemuxRequest.java
new file mode 100644
index 0000000..34a7761
--- /dev/null
+++ b/media/java/android/media/tv/tunerresourcemanager/TunerDemuxRequest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv.tunerresourcemanager;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+/**
+ * Information required to request a Tuner Demux.
+ *
+ * @hide
+ */
+public final class TunerDemuxRequest implements Parcelable {
+ static final String TAG = "TunerDemuxRequest";
+
+ public static final
+ @NonNull
+ Parcelable.Creator<TunerDemuxRequest> CREATOR =
+ new Parcelable.Creator<TunerDemuxRequest>() {
+ @Override
+ public TunerDemuxRequest createFromParcel(Parcel source) {
+ try {
+ return new TunerDemuxRequest(source);
+ } catch (Exception e) {
+ Log.e(TAG, "Exception creating TunerDemuxRequest from parcel", e);
+ return null;
+ }
+ }
+
+ @Override
+ public TunerDemuxRequest[] newArray(int size) {
+ return new TunerDemuxRequest[size];
+ }
+ };
+
+ /**
+ * Client id of the client that sends the request.
+ */
+ private final int mClientId;
+
+ private TunerDemuxRequest(@NonNull Parcel source) {
+ mClientId = source.readInt();
+ }
+
+ /**
+ * Constructs a new {@link TunerDemuxRequest} with the given parameters.
+ *
+ * @param clientId id of the client.
+ */
+ public TunerDemuxRequest(int clientId) {
+ mClientId = clientId;
+ }
+
+ /**
+ * Returns the id of the client.
+ */
+ public int getClientId() {
+ return mClientId;
+ }
+
+ // Parcelable
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ StringBuilder b = new StringBuilder(128);
+ b.append("TunerDemuxRequest {clientId=").append(mClientId);
+ b.append("}");
+ return b.toString();
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mClientId);
+ }
+}
diff --git a/media/java/android/media/tv/tunerresourcemanager/TunerDescramblerRequest.aidl b/media/java/android/media/tv/tunerresourcemanager/TunerDescramblerRequest.aidl
new file mode 100644
index 0000000..fbafb3b
--- /dev/null
+++ b/media/java/android/media/tv/tunerresourcemanager/TunerDescramblerRequest.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv.tunerresourcemanager;
+
+/**
+ * Information required to request a Tuner Descrambler.
+ *
+ * @hide
+ */
+parcelable TunerDescramblerRequest;
\ No newline at end of file
diff --git a/media/java/android/media/tv/tunerresourcemanager/TunerDescramblerRequest.java b/media/java/android/media/tv/tunerresourcemanager/TunerDescramblerRequest.java
new file mode 100644
index 0000000..5816287
--- /dev/null
+++ b/media/java/android/media/tv/tunerresourcemanager/TunerDescramblerRequest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.tv.tunerresourcemanager;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+/**
+ * Information required to request a Tuner Descrambler.
+ *
+ * @hide
+ */
+public final class TunerDescramblerRequest implements Parcelable {
+ static final String TAG = "TunerDescramblerRequest";
+
+ public static final
+ @NonNull
+ Parcelable.Creator<TunerDescramblerRequest> CREATOR =
+ new Parcelable.Creator<TunerDescramblerRequest>() {
+ @Override
+ public TunerDescramblerRequest createFromParcel(Parcel source) {
+ try {
+ return new TunerDescramblerRequest(source);
+ } catch (Exception e) {
+ Log.e(TAG, "Exception creating TunerDescramblerRequest from parcel", e);
+ return null;
+ }
+ }
+
+ @Override
+ public TunerDescramblerRequest[] newArray(int size) {
+ return new TunerDescramblerRequest[size];
+ }
+ };
+
+ /**
+ * Client id of the client that sends the request.
+ */
+ private final int mClientId;
+
+ private TunerDescramblerRequest(@NonNull Parcel source) {
+ mClientId = source.readInt();
+ }
+
+ /**
+ * Constructs a new {@link TunerDescramblerRequest} with the given parameters.
+ *
+ * @param clientId id of the client.
+ */
+ public TunerDescramblerRequest(int clientId) {
+ mClientId = clientId;
+ }
+
+ /**
+ * Returns the id of the client.
+ */
+ public int getClientId() {
+ return mClientId;
+ }
+
+ // Parcelable
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ StringBuilder b = new StringBuilder(128);
+ b.append("TunerDescramblerRequest {clientId=").append(mClientId);
+ b.append("}");
+ return b.toString();
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mClientId);
+ }
+}
diff --git a/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java b/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java
index 7c11ed4..524b6c2 100644
--- a/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java
+++ b/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java
@@ -65,6 +65,7 @@
public static final int INVALID_LNB_ID = -1;
public static final int INVALID_TV_INPUT_DEVICE_ID = -1;
public static final int INVALID_TV_INPUT_PORT_ID = -1;
+ public static final int INVALID_RESOURCE_HANDLE = -1;
private final ITunerResourceManager mService;
private final int mUserId;
@@ -260,6 +261,71 @@
}
/**
+ * Requests a Tuner Demux resource.
+ *
+ * <p>There are three possible scenarios:
+ * <ul>
+ * <li>If there is Demux available, the API would send the handle back.
+ *
+ * <li>If no Demux is available but the current request has a higher priority than other uses of
+ * demuxes, the API will send {@link IResourcesReclaimListener#onReclaimResources()} to the
+ * {@link Tuner}. Tuner would handle the resource reclaim on the holder of lower priority and
+ * notify the holder of its resource loss.
+ *
+ * <li>If no Demux system can be granted, the API would return false.
+ * <ul>
+ *
+ * @param request {@link TunerDemuxRequest} information of the current request.
+ * @param demuxHandle a one-element array to return the granted Demux handle.
+ * If no Demux granted, this will return {@link #INVALID_RESOURCE_HANDLE}.
+ *
+ * @return true if there is Demux granted.
+ */
+ public boolean requestDemux(@NonNull TunerDemuxRequest request, @NonNull int[] demuxHandle) {
+ boolean result = false;
+ try {
+ result = mService.requestDemux(request, demuxHandle);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ return result;
+ }
+
+ /**
+ * Requests a Tuner Descrambler resource.
+ *
+ * <p>There are three possible scenarios:
+ * <ul>
+ * <li>If there is Descrambler available, the API would send the handle back.
+ *
+ * <li>If no Descrambler is available but the current request has a higher priority than other
+ * uses of descramblers, the API will send
+ * {@link IResourcesReclaimListener#onReclaimResources()} to the {@link Tuner}. Tuner would
+ * handle the resource reclaim on the holder of lower priority and notify the holder of its
+ * resource loss.
+ *
+ * <li>If no Descrambler system can be granted, the API would return false.
+ * <ul>
+ *
+ * @param request {@link TunerDescramblerRequest} information of the current request.
+ * @param descramblerHandle a one-element array to return the granted Descrambler handle.
+ * If no Descrambler granted, this will return
+ * {@link #INVALID_RESOURCE_HANDLE}.
+ *
+ * @return true if there is Descrambler granted.
+ */
+ public boolean requestDescrambler(@NonNull TunerDescramblerRequest request,
+ @NonNull int[] descramblerHandle) {
+ boolean result = false;
+ try {
+ result = mService.requestDescrambler(request, descramblerHandle);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ return result;
+ }
+
+ /**
* Requests a CAS session resource.
*
* <p>There are three possible scenarios:
@@ -345,6 +411,36 @@
}
/**
+ * Notifies the TRM that the Demux with the given handle has been released.
+ *
+ * <p>Client must call this whenever it releases an Demux.
+ *
+ * @param demuxHandle the handle of the released Tuner Demux.
+ */
+ public void releaseDemux(int demuxHandle) {
+ try {
+ mService.releaseDemux(demuxHandle);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Notifies the TRM that the Descrambler with the given handle has been released.
+ *
+ * <p>Client must call this whenever it releases an Descrambler.
+ *
+ * @param descramblerHandle the handle of the released Tuner Descrambler.
+ */
+ public void releaseDescrambler(int descramblerHandle) {
+ try {
+ mService.releaseDescrambler(descramblerHandle);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Notifies the TRM that the given Cas session has been released.
*
* <p>Client must call this whenever it releases a Cas session.
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 01f068a..a37c9e5 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -138,11 +138,13 @@
jfieldID filterContext;
jfieldID timeFilterContext;
jfieldID descramblerContext;
- jfieldID dvrContext;
+ jfieldID dvrRecorderContext;
+ jfieldID dvrPlaybackContext;
jmethodID frontendInitID;
jmethodID filterInitID;
jmethodID timeFilterInitID;
- jmethodID dvrInitID;
+ jmethodID dvrRecorderInitID;
+ jmethodID dvrPlaybackInitID;
jmethodID onFrontendEventID;
jmethodID onFilterStatusID;
jmethodID onFilterEventID;
@@ -1072,6 +1074,37 @@
return lnbObj;
}
+jobject JTuner::openLnbByName(jstring name) {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ std::string lnbName(env->GetStringUTFChars(name, nullptr));
+ sp<ILnb> iLnbSp;
+ Result res;
+ LnbId id;
+ mTuner->openLnbByName(lnbName, [&](Result r, LnbId lnbId, const sp<ILnb>& lnb) {
+ res = r;
+ iLnbSp = lnb;
+ id = lnbId;
+ });
+ if (res != Result::SUCCESS || iLnbSp == nullptr) {
+ ALOGE("Failed to open lnb");
+ return NULL;
+ }
+ mLnb = iLnbSp;
+ sp<LnbCallback> lnbCb = new LnbCallback(mObject, id);
+ mLnb->setCallback(lnbCb);
+
+ jobject lnbObj = env->NewObject(
+ env->FindClass("android/media/tv/tuner/Lnb"),
+ gFields.lnbInitID,
+ id);
+
+ sp<Lnb> lnbSp = new Lnb(iLnbSp, lnbObj);
+ lnbSp->incStrong(lnbObj);
+ env->SetLongField(lnbObj, gFields.lnbContext, (jlong) lnbSp.get());
+
+ return lnbObj;
+}
+
int JTuner::tune(const FrontendSettings& settings) {
if (mFe == NULL) {
ALOGE("frontend is not initialized");
@@ -1302,7 +1335,7 @@
return timeFilterObj;
}
-jobject JTuner::openDvr(DvrType type, int bufferSize) {
+jobject JTuner::openDvr(DvrType type, jlong bufferSize) {
ALOGD("JTuner::openDvr");
if (mDemux == NULL) {
if (openDemux() != Result::SUCCESS) {
@@ -1311,24 +1344,38 @@
}
sp<IDvr> iDvrSp;
sp<DvrCallback> callback = new DvrCallback();
- mDemux->openDvr(type, bufferSize, callback,
- [&](Result, const sp<IDvr>& dvr) {
+ Result res;
+ mDemux->openDvr(type, (uint32_t) bufferSize, callback,
+ [&](Result r, const sp<IDvr>& dvr) {
+ res = r;
iDvrSp = dvr;
});
- if (iDvrSp == NULL) {
+ if (res != Result::SUCCESS || iDvrSp == NULL) {
return NULL;
}
JNIEnv *env = AndroidRuntime::getJNIEnv();
- jobject dvrObj =
- env->NewObject(
- env->FindClass("android/media/tv/tuner/dvr/Dvr"),
- gFields.dvrInitID,
- mObject);
- sp<Dvr> dvrSp = new Dvr(iDvrSp, dvrObj);
- dvrSp->incStrong(dvrObj);
- env->SetLongField(dvrObj, gFields.dvrContext, (jlong)dvrSp.get());
+ jobject dvrObj;
+ if (type == DvrType::RECORD) {
+ dvrObj =
+ env->NewObject(
+ env->FindClass("android/media/tv/tuner/dvr/DvrRecorder"),
+ gFields.dvrRecorderInitID,
+ mObject);
+ sp<Dvr> dvrSp = new Dvr(iDvrSp, dvrObj);
+ dvrSp->incStrong(dvrObj);
+ env->SetLongField(dvrObj, gFields.dvrRecorderContext, (jlong)dvrSp.get());
+ } else {
+ dvrObj =
+ env->NewObject(
+ env->FindClass("android/media/tv/tuner/dvr/DvrPlayback"),
+ gFields.dvrPlaybackInitID,
+ mObject);
+ sp<Dvr> dvrSp = new Dvr(iDvrSp, dvrObj);
+ dvrSp->incStrong(dvrObj);
+ env->SetLongField(dvrObj, gFields.dvrPlaybackContext, (jlong)dvrSp.get());
+ }
callback->setDvr(dvrObj);
@@ -1852,7 +1899,11 @@
}
static sp<Dvr> getDvr(JNIEnv *env, jobject dvr) {
- return (Dvr *)env->GetLongField(dvr, gFields.dvrContext);
+ bool isRecorder =
+ env->IsInstanceOf(dvr, env->FindClass("android/media/tv/tuner/dvr/DvrRecorder"));
+ jfieldID fieldId =
+ isRecorder ? gFields.dvrRecorderContext : gFields.dvrPlaybackContext;
+ return (Dvr *)env->GetLongField(dvr, fieldId);
}
static void android_media_tv_Tuner_native_init(JNIEnv *env) {
@@ -1872,8 +1923,7 @@
jclass lnbClazz = env->FindClass("android/media/tv/tuner/Lnb");
gFields.lnbContext = env->GetFieldID(lnbClazz, "mNativeContext", "J");
- gFields.lnbInitID =
- env->GetMethodID(lnbClazz, "<init>", "(I)V");
+ gFields.lnbInitID = env->GetMethodID(lnbClazz, "<init>", "(I)V");
jclass filterClazz = env->FindClass("android/media/tv/tuner/filter/Filter");
gFields.filterContext = env->GetFieldID(filterClazz, "mNativeContext", "J");
@@ -1894,9 +1944,13 @@
gFields.descramblerInitID =
env->GetMethodID(descramblerClazz, "<init>", "()V");
- jclass dvrClazz = env->FindClass("android/media/tv/tuner/dvr/Dvr");
- gFields.dvrContext = env->GetFieldID(dvrClazz, "mNativeContext", "J");
- gFields.dvrInitID = env->GetMethodID(dvrClazz, "<init>", "()V");
+ jclass dvrRecorderClazz = env->FindClass("android/media/tv/tuner/dvr/DvrRecorder");
+ gFields.dvrRecorderContext = env->GetFieldID(dvrRecorderClazz, "mNativeContext", "J");
+ gFields.dvrRecorderInitID = env->GetMethodID(dvrRecorderClazz, "<init>", "()V");
+
+ jclass dvrPlaybackClazz = env->FindClass("android/media/tv/tuner/dvr/DvrPlayback");
+ gFields.dvrPlaybackContext = env->GetFieldID(dvrPlaybackClazz, "mNativeContext", "J");
+ gFields.dvrPlaybackInitID = env->GetMethodID(dvrPlaybackClazz, "<init>", "()V");
jclass linearBlockClazz = env->FindClass("android/media/MediaCodec$LinearBlock");
gFields.linearBlockInitID = env->GetMethodID(linearBlockClazz, "<init>", "()V");
@@ -1996,6 +2050,12 @@
return tuner->openLnbById(id);
}
+static jobject android_media_tv_Tuner_open_lnb_by_name(JNIEnv *env, jobject thiz, jstring name) {
+ sp<JTuner> tuner = getTuner(env, thiz);
+ return tuner->openLnbByName(name);
+}
+
+
static jobject android_media_tv_Tuner_open_filter(
JNIEnv *env, jobject thiz, jint type, jint subType, jlong bufferSize) {
sp<JTuner> tuner = getTuner(env, thiz);
@@ -2618,13 +2678,15 @@
}
static jobject android_media_tv_Tuner_open_dvr_recorder(
- JNIEnv* /* env */, jobject /* thiz */, jlong /* bufferSize */) {
- return NULL;
+ JNIEnv* env, jobject thiz, jlong bufferSize) {
+ sp<JTuner> tuner = getTuner(env, thiz);
+ return tuner->openDvr(DvrType::RECORD, bufferSize);
}
static jobject android_media_tv_Tuner_open_dvr_playback(
- JNIEnv* /* env */, jobject /* thiz */, jlong /* bufferSize */) {
- return NULL;
+ JNIEnv* env, jobject thiz, jlong bufferSize) {
+ sp<JTuner> tuner = getTuner(env, thiz);
+ return tuner->openDvr(DvrType::PLAYBACK, bufferSize);
}
static jobject android_media_tv_Tuner_get_demux_caps(JNIEnv*, jobject) {
@@ -2678,11 +2740,13 @@
}
static int android_media_tv_Tuner_start_dvr(JNIEnv *env, jobject dvr) {
+
sp<IDvr> dvrSp = getDvr(env, dvr)->getIDvr();
if (dvrSp == NULL) {
ALOGD("Failed to start dvr: dvr not found");
return false;
}
+
Result result = dvrSp->start();
return (int) result;
}
@@ -2888,6 +2952,8 @@
(void *)android_media_tv_Tuner_get_lnb_ids },
{ "nativeOpenLnbById", "(I)Landroid/media/tv/tuner/Lnb;",
(void *)android_media_tv_Tuner_open_lnb_by_id },
+ { "nativeOpenLnbByName", "(Ljava/lang/String;)Landroid/media/tv/tuner/Lnb;",
+ (void *)android_media_tv_Tuner_open_lnb_by_name },
{ "nativeOpenDescrambler", "()Landroid/media/tv/tuner/Descrambler;",
(void *)android_media_tv_Tuner_open_descrambler },
{ "nativeOpenDvrRecorder", "(J)Landroid/media/tv/tuner/dvr/DvrRecorder;",
@@ -2930,7 +2996,7 @@
{ "nativeClose", "()I", (void *)android_media_tv_Tuner_close_descrambler },
};
-static const JNINativeMethod gDvrMethods[] = {
+static const JNINativeMethod gDvrRecorderMethods[] = {
{ "nativeAttachFilter", "(Landroid/media/tv/tuner/filter/Filter;)I",
(void *)android_media_tv_Tuner_attach_filter },
{ "nativeDetachFilter", "(Landroid/media/tv/tuner/filter/Filter;)I",
@@ -2942,14 +3008,22 @@
{ "nativeFlushDvr", "()I", (void *)android_media_tv_Tuner_flush_dvr },
{ "nativeClose", "()I", (void *)android_media_tv_Tuner_close_dvr },
{ "nativeSetFileDescriptor", "(I)V", (void *)android_media_tv_Tuner_dvr_set_fd },
-};
-
-static const JNINativeMethod gDvrRecorderMethods[] = {
{ "nativeWrite", "(J)J", (void *)android_media_tv_Tuner_write_dvr },
{ "nativeWrite", "([BJJ)J", (void *)android_media_tv_Tuner_write_dvr_to_array },
};
static const JNINativeMethod gDvrPlaybackMethods[] = {
+ { "nativeAttachFilter", "(Landroid/media/tv/tuner/filter/Filter;)I",
+ (void *)android_media_tv_Tuner_attach_filter },
+ { "nativeDetachFilter", "(Landroid/media/tv/tuner/filter/Filter;)I",
+ (void *)android_media_tv_Tuner_detach_filter },
+ { "nativeConfigureDvr", "(Landroid/media/tv/tuner/dvr/DvrSettings;)I",
+ (void *)android_media_tv_Tuner_configure_dvr },
+ { "nativeStartDvr", "()I", (void *)android_media_tv_Tuner_start_dvr },
+ { "nativeStopDvr", "()I", (void *)android_media_tv_Tuner_stop_dvr },
+ { "nativeFlushDvr", "()I", (void *)android_media_tv_Tuner_flush_dvr },
+ { "nativeClose", "()I", (void *)android_media_tv_Tuner_close_dvr },
+ { "nativeSetFileDescriptor", "(I)V", (void *)android_media_tv_Tuner_dvr_set_fd },
{ "nativeRead", "(J)J", (void *)android_media_tv_Tuner_read_dvr },
{ "nativeRead", "([BJJ)J", (void *)android_media_tv_Tuner_read_dvr_from_array },
};
@@ -2990,13 +3064,6 @@
return false;
}
if (AndroidRuntime::registerNativeMethods(
- env, "android/media/tv/tuner/dvr/Dvr",
- gDvrMethods,
- NELEM(gDvrMethods)) != JNI_OK) {
- ALOGE("Failed to register dvr native methods");
- return false;
- }
- if (AndroidRuntime::registerNativeMethods(
env, "android/media/tv/tuner/dvr/DvrRecorder",
gDvrRecorderMethods,
NELEM(gDvrRecorderMethods)) != JNI_OK) {
diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h
index d3298a8..5d2bba6 100644
--- a/media/jni/android_media_tv_Tuner.h
+++ b/media/jni/android_media_tv_Tuner.h
@@ -180,10 +180,11 @@
int setLna(bool enable);
jobject getLnbIds();
jobject openLnbById(int id);
+ jobject openLnbByName(jstring name);
jobject openFilter(DemuxFilterType type, int bufferSize);
jobject openTimeFilter();
jobject openDescrambler();
- jobject openDvr(DvrType type, int bufferSize);
+ jobject openDvr(DvrType type, jlong bufferSize);
protected:
Result openDemux();
diff --git a/media/jni/soundpool/StreamManager.h b/media/jni/soundpool/StreamManager.h
index 15b39f2..30ad220 100644
--- a/media/jni/soundpool/StreamManager.h
+++ b/media/jni/soundpool/StreamManager.h
@@ -70,9 +70,10 @@
static int staticFunction(void *data) {
JavaThread *jt = static_cast<JavaThread *>(data);
jt->mF();
+ jt->mIsClosed = true; // set the flag that we are closed
+ // now before we allow the destructor to execute;
+ // otherwise there may be a use after free.
jt->mPromise.set_value();
- jt->mIsClosed = true; // publicly inform that we are closed
- // after we have accessed all variables.
return 0;
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
index 6354ccd..ebd7658 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
@@ -284,12 +284,12 @@
ICameraDeviceCallbacks dummyCallbacks = new DummyCameraDeviceCallbacks();
String clientPackageName = getContext().getPackageName();
- String clientFeatureId = getContext().getFeatureId();
+ String clientAttributionTag = getContext().getAttributionTag();
ICameraDeviceUser cameraUser =
mUtils.getCameraService().connectDevice(
dummyCallbacks, String.valueOf(cameraId),
- clientPackageName, clientFeatureId,
+ clientPackageName, clientAttributionTag,
ICameraService.USE_CALLING_UID);
assertNotNull(String.format("Camera %s was null", cameraId), cameraUser);
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
index 466c5f4..bf3e746 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
@@ -238,12 +238,12 @@
ICameraDeviceCallbacks.Stub dummyCallbacks = new DummyCameraDeviceCallbacks();
String clientPackageName = getContext().getPackageName();
- String clientFeatureId = getContext().getFeatureId();
+ String clientAttributionTag = getContext().getAttributionTag();
mMockCb = spy(dummyCallbacks);
mCameraUser = mUtils.getCameraService().connectDevice(mMockCb, mCameraId,
- clientPackageName, clientFeatureId, ICameraService.USE_CALLING_UID);
+ clientPackageName, clientAttributionTag, ICameraService.USE_CALLING_UID);
assertNotNull(String.format("Camera %s was null", mCameraId), mCameraUser);
mHandlerThread = new HandlerThread(TAG);
mHandlerThread.start();
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
index 140c075..8292d30 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
@@ -24,7 +24,6 @@
import com.android.keyguard.KeyguardViewController;
import com.android.systemui.car.CarDeviceProvisionedController;
import com.android.systemui.car.CarDeviceProvisionedControllerImpl;
-import com.android.systemui.car.CarNotificationInterruptionStateProvider;
import com.android.systemui.dagger.SystemUIRootComponent;
import com.android.systemui.dock.DockManager;
import com.android.systemui.dock.DockManagerImpl;
@@ -41,7 +40,6 @@
import com.android.systemui.statusbar.car.CarStatusBar;
import com.android.systemui.statusbar.car.CarStatusBarKeyguardViewManager;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.KeyguardEnvironmentImpl;
@@ -67,10 +65,6 @@
@Module(includes = {DividerModule.class})
abstract class CarSystemUIModule {
- @Binds
- abstract NotificationInterruptionStateProvider bindNotificationInterruptionStateProvider(
- CarNotificationInterruptionStateProvider notificationInterruptionStateProvider);
-
@Singleton
@Provides
@Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME)
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationInterruptionStateProvider.java b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationInterruptionStateProvider.java
deleted file mode 100644
index 447e579..0000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationInterruptionStateProvider.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.car;
-
-import android.content.Context;
-
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.notification.NotificationFilter;
-import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.policy.BatteryController;
-
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-/** Auto-specific implementation of {@link NotificationInterruptionStateProvider}. */
-@Singleton
-public class CarNotificationInterruptionStateProvider extends
- NotificationInterruptionStateProvider {
-
- @Inject
- public CarNotificationInterruptionStateProvider(Context context,
- NotificationFilter filter,
- StatusBarStateController stateController,
- BatteryController batteryController) {
- super(context, filter, stateController, batteryController);
- }
-
- @Override
- public boolean shouldHeadsUp(NotificationEntry entry) {
- // Because space is usually constrained in the auto use-case, there should not be a
- // pinned notification when the shade has been expanded. Ensure this by not pinning any
- // notification if the shade is already opened.
- if (!getPresenter().isPresenterFullyCollapsed()) {
- return false;
- }
-
- return super.shouldHeadsUp(entry);
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index b2e2104..411f14d 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -95,13 +95,15 @@
import com.android.systemui.statusbar.SuperStatusBarViewFactory;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.VibratorHelper;
-import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
-import com.android.systemui.statusbar.notification.NotificationAlertingManager;
-import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.init.NotificationsController;
+import com.android.systemui.statusbar.notification.interruption.BypassHeadsUpNotifier;
+import com.android.systemui.statusbar.notification.interruption.NotificationAlertingManager;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptSuppressor;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.phone.AutoHideController;
@@ -249,7 +251,7 @@
RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
NotificationGutsManager notificationGutsManager,
NotificationLogger notificationLogger,
- NotificationInterruptionStateProvider notificationInterruptionStateProvider,
+ NotificationInterruptStateProvider notificationInterruptStateProvider,
NotificationViewHierarchyManager notificationViewHierarchyManager,
KeyguardViewMediator keyguardViewMediator,
NotificationAlertingManager notificationAlertingManager,
@@ -335,7 +337,7 @@
remoteInputQuickSettingsDisabler,
notificationGutsManager,
notificationLogger,
- notificationInterruptionStateProvider,
+ notificationInterruptStateProvider,
notificationViewHierarchyManager,
keyguardViewMediator,
notificationAlertingManager,
@@ -488,6 +490,22 @@
.isCurrentUserSetupInProgress();
}
});
+
+ mNotificationInterruptStateProvider.addSuppressor(new NotificationInterruptSuppressor() {
+ @Override
+ public String getName() {
+ return TAG;
+ }
+
+ @Override
+ public boolean suppressInterruptions(NotificationEntry entry) {
+ // Because space is usually constrained in the auto use-case, there should not be a
+ // pinned notification when the shade has been expanded.
+ // Ensure this by not allowing any interruptions (ie: pinning any notifications) if
+ // the shade is already opened.
+ return !getPresenter().isPresenterFullyCollapsed();
+ }
+ });
}
@Override
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
index 4754118..160268b 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
@@ -62,13 +62,13 @@
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.dagger.StatusBarDependenciesModule;
-import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
-import com.android.systemui.statusbar.notification.NotificationAlertingManager;
-import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.init.NotificationsController;
+import com.android.systemui.statusbar.notification.interruption.BypassHeadsUpNotifier;
+import com.android.systemui.statusbar.notification.interruption.NotificationAlertingManager;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.row.NotificationRowModule;
@@ -146,7 +146,7 @@
RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
NotificationGutsManager notificationGutsManager,
NotificationLogger notificationLogger,
- NotificationInterruptionStateProvider notificationInterruptionStateProvider,
+ NotificationInterruptStateProvider notificationInterruptionStateProvider,
NotificationViewHierarchyManager notificationViewHierarchyManager,
KeyguardViewMediator keyguardViewMediator,
NotificationAlertingManager notificationAlertingManager,
diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java
index f93faeb..ace50f3 100644
--- a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java
+++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java
@@ -545,7 +545,7 @@
bundle.putString(META_DATA_PREFERENCE_KEYHINT, key);
}
try {
- return provider.call(context.getPackageName(), context.getFeatureId(),
+ return provider.call(context.getPackageName(), context.getAttributionTag(),
uri.getAuthority(), method, uri.toString(), bundle);
} catch (RemoteException e) {
return null;
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index e8e1d0b..00f6bcb 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1039,7 +1039,7 @@
<!-- Title for the accessibility preference to configure display color space correction. [CHAR LIMIT=NONE] -->
<string name="accessibility_display_daltonizer_preference_title">Color correction</string>
<!-- Subtitle for the accessibility preference to configure display color space correction. [CHAR LIMIT=NONE] -->
- <string name="accessibility_display_daltonizer_preference_subtitle">Color correction helps people with colorblindness see more accurate colors</string>
+ <string name="accessibility_display_daltonizer_preference_subtitle">Color correction helps the device display more accurate colors. Color correction may be helpful for people with colorblindness.</string>
<!-- Summary shown for color space correction preference when its value is overridden by another preference [CHAR LIMIT=35] -->
<string name="daltonizer_type_overridden">Overridden by <xliff:g id="title" example="Simulate color space">%1$s</xliff:g></string>
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAccessesTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAccessesTest.java
index 68a3729..245b7843 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAccessesTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAccessesTest.java
@@ -8,7 +8,6 @@
import android.app.AppOpsManager;
import android.app.AppOpsManager.OpEntry;
-import android.app.AppOpsManager.OpFeatureEntry;
import android.app.AppOpsManager.PackageOps;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -163,6 +162,6 @@
AppOpsManager.OP_FLAG_SELF), new AppOpsManager.NoteOpEvent(time, -1, null));
return new OpEntry(op, AppOpsManager.MODE_ALLOWED, Collections.singletonMap(null,
- new OpFeatureEntry(op, false, accessEvents, null)));
+ new AppOpsManager.AttributedOpEntry(op, false, accessEvents, null)));
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAppsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAppsTest.java
index 3f8d758..cc9b931 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAppsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAppsTest.java
@@ -7,7 +7,7 @@
import android.app.AppOpsManager;
import android.app.AppOpsManager.OpEntry;
-import android.app.AppOpsManager.OpFeatureEntry;
+import android.app.AppOpsManager.AttributedOpEntry;
import android.app.AppOpsManager.PackageOps;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -18,8 +18,6 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.util.LongSparseArray;
-import android.util.LongSparseLongArray;
-import android.util.Pair;
import org.junit.Before;
import org.junit.Test;
@@ -164,6 +162,6 @@
AppOpsManager.OP_FLAG_SELF), new AppOpsManager.NoteOpEvent(time, duration, null));
return new OpEntry(op, AppOpsManager.MODE_ALLOWED, Collections.singletonMap(null,
- new OpFeatureEntry(op, false, accessEvents, null)));
+ new AttributedOpEntry(op, false, accessEvents, null)));
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
index 1e888da..18d8f14 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
@@ -19,7 +19,6 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -121,8 +120,6 @@
verify(currentDevice).disconnect();
verify(device).connect();
- verify(mCallback).onSelectedDeviceStateChanged(any(),
- eq(LocalMediaManager.MediaDeviceState.STATE_DISCONNECTED));
}
@Test
@@ -368,7 +365,8 @@
mLocalMediaManager.mMediaDeviceCallback.onConnectedDeviceChanged(TEST_DEVICE_ID_2);
assertThat(mLocalMediaManager.getCurrentConnectedDevice()).isEqualTo(device2);
- verify(mCallback).onDeviceAttributesChanged();
+ verify(mCallback).onSelectedDeviceStateChanged(device2,
+ LocalMediaManager.MediaDeviceState.STATE_CONNECTED);
}
@Test
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index 8fa98c8..d350d9d 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -141,6 +141,8 @@
Settings.Secure.NOTIFICATION_NEW_INTERRUPTION_MODEL,
Settings.Secure.TRUST_AGENTS_EXTEND_UNLOCK,
Settings.Secure.UI_NIGHT_MODE,
+ Settings.Secure.DARK_THEME_CUSTOM_START_TIME,
+ Settings.Secure.DARK_THEME_CUSTOM_END_TIME,
Settings.Secure.LOCK_SCREEN_WHEN_TRUST_LOST,
Settings.Secure.SKIP_DIRECTION,
Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 75c5f95..4d33b62 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -28,6 +28,7 @@
import static android.provider.settings.validators.SettingsValidators.NON_NEGATIVE_INTEGER_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.NULLABLE_COMPONENT_NAME_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.PACKAGE_NAME_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.NONE_NEGATIVE_LONG_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.TILE_LIST_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.TTS_LIST_VALIDATOR;
@@ -235,7 +236,9 @@
VALIDATORS.put(Secure.AWARE_TAP_PAUSE_TOUCH_COUNT, NON_NEGATIVE_INTEGER_VALIDATOR);
VALIDATORS.put(Secure.ODI_CAPTIONS_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.DARK_MODE_DIALOG_SEEN, BOOLEAN_VALIDATOR);
- VALIDATORS.put(Secure.UI_NIGHT_MODE, new InclusiveIntegerRangeValidator(0, 2));
+ VALIDATORS.put(Secure.UI_NIGHT_MODE, NON_NEGATIVE_INTEGER_VALIDATOR);
+ VALIDATORS.put(Secure.DARK_THEME_CUSTOM_START_TIME, NONE_NEGATIVE_LONG_VALIDATOR);
+ VALIDATORS.put(Secure.DARK_THEME_CUSTOM_END_TIME, NONE_NEGATIVE_LONG_VALIDATOR);
VALIDATORS.put(Secure.GLOBAL_ACTIONS_PANEL_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.AWARE_LOCK_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.DISPLAY_DENSITY_FORCED, NON_NEGATIVE_INTEGER_VALIDATOR);
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SettingsValidators.java
index 71c7544..8d5c6e6 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SettingsValidators.java
@@ -207,4 +207,15 @@
static final Validator ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR =
new AccessibilityShortcutTargetListValidator();
+
+ static final Validator NONE_NEGATIVE_LONG_VALIDATOR = new Validator() {
+ @Override
+ public boolean validate(String value) {
+ try {
+ return Long.parseLong(value) >= 0;
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ }
+ };
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index 36bb8ef..b6e31d2 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -75,6 +75,9 @@
sBroadcastOnRestore.add(Settings.Secure.ENABLED_VR_LISTENERS);
sBroadcastOnRestore.add(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
sBroadcastOnRestore.add(Settings.Global.BLUETOOTH_ON);
+ sBroadcastOnRestore.add(Settings.Secure.UI_NIGHT_MODE);
+ sBroadcastOnRestore.add(Settings.Secure.DARK_THEME_CUSTOM_START_TIME);
+ sBroadcastOnRestore.add(Settings.Secure.DARK_THEME_CUSTOM_END_TIME);
}
private interface SettingsLookup {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 2dc6f39..5a9d749 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -2778,6 +2778,11 @@
public boolean insertSettingLocked(int type, int userId, String name, String value,
String tag, boolean makeDefault, boolean forceNonSystemPackage, String packageName,
boolean forceNotify, Set<String> criticalSettings, boolean overrideableByRestore) {
+ if (overrideableByRestore != Settings.DEFAULT_OVERRIDEABLE_BY_RESTORE) {
+ getContext().enforceCallingOrSelfPermission(
+ Manifest.permission.MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE,
+ "Caller is not allowed to modify settings overrideable by restore");
+ }
final int key = makeKey(type, userId);
boolean success = false;
diff --git a/packages/SettingsProvider/test/src/android/provider/settings/validators/SettingsValidatorsTest.java b/packages/SettingsProvider/test/src/android/provider/settings/validators/SettingsValidatorsTest.java
index bb9e6f6..9134d87 100644
--- a/packages/SettingsProvider/test/src/android/provider/settings/validators/SettingsValidatorsTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/settings/validators/SettingsValidatorsTest.java
@@ -277,6 +277,27 @@
}
@Test
+ public void testPositiveLongValidator_zero() {
+ assertTrue(SettingsValidators.NONE_NEGATIVE_LONG_VALIDATOR.validate("0"));
+ }
+
+ @Test
+ public void testPositiveLongValidator_negative() {
+ assertFalse(SettingsValidators.NONE_NEGATIVE_LONG_VALIDATOR.validate("-5"));
+ }
+
+
+ @Test
+ public void testPositiveLongValidator_positive() {
+ assertTrue(SettingsValidators.NONE_NEGATIVE_LONG_VALIDATOR.validate("5"));
+ }
+
+ @Test
+ public void testPositiveLongValidator_floatFormat() {
+ assertFalse(SettingsValidators.NONE_NEGATIVE_LONG_VALIDATOR.validate("4.4756"));
+ }
+
+ @Test
public void testTTSListValidator_withNullInput_returnsFalse() {
assertFalse(SettingsValidators.TTS_LIST_VALIDATOR.validate(null));
}
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 181e0c0..8f859b2 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -275,6 +275,9 @@
<!-- Permission needed to test registering pull atom callbacks -->
<uses-permission android:name="android.permission.REGISTER_STATS_PULL_ATOM" />
+ <!-- Permission needed to modify settings overrideable by restore in CTS tests -->
+ <uses-permission android:name="android.permission.MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE" />
+
<application android:label="@string/app_label"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/SystemUI/TEST_MAPPING b/packages/SystemUI/TEST_MAPPING
index cff958f..c036b04 100644
--- a/packages/SystemUI/TEST_MAPPING
+++ b/packages/SystemUI/TEST_MAPPING
@@ -12,6 +12,9 @@
"include-annotation": "android.platform.test.scenario.annotation.Scenario"
},
{
+ "exclude-annotation": "org.junit.Ignore"
+ },
+ {
"exclude-annotation": "androidx.test.filters.FlakyTest"
}
]
@@ -28,6 +31,9 @@
"include-annotation": "android.platform.test.scenario.annotation.Scenario"
},
{
+ "exclude-annotation": "org.junit.Ignore"
+ },
+ {
"exclude-annotation": "androidx.test.filters.FlakyTest"
},
{
diff --git a/packages/SystemUI/res/color/control_background.xml b/packages/SystemUI/res/color/control_background.xml
deleted file mode 100644
index 977310c..0000000
--- a/packages/SystemUI/res/color/control_background.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_enabled="false"
- android:color="@color/control_default_background" />
- <item android:color="@color/GM2_blue_200"
- android:alpha="0.2" />
-</selector>
diff --git a/packages/SystemUI/res/color/light_background.xml b/packages/SystemUI/res/color/light_background.xml
deleted file mode 100644
index 1299464..0000000
--- a/packages/SystemUI/res/color/light_background.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_enabled="false"
- android:color="@color/control_default_background" />
- <item android:color="@color/GM2_yellow_200"
- android:alpha="0.2" />
-</selector>
diff --git a/packages/SystemUI/res/color/thermo_cool_background.xml b/packages/SystemUI/res/color/thermo_cool_background.xml
deleted file mode 100644
index 977310c..0000000
--- a/packages/SystemUI/res/color/thermo_cool_background.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_enabled="false"
- android:color="@color/control_default_background" />
- <item android:color="@color/GM2_blue_200"
- android:alpha="0.2" />
-</selector>
diff --git a/packages/SystemUI/res/color/thermo_heat_background.xml b/packages/SystemUI/res/color/thermo_heat_background.xml
deleted file mode 100644
index 2709ebe..0000000
--- a/packages/SystemUI/res/color/thermo_heat_background.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_enabled="false"
- android:color="@color/control_default_background" />
- <item android:color="@color/GM2_red_200"
- android:alpha="0.2" />
-</selector>
diff --git a/packages/SystemUI/res/layout/controls_base_item.xml b/packages/SystemUI/res/layout/controls_base_item.xml
index 374e3b1..c58f572 100644
--- a/packages/SystemUI/res/layout/controls_base_item.xml
+++ b/packages/SystemUI/res/layout/controls_base_item.xml
@@ -21,8 +21,9 @@
android:layout_weight="1"
android:layout_height="@dimen/control_height"
android:padding="@dimen/control_padding"
- android:clickable="true"
+ android:clickable="false"
android:focusable="true"
+ android:screenReaderFocusable="true"
android:layout_marginLeft="@dimen/control_base_item_margin"
android:layout_marginRight="@dimen/control_base_item_margin"
android:background="@drawable/control_background">
@@ -32,6 +33,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="@dimen/control_padding_adjustment"
+ android:clickable="false"
+ android:focusable="false"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
@@ -42,6 +45,8 @@
android:textAppearance="@style/TextAppearance.Control.Status"
android:paddingTop="@dimen/control_padding_adjustment"
android:paddingStart="@dimen/control_status_padding"
+ android:clickable="false"
+ android:focusable="false"
app:layout_constraintBottom_toBottomOf="@+id/icon"
app:layout_constraintStart_toEndOf="@+id/icon" />
@@ -52,6 +57,8 @@
android:textAppearance="@style/TextAppearance.Control.Status"
android:paddingTop="@dimen/control_padding_adjustment"
android:paddingStart="@dimen/control_status_padding"
+ android:clickable="false"
+ android:focusable="false"
app:layout_constraintBottom_toBottomOf="@+id/icon"
app:layout_constraintStart_toEndOf="@+id/status" />
@@ -62,6 +69,8 @@
android:textAppearance="@style/TextAppearance.Control.Title"
android:paddingLeft="@dimen/control_padding_adjustment"
android:paddingRight="@dimen/control_padding_adjustment"
+ android:clickable="false"
+ android:focusable="false"
app:layout_constraintBottom_toTopOf="@+id/subtitle"
app:layout_constraintStart_toStartOf="parent" />
@@ -73,6 +82,8 @@
android:paddingLeft="@dimen/control_padding_adjustment"
android:paddingRight="@dimen/control_padding_adjustment"
android:paddingBottom="@dimen/control_padding_adjustment"
+ android:clickable="false"
+ android:focusable="false"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
diff --git a/packages/SystemUI/res/layout/controls_onboarding.xml b/packages/SystemUI/res/layout/controls_onboarding.xml
new file mode 100644
index 0000000..577a3b4
--- /dev/null
+++ b/packages/SystemUI/res/layout/controls_onboarding.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:padding="4dp"
+ android:orientation="vertical">
+
+ <View
+ android:id="@+id/arrow"
+ android:elevation="2dp"
+ android:layout_width="10dp"
+ android:layout_height="8dp"
+ android:layout_marginBottom="-2dp"
+ android:layout_gravity="center_horizontal"/>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingStart="24dp"
+ android:paddingEnd="4dp"
+ android:background="@drawable/recents_onboarding_toast_rounded_background"
+ android:layout_gravity="center_horizontal"
+ android:elevation="2dp"
+ android:orientation="horizontal">
+
+ <TextView
+ android:id="@+id/onboarding_text"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_gravity="center_vertical"
+ android:textColor="?attr/wallpaperTextColor"
+ android:textSize="16sp"/>
+ <ImageView
+ android:id="@+id/dismiss"
+ android:layout_width="40dp"
+ android:layout_height="40dp"
+ android:layout_gravity="center_vertical"
+ android:padding="10dp"
+ android:layout_marginStart="2dp"
+ android:layout_marginEnd="2dp"
+ android:alpha="0.7"
+ android:src="@drawable/ic_close_white"
+ android:tint="?attr/wallpaperTextColor"
+ android:background="?android:attr/selectableItemBackgroundBorderless"
+ android:contentDescription="@string/accessibility_desc_close"/>
+ </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/controls_structure_page.xml b/packages/SystemUI/res/layout/controls_structure_page.xml
index 2c7e168..047ab98 100644
--- a/packages/SystemUI/res/layout/controls_structure_page.xml
+++ b/packages/SystemUI/res/layout/controls_structure_page.xml
@@ -15,17 +15,10 @@
~ limitations under the License.
-->
-<androidx.core.widget.NestedScrollView
+<androidx.recyclerview.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/listAll"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
- android:layout_marginTop="@dimen/controls_management_list_margin">
-
- <androidx.recyclerview.widget.RecyclerView
- android:id="@+id/listAll"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- />
-
-</androidx.core.widget.NestedScrollView>
\ No newline at end of file
+ android:layout_marginTop="@dimen/controls_management_list_margin"/>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 80c1ac8..56e2b06 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -225,4 +225,8 @@
<color name="control_default_background">@color/GM2_grey_900</color>
<color name="control_list_popup_background">@*android:color/background_floating_material_dark</color>
<color name="control_spinner_dropdown">@*android:color/foreground_material_dark</color>
+ <color name="control_enabled_light_background">@color/GM2_yellow_200</color>
+ <color name="control_enabled_thermo_heat_background">@color/GM2_red_200</color>
+ <color name="control_enabled_thermo_cool_background">@color/GM2_blue_200</color>
+ <color name="control_enabled_default_background">@color/GM2_blue_200</color>
</resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index d160829..217abbe 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -117,7 +117,7 @@
<!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" -->
<string name="quick_settings_tiles_stock" translatable="false">
- wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,location,hotspot,inversion,saver,dark,work,cast,night,controls,screenrecord
+ wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,location,hotspot,inversion,saver,dark,work,cast,night,screenrecord
</string>
<!-- The tiles to display in QuickSettings -->
@@ -468,6 +468,9 @@
<!-- On debuggable builds, alert the user if SystemUI PSS goes over this number (in kb) -->
<integer name="watch_heap_limit">256000</integer>
+ <!-- Animation duration for resizing of PIP when entering/exiting. -->
+ <integer name="config_pipResizeAnimationDuration">425</integer>
+
<!-- Allow dragging the PIP to a location to close it -->
<bool name="config_pipEnableDismissDragToEdge">true</bool>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index a246b39..e45cbec 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1231,7 +1231,7 @@
<dimen name="control_height">106dp</dimen>
<dimen name="control_padding">12dp</dimen>
<dimen name="control_padding_adjustment">4dp</dimen>
- <dimen name="control_status_normal">12sp</dimen>
+ <dimen name="control_status_normal">14sp</dimen>
<dimen name="control_status_expanded">18sp</dimen>
<dimen name="control_base_item_margin">2dp</dimen>
<dimen name="control_status_padding">3dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index caf22fe..3543073 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2631,10 +2631,7 @@
<string name="controls_favorite_default_title">Controls</string>
<!-- Controls management controls screen subtitle [CHAR LIMIT=NONE] -->
<string name="controls_favorite_subtitle">Choose controls for quick access</string>
- <!-- Controls management controls screen favorites header [CHAR LIMIT=50] -->
- <string name="controls_favorite_header_favorites">Favorites</string>
- <!-- Controls management controls screen all header [CHAR LIMIT=50] -->
- <string name="controls_favorite_header_all">All</string>
+
<!-- Controls management controls screen error on load message [CHAR LIMIT=60] -->
<string name="controls_favorite_load_error">The list of all controls could not be loaded.</string>
<!-- Controls management controls screen header for Other zone [CHAR LIMIT=60] -->
@@ -2653,4 +2650,7 @@
<string name="controls_pin_verify">Verify device PIN</string>
<!-- Controls PIN entry dialog, text hint [CHAR LIMIT=30] -->
<string name="controls_pin_instructions">Enter PIN</string>
+
+ <!-- Tooltip to show in management screen when there are multiple structures [CHAR_LIMIT=50] -->
+ <string name="controls_structure_tooltip">Swipe to see other structures</string>
</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 125dd8f..20b88a1 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -650,6 +650,7 @@
<!-- Controls styles -->
<style name="Theme.ControlsManagement" parent="@android:style/Theme.DeviceDefault.NoActionBar">
<item name="android:windowIsTranslucent">false</item>
+ <item name="wallpaperTextColor">@*android:color/primary_text_material_dark</item>
</style>
<style name="TextAppearance.Control">
@@ -676,7 +677,7 @@
<style name="TextAppearance.Control.Status">
<item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item>
- <item name="android:textSize">@dimen/control_text_size</item>
+ <item name="android:textSize">@dimen/control_status_normal</item>
<item name="android:textColor">@color/control_primary_text</item>
</style>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
index 1c6223b..9e9b9dc 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
@@ -37,7 +37,8 @@
public void onTaskSnapshotChanged(int taskId, ThumbnailData snapshot) { }
public void onActivityPinned(String packageName, int userId, int taskId, int stackId) { }
public void onActivityUnpinned() { }
- public void onPinnedActivityRestartAttempt(boolean clearedTask) { }
+ public void onActivityRestartAttempt(RunningTaskInfo task, boolean homeTaskVisible,
+ boolean clearedTask) { }
public void onActivityForcedResizable(String packageName, int taskId, int reason) { }
public void onActivityDismissingDockedStack() { }
public void onActivityLaunchOnSecondaryDisplayFailed() { }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
index cbdd3f8..ce9cbab 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
@@ -30,6 +30,7 @@
import android.os.Trace;
import android.util.Log;
+import com.android.internal.os.SomeArgs;
import com.android.systemui.shared.recents.model.ThumbnailData;
import java.util.ArrayList;
@@ -120,11 +121,14 @@
}
@Override
- public void onPinnedActivityRestartAttempt(boolean clearedTask)
- throws RemoteException {
- mHandler.removeMessages(H.ON_PINNED_ACTIVITY_RESTART_ATTEMPT);
- mHandler.obtainMessage(H.ON_PINNED_ACTIVITY_RESTART_ATTEMPT, clearedTask ? 1 : 0, 0)
- .sendToTarget();
+ public void onActivityRestartAttempt(RunningTaskInfo task, boolean homeTaskVisible,
+ boolean clearedTask) throws RemoteException {
+ final SomeArgs args = SomeArgs.obtain();
+ args.arg1 = task;
+ args.argi1 = homeTaskVisible ? 1 : 0;
+ args.argi2 = clearedTask ? 1 : 0;
+ mHandler.removeMessages(H.ON_ACTIVITY_RESTART_ATTEMPT);
+ mHandler.obtainMessage(H.ON_ACTIVITY_RESTART_ATTEMPT, args).sendToTarget();
}
@Override
@@ -236,7 +240,7 @@
private static final int ON_TASK_STACK_CHANGED = 1;
private static final int ON_TASK_SNAPSHOT_CHANGED = 2;
private static final int ON_ACTIVITY_PINNED = 3;
- private static final int ON_PINNED_ACTIVITY_RESTART_ATTEMPT = 4;
+ private static final int ON_ACTIVITY_RESTART_ATTEMPT = 4;
private static final int ON_ACTIVITY_FORCED_RESIZABLE = 6;
private static final int ON_ACTIVITY_DISMISSING_DOCKED_STACK = 7;
private static final int ON_TASK_PROFILE_LOCKED = 8;
@@ -296,10 +300,14 @@
}
break;
}
- case ON_PINNED_ACTIVITY_RESTART_ATTEMPT: {
+ case ON_ACTIVITY_RESTART_ATTEMPT: {
+ final SomeArgs args = (SomeArgs) msg.obj;
+ final RunningTaskInfo task = (RunningTaskInfo) args.arg1;
+ final boolean homeTaskVisible = args.argi1 != 0;
+ final boolean clearedTask = args.argi2 != 0;
for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
- mTaskStackListeners.get(i).onPinnedActivityRestartAttempt(
- msg.arg1 != 0);
+ mTaskStackListeners.get(i).onActivityRestartAttempt(task,
+ homeTaskVisible, clearedTask);
}
break;
}
@@ -419,6 +427,9 @@
}
}
}
+ if (msg.obj instanceof SomeArgs) {
+ ((SomeArgs) msg.obj).recycle();
+ }
}
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WallpaperManagerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WallpaperManagerCompat.java
index b813e21..7570c2c 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WallpaperManagerCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WallpaperManagerCompat.java
@@ -18,7 +18,11 @@
import android.app.WallpaperManager;
import android.content.Context;
+import android.os.IBinder;
+/**
+ * @see WallpaperManager
+ */
public class WallpaperManagerCompat {
private final WallpaperManager mWallpaperManager;
@@ -26,7 +30,10 @@
mWallpaperManager = context.getSystemService(WallpaperManager.class);
}
- public void setWallpaperZoomOut(float zoom) {
- mWallpaperManager.setWallpaperZoomOut(zoom);
+ /**
+ * @see WallpaperManager#setWallpaperZoomOut(IBinder, float)
+ */
+ public void setWallpaperZoomOut(IBinder windowToken, float zoom) {
+ mWallpaperManager.setWallpaperZoomOut(windowToken, zoom);
}
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 3cf07d1..ba8a1a9 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -19,9 +19,7 @@
import static android.view.ViewRootImpl.sNewInsetsMode;
import static android.view.WindowInsets.Type.ime;
import static android.view.WindowInsets.Type.systemBars;
-
import static com.android.systemui.DejankUtils.whitelistIpcs;
-
import static java.lang.Integer.max;
import android.app.Activity;
@@ -30,6 +28,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.res.ColorStateList;
+import android.graphics.Rect;
import android.metrics.LogMaker;
import android.os.Handler;
import android.os.Looper;
@@ -512,8 +511,6 @@
boolean finish = false;
boolean strongAuth = false;
int eventSubtype = -1;
- mCurrentSecuritySelection = whitelistIpcs(() ->
- mSecurityModel.getSecurityMode(targetUserId));
if (mUpdateMonitor.getUserHasTrust(targetUserId)) {
finish = true;
eventSubtype = BOUNCER_DISMISS_EXTENDED_ACCESS;
@@ -521,8 +518,13 @@
finish = true;
eventSubtype = BOUNCER_DISMISS_BIOMETRIC;
} else if (SecurityMode.None == mCurrentSecuritySelection) {
- finish = true; // no security required
- eventSubtype = BOUNCER_DISMISS_NONE_SECURITY;
+ SecurityMode securityMode = mSecurityModel.getSecurityMode(targetUserId);
+ if (SecurityMode.None == securityMode) {
+ finish = true; // no security required
+ eventSubtype = BOUNCER_DISMISS_NONE_SECURITY;
+ } else {
+ showSecurityScreen(securityMode); // switch to the alternate security view
+ }
} else if (authenticated) {
switch (mCurrentSecuritySelection) {
case Pattern:
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 4508fc7..431c451 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -379,7 +379,7 @@
if (DEBUG_SIM_STATES) {
Log.v(TAG, "onSubscriptionInfoChanged()");
List<SubscriptionInfo> sil = mSubscriptionManager
- .getActiveAndHiddenSubscriptionInfoList();
+ .getCompleteActiveSubscriptionInfoList();
if (sil != null) {
for (SubscriptionInfo subInfo : sil) {
Log.v(TAG, "SubInfo:" + subInfo);
@@ -433,10 +433,10 @@
public List<SubscriptionInfo> getSubscriptionInfo(boolean forceReload) {
List<SubscriptionInfo> sil = mSubscriptionInfo;
if (sil == null || forceReload) {
- sil = mSubscriptionManager.getActiveAndHiddenSubscriptionInfoList();
+ sil = mSubscriptionManager.getCompleteActiveSubscriptionInfoList();
}
if (sil == null) {
- // getActiveAndHiddenSubscriptionInfoList was null callers expect an empty list.
+ // getCompleteActiveSubscriptionInfoList was null callers expect an empty list.
mSubscriptionInfo = new ArrayList<SubscriptionInfo>();
} else {
mSubscriptionInfo = sil;
@@ -1086,7 +1086,7 @@
mHandler.sendEmptyMessage(MSG_TIME_UPDATE);
} else if (Intent.ACTION_TIMEZONE_CHANGED.equals(action)) {
final Message msg = mHandler.obtainMessage(
- MSG_TIMEZONE_UPDATE, intent.getStringExtra("time-zone"));
+ MSG_TIMEZONE_UPDATE, intent.getStringExtra(Intent.EXTRA_TIMEZONE));
mHandler.sendMessage(msg);
} else if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index a868cf5..b6152da 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -71,12 +71,11 @@
import com.android.systemui.statusbar.NotificationViewHierarchyManager;
import com.android.systemui.statusbar.SmartReplyController;
import com.android.systemui.statusbar.VibratorHelper;
-import com.android.systemui.statusbar.notification.NotificationAlertingManager;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment;
import com.android.systemui.statusbar.notification.NotificationFilter;
-import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.interruption.NotificationAlertingManager;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ChannelEditorDialogController;
import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
@@ -289,7 +288,6 @@
@Inject Lazy<NotificationLogger> mNotificationLogger;
@Inject Lazy<NotificationViewHierarchyManager> mNotificationViewHierarchyManager;
@Inject Lazy<NotificationFilter> mNotificationFilter;
- @Inject Lazy<NotificationInterruptionStateProvider> mNotificationInterruptionStateProvider;
@Inject Lazy<KeyguardDismissUtil> mKeyguardDismissUtil;
@Inject Lazy<SmartReplyController> mSmartReplyController;
@Inject Lazy<RemoteInputQuickSettingsDisabler> mRemoteInputQuickSettingsDisabler;
@@ -489,8 +487,6 @@
mProviders.put(NotificationViewHierarchyManager.class,
mNotificationViewHierarchyManager::get);
mProviders.put(NotificationFilter.class, mNotificationFilter::get);
- mProviders.put(NotificationInterruptionStateProvider.class,
- mNotificationInterruptionStateProvider::get);
mProviders.put(KeyguardDismissUtil.class, mKeyguardDismissUtil::get);
mProviders.put(SmartReplyController.class, mSmartReplyController::get);
mProviders.put(RemoteInputQuickSettingsDisabler.class,
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index dbcdead..23fa645 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -203,6 +203,11 @@
}
}
+ @Override
+ public boolean shouldZoomOutWallpaper() {
+ return true;
+ }
+
private void waitForBackgroundRendering() {
synchronized (mMonitor) {
try {
diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java
index 5e6589f..6aa2326 100644
--- a/packages/SystemUI/src/com/android/systemui/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/Prefs.java
@@ -59,7 +59,8 @@
Key.TOUCHED_RINGER_TOGGLE,
Key.HAS_SEEN_ODI_CAPTIONS_TOOLTIP,
Key.HAS_SEEN_BUBBLES_EDUCATION,
- Key.HAS_SEEN_BUBBLES_MANAGE_EDUCATION
+ Key.HAS_SEEN_BUBBLES_MANAGE_EDUCATION,
+ Key.CONTROLS_STRUCTURE_SWIPE_TOOLTIP_COUNT
})
public @interface Key {
@Deprecated
@@ -107,6 +108,7 @@
String HAS_SEEN_ODI_CAPTIONS_TOOLTIP = "HasSeenODICaptionsTooltip";
String HAS_SEEN_BUBBLES_EDUCATION = "HasSeenBubblesOnboarding";
String HAS_SEEN_BUBBLES_MANAGE_EDUCATION = "HasSeenBubblesManageOnboarding";
+ String CONTROLS_STRUCTURE_SWIPE_TOOLTIP_COUNT = "ControlsStructureSwipeTooltipCount";
}
public static boolean getBoolean(Context context, @Key String key, boolean defaultValue) {
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index cab9f18..537a812 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -48,6 +48,7 @@
import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.Rect;
+import android.graphics.RectF;
import android.graphics.Region;
import android.hardware.display.DisplayManager;
import android.os.Handler;
@@ -725,7 +726,8 @@
private final Rect mBoundingRect = new Rect();
private final Path mBoundingPath = new Path();
// Don't initialize these yet because they may never exist
- private Rect mProtectionRect;
+ private RectF mProtectionRect;
+ private RectF mProtectionRectOrig;
private Path mProtectionPath;
private Path mProtectionPathOrig;
private Rect mTotalBounds = new Rect();
@@ -818,7 +820,11 @@
mProtectionPath = new Path();
}
mProtectionPathOrig.set(protectionPath);
- mProtectionRect = pathBounds;
+ if (mProtectionRectOrig == null) {
+ mProtectionRectOrig = new RectF();
+ mProtectionRect = new RectF();
+ }
+ mProtectionRectOrig.set(pathBounds);
}
void setShowProtection(boolean shouldShow) {
@@ -898,6 +904,7 @@
// Reset the protection path so we don't aggregate rotations
mProtectionPath.set(mProtectionPathOrig);
mProtectionPath.transform(m);
+ m.mapRect(mProtectionRect, mProtectionRectOrig);
}
}
@@ -964,7 +971,8 @@
if (mShowProtection) {
// Make sure that our measured height encompases the protection
mTotalBounds.union(mBoundingRect);
- mTotalBounds.union(mProtectionRect);
+ mTotalBounds.union((int) mProtectionRect.left, (int) mProtectionRect.top,
+ (int) mProtectionRect.right, (int) mProtectionRect.bottom);
setMeasuredDimension(
resolveSizeAndState(mTotalBounds.width(), widthMeasureSpec, 0),
resolveSizeAndState(mTotalBounds.height(), heightMeasureSpec, 0));
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 22c2c7e..406e7ce 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -83,11 +83,11 @@
import com.android.systemui.statusbar.NotificationRemoveInterceptor;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.ShadeController;
@@ -169,7 +169,7 @@
// Callback that updates BubbleOverflowActivity on data change.
@Nullable private Runnable mOverflowCallback = null;
- private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
+ private final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
private IStatusBarService mBarService;
// Used for determining view rect for touch interaction
@@ -279,7 +279,7 @@
ShadeController shadeController,
BubbleData data,
ConfigurationController configurationController,
- NotificationInterruptionStateProvider interruptionStateProvider,
+ NotificationInterruptStateProvider interruptionStateProvider,
ZenModeController zenModeController,
NotificationLockscreenUserManager notifUserManager,
NotificationGroupManager groupManager,
@@ -304,7 +304,7 @@
BubbleData data,
@Nullable BubbleStackView.SurfaceSynchronizer synchronizer,
ConfigurationController configurationController,
- NotificationInterruptionStateProvider interruptionStateProvider,
+ NotificationInterruptStateProvider interruptionStateProvider,
ZenModeController zenModeController,
NotificationLockscreenUserManager notifUserManager,
NotificationGroupManager groupManager,
@@ -316,7 +316,7 @@
dumpManager.registerDumpable(TAG, this);
mContext = context;
mShadeController = shadeController;
- mNotificationInterruptionStateProvider = interruptionStateProvider;
+ mNotificationInterruptStateProvider = interruptionStateProvider;
mNotifUserManager = notifUserManager;
mZenModeController = zenModeController;
mFloatingContentCoordinator = floatingContentCoordinator;
@@ -632,7 +632,7 @@
for (NotificationEntry e :
mNotificationEntryManager.getActiveNotificationsForCurrentUser()) {
if (savedBubbleKeys.contains(e.getKey())
- && mNotificationInterruptionStateProvider.shouldBubbleUp(e)
+ && mNotificationInterruptStateProvider.shouldBubbleUp(e)
&& canLaunchInActivityView(mContext, e)) {
updateBubble(e, /* suppressFlyout= */ true);
}
@@ -894,7 +894,7 @@
boolean wasAdjusted = BubbleExperimentConfig.adjustForExperiments(
mContext, entry, previouslyUserCreated, userBlocked);
- if (mNotificationInterruptionStateProvider.shouldBubbleUp(entry)
+ if (mNotificationInterruptStateProvider.shouldBubbleUp(entry)
&& (canLaunchInActivityView(mContext, entry) || wasAdjusted)) {
if (wasAdjusted && !previouslyUserCreated) {
// Gotta treat the auto-bubbled / whitelisted packaged bubbles as usercreated
@@ -910,7 +910,7 @@
boolean wasAdjusted = BubbleExperimentConfig.adjustForExperiments(
mContext, entry, previouslyUserCreated, userBlocked);
- boolean shouldBubble = mNotificationInterruptionStateProvider.shouldBubbleUp(entry)
+ boolean shouldBubble = mNotificationInterruptStateProvider.shouldBubbleUp(entry)
&& (canLaunchInActivityView(mContext, entry) || wasAdjusted);
if (!shouldBubble && mBubbleData.hasBubbleWithKey(entry.getKey())) {
// It was previously a bubble but no longer a bubble -- lets remove it
@@ -1227,6 +1227,17 @@
}
@Override
+ public void onActivityRestartAttempt(RunningTaskInfo task, boolean homeTaskVisible,
+ boolean clearedTask) {
+ for (Bubble b : mBubbleData.getBubbles()) {
+ if (b.getDisplayId() == task.displayId) {
+ expandStackAndSelectBubble(b.getKey());
+ return;
+ }
+ }
+ }
+
+ @Override
public void onActivityLaunchOnSecondaryDisplayRerouted() {
if (mStackView != null) {
mBubbleData.setExpanded(false);
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index aedd2db..0778d5b 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -424,6 +424,7 @@
private int mOrientation = Configuration.ORIENTATION_UNDEFINED;
+ @Nullable
private BubbleOverflow mBubbleOverflow;
private boolean mShouldShowUserEducation;
@@ -1386,6 +1387,11 @@
if (DEBUG_BUBBLE_STACK_VIEW) {
Log.d(TAG, "onBubbleDragStart: bubble=" + bubble);
}
+
+ if (mBubbleOverflow != null && bubble.equals(mBubbleOverflow.getIconView())) {
+ return;
+ }
+
mExpandedAnimationController.prepareForBubbleDrag(bubble, mMagneticTarget);
// We're dragging an individual bubble, so set the magnetized object to the magnetized
@@ -1398,7 +1404,8 @@
/** Called with the coordinates to which an individual bubble has been dragged. */
public void onBubbleDragged(View bubble, float x, float y) {
- if (!mIsExpanded || mIsExpansionAnimating) {
+ if (!mIsExpanded || mIsExpansionAnimating
+ || (mBubbleOverflow != null && bubble.equals(mBubbleOverflow.getIconView()))) {
return;
}
@@ -1413,7 +1420,8 @@
Log.d(TAG, "onBubbleDragFinish: bubble=" + bubble);
}
- if (!mIsExpanded || mIsExpansionAnimating) {
+ if (!mIsExpanded || mIsExpansionAnimating
+ || (mBubbleOverflow != null && bubble.equals(mBubbleOverflow.getIconView()))) {
return;
}
@@ -1421,6 +1429,18 @@
hideDismissTarget();
}
+ /** Expands the clicked bubble. */
+ public void expandBubble(Bubble bubble) {
+ if (bubble.equals(mBubbleData.getSelectedBubble())) {
+ // If the bubble we're supposed to expand is the selected bubble, that means the
+ // overflow bubble is currently expanded. Don't tell BubbleData to set this bubble as
+ // selected, since it already is. Just call the stack's setSelectedBubble to expand it.
+ setSelectedBubble(bubble);
+ } else {
+ mBubbleData.setSelectedBubble(bubble);
+ }
+ }
+
void onDragStart() {
if (DEBUG_BUBBLE_STACK_VIEW) {
Log.d(TAG, "onDragStart()");
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
index 0c5bef4..132c45f 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
@@ -189,7 +189,7 @@
if (key == BubbleOverflow.KEY) {
mStack.showOverflow();
} else {
- mBubbleData.setSelectedBubble(mBubbleData.getBubbleWithKey(key));
+ mStack.expandBubble(mBubbleData.getBubbleWithKey(key));
}
}
resetForNextGesture();
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 ac97d8a..27c9e98 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java
@@ -25,8 +25,8 @@
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.ShadeController;
@@ -54,7 +54,7 @@
ShadeController shadeController,
BubbleData data,
ConfigurationController configurationController,
- NotificationInterruptionStateProvider interruptionStateProvider,
+ NotificationInterruptStateProvider interruptionStateProvider,
ZenModeController zenModeController,
NotificationLockscreenUserManager notifUserManager,
NotificationGroupManager groupManager,
diff --git a/packages/SystemUI/src/com/android/systemui/controls/TooltipManager.kt b/packages/SystemUI/src/com/android/systemui/controls/TooltipManager.kt
new file mode 100644
index 0000000..6e17bc9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/controls/TooltipManager.kt
@@ -0,0 +1,160 @@
+/*
+ * 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.controls
+
+import android.annotation.StringRes
+import android.content.Context
+import android.graphics.CornerPathEffect
+import android.graphics.drawable.ShapeDrawable
+import android.util.TypedValue
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.view.animation.AccelerateInterpolator
+import android.view.animation.DecelerateInterpolator
+import android.widget.TextView
+import com.android.systemui.Prefs
+import com.android.systemui.R
+import com.android.systemui.recents.TriangleShape
+
+/**
+ * Manager for showing an onboarding tooltip on screen.
+ *
+ * The tooltip can be made to appear below or above a point. The number of times it will appear
+ * is determined by an shared preference (defined in [Prefs]).
+ *
+ * @property context A context to use to inflate the views and retrieve shared preferences from
+ * @property preferenceName name of the preference to use to track the number of times the tooltip
+ * has been shown.
+ * @property maxTimesShown the maximum number of times to show the tooltip
+ * @property below whether the tooltip should appear below (with up pointing arrow) or above (down
+ * pointing arrow) the specified point.
+ * @see [TooltipManager.show]
+ */
+class TooltipManager(
+ context: Context,
+ private val preferenceName: String,
+ private val maxTimesShown: Int = 2,
+ private val below: Boolean = true
+) {
+
+ companion object {
+ private const val SHOW_DELAY_MS: Long = 500
+ private const val SHOW_DURATION_MS: Long = 300
+ private const val HIDE_DURATION_MS: Long = 100
+ }
+
+ private var shown = Prefs.getInt(context, preferenceName, 0)
+
+ val layout: ViewGroup =
+ LayoutInflater.from(context).inflate(R.layout.controls_onboarding, null) as ViewGroup
+ val preferenceStorer = { num: Int ->
+ Prefs.putInt(context, preferenceName, num)
+ }
+
+ init {
+ layout.alpha = 0f
+ }
+
+ private val textView = layout.requireViewById<TextView>(R.id.onboarding_text)
+ private val dismissView = layout.requireViewById<View>(R.id.dismiss).apply {
+ setOnClickListener {
+ hide(true)
+ }
+ }
+
+ private val arrowView = layout.requireViewById<View>(R.id.arrow).apply {
+ val typedValue = TypedValue()
+ context.theme.resolveAttribute(android.R.attr.colorAccent, typedValue, true)
+ val toastColor = context.resources.getColor(typedValue.resourceId, context.theme)
+ val arrowRadius = context.resources.getDimensionPixelSize(
+ R.dimen.recents_onboarding_toast_arrow_corner_radius)
+ val arrowLp = layoutParams
+ val arrowDrawable = ShapeDrawable(TriangleShape.create(
+ arrowLp.width.toFloat(), arrowLp.height.toFloat(), below))
+ val arrowPaint = arrowDrawable.paint
+ arrowPaint.color = toastColor
+ // The corner path effect won't be reflected in the shadow, but shouldn't be noticeable.
+ arrowPaint.pathEffect = CornerPathEffect(arrowRadius.toFloat())
+ setBackground(arrowDrawable)
+ }
+
+ init {
+ if (!below) {
+ layout.removeView(arrowView)
+ layout.addView(arrowView)
+ (arrowView.layoutParams as ViewGroup.MarginLayoutParams).apply {
+ bottomMargin = topMargin
+ topMargin = 0
+ }
+ }
+ }
+
+ /**
+ * Show the tooltip
+ *
+ * @param stringRes the id of the string to show in the tooltip
+ * @param x horizontal position (w.r.t. screen) for the arrow point
+ * @param y vertical position (w.r.t. screen) for the arrow point
+ */
+ fun show(@StringRes stringRes: Int, x: Int, y: Int) {
+ if (!shouldShow()) return
+ textView.setText(stringRes)
+ shown++
+ preferenceStorer(shown)
+ layout.post {
+ val p = IntArray(2)
+ layout.getLocationOnScreen(p)
+ layout.translationX = (x - p[0] - layout.width / 2).toFloat()
+ layout.translationY = (y - p[1]).toFloat() - if (!below) layout.height else 0
+ if (layout.alpha == 0f) {
+ layout.animate()
+ .alpha(1f)
+ .withLayer()
+ .setStartDelay(SHOW_DELAY_MS)
+ .setDuration(SHOW_DURATION_MS)
+ .setInterpolator(DecelerateInterpolator())
+ .start()
+ }
+ }
+ }
+
+ /**
+ * Hide the tooltip
+ *
+ * @param animate whether to animate the fade out
+ */
+ fun hide(animate: Boolean = false) {
+ if (layout.alpha == 0f) return
+ layout.post {
+ if (animate) {
+ layout.animate()
+ .alpha(0f)
+ .withLayer()
+ .setStartDelay(0)
+ .setDuration(HIDE_DURATION_MS)
+ .setInterpolator(AccelerateInterpolator())
+ .start()
+ } else {
+ layout.animate().cancel()
+ layout.alpha = 0f
+ }
+ }
+ }
+
+ private fun shouldShow() = shown < maxTimesShown
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingController.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingController.kt
index fd6e256..c5af436 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingController.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingController.kt
@@ -38,8 +38,9 @@
*
* @param component The [ComponentName] of the service to bind
* @param callback a callback to return the loaded controls to (or an error).
+ * @return a runnable to cancel the load
*/
- fun bindAndLoad(component: ComponentName, callback: LoadCallback)
+ fun bindAndLoad(component: ComponentName, callback: LoadCallback): Runnable
/**
* Request to bind to the given service.
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt
index 8f02c25..f8d4a39 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt
@@ -31,7 +31,6 @@
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.util.concurrency.DelayableExecutor
import dagger.Lazy
-import java.util.concurrent.atomic.AtomicBoolean
import javax.inject.Inject
import javax.inject.Singleton
@@ -47,8 +46,6 @@
private const val TAG = "ControlsBindingControllerImpl"
}
- private val refreshing = AtomicBoolean(false)
-
private var currentUser = UserHandle.of(ActivityManager.getCurrentUser())
override val currentUserId: Int
@@ -56,6 +53,12 @@
private var currentProvider: ControlsProviderLifecycleManager? = null
+ /*
+ * Will track any active subscriber for subscribe/unsubscribe requests coming into
+ * this controller. Only one can be active at any time
+ */
+ private var statefulControlSubscriber: StatefulControlSubscriber? = null
+
private val actionCallbackService = object : IControlsActionCallback.Stub() {
override fun accept(
token: IBinder,
@@ -66,27 +69,6 @@
}
}
- private val subscriberService = object : IControlsSubscriber.Stub() {
- override fun onSubscribe(token: IBinder, subs: IControlsSubscription) {
- backgroundExecutor.execute(OnSubscribeRunnable(token, subs))
- }
-
- override fun onNext(token: IBinder, c: Control) {
- if (!refreshing.get()) {
- Log.d(TAG, "Refresh outside of window for token:$token")
- } else {
- backgroundExecutor.execute(OnNextRunnable(token, c))
- }
- }
- override fun onError(token: IBinder, s: String) {
- backgroundExecutor.execute(OnErrorRunnable(token, s))
- }
-
- override fun onComplete(token: IBinder) {
- backgroundExecutor.execute(OnCompleteRunnable(token))
- }
- }
-
@VisibleForTesting
internal open fun createProviderManager(component: ComponentName):
ControlsProviderLifecycleManager {
@@ -94,43 +76,45 @@
context,
backgroundExecutor,
actionCallbackService,
- subscriberService,
currentUser,
component
)
}
private fun retrieveLifecycleManager(component: ComponentName):
- ControlsProviderLifecycleManager? {
+ ControlsProviderLifecycleManager {
if (currentProvider != null && currentProvider?.componentName != component) {
unbind()
}
- if (currentProvider == null) {
- currentProvider = createProviderManager(component)
- }
+ val provider = currentProvider ?: createProviderManager(component)
+ currentProvider = provider
- return currentProvider
+ return provider
}
override fun bindAndLoad(
component: ComponentName,
callback: ControlsBindingController.LoadCallback
- ) {
- retrieveLifecycleManager(component)?.maybeBindAndLoad(LoadSubscriber(callback))
+ ): Runnable {
+ val subscriber = LoadSubscriber(callback)
+ retrieveLifecycleManager(component).maybeBindAndLoad(subscriber)
+ return subscriber.loadCancel()
}
override fun subscribe(structureInfo: StructureInfo) {
- if (refreshing.compareAndSet(false, true)) {
- val provider = retrieveLifecycleManager(structureInfo.componentName)
- provider?.maybeBindAndSubscribe(structureInfo.controls.map { it.controlId })
- }
+ // make sure this has happened. only allow one active subscription
+ unsubscribe()
+
+ statefulControlSubscriber = null
+ val provider = retrieveLifecycleManager(structureInfo.componentName)
+ val scs = StatefulControlSubscriber(lazyController.get(), provider, backgroundExecutor)
+ statefulControlSubscriber = scs
+ provider.maybeBindAndSubscribe(structureInfo.controls.map { it.controlId }, scs)
}
override fun unsubscribe() {
- if (refreshing.compareAndSet(true, false)) {
- currentProvider?.unsubscribe()
- }
+ statefulControlSubscriber?.cancel()
}
override fun action(
@@ -138,20 +122,24 @@
controlInfo: ControlInfo,
action: ControlAction
) {
- retrieveLifecycleManager(componentName)
- ?.maybeBindAndSendAction(controlInfo.controlId, action)
+ if (statefulControlSubscriber == null) {
+ Log.w(TAG, "No actions can occur outside of an active subscription. Ignoring.")
+ } else {
+ retrieveLifecycleManager(componentName)
+ .maybeBindAndSendAction(controlInfo.controlId, action)
+ }
}
override fun bindService(component: ComponentName) {
- retrieveLifecycleManager(component)?.bindService()
+ retrieveLifecycleManager(component).bindService()
}
override fun changeUser(newUser: UserHandle) {
if (newUser == currentUser) return
+ unsubscribe()
unbind()
-
- refreshing.set(false)
+ currentProvider = null
currentUser = newUser
}
@@ -172,8 +160,8 @@
override fun toString(): String {
return StringBuilder(" ControlsBindingController:\n").apply {
- append(" refreshing=${refreshing.get()}\n")
append(" currentUser=$currentUser\n")
+ append(" StatefulControlSubscriber=$statefulControlSubscriber")
append(" Providers=$currentProvider\n")
}.toString()
}
@@ -208,22 +196,6 @@
) : CallbackRunnable(token) {
override fun doRun() {
callback.accept(list)
- provider?.unbindService()
- }
- }
-
- private inner class OnNextRunnable(
- token: IBinder,
- val control: Control
- ) : CallbackRunnable(token) {
- override fun doRun() {
- if (!refreshing.get()) {
- Log.d(TAG, "onRefresh outside of window from:${provider?.componentName}")
- }
-
- provider?.let {
- lazyController.get().refreshStatus(it.componentName, control)
- }
}
}
@@ -232,33 +204,7 @@
val subscription: IControlsSubscription
) : CallbackRunnable(token) {
override fun doRun() {
- if (!refreshing.get()) {
- Log.d(TAG, "onRefresh outside of window from '${provider?.componentName}'")
- }
- provider?.let {
- it.startSubscription(subscription)
- }
- }
- }
-
- private inner class OnCompleteRunnable(
- token: IBinder
- ) : CallbackRunnable(token) {
- override fun doRun() {
- provider?.let {
- Log.i(TAG, "onComplete receive from '${it.componentName}'")
- }
- }
- }
-
- private inner class OnErrorRunnable(
- token: IBinder,
- val error: String
- ) : CallbackRunnable(token) {
- override fun doRun() {
- provider?.let {
- Log.e(TAG, "onError receive from '${it.componentName}': $error")
- }
+ provider?.startSubscription(subscription)
}
}
@@ -292,8 +238,14 @@
) : IControlsSubscriber.Stub() {
val loadedControls = ArrayList<Control>()
var hasError = false
+ private var _loadCancelInternal: (() -> Unit)? = null
+ fun loadCancel() = Runnable {
+ Log.d(TAG, "Cancel load requested")
+ _loadCancelInternal?.invoke()
+ }
override fun onSubscribe(token: IBinder, subs: IControlsSubscription) {
+ _loadCancelInternal = subs::cancel
backgroundExecutor.execute(OnSubscribeRunnable(token, subs))
}
@@ -302,11 +254,15 @@
}
override fun onError(token: IBinder, s: String) {
hasError = true
+ _loadCancelInternal = {}
+ currentProvider?.cancelLoadTimeout()
backgroundExecutor.execute(OnLoadErrorRunnable(token, s, callback))
}
override fun onComplete(token: IBinder) {
+ _loadCancelInternal = {}
if (!hasError) {
+ currentProvider?.cancelLoadTimeout()
backgroundExecutor.execute(OnLoadRunnable(token, loadedControls, callback))
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt
index 7eafe2e..9e0d26c 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt
@@ -59,6 +59,11 @@
)
/**
+ * Cancels a pending load call
+ */
+ fun cancelLoad()
+
+ /**
* Request to subscribe for favorited controls per structure
*
* @param structureInfo structure to limit the subscription to
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
index e5d36f9..9cb902f 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
@@ -72,6 +72,8 @@
private var userChanging: Boolean = true
+ private var loadCanceller: Runnable? = null
+
private var currentUser = UserHandle.of(ActivityManager.getCurrentUser())
override val currentUserId
get() = currentUser.identifier
@@ -213,8 +215,9 @@
if (!confirmAvailability()) {
if (userChanging) {
// Try again later, userChanging should not last forever. If so, we have bigger
- // problems
- executor.executeDelayed(
+ // problems. This will return a runnable that allows to cancel the delayed version,
+ // it will not be able to cancel the load if
+ loadCanceller = executor.executeDelayed(
{ loadForComponent(componentName, dataCallback) },
USER_CHANGE_RETRY_DELAY,
TimeUnit.MILLISECONDS
@@ -224,10 +227,11 @@
}
return
}
- bindingController.bindAndLoad(
+ loadCanceller = bindingController.bindAndLoad(
componentName,
object : ControlsBindingController.LoadCallback {
override fun accept(controls: List<Control>) {
+ loadCanceller = null
executor.execute {
val favoritesForComponentKeys = Favorites
.getControlsForComponent(componentName).map { it.controlId }
@@ -251,12 +255,12 @@
controlsWithFavorite,
favoritesForComponentKeys
)
-
dataCallback.accept(loadData)
}
}
override fun error(message: String) {
+ loadCanceller = null
executor.execute {
val loadData = Favorites.getControlsForComponent(componentName)
.let { controls ->
@@ -269,7 +273,6 @@
true
)
}
-
dataCallback.accept(loadData)
}
}
@@ -277,6 +280,12 @@
)
}
+ override fun cancelLoad() {
+ loadCanceller?.let {
+ executor.execute(it)
+ }
+ }
+
private fun createRemovedStatus(
componentName: ComponentName,
controlInfo: ControlInfo,
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt
index 86e8e83..4918bd7 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt
@@ -58,7 +58,6 @@
private val context: Context,
private val executor: DelayableExecutor,
private val actionCallbackService: IControlsActionCallback.Stub,
- private val subscriberService: IControlsSubscriber.Stub,
val user: UserHandle,
val componentName: ComponentName
) : IBinder.DeathRecipient {
@@ -157,10 +156,9 @@
load(msg.subscriber)
}
- queue.filter { it is Message.Subscribe }.flatMap { (it as Message.Subscribe).list }.run {
- if (this.isNotEmpty()) {
- subscribe(this)
- }
+ queue.filter { it is Message.Subscribe }.forEach {
+ val msg = it as Message.Subscribe
+ subscribe(msg.list, msg.subscriber)
}
queue.filter { it is Message.Action }.forEach {
val msg = it as Message.Action
@@ -185,9 +183,9 @@
}
}
- private fun unqueueMessage(message: Message) {
+ private fun unqueueMessageType(type: Int) {
synchronized(queuedMessages) {
- queuedMessages.removeIf { it.type == message.type }
+ queuedMessages.removeIf { it.type == type }
}
}
@@ -219,7 +217,7 @@
* @param subscriber the subscriber that manages coordination for loading controls
*/
fun maybeBindAndLoad(subscriber: IControlsSubscriber.Stub) {
- unqueueMessage(Message.Unbind)
+ unqueueMessageType(MSG_UNBIND)
onLoadCanceller = executor.executeDelayed({
// Didn't receive a response in time, log and send back error
Log.d(TAG, "Timeout waiting onLoad for $componentName")
@@ -230,6 +228,11 @@
invokeOrQueue({ load(subscriber) }, Message.Load(subscriber))
}
+ fun cancelLoadTimeout() {
+ onLoadCanceller?.run()
+ onLoadCanceller = null
+ }
+
/**
* Request a subscription to the [Publisher] returned by [ControlsProviderService.publisherFor]
*
@@ -237,16 +240,20 @@
*
* @param controlIds a list of the ids of controls to send status back.
*/
- fun maybeBindAndSubscribe(controlIds: List<String>) {
- invokeOrQueue({ subscribe(controlIds) }, Message.Subscribe(controlIds))
+ fun maybeBindAndSubscribe(controlIds: List<String>, subscriber: IControlsSubscriber) {
+ invokeOrQueue(
+ { subscribe(controlIds, subscriber) },
+ Message.Subscribe(controlIds, subscriber)
+ )
}
- private fun subscribe(controlIds: List<String>) {
+ private fun subscribe(controlIds: List<String>, subscriber: IControlsSubscriber) {
if (DEBUG) {
Log.d(TAG, "subscribe $componentName - $controlIds")
}
- if (!(wrapper?.subscribe(controlIds, subscriberService) ?: false)) {
- queueMessage(Message.Subscribe(controlIds))
+
+ if (!(wrapper?.subscribe(controlIds, subscriber) ?: false)) {
+ queueMessage(Message.Subscribe(controlIds, subscriber))
binderDied()
}
}
@@ -276,10 +283,13 @@
/**
* Starts the subscription to the [ControlsProviderService] and requests status of controls.
*
- * @param subscription the subscriber to use to request controls
+ * @param subscription the subscription to use to request controls
* @see maybeBindAndLoad
*/
fun startSubscription(subscription: IControlsSubscription) {
+ if (DEBUG) {
+ Log.d(TAG, "startSubscription: $subscription")
+ }
synchronized(subscriptions) {
subscriptions.add(subscription)
}
@@ -287,30 +297,26 @@
}
/**
- * Unsubscribe from this service, cancelling all status requests.
+ * Cancels the subscription to the [ControlsProviderService].
+ *
+ * @param subscription the subscription to cancel
+ * @see maybeBindAndLoad
*/
- fun unsubscribe() {
+ fun cancelSubscription(subscription: IControlsSubscription) {
if (DEBUG) {
- Log.d(TAG, "unsubscribe $componentName")
+ Log.d(TAG, "cancelSubscription: $subscription")
}
- unqueueMessage(Message.Subscribe(emptyList())) // Removes all subscribe messages
-
- val subs = synchronized(subscriptions) {
- ArrayList(subscriptions).also {
- subscriptions.clear()
- }
+ synchronized(subscriptions) {
+ subscriptions.remove(subscription)
}
-
- subs.forEach {
- wrapper?.cancel(it)
- }
+ wrapper?.cancel(subscription)
}
/**
* Request bind to the service.
*/
fun bindService() {
- unqueueMessage(Message.Unbind)
+ unqueueMessageType(MSG_UNBIND)
bindService(true)
}
@@ -321,8 +327,16 @@
onLoadCanceller?.run()
onLoadCanceller = null
- // just in case this wasn't called already
- unsubscribe()
+ // be sure to cancel all subscriptions
+ val subs = synchronized(subscriptions) {
+ ArrayList(subscriptions).also {
+ subscriptions.clear()
+ }
+ }
+
+ subs.forEach {
+ wrapper?.cancel(it)
+ }
bindService(false)
}
@@ -346,7 +360,7 @@
object Unbind : Message() {
override val type = MSG_UNBIND
}
- class Subscribe(val list: List<String>) : Message() {
+ class Subscribe(val list: List<String>, val subscriber: IControlsSubscriber) : Message() {
override val type = MSG_SUBSCRIBE
}
class Action(val id: String, val action: ControlAction) : Message() {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/StatefulControlSubscriber.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/StatefulControlSubscriber.kt
new file mode 100644
index 0000000..a371aa6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/StatefulControlSubscriber.kt
@@ -0,0 +1,96 @@
+/*
+ * 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.controls.controller
+
+import android.os.IBinder
+import android.service.controls.Control
+import android.service.controls.IControlsSubscriber
+import android.service.controls.IControlsSubscription
+import android.util.Log
+import com.android.systemui.util.concurrency.DelayableExecutor
+
+/**
+ * A single subscriber, supporting stateful controls for publishers created by
+ * {@link ControlsProviderService#createPublisherFor}. In general, this subscription will remain
+ * active until the SysUi chooses to cancel it.
+ */
+class StatefulControlSubscriber(
+ private val controller: ControlsController,
+ private val provider: ControlsProviderLifecycleManager,
+ private val bgExecutor: DelayableExecutor
+) : IControlsSubscriber.Stub() {
+ private var subscriptionOpen = false
+ private var subscription: IControlsSubscription? = null
+
+ companion object {
+ private const val TAG = "StatefulControlSubscriber"
+ }
+
+ private fun run(token: IBinder, f: () -> Unit) {
+ if (provider.token == token) {
+ bgExecutor.execute { f() }
+ }
+ }
+
+ override fun onSubscribe(token: IBinder, subs: IControlsSubscription) {
+ run(token) {
+ subscriptionOpen = true
+ subscription = subs
+ provider.startSubscription(subs)
+ }
+ }
+
+ override fun onNext(token: IBinder, control: Control) {
+ run(token) {
+ if (!subscriptionOpen) {
+ Log.w(TAG, "Refresh outside of window for token:$token")
+ } else {
+ controller.refreshStatus(provider.componentName, control)
+ }
+ }
+ }
+ override fun onError(token: IBinder, error: String) {
+ run(token) {
+ if (subscriptionOpen) {
+ subscriptionOpen = false
+ Log.e(TAG, "onError receive from '${provider.componentName}': $error")
+ }
+ }
+ }
+
+ override fun onComplete(token: IBinder) {
+ run(token) {
+ if (subscriptionOpen) {
+ subscriptionOpen = false
+ Log.i(TAG, "onComplete receive from '${provider.componentName}'")
+ }
+ }
+ }
+
+ fun cancel() {
+ if (!subscriptionOpen) return
+ bgExecutor.execute {
+ if (subscriptionOpen) {
+ subscriptionOpen = false
+ subscription?.let {
+ provider.cancelSubscription(it)
+ }
+ subscription = null
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
index 04715ab..f2303e6 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
@@ -19,22 +19,27 @@
import android.app.Activity
import android.content.ComponentName
import android.content.Intent
+import android.content.res.Configuration
import android.graphics.drawable.Drawable
import android.os.Bundle
import android.text.TextUtils
+import android.view.Gravity
import android.view.View
+import android.view.ViewGroup
import android.view.ViewStub
import android.widget.Button
+import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.TextView
import androidx.viewpager2.widget.ViewPager2
+import com.android.systemui.Prefs
import com.android.systemui.R
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.controls.ControlsServiceInfo
+import com.android.systemui.controls.TooltipManager
import com.android.systemui.controls.controller.ControlsControllerImpl
import com.android.systemui.controls.controller.StructureInfo
import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.qs.PageIndicator
import com.android.systemui.settings.CurrentUserTracker
import java.text.Collator
import java.util.concurrent.Executor
@@ -51,6 +56,8 @@
companion object {
private const val TAG = "ControlsFavoritingActivity"
const val EXTRA_APP = "extra_app_label"
+ private const val TOOLTIP_PREFS_KEY = Prefs.Key.CONTROLS_STRUCTURE_SWIPE_TOOLTIP_COUNT
+ private const val TOOLTIP_MAX_SHOWN = 2
}
private var component: ComponentName? = null
@@ -61,7 +68,9 @@
private lateinit var titleView: TextView
private lateinit var iconView: ImageView
private lateinit var iconFrame: View
- private lateinit var pageIndicator: PageIndicator
+ private lateinit var pageIndicator: ManagementPageIndicator
+ private var mTooltipManager: TooltipManager? = null
+ private lateinit var doneButton: View
private var listOfStructures = emptyList<StructureContainer>()
private lateinit var comparator: Comparator<StructureContainer>
@@ -129,6 +138,7 @@
StructureContainer(it.key, AllModel(it.value, favoriteKeys, emptyZoneString))
}.sortedWith(comparator)
executor.execute {
+ doneButton.isEnabled = true
structurePager.adapter = StructureAdapter(listOfStructures)
if (error) {
statusText.text = resources.getText(R.string.controls_favorite_load_error)
@@ -174,7 +184,47 @@
}
statusText = requireViewById(R.id.status_message)
- pageIndicator = requireViewById(R.id.structure_page_indicator)
+ if (shouldShowTooltip()) {
+ mTooltipManager = TooltipManager(statusText.context,
+ TOOLTIP_PREFS_KEY, TOOLTIP_MAX_SHOWN)
+ addContentView(
+ mTooltipManager?.layout,
+ FrameLayout.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ Gravity.TOP or Gravity.LEFT
+ )
+ )
+ }
+ pageIndicator = requireViewById<ManagementPageIndicator>(
+ R.id.structure_page_indicator).apply {
+ addOnLayoutChangeListener(object : View.OnLayoutChangeListener {
+ override fun onLayoutChange(
+ v: View,
+ left: Int,
+ top: Int,
+ right: Int,
+ bottom: Int,
+ oldLeft: Int,
+ oldTop: Int,
+ oldRight: Int,
+ oldBottom: Int
+ ) {
+ if (v.visibility == View.VISIBLE && mTooltipManager != null) {
+ val p = IntArray(2)
+ v.getLocationOnScreen(p)
+ val x = p[0] + (right - left) / 2
+ val y = p[1] + bottom - top
+ mTooltipManager?.show(R.string.controls_structure_tooltip, x, y)
+ }
+ }
+ })
+ visibilityListener = {
+ if (it != View.VISIBLE) {
+ mTooltipManager?.hide(true)
+ }
+ }
+ }
titleView = requireViewById<TextView>(R.id.title).apply {
text = appName ?: resources.getText(R.string.controls_favorite_default_title)
@@ -184,6 +234,12 @@
iconView = requireViewById(com.android.internal.R.id.icon)
iconFrame = requireViewById(R.id.icon_frame)
structurePager = requireViewById<ViewPager2>(R.id.structure_pager)
+ structurePager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
+ override fun onPageSelected(position: Int) {
+ super.onPageSelected(position)
+ mTooltipManager?.hide(true)
+ }
+ })
bindButtons()
}
@@ -195,23 +251,41 @@
}
}
- requireViewById<Button>(R.id.done).setOnClickListener {
- if (component == null) return@setOnClickListener
- listOfStructures.forEach {
- val favoritesForStorage = it.model.favorites.map { it.build() }
- controller.replaceFavoritesForStructure(StructureInfo(component!!, it.structureName,
- favoritesForStorage))
+ doneButton = requireViewById<Button>(R.id.done).apply {
+ isEnabled = false
+ setOnClickListener {
+ if (component == null) return@setOnClickListener
+ listOfStructures.forEach {
+ val favoritesForStorage = it.model.favorites.map { it.build() }
+ controller.replaceFavoritesForStructure(
+ StructureInfo(component!!, it.structureName, favoritesForStorage)
+ )
+ }
+ finishAffinity()
}
-
- finishAffinity()
}
}
+ override fun onPause() {
+ super.onPause()
+ mTooltipManager?.hide(false)
+ }
+
+ override fun onConfigurationChanged(newConfig: Configuration) {
+ super.onConfigurationChanged(newConfig)
+ mTooltipManager?.hide(false)
+ }
+
override fun onDestroy() {
currentUserTracker.stopTracking()
listingController.removeCallback(listingCallback)
+ controller.cancelLoad()
super.onDestroy()
}
+
+ private fun shouldShowTooltip(): Boolean {
+ return Prefs.getInt(applicationContext, TOOLTIP_PREFS_KEY, 0) < TOOLTIP_MAX_SHOWN
+ }
}
data class StructureContainer(val structureName: CharSequence, val model: ControlsModel)
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ManagementPageIndicator.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ManagementPageIndicator.kt
index 4289274..72b1098 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ManagementPageIndicator.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ManagementPageIndicator.kt
@@ -40,4 +40,13 @@
super.setLocation(location)
}
}
+
+ var visibilityListener: (Int) -> Unit = {}
+
+ override fun onVisibilityChanged(changedView: View, visibility: Int) {
+ super.onVisibilityChanged(changedView, visibility)
+ if (changedView == this) {
+ visibilityListener(visibility)
+ }
+ }
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
index fc5663f..b439206 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt
@@ -17,8 +17,8 @@
package com.android.systemui.controls.ui
import android.content.Context
-import android.graphics.BlendMode
import android.graphics.drawable.ClipDrawable
+import android.graphics.drawable.GradientDrawable
import android.graphics.drawable.LayerDrawable
import android.service.controls.Control
import android.service.controls.actions.ControlAction
@@ -39,6 +39,8 @@
import kotlin.reflect.KClass
private const val UPDATE_DELAY_IN_MILLIS = 3000L
+private const val ALPHA_ENABLED = (255.0 * 0.2).toInt()
+private const val ALPHA_DISABLED = 255
class ControlViewHolder(
val layout: ViewGroup,
@@ -69,7 +71,7 @@
cancelUpdate?.run()
- val (status, template) = cws.control?.let {
+ val (controlStatus, template) = cws.control?.let {
title.setText(it.getTitle())
subtitle.setText(it.getSubtitle())
Pair(it.getStatus(), it.getControlTemplate())
@@ -80,20 +82,28 @@
}
cws.control?.let {
+ layout.setClickable(true)
layout.setOnLongClickListener(View.OnLongClickListener() {
ControlActionCoordinator.longPress(this@ControlViewHolder)
true
})
}
- val clazz = findBehavior(status, template)
+ val clazz = findBehavior(controlStatus, template)
if (behavior == null || behavior!!::class != clazz) {
// Behavior changes can signal a change in template from the app or
// first time setup
behavior = clazz.java.newInstance()
behavior?.initialize(this)
+
+ // let behaviors define their own, if necessary, and clear any existing ones
+ layout.setAccessibilityDelegate(null)
}
+
behavior?.bind(cws)
+
+ layout.setContentDescription(
+ "${title.text} ${subtitle.text} ${status.text} ${statusExtra.text}")
}
fun actionResponse(@ControlAction.ResponseResult response: Int) {
@@ -136,16 +146,21 @@
val ri = RenderInfo.lookup(context, cws.componentName, deviceType, enabled, offset)
val fg = context.getResources().getColorStateList(ri.foreground, context.getTheme())
- val bg = context.getResources().getColorStateList(ri.background, context.getTheme())
+ val (bg, alpha) = if (enabled) {
+ Pair(ri.enabledBackground, ALPHA_ENABLED)
+ } else {
+ Pair(R.color.control_default_background, ALPHA_DISABLED)
+ }
+
status.setTextColor(fg)
statusExtra.setTextColor(fg)
icon.setImageDrawable(ri.icon)
icon.setImageTintList(fg)
- clipLayer.getDrawable().apply {
- setTintBlendMode(BlendMode.HUE)
- setTintList(bg)
+ (clipLayer.getDrawable() as GradientDrawable).apply {
+ setColor(context.getResources().getColor(bg, context.getTheme()))
+ setAlpha(alpha)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
index bde966c..138cd47 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt
@@ -406,7 +406,7 @@
setText(item.getTitle())
}
view.requireViewById<ImageView>(R.id.app_icon).apply {
- setContentDescription(item.getTitle())
+ setContentDescription(item.appName)
setImageDrawable(item.icon)
}
return view
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt
index 56267be..27e4649 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt
@@ -16,6 +16,7 @@
package com.android.systemui.controls.ui
+import android.annotation.ColorRes
import android.annotation.MainThread
import android.content.ComponentName
import android.content.Context
@@ -37,8 +38,11 @@
}
}
-data class RenderInfo(val icon: Drawable, val foreground: Int, val background: Int) {
-
+data class RenderInfo(
+ val icon: Drawable,
+ val foreground: Int,
+ @ColorRes val enabledBackground: Int
+) {
companion object {
const val APP_ICON_ID = -1
private val iconMap = SparseArray<Drawable>()
@@ -72,6 +76,7 @@
icon = iconMap.get(resourceId)
if (icon == null) {
icon = context.resources.getDrawable(resourceId, null)
+ icon.mutate()
iconMap.put(resourceId, icon)
}
}
@@ -94,12 +99,13 @@
private val deviceColorMap = mapOf<Int, Pair<Int, Int>>(
(THERMOSTAT_RANGE + TemperatureControlTemplate.MODE_HEAT) to
- Pair(R.color.thermo_heat_foreground, R.color.thermo_heat_background),
+ Pair(R.color.thermo_heat_foreground, R.color.control_enabled_thermo_heat_background),
(THERMOSTAT_RANGE + TemperatureControlTemplate.MODE_COOL) to
- Pair(R.color.thermo_cool_foreground, R.color.thermo_cool_background),
- DeviceTypes.TYPE_LIGHT to Pair(R.color.light_foreground, R.color.light_background)
+ Pair(R.color.thermo_cool_foreground, R.color.control_enabled_thermo_cool_background),
+ DeviceTypes.TYPE_LIGHT
+ to Pair(R.color.light_foreground, R.color.control_enabled_light_background)
).withDefault {
- Pair(R.color.control_foreground, R.color.control_background)
+ Pair(R.color.control_foreground, R.color.control_enabled_default_background)
}
private val deviceIconMap = mapOf<Int, IconState>(
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
index 6595b55..c495c58 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
@@ -16,6 +16,7 @@
package com.android.systemui.controls.ui
+import android.os.Bundle
import android.content.Context
import android.graphics.drawable.Drawable
import android.graphics.drawable.LayerDrawable
@@ -24,6 +25,9 @@
import android.view.GestureDetector.SimpleOnGestureListener
import android.view.MotionEvent
import android.view.View
+import android.view.ViewGroup
+import android.view.accessibility.AccessibilityEvent
+import android.view.accessibility.AccessibilityNodeInfo
import android.widget.TextView
import android.service.controls.Control
import android.service.controls.actions.FloatAction
@@ -94,6 +98,71 @@
updateRange(currentRatio, checked)
cvh.applyRenderInfo(checked)
+
+ /*
+ * This is custom widget behavior, so add a new accessibility delegate to
+ * handle clicks and range events. Present as a seek bar control.
+ */
+ cvh.layout.setAccessibilityDelegate(object : View.AccessibilityDelegate() {
+ override fun onInitializeAccessibilityNodeInfo(
+ host: View,
+ info: AccessibilityNodeInfo
+ ) {
+ super.onInitializeAccessibilityNodeInfo(host, info)
+
+ val min = levelToRangeValue(MIN_LEVEL)
+ val current = levelToRangeValue(clipLayer.getLevel())
+ val max = levelToRangeValue(MAX_LEVEL)
+
+ val step = rangeTemplate.getStepValue().toDouble()
+ val type = if (step == Math.floor(step)) {
+ AccessibilityNodeInfo.RangeInfo.RANGE_TYPE_INT
+ } else {
+ AccessibilityNodeInfo.RangeInfo.RANGE_TYPE_FLOAT
+ }
+
+ val rangeInfo = AccessibilityNodeInfo.RangeInfo.obtain(type, min, max, current)
+ info.setRangeInfo(rangeInfo)
+ info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SET_PROGRESS)
+ }
+
+ override fun performAccessibilityAction(
+ host: View,
+ action: Int,
+ arguments: Bundle?
+ ): Boolean {
+ val handled = when (action) {
+ AccessibilityNodeInfo.ACTION_CLICK -> {
+ ControlActionCoordinator.toggle(cvh, template.getTemplateId(),
+ template.isChecked())
+ true
+ }
+ AccessibilityNodeInfo.AccessibilityAction.ACTION_SET_PROGRESS.getId() -> {
+ if (arguments == null || !arguments.containsKey(
+ AccessibilityNodeInfo.ACTION_ARGUMENT_PROGRESS_VALUE)) {
+ false
+ } else {
+ val value = arguments.getFloat(
+ AccessibilityNodeInfo.ACTION_ARGUMENT_PROGRESS_VALUE)
+ val ratioDiff = (value - rangeTemplate.getCurrentValue()) /
+ (rangeTemplate.getMaxValue() - rangeTemplate.getMinValue())
+ updateRange(ratioDiff, template.isChecked())
+ endUpdateRange()
+ true
+ }
+ }
+ else -> false
+ }
+
+ return handled || super.performAccessibilityAction(host, action, arguments)
+ }
+
+ override fun onRequestSendAccessibilityEvent(
+ host: ViewGroup,
+ child: View,
+ event: AccessibilityEvent
+ ): Boolean = false
+ })
}
fun beginUpdateRange() {
@@ -108,7 +177,7 @@
clipLayer.setLevel(newLevel)
if (checked) {
- val newValue = levelToRangeValue()
+ val newValue = levelToRangeValue(clipLayer.getLevel())
val formattedNewValue = format(rangeTemplate.getFormatString().toString(),
DEFAULT_FORMAT, newValue)
@@ -133,8 +202,8 @@
}
}
- private fun levelToRangeValue(): Float {
- val ratio = clipLayer.getLevel().toFloat() / MAX_LEVEL
+ private fun levelToRangeValue(i: Int): Float {
+ val ratio = i.toFloat() / MAX_LEVEL
return rangeTemplate.getMinValue() +
(ratio * (rangeTemplate.getMaxValue() - rangeTemplate.getMinValue()))
}
@@ -143,7 +212,8 @@
statusExtra.setTextSize(TypedValue.COMPLEX_UNIT_PX, context.getResources()
.getDimensionPixelSize(R.dimen.control_status_normal).toFloat())
status.setVisibility(View.VISIBLE)
- cvh.action(FloatAction(rangeTemplate.getTemplateId(), findNearestStep(levelToRangeValue())))
+ cvh.action(FloatAction(rangeTemplate.getTemplateId(),
+ findNearestStep(levelToRangeValue(clipLayer.getLevel()))))
}
fun findNearestStep(value: Float): Float {
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
index 6c502d2..3a4b273 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
@@ -90,7 +90,7 @@
/** */
@Provides
- public AmbientDisplayConfiguration provideAmbientDispalyConfiguration(Context context) {
+ public AmbientDisplayConfiguration provideAmbientDisplayConfiguration(Context context) {
return new AmbientDisplayConfiguration(context);
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 513580f..2e9ce12 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -19,7 +19,6 @@
import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.PackageManager;
-import android.view.Choreographer;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.BootCompleteCache;
@@ -31,22 +30,16 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.recents.Recents;
import com.android.systemui.stackdivider.Divider;
-import com.android.systemui.statusbar.BlurUtils;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.NotificationShadeWindowBlurController;
-import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
import com.android.systemui.statusbar.notification.people.PeopleHubModule;
import com.android.systemui.statusbar.notification.row.dagger.ExpandableNotificationRowComponent;
import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent;
-import com.android.systemui.statusbar.phone.BiometricUnlockController;
import com.android.systemui.statusbar.phone.KeyguardLiftController;
-import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
import com.android.systemui.statusbar.policy.HeadsUpManager;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.ConcurrencyModule;
import com.android.systemui.util.sensors.AsyncSensorManager;
import com.android.systemui.util.time.SystemClock;
@@ -98,21 +91,6 @@
keyguardUpdateMonitor, dumpManager);
}
- @Singleton
- @Provides
- @Nullable
- static NotificationShadeWindowBlurController providesBlurController(BlurUtils blurUtils,
- SysuiStatusBarStateController statusBarStateController,
- DumpManager dumpManager, BiometricUnlockController biometricUnlockController,
- KeyguardStateController keyguardStateController,
- NotificationShadeWindowController notificationShadeWindowController,
- Choreographer choreographer) {
- return blurUtils.supportsBlursOnWindows() ? new NotificationShadeWindowBlurController(
- statusBarStateController, blurUtils, biometricUnlockController,
- keyguardStateController, notificationShadeWindowController, choreographer,
- dumpManager) : null;
- }
-
/** */
@Binds
public abstract NotificationRowBinder bindNotificationRowBinder(
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
index c45063a..f6fccc0 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenBrightness.java
@@ -161,15 +161,8 @@
}
int scrimOpacity = -1;
- if (mPaused || mScreenOff) {
- // If AOD is paused, force the screen black until the
- // sensor reports a new brightness. This ensures that when the screen comes on
- // again, it will only show after the brightness sensor has stabilized,
- // avoiding a potential flicker.
- scrimOpacity = 255;
- } else if (!mScreenOff && mLightSensor == null) {
- // No light sensor but previous state turned the screen black. Make the scrim
- // transparent and below views visible.
+ if (mLightSensor == null) {
+ // No light sensor, scrims are always transparent.
scrimOpacity = 0;
} else if (brightnessReady) {
// Only unblank scrim once brightness is ready.
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 786ad2c..59b28b4 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -99,7 +99,7 @@
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.GlobalActions.GlobalActionsManager;
import com.android.systemui.plugins.GlobalActionsPanelPlugin;
-import com.android.systemui.statusbar.BlurUtils;
+import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.policy.ConfigurationController;
@@ -162,7 +162,7 @@
private final IActivityManager mIActivityManager;
private final TelecomManager mTelecomManager;
private final MetricsLogger mMetricsLogger;
- private final BlurUtils mBlurUtils;
+ private final NotificationShadeDepthController mDepthController;
private ArrayList<Action> mItems;
private ActionsDialog mDialog;
@@ -207,7 +207,7 @@
KeyguardStateController keyguardStateController, UserManager userManager,
TrustManager trustManager, IActivityManager iActivityManager,
@Nullable TelecomManager telecomManager, MetricsLogger metricsLogger,
- BlurUtils blurUtils, SysuiColorExtractor colorExtractor,
+ NotificationShadeDepthController depthController, SysuiColorExtractor colorExtractor,
IStatusBarService statusBarService,
NotificationShadeWindowController notificationShadeWindowController,
ControlsUiController controlsUiController, IWindowManager iWindowManager,
@@ -229,7 +229,7 @@
mIActivityManager = iActivityManager;
mTelecomManager = telecomManager;
mMetricsLogger = metricsLogger;
- mBlurUtils = blurUtils;
+ mDepthController = depthController;
mSysuiColorExtractor = colorExtractor;
mStatusBarService = statusBarService;
mNotificationShadeWindowController = notificationShadeWindowController;
@@ -437,7 +437,7 @@
: null;
ActionsDialog dialog = new ActionsDialog(mContext, mAdapter, panelViewController,
- mBlurUtils, mSysuiColorExtractor, mStatusBarService,
+ mDepthController, mSysuiColorExtractor, mStatusBarService,
mNotificationShadeWindowController,
shouldShowControls() ? mControlsUiController : null);
dialog.setCanceledOnTouchOutside(false); // Handled by the custom class.
@@ -1570,20 +1570,21 @@
private ResetOrientationData mResetOrientationData;
private boolean mHadTopUi;
private final NotificationShadeWindowController mNotificationShadeWindowController;
- private final BlurUtils mBlurUtils;
+ private final NotificationShadeDepthController mDepthController;
private ControlsUiController mControlsUiController;
private ViewGroup mControlsView;
ActionsDialog(Context context, MyAdapter adapter,
- GlobalActionsPanelPlugin.PanelViewController plugin, BlurUtils blurUtils,
+ GlobalActionsPanelPlugin.PanelViewController plugin,
+ NotificationShadeDepthController depthController,
SysuiColorExtractor sysuiColorExtractor, IStatusBarService statusBarService,
NotificationShadeWindowController notificationShadeWindowController,
ControlsUiController controlsUiController) {
super(context, com.android.systemui.R.style.Theme_SystemUI_Dialog_GlobalActions);
mContext = context;
mAdapter = adapter;
- mBlurUtils = blurUtils;
+ mDepthController = depthController;
mColorExtractor = sysuiColorExtractor;
mStatusBarService = statusBarService;
mNotificationShadeWindowController = notificationShadeWindowController;
@@ -1792,8 +1793,8 @@
float animatedValue = animation.getAnimatedFraction();
int alpha = (int) (animatedValue * mScrimAlpha * 255);
mBackgroundDrawable.setAlpha(alpha);
- mBlurUtils.applyBlur(mGlobalActionsLayout.getViewRootImpl(),
- mBlurUtils.radiusForRatio(animatedValue));
+ mDepthController.updateGlobalDialogVisibility(animatedValue,
+ mGlobalActionsLayout);
})
.start();
if (mControlsUiController != null) {
@@ -1822,8 +1823,8 @@
float animatedValue = 1f - animation.getAnimatedFraction();
int alpha = (int) (animatedValue * mScrimAlpha * 255);
mBackgroundDrawable.setAlpha(alpha);
- mBlurUtils.applyBlur(mGlobalActionsLayout.getViewRootImpl(),
- mBlurUtils.radiusForRatio(animatedValue));
+ mDepthController.updateGlobalDialogVisibility(animatedValue,
+ mGlobalActionsLayout);
})
.start();
dismissPanel();
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
index 280a248..bbb57bd 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
@@ -151,7 +151,7 @@
if (mBlurUtils.supportsBlursOnWindows()) {
background.setAlpha((int) (ScrimController.BUSY_SCRIM_ALPHA * 255));
mBlurUtils.applyBlur(d.getWindow().getDecorView().getViewRootImpl(),
- mBlurUtils.radiusForRatio(1));
+ mBlurUtils.blurRadiusOfRatio(1));
} else {
background.setAlpha((int) (SHUTDOWN_SCRIM_ALPHA * 255));
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
index ae380b7..c281ece 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
@@ -93,7 +93,7 @@
return mIatm.startActivityAsUser(
mContext.getIApplicationThread() /*caller*/,
mContext.getBasePackageName() /*callingPackage*/,
- mContext.getFeatureId() /*callingFeatureId*/,
+ mContext.getAttributionTag() /*callingAttributionTag*/,
intent /*intent*/,
intent.resolveTypeIfNeeded(mContext.getContentResolver()) /*resolvedType*/,
null /*resultTo*/,
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
index 67802bc..41bace7 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
@@ -37,7 +37,6 @@
private static final float FRACTION_START = 0f;
private static final float FRACTION_END = 1f;
- public static final int DURATION_DEFAULT_MS = 425;
public static final int ANIM_TYPE_BOUNDS = 0;
public static final int ANIM_TYPE_ALPHA = 1;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
index 00b977e..90b6570 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
@@ -18,7 +18,6 @@
import static com.android.systemui.pip.PipAnimationController.ANIM_TYPE_ALPHA;
import static com.android.systemui.pip.PipAnimationController.ANIM_TYPE_BOUNDS;
-import static com.android.systemui.pip.PipAnimationController.DURATION_DEFAULT_MS;
import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_NONE;
import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_SAME;
import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_FULLSCREEN;
@@ -81,6 +80,7 @@
private final Rect mLastReportedBounds = new Rect();
private final int mCornerRadius;
private final Map<IBinder, Rect> mBoundsToRestore = new HashMap<>();
+ private final int mEnterExitAnimationDuration;
// These callbacks are called on the update thread
private final PipAnimationController.PipAnimationCallback mPipAnimationCallback =
@@ -180,6 +180,8 @@
mPipBoundsHandler = boundsHandler;
mPipAnimationController = new PipAnimationController(context);
mCornerRadius = context.getResources().getDimensionPixelSize(R.dimen.pip_corner_radius);
+ mEnterExitAnimationDuration = context.getResources()
+ .getInteger(R.integer.config_pipResizeAnimationDuration);
}
public Handler getUpdateHandler() {
@@ -235,14 +237,14 @@
mBoundsToRestore.put(mToken.asBinder(), currentBounds);
if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) {
scheduleAnimateResizePip(currentBounds, destinationBounds,
- TRANSITION_DIRECTION_TO_PIP, DURATION_DEFAULT_MS, null);
+ TRANSITION_DIRECTION_TO_PIP, mEnterExitAnimationDuration, null);
} else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
mUpdateHandler.post(() -> mPipAnimationController
.getAnimator(mLeash, destinationBounds, 0f, 1f)
.setTransitionDirection(TRANSITION_DIRECTION_TO_PIP)
.setCornerRadius(mCornerRadius)
.setPipAnimationCallback(mPipAnimationCallback)
- .setDuration(DURATION_DEFAULT_MS)
+ .setDuration(mEnterExitAnimationDuration)
.start());
mOneShotAnimationType = ANIM_TYPE_BOUNDS;
} else {
@@ -260,7 +262,7 @@
}
final Rect boundsToRestore = mBoundsToRestore.remove(mToken.asBinder());
scheduleAnimateResizePip(mLastReportedBounds, boundsToRestore,
- TRANSITION_DIRECTION_TO_FULLSCREEN, DURATION_DEFAULT_MS, null);
+ TRANSITION_DIRECTION_TO_FULLSCREEN, mEnterExitAnimationDuration, null);
mInPip = false;
}
@@ -278,7 +280,7 @@
final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(
getAspectRatioOrDefault(newParams), null /* bounds */);
Objects.requireNonNull(destinationBounds, "Missing destination bounds");
- scheduleAnimateResizePip(destinationBounds, DURATION_DEFAULT_MS, null);
+ scheduleAnimateResizePip(destinationBounds, mEnterExitAnimationDuration, null);
}
/**
@@ -415,11 +417,16 @@
}
mLastReportedBounds.set(destinationBounds);
try {
+ // If we are animating to fullscreen, then we need to reset the override bounds on the
+ // task to ensure that the task "matches" the parent's bounds
+ Rect taskBounds = direction == TRANSITION_DIRECTION_TO_FULLSCREEN
+ ? null
+ : destinationBounds;
final WindowContainerTransaction wct = new WindowContainerTransaction();
if (direction == TRANSITION_DIRECTION_TO_PIP) {
- wct.scheduleFinishEnterPip(mToken, destinationBounds);
+ wct.scheduleFinishEnterPip(mToken, taskBounds);
} else {
- wct.setBounds(mToken, destinationBounds);
+ wct.setBounds(mToken, taskBounds);
}
wct.setBoundsChangeTransaction(mToken, tx);
mTaskOrganizerController.applyContainerTransaction(wct, null /* ITaskOrganizer */);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipAppOpsListener.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipAppOpsListener.java
index b09d6e1..7dfd99c 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipAppOpsListener.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipAppOpsListener.java
@@ -44,7 +44,7 @@
try {
// Dismiss the PiP once the user disables the app ops setting for that package
final Pair<ComponentName, Integer> topPipActivityInfo =
- PipUtils.getTopPinnedActivity(mContext, mActivityManager);
+ PipUtils.getTopPipActivity(mContext, mActivityManager);
if (topPipActivityInfo.first != null) {
final ApplicationInfo appInfo = mContext.getPackageManager()
.getApplicationInfoAsUser(packageName, 0, topPipActivityInfo.second);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index eed81bf..2aac188 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -115,7 +115,7 @@
@Override
public void onActivityUnpinned() {
- final Pair<ComponentName, Integer> topPipActivityInfo = PipUtils.getTopPinnedActivity(
+ final Pair<ComponentName, Integer> topPipActivityInfo = PipUtils.getTopPipActivity(
mContext, mActivityManager);
final ComponentName topActivity = topPipActivityInfo.first;
mMenuController.onActivityUnpinned();
@@ -128,7 +128,12 @@
}
@Override
- public void onPinnedActivityRestartAttempt(boolean clearedTask) {
+ public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
+ boolean homeTaskVisible, boolean clearedTask) {
+ if (task.configuration.windowConfiguration.getWindowingMode()
+ != WINDOWING_MODE_PINNED) {
+ return;
+ }
mTouchHandler.getMotionHelper().expandPip(clearedTask /* skipAnimation */);
}
};
@@ -232,6 +237,12 @@
mTouchHandler.getMotionHelper());
displayController.addDisplayChangingController(mRotationController);
+ // Ensure that we have the display info in case we get calls to update the bounds before the
+ // listener calls back
+ final DisplayInfo displayInfo = new DisplayInfo();
+ context.getDisplay().getDisplayInfo(displayInfo);
+ mPipBoundsHandler.onDisplayInfoChanged(displayInfo);
+
try {
ActivityTaskManager.getTaskOrganizerController().registerTaskOrganizer(
mPipTaskOrganizer, WINDOWING_MODE_PINNED);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java
index e57b416..849a62a 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java
@@ -231,7 +231,7 @@
*/
private void resolveActiveMediaController(List<MediaController> controllers) {
if (controllers != null) {
- final ComponentName topActivity = PipUtils.getTopPinnedActivity(mContext,
+ final ComponentName topActivity = PipUtils.getTopPipActivity(mContext,
mActivityManager).first;
if (topActivity != null) {
for (int i = 0; i < controllers.size(); i++) {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
index fc04f79..2b9b171 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
@@ -569,7 +569,7 @@
private void showSettings() {
final Pair<ComponentName, Integer> topPipActivityInfo =
- PipUtils.getTopPinnedActivity(this, ActivityManager.getService());
+ PipUtils.getTopPipActivity(this, ActivityManager.getService());
if (topPipActivityInfo.first != null) {
final UserHandle user = UserHandle.of(topPipActivityInfo.second);
final Intent settingsIntent = new Intent(ACTION_PICTURE_IN_PICTURE_SETTINGS,
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index 90db91a..b5fb1a9 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -31,6 +31,7 @@
import android.os.Handler;
import android.os.RemoteException;
import android.util.Log;
+import android.util.Pair;
import android.util.Size;
import android.view.IPinnedStackController;
import android.view.InputEvent;
@@ -148,8 +149,11 @@
@Override
public void onPipDismiss() {
- MetricsLoggerWrapper.logPictureInPictureDismissByTap(mContext,
- PipUtils.getTopPinnedActivity(mContext, mActivityManager));
+ Pair<ComponentName, Integer> topPipActivity = PipUtils.getTopPipActivity(mContext,
+ mActivityManager);
+ if (topPipActivity.first != null) {
+ MetricsLoggerWrapper.logPictureInPictureDismissByTap(mContext, topPipActivity);
+ }
mMotionHelper.dismissPip();
}
@@ -653,7 +657,7 @@
// Check if the user dragged or flung the PiP offscreen to dismiss it
if (mMotionHelper.shouldDismissPip() || isFlingToBot) {
MetricsLoggerWrapper.logPictureInPictureDismissByDrag(mContext,
- PipUtils.getTopPinnedActivity(mContext, mActivityManager));
+ PipUtils.getTopPipActivity(mContext, mActivityManager));
mMotionHelper.animateDismiss(
vel.x, vel.y,
PipTouchHandler.this::updateDismissFraction /* updateAction */);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipUtils.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipUtils.java
index 1ed1904..4cfec01 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipUtils.java
@@ -36,7 +36,7 @@
* @return the ComponentName and user id of the top non-SystemUI activity in the pinned stack.
* The component name may be null if no such activity exists.
*/
- public static Pair<ComponentName, Integer> getTopPinnedActivity(Context context,
+ public static Pair<ComponentName, Integer> getTopPipActivity(Context context,
IActivityManager activityManager) {
try {
final String sysUiPackageName = context.getPackageName();
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
index a5e9dbc..6206dd5 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -20,8 +20,6 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-import static com.android.systemui.pip.PipAnimationController.DURATION_DEFAULT_MS;
-
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityManager.StackInfo;
import android.app.ActivityTaskManager;
@@ -136,6 +134,7 @@
private String[] mLastPackagesResourceGranted;
private PipNotification mPipNotification;
private ParceledListSlice mCustomActions;
+ private int mResizeAnimationDuration;
// Used to calculate the movement bounds
private final DisplayInfo mTmpDisplayInfo = new DisplayInfo();
@@ -238,6 +237,8 @@
mInitialized = true;
mContext = context;
mPipBoundsHandler = pipBoundsHandler;
+ mResizeAnimationDuration = context.getResources()
+ .getInteger(R.integer.config_pipResizeAnimationDuration);
mPipTaskOrganizer = new PipTaskOrganizer(mContext, mPipBoundsHandler);
mPipTaskOrganizer.registerPipTransitionCallback(this);
mActivityTaskManager = ActivityTaskManager.getService();
@@ -436,7 +437,8 @@
mCurrentPipBounds = mPipBounds;
break;
}
- mPipTaskOrganizer.scheduleAnimateResizePip(mCurrentPipBounds, DURATION_DEFAULT_MS, null);
+ mPipTaskOrganizer.scheduleAnimateResizePip(mCurrentPipBounds, mResizeAnimationDuration,
+ null);
}
/**
@@ -680,7 +682,12 @@
}
@Override
- public void onPinnedActivityRestartAttempt(boolean clearedTask) {
+ public void onActivityRestartAttempt(RunningTaskInfo task, boolean homeTaskVisible,
+ boolean clearedTask) {
+ if (task.configuration.windowConfiguration.getWindowingMode()
+ != WINDOWING_MODE_PINNED) {
+ return;
+ }
if (DEBUG) Log.d(TAG, "onPinnedActivityRestartAttempt()");
// If PIPed activity is launched again by Launcher or intent, make it fullscreen.
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
index 17ac5e5..fab7191 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java
@@ -274,8 +274,8 @@
try {
tile = createTile(tileSpec);
if (tile != null) {
+ tile.setTileSpec(tileSpec);
if (tile.isAvailable()) {
- tile.setTileSpec(tileSpec);
newTiles.put(tileSpec, tile);
mQSLogger.logTileAdded(tileSpec);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
index f3e2f10..5bf44c6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java
@@ -20,6 +20,8 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static com.android.systemui.shared.system.WindowManagerWrapper.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.trust.TrustManager;
@@ -37,6 +39,7 @@
import com.android.systemui.R;
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -63,6 +66,21 @@
private TrustManager mTrustManager;
private OverviewProxyService mOverviewProxyService;
+ private TaskStackChangeListener mListener = new TaskStackChangeListener() {
+ @Override
+ public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
+ boolean homeTaskVisible, boolean clearedTask) {
+ if (task.configuration.windowConfiguration.getWindowingMode()
+ != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
+ return;
+ }
+
+ if (homeTaskVisible) {
+ showRecentApps(false /* triggeredFromAltTab */);
+ }
+ }
+ };
+
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
@Inject
public OverviewProxyRecentsImpl(Optional<Lazy<StatusBar>> statusBarLazy,
@@ -77,6 +95,7 @@
mHandler = new Handler();
mTrustManager = (TrustManager) context.getSystemService(Context.TRUST_SERVICE);
mOverviewProxyService = Dependency.get(OverviewProxyService.class);
+ ActivityManagerWrapper.getInstance().registerTaskStackListener(mListener);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index fb68153..ea5ec05 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -148,6 +148,8 @@
* regardless of what has focus.
*/
private boolean mTargetShown = false;
+ private float mTargetPrimaryDim = 0.f;
+ private float mTargetSecondaryDim = 0.f;
// The following are the current (most recent) states set during animation
/** {@code true} if the secondary split has IME focus. */
@@ -186,8 +188,12 @@
@Override
public void onImeStartPositioning(int displayId, int hiddenTop, int shownTop,
boolean imeShouldShow, SurfaceControl.Transaction t) {
+ if (!inSplitMode()) {
+ return;
+ }
+ final boolean splitIsVisible = !mView.isHidden();
mSecondaryHasFocus = getSecondaryHasFocus(displayId);
- mTargetAdjusted = imeShouldShow && mSecondaryHasFocus
+ mTargetAdjusted = splitIsVisible && imeShouldShow && mSecondaryHasFocus
&& !mSplitLayout.mDisplayLayout.isLandscape();
mHiddenTop = hiddenTop;
mShownTop = shownTop;
@@ -195,6 +201,10 @@
if (mLastAdjustTop < 0) {
mLastAdjustTop = imeShouldShow ? hiddenTop : shownTop;
}
+ mTargetPrimaryDim = (mSecondaryHasFocus && mTargetShown && splitIsVisible)
+ ? ADJUSTED_NONFOCUS_DIM : 0.f;
+ mTargetSecondaryDim = (!mSecondaryHasFocus && mTargetShown && splitIsVisible)
+ ? ADJUSTED_NONFOCUS_DIM : 0.f;
if (mAnimation != null || (mImeWasShown && imeShouldShow
&& mTargetAdjusted != mAdjusted)) {
// We need to animate adjustment independently of the IME position, so
@@ -202,7 +212,11 @@
// different split's editor has gained focus while the IME is still visible.
startAsyncAnimation();
}
- updateImeAdjustState();
+ if (splitIsVisible) {
+ // If split is hidden, we don't want to trigger any relayouts that would cause the
+ // divider to show again.
+ updateImeAdjustState();
+ }
}
private void updateImeAdjustState() {
@@ -245,7 +259,7 @@
@Override
public void onImePositionChanged(int displayId, int imeTop,
SurfaceControl.Transaction t) {
- if (mAnimation != null) {
+ if (mAnimation != null || !inSplitMode()) {
// Not synchronized with IME anymore, so return.
return;
}
@@ -257,7 +271,7 @@
@Override
public void onImeEndPositioning(int displayId, boolean cancelled,
SurfaceControl.Transaction t) {
- if (mAnimation != null) {
+ if (mAnimation != null || !inSplitMode()) {
// Not synchronized with IME anymore, so return.
return;
}
@@ -273,14 +287,10 @@
mSplitLayout.mAdjustedSecondary);
}
final float invProg = 1.f - progress;
- final float targetPrimaryDim =
- (mSecondaryHasFocus && mTargetShown) ? ADJUSTED_NONFOCUS_DIM : 0.f;
- final float targetSecondaryDim =
- (!mSecondaryHasFocus && mTargetShown) ? ADJUSTED_NONFOCUS_DIM : 0.f;
mView.setResizeDimLayer(t, true /* primary */,
- mLastPrimaryDim * invProg + progress * targetPrimaryDim);
+ mLastPrimaryDim * invProg + progress * mTargetPrimaryDim);
mView.setResizeDimLayer(t, false /* primary */,
- mLastSecondaryDim * invProg + progress * targetSecondaryDim);
+ mLastSecondaryDim * invProg + progress * mTargetSecondaryDim);
}
private void onEnd(boolean cancelled, SurfaceControl.Transaction t) {
@@ -289,10 +299,8 @@
mAdjusted = mTargetAdjusted;
mImeWasShown = mTargetShown;
mLastAdjustTop = mAdjusted ? mShownTop : mHiddenTop;
- mLastPrimaryDim =
- (mSecondaryHasFocus && mTargetShown) ? ADJUSTED_NONFOCUS_DIM : 0.f;
- mLastSecondaryDim =
- (!mSecondaryHasFocus && mTargetShown) ? ADJUSTED_NONFOCUS_DIM : 0.f;
+ mLastPrimaryDim = mTargetPrimaryDim;
+ mLastSecondaryDim = mTargetSecondaryDim;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 477cbb7..4114bb9 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -165,6 +165,10 @@
// The view is removed or in the process of been removed from the system.
private boolean mRemoved;
+ // Whether the surface for this view has been hidden regardless of actual visibility. This is
+ // used interact with keyguard.
+ private boolean mSurfaceHidden = false;
+
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
@@ -414,6 +418,10 @@
/** Unlike setVisible, this directly hides the surface without changing view visibility. */
void setHidden(boolean hidden) {
+ if (mSurfaceHidden == hidden) {
+ return;
+ }
+ mSurfaceHidden = hidden;
post(() -> {
final SurfaceControl sc = getWindowSurfaceControl();
if (sc == null) {
@@ -430,6 +438,10 @@
});
}
+ boolean isHidden() {
+ return mSurfaceHidden;
+ }
+
public boolean startDragging(boolean animate, boolean touching) {
cancelFlingAnimation();
if (touching) {
@@ -1071,7 +1083,7 @@
void setResizeDimLayer(Transaction t, boolean primary, float alpha) {
SurfaceControl dim = primary ? mTiles.mPrimaryDim : mTiles.mSecondaryDim;
- if (alpha <= 0.f) {
+ if (alpha <= 0.001f) {
t.hide(dim);
} else {
t.setAlpha(dim, alpha);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt b/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt
index 34c0860..c523b7b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BlurUtils.kt
@@ -50,7 +50,7 @@
/**
* Translates a ratio from 0 to 1 to a blur radius in pixels.
*/
- fun radiusForRatio(ratio: Float): Int {
+ fun blurRadiusOfRatio(ratio: Float): Int {
if (ratio == 0f) {
return 0
}
@@ -58,6 +58,17 @@
}
/**
+ * Translates a blur radius in pixels to a ratio between 0 to 1.
+ */
+ fun ratioOfBlurRadius(blur: Int): Float {
+ if (blur == 0) {
+ return 0f
+ }
+ return MathUtils.map(minBlurRadius.toFloat(), maxBlurRadius.toFloat(),
+ 0f /* maxStart */, 1f /* maxStop */, blur.toFloat())
+ }
+
+ /**
* Applies background blurs to a {@link ViewRootImpl}.
*
* @param viewRootImpl The window root.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowBlurController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
similarity index 79%
rename from packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowBlurController.kt
rename to packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
index 6e905a3..eb8526d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeWindowBlurController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
@@ -19,6 +19,7 @@
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.ValueAnimator
+import android.app.WallpaperManager
import android.view.Choreographer
import android.view.View
import androidx.dynamicanimation.animation.FloatPropertyCompat
@@ -30,7 +31,6 @@
import com.android.systemui.dump.DumpManager
import com.android.systemui.statusbar.phone.BiometricUnlockController
import com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK
-import com.android.systemui.statusbar.phone.NotificationShadeWindowController
import com.android.systemui.statusbar.phone.PanelExpansionListener
import com.android.systemui.statusbar.policy.KeyguardStateController
import java.io.FileDescriptor
@@ -43,13 +43,13 @@
* Controller responsible for statusbar window blur.
*/
@Singleton
-class NotificationShadeWindowBlurController @Inject constructor(
+class NotificationShadeDepthController @Inject constructor(
private val statusBarStateController: SysuiStatusBarStateController,
private val blurUtils: BlurUtils,
private val biometricUnlockController: BiometricUnlockController,
private val keyguardStateController: KeyguardStateController,
- private val notificationShadeWindowController: NotificationShadeWindowController,
private val choreographer: Choreographer,
+ private val wallpaperManager: WallpaperManager,
dumpManager: DumpManager
) : PanelExpansionListener, Dumpable {
companion object {
@@ -58,20 +58,22 @@
}
lateinit var root: View
+ private var blurRoot: View? = null
private var keyguardAnimator: Animator? = null
private var notificationAnimator: Animator? = null
private var updateScheduled: Boolean = false
private var shadeExpansion = 1.0f
private val shadeSpring = SpringAnimation(this, object :
- FloatPropertyCompat<NotificationShadeWindowBlurController>("shadeBlurRadius") {
- override fun setValue(rect: NotificationShadeWindowBlurController?, value: Float) {
+ FloatPropertyCompat<NotificationShadeDepthController>("shadeBlurRadius") {
+ override fun setValue(rect: NotificationShadeDepthController?, value: Float) {
shadeBlurRadius = value.toInt()
}
- override fun getValue(rect: NotificationShadeWindowBlurController?): Float {
+ override fun getValue(rect: NotificationShadeDepthController?): Float {
return shadeBlurRadius.toFloat()
}
})
+ private val zoomInterpolator = Interpolators.ACCELERATE_DECELERATE
private var shadeBlurRadius = 0
set(value) {
if (field == value) return
@@ -84,12 +86,7 @@
field = value
scheduleUpdate()
}
- private var incomingNotificationBlurRadius = 0
- set(value) {
- if (field == value) return
- field = value
- scheduleUpdate()
- }
+ private var globalDialogVisibility = 0f
/**
* Callback that updates the window blur value and is called only once per frame.
@@ -97,13 +94,12 @@
private val updateBlurCallback = Choreographer.FrameCallback {
updateScheduled = false
- var notificationBlur = 0
- if (statusBarStateController.state == StatusBarState.KEYGUARD) {
- notificationBlur = (incomingNotificationBlurRadius * shadeExpansion).toInt()
- }
-
- val blur = max(max(shadeBlurRadius, wakeAndUnlockBlurRadius), notificationBlur)
- blurUtils.applyBlur(root.viewRootImpl, blur)
+ val blur = max(shadeBlurRadius,
+ max(wakeAndUnlockBlurRadius, blurUtils.blurRadiusOfRatio(globalDialogVisibility)))
+ blurUtils.applyBlur(blurRoot?.viewRootImpl ?: root.viewRootImpl, blur)
+ val rawZoom = max(blurUtils.ratioOfBlurRadius(blur), globalDialogVisibility)
+ wallpaperManager.setWallpaperZoomOut(root.windowToken,
+ zoomInterpolator.getInterpolation(rawZoom))
}
/**
@@ -123,7 +119,7 @@
interpolator = Interpolators.DECELERATE_QUINT
addUpdateListener { animation: ValueAnimator ->
wakeAndUnlockBlurRadius =
- blurUtils.radiusForRatio(animation.animatedValue as Float)
+ blurUtils.blurRadiusOfRatio(animation.animatedValue as Float)
}
addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator?) {
@@ -163,7 +159,7 @@
var newBlur = 0
if (statusBarStateController.state == StatusBarState.SHADE) {
- newBlur = blurUtils.radiusForRatio(expansion)
+ newBlur = blurUtils.blurRadiusOfRatio(expansion)
}
if (shadeBlurRadius == newBlur) {
@@ -172,20 +168,29 @@
shadeSpring.animateToFinalPosition(newBlur.toFloat())
}
- private fun scheduleUpdate() {
+ private fun scheduleUpdate(viewToBlur: View? = null) {
if (updateScheduled) {
return
}
updateScheduled = true
+ blurRoot = viewToBlur
choreographer.postFrameCallback(updateBlurCallback)
}
+ fun updateGlobalDialogVisibility(visibility: Float, dialogView: View) {
+ if (visibility == globalDialogVisibility) {
+ return
+ }
+ globalDialogVisibility = visibility
+ scheduleUpdate(dialogView)
+ }
+
override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
- IndentingPrintWriter(pw, " ").use {
+ IndentingPrintWriter(pw, " ").let {
it.println("StatusBarWindowBlurController:")
it.increaseIndent()
it.println("shadeBlurRadius: $shadeBlurRadius")
it.println("wakeAndUnlockBlur: $wakeAndUnlockBlurRadius")
}
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
index 8a23e37..2747696 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.notification
import android.animation.ObjectAnimator
-import android.content.Context
import android.util.FloatProperty
import com.android.systemui.Interpolators
import com.android.systemui.plugins.statusbar.StatusBarStateController
@@ -26,10 +25,10 @@
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
import com.android.systemui.statusbar.notification.stack.StackStateAnimator
import com.android.systemui.statusbar.phone.DozeParameters
-import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
import com.android.systemui.statusbar.phone.KeyguardBypassController
import com.android.systemui.statusbar.phone.NotificationIconAreaController
import com.android.systemui.statusbar.phone.PanelExpansionListener
+import com.android.systemui.statusbar.policy.HeadsUpManager
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener
import javax.inject.Inject
@@ -37,15 +36,14 @@
@Singleton
class NotificationWakeUpCoordinator @Inject constructor(
- private val mHeadsUpManagerPhone: HeadsUpManagerPhone,
- private val statusBarStateController: StatusBarStateController,
- private val bypassController: KeyguardBypassController,
- private val dozeParameters: DozeParameters)
- : OnHeadsUpChangedListener, StatusBarStateController.StateListener,
- PanelExpansionListener {
+ private val mHeadsUpManager: HeadsUpManager,
+ private val statusBarStateController: StatusBarStateController,
+ private val bypassController: KeyguardBypassController,
+ private val dozeParameters: DozeParameters
+) : OnHeadsUpChangedListener, StatusBarStateController.StateListener, PanelExpansionListener {
- private val mNotificationVisibility
- = object : FloatProperty<NotificationWakeUpCoordinator>("notificationVisibility") {
+ private val mNotificationVisibility = object : FloatProperty<NotificationWakeUpCoordinator>(
+ "notificationVisibility") {
override fun setValue(coordinator: NotificationWakeUpCoordinator, value: Float) {
coordinator.setVisibilityAmount(value)
@@ -78,10 +76,10 @@
field = value
willWakeUp = false
if (value) {
- if (mNotificationsVisible && !mNotificationsVisibleForExpansion
- && !bypassController.bypassEnabled) {
+ if (mNotificationsVisible && !mNotificationsVisibleForExpansion &&
+ !bypassController.bypassEnabled) {
// We're waking up while pulsing, let's make sure the animation looks nice
- mStackScroller.wakeUpFromPulse();
+ mStackScroller.wakeUpFromPulse()
}
if (bypassController.bypassEnabled && !mNotificationsVisible) {
// Let's make sure our huns become visible once we are waking up in case
@@ -100,7 +98,7 @@
}
private var collapsedEnoughToHide: Boolean = false
- lateinit var iconAreaController : NotificationIconAreaController
+ lateinit var iconAreaController: NotificationIconAreaController
var pulsing: Boolean = false
set(value) {
@@ -132,8 +130,8 @@
var canShow = pulsing
if (bypassController.bypassEnabled) {
// We also allow pulsing on the lock screen!
- canShow = canShow || (wakingUp || willWakeUp || fullyAwake)
- && statusBarStateController.state == StatusBarState.KEYGUARD
+ canShow = canShow || (wakingUp || willWakeUp || fullyAwake) &&
+ statusBarStateController.state == StatusBarState.KEYGUARD
// We want to hide the notifications when collapsed too much
if (collapsedEnoughToHide) {
canShow = false
@@ -143,7 +141,7 @@
}
init {
- mHeadsUpManagerPhone.addListener(this)
+ mHeadsUpManager.addListener(this)
statusBarStateController.addCallback(this)
addListener(object : WakeUpListener {
override fun onFullyHiddenChanged(isFullyHidden: Boolean) {
@@ -155,7 +153,7 @@
increaseSpeed = false)
}
}
- });
+ })
}
fun setStackScroller(stackScroller: NotificationStackScrollLayout) {
@@ -178,46 +176,55 @@
* @param animate should this change be animated
* @param increaseSpeed should the speed be increased of the animation
*/
- fun setNotificationsVisibleForExpansion(visible: Boolean, animate: Boolean,
- increaseSpeed: Boolean) {
+ fun setNotificationsVisibleForExpansion(
+ visible: Boolean,
+ animate: Boolean,
+ increaseSpeed: Boolean
+ ) {
mNotificationsVisibleForExpansion = visible
updateNotificationVisibility(animate, increaseSpeed)
if (!visible && mNotificationsVisible) {
// If we stopped expanding and we're still visible because we had a pulse that hasn't
// times out, let's release them all to make sure were not stuck in a state where
// notifications are visible
- mHeadsUpManagerPhone.releaseAllImmediately()
+ mHeadsUpManager.releaseAllImmediately()
}
}
fun addListener(listener: WakeUpListener) {
- wakeUpListeners.add(listener);
+ wakeUpListeners.add(listener)
}
fun removeListener(listener: WakeUpListener) {
- wakeUpListeners.remove(listener);
+ wakeUpListeners.remove(listener)
}
- private fun updateNotificationVisibility(animate: Boolean, increaseSpeed: Boolean) {
+ private fun updateNotificationVisibility(
+ animate: Boolean,
+ increaseSpeed: Boolean
+ ) {
// TODO: handle Lockscreen wakeup for bypass when we're not pulsing anymore
- var visible = mNotificationsVisibleForExpansion || mHeadsUpManagerPhone.hasNotifications()
+ var visible = mNotificationsVisibleForExpansion || mHeadsUpManager.hasNotifications()
visible = visible && canShowPulsingHuns
if (!visible && mNotificationsVisible && (wakingUp || willWakeUp) && mDozeAmount != 0.0f) {
// let's not make notifications invisible while waking up, otherwise the animation
// is strange
- return;
+ return
}
setNotificationsVisible(visible, animate, increaseSpeed)
}
- private fun setNotificationsVisible(visible: Boolean, animate: Boolean,
- increaseSpeed: Boolean) {
+ private fun setNotificationsVisible(
+ visible: Boolean,
+ animate: Boolean,
+ increaseSpeed: Boolean
+ ) {
if (mNotificationsVisible == visible) {
return
}
mNotificationsVisible = visible
- mVisibilityAnimator?.cancel();
+ mVisibilityAnimator?.cancel()
if (animate) {
notifyAnimationStart(visible)
startVisibilityAnimation(increaseSpeed)
@@ -230,8 +237,8 @@
if (updateDozeAmountIfBypass()) {
return
}
- if (linear != 1.0f && linear != 0.0f
- && (mLinearDozeAmount == 0.0f || mLinearDozeAmount == 1.0f)) {
+ if (linear != 1.0f && linear != 0.0f &&
+ (mLinearDozeAmount == 0.0f || mLinearDozeAmount == 1.0f)) {
// Let's notify the scroller that an animation started
notifyAnimationStart(mLinearDozeAmount == 1.0f)
}
@@ -245,17 +252,17 @@
mStackScroller.setDozeAmount(mDozeAmount)
updateHideAmount()
if (changed && linear == 0.0f) {
- setNotificationsVisible(visible = false, animate = false, increaseSpeed = false);
+ setNotificationsVisible(visible = false, animate = false, increaseSpeed = false)
setNotificationsVisibleForExpansion(visible = false, animate = false,
increaseSpeed = false)
}
}
override fun onStateChanged(newState: Int) {
- updateDozeAmountIfBypass();
+ updateDozeAmountIfBypass()
if (bypassController.bypassEnabled &&
- newState == StatusBarState.KEYGUARD && state == StatusBarState.SHADE_LOCKED
- && (!statusBarStateController.isDozing || shouldAnimateVisibility())) {
+ newState == StatusBarState.KEYGUARD && state == StatusBarState.SHADE_LOCKED &&
+ (!statusBarStateController.isDozing || shouldAnimateVisibility())) {
// We're leaving shade locked. Let's animate the notifications away
setNotificationsVisible(visible = true, increaseSpeed = false, animate = false)
setNotificationsVisible(visible = false, increaseSpeed = false, animate = true)
@@ -266,23 +273,23 @@
override fun onPanelExpansionChanged(expansion: Float, tracking: Boolean) {
val collapsedEnough = expansion <= 0.9f
if (collapsedEnough != this.collapsedEnoughToHide) {
- val couldShowPulsingHuns = canShowPulsingHuns;
+ val couldShowPulsingHuns = canShowPulsingHuns
this.collapsedEnoughToHide = collapsedEnough
if (couldShowPulsingHuns && !canShowPulsingHuns) {
updateNotificationVisibility(animate = true, increaseSpeed = true)
- mHeadsUpManagerPhone.releaseAllImmediately()
+ mHeadsUpManager.releaseAllImmediately()
}
}
}
private fun updateDozeAmountIfBypass(): Boolean {
if (bypassController.bypassEnabled) {
- var amount = 1.0f;
- if (statusBarStateController.state == StatusBarState.SHADE
- || statusBarStateController.state == StatusBarState.SHADE_LOCKED) {
- amount = 0.0f;
+ var amount = 1.0f
+ if (statusBarStateController.state == StatusBarState.SHADE ||
+ statusBarStateController.state == StatusBarState.SHADE_LOCKED) {
+ amount = 0.0f
}
- setDozeAmount(amount, amount)
+ setDozeAmount(amount, amount)
return true
}
return false
@@ -300,7 +307,7 @@
visibilityAnimator.setInterpolator(Interpolators.LINEAR)
var duration = StackStateAnimator.ANIMATION_DURATION_WAKEUP.toLong()
if (increaseSpeed) {
- duration = (duration.toFloat() / 1.5F).toLong();
+ duration = (duration.toFloat() / 1.5F).toLong()
}
visibilityAnimator.setDuration(duration)
visibilityAnimator.start()
@@ -311,7 +318,7 @@
mLinearVisibilityAmount = visibilityAmount
mVisibilityAmount = mVisibilityInterpolator.getInterpolation(
visibilityAmount)
- handleAnimationFinished();
+ handleAnimationFinished()
updateHideAmount()
}
@@ -322,7 +329,7 @@
}
}
- fun getWakeUpHeight() : Float {
+ fun getWakeUpHeight(): Float {
return mStackScroller.wakeUpHeight
}
@@ -330,7 +337,7 @@
val linearAmount = Math.min(1.0f - mLinearVisibilityAmount, mLinearDozeAmount)
val amount = Math.min(1.0f - mVisibilityAmount, mDozeAmount)
mStackScroller.setHideAmount(linearAmount, amount)
- notificationsFullyHidden = linearAmount == 1.0f;
+ notificationsFullyHidden = linearAmount == 1.0f
}
private fun notifyAnimationStart(awake: Boolean) {
@@ -361,7 +368,7 @@
// if we animate, we see the shelf briefly visible. Instead we fully animate
// the notification and its background out
animate = false
- } else if (!wakingUp && !willWakeUp){
+ } else if (!wakingUp && !willWakeUp) {
// TODO: look that this is done properly and not by anyone else
entry.setHeadsUpAnimatingAway(true)
mEntrySetToClearWhenFinished.add(entry)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
index e8a62e4..4beeede 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
@@ -37,8 +37,8 @@
import com.android.systemui.statusbar.NotificationUiAdjustment;
import com.android.systemui.statusbar.notification.InflationException;
import com.android.systemui.statusbar.notification.NotificationClicker;
-import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowController;
import com.android.systemui.statusbar.notification.row.NotifBindPipeline;
@@ -66,7 +66,7 @@
private static final String TAG = "NotificationViewManager";
- private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
+ private final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
private final Context mContext;
private final NotifBindPipeline mNotifBindPipeline;
@@ -97,7 +97,7 @@
StatusBarStateController statusBarStateController,
NotificationGroupManager notificationGroupManager,
NotificationGutsManager notificationGutsManager,
- NotificationInterruptionStateProvider notificationInterruptionStateProvider,
+ NotificationInterruptStateProvider notificationInterruptionStateProvider,
Provider<RowInflaterTask> rowInflaterTaskProvider,
ExpandableNotificationRowComponent.Builder expandableNotificationRowComponentBuilder) {
mContext = context;
@@ -106,7 +106,7 @@
mMessagingUtil = notificationMessagingUtil;
mNotificationRemoteInputManager = notificationRemoteInputManager;
mNotificationLockscreenUserManager = notificationLockscreenUserManager;
- mNotificationInterruptionStateProvider = notificationInterruptionStateProvider;
+ mNotificationInterruptStateProvider = notificationInterruptionStateProvider;
mRowInflaterTaskProvider = rowInflaterTaskProvider;
mExpandableNotificationRowComponentBuilder = expandableNotificationRowComponentBuilder;
}
@@ -243,7 +243,7 @@
params.setUseIncreasedHeadsUpHeight(useIncreasedHeadsUp);
params.setUseLowPriority(entry.isAmbient());
- if (mNotificationInterruptionStateProvider.shouldHeadsUp(entry)) {
+ if (mNotificationInterruptStateProvider.shouldHeadsUp(entry)) {
params.requireContentViews(FLAG_CONTENT_VIEW_HEADS_UP);
}
//TODO: Replace this API with RowContentBindParams directly
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index e425ee9..1d8e979 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -31,10 +31,8 @@
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.notification.ForegroundServiceDismissalFeatureController;
-import com.android.systemui.statusbar.notification.NotificationAlertingManager;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationEntryManagerLogger;
-import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
@@ -44,6 +42,9 @@
import com.android.systemui.statusbar.notification.init.NotificationsController;
import com.android.systemui.statusbar.notification.init.NotificationsControllerImpl;
import com.android.systemui.statusbar.notification.init.NotificationsControllerStub;
+import com.android.systemui.statusbar.notification.interruption.NotificationAlertingManager;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.logging.NotificationPanelLogger;
import com.android.systemui.statusbar.notification.logging.NotificationPanelLoggerImpl;
@@ -58,6 +59,7 @@
import javax.inject.Singleton;
+import dagger.Binds;
import dagger.Lazy;
import dagger.Module;
import dagger.Provides;
@@ -127,7 +129,7 @@
NotificationRemoteInputManager remoteInputManager,
VisualStabilityManager visualStabilityManager,
StatusBarStateController statusBarStateController,
- NotificationInterruptionStateProvider notificationInterruptionStateProvider,
+ NotificationInterruptStateProvider notificationInterruptStateProvider,
NotificationListener notificationListener,
HeadsUpManager headsUpManager) {
return new NotificationAlertingManager(
@@ -135,7 +137,7 @@
remoteInputManager,
visualStabilityManager,
statusBarStateController,
- notificationInterruptionStateProvider,
+ notificationInterruptStateProvider,
notificationListener,
headsUpManager);
}
@@ -210,4 +212,9 @@
NotificationEntryManager entryManager) {
return featureFlags.isNewNotifPipelineRenderingEnabled() ? pipeline.get() : entryManager;
}
+
+ /** */
+ @Binds
+ NotificationInterruptStateProvider bindNotificationInterruptStateProvider(
+ NotificationInterruptStateProviderImpl notificationInterruptStateProviderImpl);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/BypassHeadsUpNotifier.kt
similarity index 96%
rename from packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/BypassHeadsUpNotifier.kt
index 269a7a5..88888d1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/BypassHeadsUpNotifier.kt
@@ -14,7 +14,7 @@
* limitations under the License
*/
-package com.android.systemui.statusbar.notification
+package com.android.systemui.statusbar.notification.interruption
import android.content.Context
import android.media.MediaMetadata
@@ -24,6 +24,7 @@
import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.NotificationMediaManager
import com.android.systemui.statusbar.StatusBarState
+import com.android.systemui.statusbar.notification.NotificationEntryManager
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
import com.android.systemui.statusbar.phone.KeyguardBypassController
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationAlertingManager.java
similarity index 90%
rename from packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationAlertingManager.java
index df21f0b..b572502 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationAlertingManager.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.notification;
+package com.android.systemui.statusbar.notification.interruption;
import static com.android.systemui.statusbar.NotificationRemoteInputManager.FORCE_REMOTE_INPUT_HISTORY;
import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP;
@@ -27,6 +27,9 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
+import com.android.systemui.statusbar.notification.NotificationEntryListener;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.dagger.NotificationsModule;
import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -39,7 +42,7 @@
private final NotificationRemoteInputManager mRemoteInputManager;
private final VisualStabilityManager mVisualStabilityManager;
private final StatusBarStateController mStatusBarStateController;
- private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
+ private final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
private final NotificationListener mNotificationListener;
private HeadsUpManager mHeadsUpManager;
@@ -52,13 +55,13 @@
NotificationRemoteInputManager remoteInputManager,
VisualStabilityManager visualStabilityManager,
StatusBarStateController statusBarStateController,
- NotificationInterruptionStateProvider notificationInterruptionStateProvider,
+ NotificationInterruptStateProvider notificationInterruptionStateProvider,
NotificationListener notificationListener,
HeadsUpManager headsUpManager) {
mRemoteInputManager = remoteInputManager;
mVisualStabilityManager = visualStabilityManager;
mStatusBarStateController = statusBarStateController;
- mNotificationInterruptionStateProvider = notificationInterruptionStateProvider;
+ mNotificationInterruptStateProvider = notificationInterruptionStateProvider;
mNotificationListener = notificationListener;
mHeadsUpManager = headsUpManager;
@@ -94,7 +97,7 @@
if (entry.getRow().getPrivateLayout().getHeadsUpChild() != null) {
// Possible for shouldHeadsUp to change between the inflation starting and ending.
// If it does and we no longer need to heads up, we should free the view.
- if (mNotificationInterruptionStateProvider.shouldHeadsUp(entry)) {
+ if (mNotificationInterruptStateProvider.shouldHeadsUp(entry)) {
mHeadsUpManager.showNotification(entry);
if (!mStatusBarStateController.isDozing()) {
// Mark as seen immediately
@@ -109,7 +112,7 @@
private void updateAlertState(NotificationEntry entry) {
boolean alertAgain = alertAgain(entry, entry.getSbn().getNotification());
// includes check for whether this notification should be filtered:
- boolean shouldAlert = mNotificationInterruptionStateProvider.shouldHeadsUp(entry);
+ boolean shouldAlert = mNotificationInterruptStateProvider.shouldHeadsUp(entry);
final boolean wasAlerting = mHeadsUpManager.isAlerting(entry.getKey());
if (wasAlerting) {
if (shouldAlert) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java
new file mode 100644
index 0000000..3292a8f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java
@@ -0,0 +1,59 @@
+/*
+ * 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.interruption;
+
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+
+/**
+ * Provides bubble-up and heads-up state for notification entries.
+ *
+ * When a notification is heads-up when dozing, this is also called "pulsing."
+ */
+public interface NotificationInterruptStateProvider {
+ /**
+ * If the device is awake (not dozing):
+ * Whether the notification should peek in from the top and alert the user.
+ *
+ * If the device is dozing:
+ * Whether the notification should show the ambient view of the notification ("pulse").
+ *
+ * @param entry the entry to check
+ * @return true if the entry should heads up, false otherwise
+ */
+ boolean shouldHeadsUp(NotificationEntry entry);
+
+ /**
+ * Whether the notification should appear as a bubble with a fly-out on top of the screen.
+ *
+ * @param entry the entry to check
+ * @return true if the entry should bubble up, false otherwise
+ */
+ boolean shouldBubbleUp(NotificationEntry entry);
+
+ /**
+ * Whether to launch the entry's full screen intent when the entry is added.
+ *
+ * @param entry the entry that was added
+ * @return {@code true} if we should launch the full screen intent
+ */
+ boolean shouldLaunchFullScreenIntentWhenAdded(NotificationEntry entry);
+
+ /**
+ * Add a component that can suppress visual interruptions.
+ */
+ void addSuppressor(NotificationInterruptSuppressor suppressor);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
similarity index 63%
rename from packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
index bbf2dde..46d5044 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
@@ -14,33 +14,35 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.notification;
+package com.android.systemui.statusbar.notification.interruption;
import static com.android.systemui.statusbar.StatusBarState.SHADE;
import android.app.NotificationManager;
-import android.content.Context;
+import android.content.ContentResolver;
import android.database.ContentObserver;
import android.hardware.display.AmbientDisplayConfiguration;
+import android.os.Handler;
import android.os.PowerManager;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.UserHandle;
import android.provider.Settings;
-import android.service.dreams.DreamService;
import android.service.dreams.IDreamManager;
import android.service.notification.StatusBarNotification;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.Dependency;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.notification.NotificationFilter;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
+import java.util.ArrayList;
+import java.util.List;
+
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -48,120 +50,84 @@
* Provides heads-up and pulsing state for notification entries.
*/
@Singleton
-public class NotificationInterruptionStateProvider {
-
+public class NotificationInterruptStateProviderImpl implements NotificationInterruptStateProvider {
private static final String TAG = "InterruptionStateProvider";
- private static final boolean DEBUG = false;
+ private static final boolean DEBUG = true; //false;
private static final boolean DEBUG_HEADS_UP = true;
private static final boolean ENABLE_HEADS_UP = true;
private static final String SETTING_HEADS_UP_TICKER = "ticker_gets_heads_up";
+ private final List<NotificationInterruptSuppressor> mSuppressors = new ArrayList<>();
private final StatusBarStateController mStatusBarStateController;
private final NotificationFilter mNotificationFilter;
- private final AmbientDisplayConfiguration mAmbientDisplayConfiguration;
-
- private final Context mContext;
+ private final ContentResolver mContentResolver;
private final PowerManager mPowerManager;
private final IDreamManager mDreamManager;
+ private final AmbientDisplayConfiguration mAmbientDisplayConfiguration;
private final BatteryController mBatteryController;
-
- private NotificationPresenter mPresenter;
+ private final ContentObserver mHeadsUpObserver;
private HeadsUpManager mHeadsUpManager;
- private HeadsUpSuppressor mHeadsUpSuppressor;
- private ContentObserver mHeadsUpObserver;
@VisibleForTesting
protected boolean mUseHeadsUp = false;
- private boolean mDisableNotificationAlerts;
@Inject
- public NotificationInterruptionStateProvider(Context context, NotificationFilter filter,
- StatusBarStateController stateController, BatteryController batteryController) {
- this(context,
- (PowerManager) context.getSystemService(Context.POWER_SERVICE),
- IDreamManager.Stub.asInterface(
- ServiceManager.checkService(DreamService.DREAM_SERVICE)),
- new AmbientDisplayConfiguration(context),
- filter,
- batteryController,
- stateController);
- }
-
- @VisibleForTesting
- protected NotificationInterruptionStateProvider(
- Context context,
+ public NotificationInterruptStateProviderImpl(
+ ContentResolver contentResolver,
PowerManager powerManager,
IDreamManager dreamManager,
AmbientDisplayConfiguration ambientDisplayConfiguration,
NotificationFilter notificationFilter,
BatteryController batteryController,
- StatusBarStateController statusBarStateController) {
- mContext = context;
+ StatusBarStateController statusBarStateController,
+ HeadsUpManager headsUpManager,
+ @Main Handler mainHandler) {
+ mContentResolver = contentResolver;
mPowerManager = powerManager;
mDreamManager = dreamManager;
mBatteryController = batteryController;
mAmbientDisplayConfiguration = ambientDisplayConfiguration;
mNotificationFilter = notificationFilter;
mStatusBarStateController = statusBarStateController;
- }
-
- /** Sets up late-binding dependencies for this component. */
- public void setUpWithPresenter(
- NotificationPresenter notificationPresenter,
- HeadsUpManager headsUpManager,
- HeadsUpSuppressor headsUpSuppressor) {
- setUpWithPresenter(notificationPresenter, headsUpManager, headsUpSuppressor,
- new ContentObserver(Dependency.get(Dependency.MAIN_HANDLER)) {
- @Override
- public void onChange(boolean selfChange) {
- boolean wasUsing = mUseHeadsUp;
- mUseHeadsUp = ENABLE_HEADS_UP && !mDisableNotificationAlerts
- && Settings.Global.HEADS_UP_OFF != Settings.Global.getInt(
- mContext.getContentResolver(),
- Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED,
- Settings.Global.HEADS_UP_OFF);
- Log.d(TAG, "heads up is " + (mUseHeadsUp ? "enabled" : "disabled"));
- if (wasUsing != mUseHeadsUp) {
- if (!mUseHeadsUp) {
- Log.d(TAG,
- "dismissing any existing heads up notification on disable"
- + " event");
- mHeadsUpManager.releaseAllImmediately();
- }
- }
- }
- });
- }
-
- /** Sets up late-binding dependencies for this component. */
- public void setUpWithPresenter(
- NotificationPresenter notificationPresenter,
- HeadsUpManager headsUpManager,
- HeadsUpSuppressor headsUpSuppressor,
- ContentObserver observer) {
- mPresenter = notificationPresenter;
mHeadsUpManager = headsUpManager;
- mHeadsUpSuppressor = headsUpSuppressor;
- mHeadsUpObserver = observer;
+ mHeadsUpObserver = new ContentObserver(mainHandler) {
+ @Override
+ public void onChange(boolean selfChange) {
+ boolean wasUsing = mUseHeadsUp;
+ mUseHeadsUp = ENABLE_HEADS_UP
+ && Settings.Global.HEADS_UP_OFF != Settings.Global.getInt(
+ mContentResolver,
+ Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED,
+ Settings.Global.HEADS_UP_OFF);
+ Log.d(TAG, "heads up is " + (mUseHeadsUp ? "enabled" : "disabled"));
+ if (wasUsing != mUseHeadsUp) {
+ if (!mUseHeadsUp) {
+ Log.d(TAG, "dismissing any existing heads up notification on "
+ + "disable event");
+ mHeadsUpManager.releaseAllImmediately();
+ }
+ }
+ }
+ };
if (ENABLE_HEADS_UP) {
- mContext.getContentResolver().registerContentObserver(
+ mContentResolver.registerContentObserver(
Settings.Global.getUriFor(Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED),
true,
mHeadsUpObserver);
- mContext.getContentResolver().registerContentObserver(
+ mContentResolver.registerContentObserver(
Settings.Global.getUriFor(SETTING_HEADS_UP_TICKER), true,
mHeadsUpObserver);
}
mHeadsUpObserver.onChange(true); // set up
}
- /**
- * Whether the notification should appear as a bubble with a fly-out on top of the screen.
- *
- * @param entry the entry to check
- * @return true if the entry should bubble up, false otherwise
- */
+ @Override
+ public void addSuppressor(NotificationInterruptSuppressor suppressor) {
+ mSuppressors.add(suppressor);
+ }
+
+ @Override
public boolean shouldBubbleUp(NotificationEntry entry) {
final StatusBarNotification sbn = entry.getSbn();
@@ -201,12 +167,8 @@
return true;
}
- /**
- * Whether the notification should peek in from the top and alert the user.
- *
- * @param entry the entry to check
- * @return true if the entry should heads up, false otherwise
- */
+
+ @Override
public boolean shouldHeadsUp(NotificationEntry entry) {
if (mStatusBarStateController.isDozing()) {
return shouldHeadsUpWhenDozing(entry);
@@ -215,6 +177,17 @@
}
}
+ /**
+ * When an entry was added, should we launch its fullscreen intent? Examples are Alarms or
+ * incoming calls.
+ */
+ @Override
+ public boolean shouldLaunchFullScreenIntentWhenAdded(NotificationEntry entry) {
+ return entry.getSbn().getNotification().fullScreenIntent != null
+ && (!shouldHeadsUp(entry)
+ || mStatusBarStateController.getState() == StatusBarState.KEYGUARD);
+ }
+
private boolean shouldHeadsUpWhenAwake(NotificationEntry entry) {
StatusBarNotification sbn = entry.getSbn();
@@ -271,13 +244,15 @@
return false;
}
- if (!mHeadsUpSuppressor.canHeadsUp(entry, sbn)) {
- if (DEBUG_HEADS_UP) {
- Log.d(TAG, "No heads up: aborted by suppressor: " + sbn.getKey());
+ for (int i = 0; i < mSuppressors.size(); i++) {
+ if (mSuppressors.get(i).suppressAwakeHeadsUp(entry)) {
+ if (DEBUG_HEADS_UP) {
+ Log.d(TAG, "No heads up: aborted by suppressor: "
+ + mSuppressors.get(i).getName() + " sbnKey=" + sbn.getKey());
+ }
+ return false;
}
- return false;
}
-
return true;
}
@@ -325,7 +300,7 @@
}
return false;
}
- return true;
+ return true;
}
/**
@@ -334,8 +309,7 @@
* @param entry the entry to check
* @return true if these checks pass, false if the notification should not alert
*/
- @VisibleForTesting
- public boolean canAlertCommon(NotificationEntry entry) {
+ private boolean canAlertCommon(NotificationEntry entry) {
StatusBarNotification sbn = entry.getSbn();
if (mNotificationFilter.shouldFilterOut(entry)) {
@@ -352,6 +326,16 @@
}
return false;
}
+
+ for (int i = 0; i < mSuppressors.size(); i++) {
+ if (mSuppressors.get(i).suppressInterruptions(entry)) {
+ if (DEBUG_HEADS_UP) {
+ Log.d(TAG, "No alerting: aborted by suppressor: "
+ + mSuppressors.get(i).getName() + " sbnKey=" + sbn.getKey());
+ }
+ return false;
+ }
+ }
return true;
}
@@ -361,15 +345,17 @@
* @param entry the entry to check
* @return true if these checks pass, false if the notification should not alert
*/
- @VisibleForTesting
- public boolean canAlertAwakeCommon(NotificationEntry entry) {
+ private boolean canAlertAwakeCommon(NotificationEntry entry) {
StatusBarNotification sbn = entry.getSbn();
- if (mPresenter.isDeviceInVrMode()) {
- if (DEBUG_HEADS_UP) {
- Log.d(TAG, "No alerting: no huns or vr mode");
+ for (int i = 0; i < mSuppressors.size(); i++) {
+ if (mSuppressors.get(i).suppressAwakeInterruptions(entry)) {
+ if (DEBUG_HEADS_UP) {
+ Log.d(TAG, "No alerting: aborted by suppressor: "
+ + mSuppressors.get(i).getName() + " sbnKey=" + sbn.getKey());
+ }
+ return false;
}
- return false;
}
if (isSnoozedPackage(sbn)) {
@@ -392,54 +378,4 @@
private boolean isSnoozedPackage(StatusBarNotification sbn) {
return mHeadsUpManager.isSnoozed(sbn.getPackageName());
}
-
- /** Sets whether to disable all alerts. */
- public void setDisableNotificationAlerts(boolean disableNotificationAlerts) {
- mDisableNotificationAlerts = disableNotificationAlerts;
- mHeadsUpObserver.onChange(true);
- }
-
- /** Whether all alerts are disabled. */
- @VisibleForTesting
- public boolean areNotificationAlertsDisabled() {
- return mDisableNotificationAlerts;
- }
-
- /** Whether HUNs should be used. */
- @VisibleForTesting
- public boolean getUseHeadsUp() {
- return mUseHeadsUp;
- }
-
- protected NotificationPresenter getPresenter() {
- return mPresenter;
- }
-
- /**
- * When an entry was added, should we launch its fullscreen intent? Examples are Alarms or
- * incoming calls.
- *
- * @param entry the entry that was added
- * @return {@code true} if we should launch the full screen intent
- */
- public boolean shouldLaunchFullScreenIntentWhenAdded(NotificationEntry entry) {
- return entry.getSbn().getNotification().fullScreenIntent != null
- && (!shouldHeadsUp(entry)
- || mStatusBarStateController.getState() == StatusBarState.KEYGUARD);
- }
-
- /** A component which can suppress heads-up notifications due to the overall state of the UI. */
- public interface HeadsUpSuppressor {
- /**
- * Returns false if the provided notification is ineligible for heads-up according to this
- * component.
- *
- * @param entry entry of the notification that might be heads upped
- * @param sbn notification that might be heads upped
- * @return false if the notification can not be heads upped
- */
- boolean canHeadsUp(NotificationEntry entry, StatusBarNotification sbn);
-
- }
-
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptSuppressor.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptSuppressor.java
new file mode 100644
index 0000000..c19f8bd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptSuppressor.java
@@ -0,0 +1,64 @@
+/*
+ * 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.interruption;
+
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+
+/** A component which can suppress visual interruptions of notifications such as heads-up and
+ * bubble-up.
+ */
+public interface NotificationInterruptSuppressor {
+ /**
+ * A unique name to identify this suppressor.
+ */
+ default String getName() {
+ return this.getClass().getName();
+ }
+
+ /**
+ * Returns true if the provided notification is, when the device is awake, ineligible for
+ * heads-up according to this component.
+ *
+ * @param entry entry of the notification that might heads-up
+ * @return true if the heads up interruption should be suppressed when the device is awake
+ */
+ default boolean suppressAwakeHeadsUp(NotificationEntry entry) {
+ return false;
+ }
+
+ /**
+ * Returns true if the provided notification is, when the device is awake, ineligible for
+ * heads-up or bubble-up according to this component.
+ *
+ * @param entry entry of the notification that might heads-up or bubble-up
+ * @return true if interruptions should be suppressed when the device is awake
+ */
+ default boolean suppressAwakeInterruptions(NotificationEntry entry) {
+ return false;
+ }
+
+ /**
+ * Returns true if the provided notification is, regardless of awake/dozing state,
+ * ineligible for heads-up or bubble-up according to this component.
+ *
+ * @param entry entry of the notification that might heads-up or bubble-up
+ * @return true if interruptions should be suppressed
+ */
+ default boolean suppressInterruptions(NotificationEntry entry) {
+ return false;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt
index 597bdb9..be3873a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt
@@ -83,7 +83,7 @@
private val Ranking.personTypeInfo
get() = when {
- channel.isImportantConversation -> TYPE_IMPORTANT_PERSON
+ channel?.isImportantConversation == true -> TYPE_IMPORTANT_PERSON
isConversation -> TYPE_PERSON
else -> TYPE_NON_PERSON
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
index 6dd4ff9..91cf285 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
@@ -25,6 +25,8 @@
import android.annotation.Nullable;
import android.app.Notification;
import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.pm.ApplicationInfo;
import android.os.AsyncTask;
import android.os.CancellationSignal;
import android.service.notification.StatusBarNotification;
@@ -716,6 +718,10 @@
sbn.getNotification());
Context packageContext = sbn.getPackageContext(mContext);
+ if (recoveredBuilder.usesTemplate()) {
+ // For all of our templates, we want it to be RTL
+ packageContext = new RtlEnabledContext(packageContext);
+ }
Notification notification = sbn.getNotification();
if (notification.isMediaNotification()) {
MediaNotificationProcessor processor = new MediaNotificationProcessor(mContext,
@@ -782,6 +788,19 @@
// try to purge unnecessary cached entries.
mRow.getImageResolver().purgeCache();
}
+
+ private class RtlEnabledContext extends ContextWrapper {
+ private RtlEnabledContext(Context packageContext) {
+ super(packageContext);
+ }
+
+ @Override
+ public ApplicationInfo getApplicationInfo() {
+ ApplicationInfo applicationInfo = super.getApplicationInfo();
+ applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_RTL;
+ return applicationInfo;
+ }
+ }
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index ee31300..90bc075b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -492,7 +492,7 @@
try {
result = ActivityTaskManager.getService().startActivityAsUser(
null, getContext().getBasePackageName(),
- getContext().getFeatureId(), intent,
+ getContext().getAttributionTag(), intent,
intent.resolveTypeIfNeeded(getContext().getContentResolver()),
null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, o.toBundle(),
UserHandle.CURRENT.getIdentifier());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
index c5c3fff..c54fa29 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextView.java
@@ -27,6 +27,8 @@
*/
public class KeyguardIndicationTextView extends TextView {
+ private CharSequence mText = "";
+
public KeyguardIndicationTextView(Context context) {
super(context);
}
@@ -53,10 +55,12 @@
// TODO: Animation, make sure that we will show one indication long enough.
if (TextUtils.isEmpty(text)) {
+ mText = "";
setVisibility(View.INVISIBLE);
- } else {
+ } else if (!TextUtils.equals(text, mText)) {
+ mText = text;
setVisibility(View.VISIBLE);
- setText(text);
+ setText(mText);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
index f38d416..596a607 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewController.java
@@ -18,7 +18,6 @@
import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
-import android.annotation.Nullable;
import android.app.StatusBarManager;
import android.graphics.RectF;
import android.hardware.display.AmbientDisplayConfiguration;
@@ -44,7 +43,7 @@
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.DragDownHelper;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.NotificationShadeWindowBlurController;
+import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.PulseExpansionHandler;
import com.android.systemui.statusbar.SuperStatusBarViewFactory;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
@@ -82,7 +81,7 @@
private final CommandQueue mCommandQueue;
private final NotificationShadeWindowView mView;
private final ShadeController mShadeController;
- private final NotificationShadeWindowBlurController mBlurController;
+ private final NotificationShadeDepthController mDepthController;
private GestureDetector mGestureDetector;
private View mBrightnessMirror;
@@ -126,7 +125,7 @@
CommandQueue commandQueue,
ShadeController shadeController,
DockManager dockManager,
- @Nullable NotificationShadeWindowBlurController blurController,
+ NotificationShadeDepthController depthController,
NotificationShadeWindowView notificationShadeWindowView,
NotificationPanelViewController notificationPanelViewController,
SuperStatusBarViewFactory statusBarViewFactory) {
@@ -149,7 +148,7 @@
mShadeController = shadeController;
mDockManager = dockManager;
mNotificationPanelViewController = notificationPanelViewController;
- mBlurController = blurController;
+ mDepthController = depthController;
mStatusBarViewFactory = statusBarViewFactory;
// This view is not part of the newly inflated expanded status bar.
@@ -394,10 +393,8 @@
mView.getContext(), mView, expandHelperCallback,
dragDownCallback, mFalsingManager));
- if (mBlurController != null) {
- mBlurController.setRoot(mView);
- mNotificationPanelViewController.addExpansionListener(mBlurController);
- }
+ mDepthController.setRoot(mView);
+ mNotificationPanelViewController.addExpansionListener(mDepthController);
}
public NotificationShadeWindowView getView() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index b3a62d8..d343090 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -185,15 +185,15 @@
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
-import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
-import com.android.systemui.statusbar.notification.NotificationAlertingManager;
-import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.init.NotificationsController;
+import com.android.systemui.statusbar.notification.interruption.BypassHeadsUpNotifier;
+import com.android.systemui.statusbar.notification.interruption.NotificationAlertingManager;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
@@ -404,10 +404,9 @@
private final NotificationGutsManager mGutsManager;
private final NotificationLogger mNotificationLogger;
- private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
private final NotificationViewHierarchyManager mViewHierarchyManager;
private final KeyguardViewMediator mKeyguardViewMediator;
- private final NotificationAlertingManager mNotificationAlertingManager;
+ protected final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
// for disabling the status bar
private int mDisabled1 = 0;
@@ -621,10 +620,10 @@
RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
NotificationGutsManager notificationGutsManager,
NotificationLogger notificationLogger,
- NotificationInterruptionStateProvider notificationInterruptionStateProvider,
+ NotificationInterruptStateProvider notificationInterruptStateProvider,
NotificationViewHierarchyManager notificationViewHierarchyManager,
KeyguardViewMediator keyguardViewMediator,
- NotificationAlertingManager notificationAlertingManager,
+ NotificationAlertingManager notificationAlertingManager, // need to inject for now
DisplayMetrics displayMetrics,
MetricsLogger metricsLogger,
@UiBackground Executor uiBgExecutor,
@@ -701,10 +700,9 @@
mRemoteInputQuickSettingsDisabler = remoteInputQuickSettingsDisabler;
mGutsManager = notificationGutsManager;
mNotificationLogger = notificationLogger;
- mNotificationInterruptionStateProvider = notificationInterruptionStateProvider;
+ mNotificationInterruptStateProvider = notificationInterruptStateProvider;
mViewHierarchyManager = notificationViewHierarchyManager;
mKeyguardViewMediator = keyguardViewMediator;
- mNotificationAlertingManager = notificationAlertingManager;
mDisplayMetrics = displayMetrics;
mMetricsLogger = metricsLogger;
mUiBgExecutor = uiBgExecutor;
@@ -1238,9 +1236,9 @@
mPresenter = new StatusBarNotificationPresenter(mContext, mNotificationPanelViewController,
mHeadsUpManager, mNotificationShadeWindowView, mStackScroller, mDozeScrimController,
mScrimController, mActivityLaunchAnimator, mDynamicPrivacyController,
- mNotificationAlertingManager, mKeyguardStateController,
- mKeyguardIndicationController,
- this /* statusBar */, mShadeController, mCommandQueue, mInitController);
+ mKeyguardStateController, mKeyguardIndicationController,
+ this /* statusBar */, mShadeController, mCommandQueue, mInitController,
+ mNotificationInterruptStateProvider);
mNotificationShelf.setOnActivatedListener(mPresenter);
mRemoteInputManager.getController().addCallback(mNotificationShadeWindowController);
@@ -1589,8 +1587,9 @@
}
if ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) {
- mNotificationInterruptionStateProvider.setDisableNotificationAlerts(
- (state1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0);
+ if (areNotificationAlertsDisabled()) {
+ mHeadsUpManager.releaseAllImmediately();
+ }
}
if ((diff2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) != 0) {
@@ -1605,6 +1604,10 @@
}
}
+ boolean areNotificationAlertsDisabled() {
+ return (mDisabled1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0;
+ }
+
protected H createHandler() {
return new StatusBar.H();
}
@@ -2599,7 +2602,7 @@
}
try {
result = ActivityTaskManager.getService().startActivityAsUser(
- null, mContext.getBasePackageName(), mContext.getFeatureId(),
+ null, mContext.getBasePackageName(), mContext.getAttributionTag(),
intent,
intent.resolveTypeIfNeeded(mContext.getContentResolver()),
null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index e1a20b6..53fa263 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -68,12 +68,12 @@
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.policy.HeadsUpUtil;
@@ -108,7 +108,7 @@
private final NotifCollection mNotifCollection;
private final FeatureFlags mFeatureFlags;
private final StatusBarStateController mStatusBarStateController;
- private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
+ private final NotificationInterruptStateProvider mNotificationInterruptStateProvider;
private final MetricsLogger mMetricsLogger;
private final Context mContext;
private final NotificationPanelViewController mNotificationPanel;
@@ -142,7 +142,7 @@
NotificationLockscreenUserManager lockscreenUserManager,
ShadeController shadeController, StatusBar statusBar,
KeyguardStateController keyguardStateController,
- NotificationInterruptionStateProvider notificationInterruptionStateProvider,
+ NotificationInterruptStateProvider notificationInterruptStateProvider,
MetricsLogger metricsLogger, LockPatternUtils lockPatternUtils,
Handler mainThreadHandler, Handler backgroundHandler, Executor uiBgExecutor,
ActivityIntentHelper activityIntentHelper, BubbleController bubbleController,
@@ -167,7 +167,7 @@
mActivityStarter = activityStarter;
mEntryManager = entryManager;
mStatusBarStateController = statusBarStateController;
- mNotificationInterruptionStateProvider = notificationInterruptionStateProvider;
+ mNotificationInterruptStateProvider = notificationInterruptStateProvider;
mMetricsLogger = metricsLogger;
mAssistManagerLazy = assistManagerLazy;
mGroupManager = groupManager;
@@ -436,7 +436,7 @@
}
private void handleFullScreenIntent(NotificationEntry entry) {
- if (mNotificationInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry)) {
+ if (mNotificationInterruptStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry)) {
if (shouldSuppressFullScreenIntent(entry)) {
if (DEBUG) {
Log.d(TAG, "No Fullscreen intent: suppressed by DND: " + entry.getKey());
@@ -603,7 +603,7 @@
private final ActivityIntentHelper mActivityIntentHelper;
private final BubbleController mBubbleController;
private NotificationPanelViewController mNotificationPanelViewController;
- private NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
+ private NotificationInterruptStateProvider mNotificationInterruptStateProvider;
private final ShadeController mShadeController;
private NotificationPresenter mNotificationPresenter;
private ActivityLaunchAnimator mActivityLaunchAnimator;
@@ -626,7 +626,7 @@
NotificationGroupManager groupManager,
NotificationLockscreenUserManager lockscreenUserManager,
KeyguardStateController keyguardStateController,
- NotificationInterruptionStateProvider notificationInterruptionStateProvider,
+ NotificationInterruptStateProvider notificationInterruptStateProvider,
MetricsLogger metricsLogger,
LockPatternUtils lockPatternUtils,
@Main Handler mainThreadHandler,
@@ -654,7 +654,7 @@
mGroupManager = groupManager;
mLockscreenUserManager = lockscreenUserManager;
mKeyguardStateController = keyguardStateController;
- mNotificationInterruptionStateProvider = notificationInterruptionStateProvider;
+ mNotificationInterruptStateProvider = notificationInterruptStateProvider;
mMetricsLogger = metricsLogger;
mLockPatternUtils = lockPatternUtils;
mMainThreadHandler = mainThreadHandler;
@@ -712,7 +712,7 @@
mShadeController,
mStatusBar,
mKeyguardStateController,
- mNotificationInterruptionStateProvider,
+ mNotificationInterruptStateProvider,
mMetricsLogger,
mLockPatternUtils,
mMainThreadHandler,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index 30d6b507..79cea91 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -60,13 +60,13 @@
import com.android.systemui.statusbar.notification.AboveShelfObserver;
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
-import com.android.systemui.statusbar.notification.NotificationAlertingManager;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptSuppressor;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
@@ -98,8 +98,6 @@
(SysuiStatusBarStateController) Dependency.get(StatusBarStateController.class);
private final NotificationEntryManager mEntryManager =
Dependency.get(NotificationEntryManager.class);
- private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider =
- Dependency.get(NotificationInterruptionStateProvider.class);
private final NotificationMediaManager mMediaManager =
Dependency.get(NotificationMediaManager.class);
private final VisualStabilityManager mVisualStabilityManager =
@@ -140,13 +138,13 @@
ScrimController scrimController,
ActivityLaunchAnimator activityLaunchAnimator,
DynamicPrivacyController dynamicPrivacyController,
- NotificationAlertingManager notificationAlertingManager,
KeyguardStateController keyguardStateController,
KeyguardIndicationController keyguardIndicationController,
StatusBar statusBar,
ShadeController shadeController,
CommandQueue commandQueue,
- InitController initController) {
+ InitController initController,
+ NotificationInterruptStateProvider notificationInterruptStateProvider) {
mContext = context;
mKeyguardStateController = keyguardStateController;
mNotificationPanel = panel;
@@ -216,8 +214,7 @@
mEntryManager.addNotificationLifetimeExtender(mGutsManager);
mEntryManager.addNotificationLifetimeExtenders(
remoteInputManager.getLifetimeExtenders());
- mNotificationInterruptionStateProvider.setUpWithPresenter(
- this, mHeadsUpManager, this::canHeadsUp);
+ notificationInterruptStateProvider.addSuppressor(mInterruptSuppressor);
mLockscreenUserManager.setUpWithPresenter(this);
mMediaManager.setUpWithPresenter(this);
mVisualStabilityManager.setUpWithPresenter(this);
@@ -336,39 +333,6 @@
return mEntryManager.hasActiveNotifications();
}
- public boolean canHeadsUp(NotificationEntry entry, StatusBarNotification sbn) {
- if (mStatusBar.isOccluded()) {
- boolean devicePublic = mLockscreenUserManager.
- isLockscreenPublicMode(mLockscreenUserManager.getCurrentUserId());
- boolean userPublic = devicePublic
- || mLockscreenUserManager.isLockscreenPublicMode(sbn.getUserId());
- boolean needsRedaction = mLockscreenUserManager.needsRedaction(entry);
- if (userPublic && needsRedaction) {
- // TODO(b/135046837): we can probably relax this with dynamic privacy
- return false;
- }
- }
-
- if (!mCommandQueue.panelsEnabled()) {
- if (DEBUG) {
- Log.d(TAG, "No heads up: disabled panel : " + sbn.getKey());
- }
- return false;
- }
-
- if (sbn.getNotification().fullScreenIntent != null) {
- if (mAccessibilityManager.isTouchExplorationEnabled()) {
- if (DEBUG) Log.d(TAG, "No heads up: accessible fullscreen: " + sbn.getKey());
- return false;
- } else {
- // we only allow head-up on the lockscreen if it doesn't have a fullscreen intent
- return !mKeyguardStateController.isShowing()
- || mStatusBar.isOccluded();
- }
- }
- return true;
- }
-
@Override
public void onUserSwitched(int newUserId) {
// Begin old BaseStatusBar.userSwitched
@@ -507,4 +471,66 @@
}
}
};
+
+ private final NotificationInterruptSuppressor mInterruptSuppressor =
+ new NotificationInterruptSuppressor() {
+ @Override
+ public String getName() {
+ return TAG;
+ }
+
+ @Override
+ public boolean suppressAwakeHeadsUp(NotificationEntry entry) {
+ final StatusBarNotification sbn = entry.getSbn();
+ if (mStatusBar.isOccluded()) {
+ boolean devicePublic = mLockscreenUserManager
+ .isLockscreenPublicMode(mLockscreenUserManager.getCurrentUserId());
+ boolean userPublic = devicePublic
+ || mLockscreenUserManager.isLockscreenPublicMode(sbn.getUserId());
+ boolean needsRedaction = mLockscreenUserManager.needsRedaction(entry);
+ if (userPublic && needsRedaction) {
+ // TODO(b/135046837): we can probably relax this with dynamic privacy
+ return true;
+ }
+ }
+
+ if (!mCommandQueue.panelsEnabled()) {
+ if (DEBUG) {
+ Log.d(TAG, "No heads up: disabled panel : " + sbn.getKey());
+ }
+ return true;
+ }
+
+ if (sbn.getNotification().fullScreenIntent != null) {
+ // we don't allow head-up on the lockscreen (unless there's a
+ // "showWhenLocked" activity currently showing) if
+ // the potential HUN has a fullscreen intent
+ if (mKeyguardStateController.isShowing() && !mStatusBar.isOccluded()) {
+ if (DEBUG) {
+ Log.d(TAG, "No heads up: entry has fullscreen intent on lockscreen "
+ + sbn.getKey());
+ }
+ return true;
+ }
+
+ if (mAccessibilityManager.isTouchExplorationEnabled()) {
+ if (DEBUG) {
+ Log.d(TAG, "No heads up: accessible fullscreen: " + sbn.getKey());
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean suppressAwakeInterruptions(NotificationEntry entry) {
+ return isDeviceInVrMode();
+ }
+
+ @Override
+ public boolean suppressInterruptions(NotificationEntry entry) {
+ return mStatusBar.areNotificationAlertsDisabled();
+ }
+ };
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
index eec8d50..bbc7e7a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java
@@ -56,13 +56,13 @@
import com.android.systemui.statusbar.SuperStatusBarViewFactory;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.VibratorHelper;
-import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
-import com.android.systemui.statusbar.notification.NotificationAlertingManager;
-import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.init.NotificationsController;
+import com.android.systemui.statusbar.notification.interruption.BypassHeadsUpNotifier;
+import com.android.systemui.statusbar.notification.interruption.NotificationAlertingManager;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.phone.AutoHideController;
@@ -139,7 +139,7 @@
RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
NotificationGutsManager notificationGutsManager,
NotificationLogger notificationLogger,
- NotificationInterruptionStateProvider notificationInterruptionStateProvider,
+ NotificationInterruptStateProvider notificationInterruptStateProvider,
NotificationViewHierarchyManager notificationViewHierarchyManager,
KeyguardViewMediator keyguardViewMediator,
NotificationAlertingManager notificationAlertingManager,
@@ -218,7 +218,7 @@
remoteInputQuickSettingsDisabler,
notificationGutsManager,
notificationLogger,
- notificationInterruptionStateProvider,
+ notificationInterruptStateProvider,
notificationViewHierarchyManager,
keyguardViewMediator,
notificationAlertingManager,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
index 759bad4..812ce1c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
@@ -236,7 +236,7 @@
String action = intent.getAction();
if (action.equals(Intent.ACTION_TIMEZONE_CHANGED)) {
- String tz = intent.getStringExtra("time-zone");
+ String tz = intent.getStringExtra(Intent.EXTRA_TIMEZONE);
handler.post(() -> {
mCalendar = Calendar.getInstance(TimeZone.getTimeZone(tz));
if (mClockFormat != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index cebcf76..54e8e72 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -577,7 +577,7 @@
}
boolean isDataDisabled() {
- return !mPhone.isDataConnectionEnabled();
+ return !mPhone.isDataConnectionAllowed();
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index b84208c..99709402 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -630,7 +630,7 @@
@VisibleForTesting
void doUpdateMobileControllers() {
List<SubscriptionInfo> subscriptions = mSubscriptionManager
- .getActiveAndHiddenSubscriptionInfoList();
+ .getCompleteActiveSubscriptionInfoList();
if (subscriptions == null) {
subscriptions = Collections.emptyList();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/AudioRecordingDisclosureBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/AudioRecordingDisclosureBar.java
index 74739e1..e70e30a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/AudioRecordingDisclosureBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/AudioRecordingDisclosureBar.java
@@ -24,6 +24,7 @@
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.annotation.IntDef;
+import android.annotation.UiThread;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -43,7 +44,6 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
-import java.util.HashSet;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Set;
@@ -98,8 +98,27 @@
private TextView mTextView;
@State private int mState = STATE_NOT_SHOWN;
- private final Set<String> mAudioRecordingApps = new HashSet<>();
- private final Queue<String> mPendingNotifications = new LinkedList<>();
+ /**
+ * Set of the applications that currently are conducting audio recording.
+ */
+ private final Set<String> mActiveAudioRecordingPackages = new ArraySet<>();
+ /**
+ * Set of applications that we've notified the user about since the indicator came up. Meaning
+ * that if an application is in this list then at some point since the indicator came up, it
+ * was expanded showing this application's title.
+ * Used not to notify the user about the same application again while the indicator is shown.
+ * We empty this set every time the indicator goes off the screen (we always call {@code
+ * mSessionNotifiedPackages.clear()} before calling {@link #hide()}).
+ */
+ private final Set<String> mSessionNotifiedPackages = new ArraySet<>();
+ /**
+ * If an application starts recording while the TV indicator is neither in {@link
+ * #STATE_NOT_SHOWN} nor in {@link #STATE_MINIMIZED}, then we add the application's package
+ * name to the queue, from which we take packages names one by one to disclose the
+ * corresponding applications' titles to the user, whenever the indicator eventually comes to
+ * one of the two aforementioned states.
+ */
+ private final Queue<String> mPendingNotificationPackages = new LinkedList<>();
AudioRecordingDisclosureBar(Context context) {
mContext = context;
@@ -115,11 +134,16 @@
new OnActiveRecordingListener());
}
+ @UiThread
private void onStartedRecording(String packageName) {
- if (!mAudioRecordingApps.add(packageName)) {
+ if (!mActiveAudioRecordingPackages.add(packageName)) {
// This app is already known to perform recording
return;
}
+ if (!mSessionNotifiedPackages.add(packageName)) {
+ // We've already notified user about this app, no need to do it again.
+ return;
+ }
switch (mState) {
case STATE_NOT_SHOWN:
@@ -137,13 +161,14 @@
case STATE_MINIMIZING:
// Currently animating or expanded. Thus add to the pending notifications, and it
// will be picked up once the indicator comes to the STATE_MINIMIZED.
- mPendingNotifications.add(packageName);
+ mPendingNotificationPackages.add(packageName);
break;
}
}
+ @UiThread
private void onDoneRecording(String packageName) {
- if (!mAudioRecordingApps.remove(packageName)) {
+ if (!mActiveAudioRecordingPackages.remove(packageName)) {
// Was not marked as an active recorder, do nothing
return;
}
@@ -151,11 +176,13 @@
// If not MINIMIZED, will check whether the indicator should be hidden when the indicator
// comes to the STATE_MINIMIZED eventually. If is in the STATE_MINIMIZED, but there are
// other active recorders - simply ignore.
- if (mState == STATE_MINIMIZED && mAudioRecordingApps.isEmpty()) {
+ if (mState == STATE_MINIMIZED && mActiveAudioRecordingPackages.isEmpty()) {
+ mSessionNotifiedPackages.clear();
hide();
}
}
+ @UiThread
private void show(String packageName) {
// Inflate the indicator view
mIndicatorView = LayoutInflater.from(mContext).inflate(
@@ -230,6 +257,7 @@
mState = STATE_APPEARING;
}
+ @UiThread
private void expand(String packageName) {
final String label = getApplicationLabel(packageName);
mTextView.setText(mContext.getString(R.string.app_accessed_mic, label));
@@ -253,6 +281,7 @@
mState = STATE_MAXIMIZING;
}
+ @UiThread
private void minimize() {
final int targetOffset = mTextsContainers.getWidth();
final AnimatorSet set = new AnimatorSet();
@@ -274,6 +303,7 @@
mState = STATE_MINIMIZING;
}
+ @UiThread
private void hide() {
final int targetOffset =
mIndicatorView.getWidth() - (int) mIconTextsContainer.getTranslationX();
@@ -294,24 +324,28 @@
mState = STATE_DISAPPEARING;
}
+ @UiThread
private void onExpanded() {
mState = STATE_SHOWN;
mIndicatorView.postDelayed(this::minimize, MAXIMIZED_DURATION);
}
+ @UiThread
private void onMinimized() {
mState = STATE_MINIMIZED;
- if (!mPendingNotifications.isEmpty()) {
+ if (!mPendingNotificationPackages.isEmpty()) {
// There is a new application that started recording, tell the user about it.
- expand(mPendingNotifications.poll());
- } else if (mAudioRecordingApps.isEmpty()) {
- // Nobody is recording anymore, remove the indicator.
+ expand(mPendingNotificationPackages.poll());
+ } else if (mActiveAudioRecordingPackages.isEmpty()) {
+ // Nobody is recording anymore, clear state and remove the indicator.
+ mSessionNotifiedPackages.clear();
hide();
}
}
+ @UiThread
private void onHidden() {
final WindowManager windowManager = (WindowManager) mContext.getSystemService(
Context.WINDOW_SERVICE);
@@ -326,8 +360,15 @@
mBgRight = null;
mState = STATE_NOT_SHOWN;
+
+ // Check if anybody started recording while we were in STATE_DISAPPEARING
+ if (!mPendingNotificationPackages.isEmpty()) {
+ // There is a new application that started recording, tell the user about it.
+ show(mPendingNotificationPackages.poll());
+ }
}
+ @UiThread
private void startPulsatingAnimation() {
final View pulsatingView = mIconTextsContainer.findViewById(R.id.pulsating_circle);
final ObjectAnimator animator =
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
index 2452218..248bdc8 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
@@ -41,9 +41,9 @@
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.util.leak.LeakDetector;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -69,7 +69,8 @@
// Map of Uris we listen on to their settings keys.
private final ArrayMap<Uri, String> mListeningUris = new ArrayMap<>();
// Map of settings keys to the listener.
- private final HashMap<String, Set<Tunable>> mTunableLookup = new HashMap<>();
+ private final ConcurrentHashMap<String, Set<Tunable>> mTunableLookup =
+ new ConcurrentHashMap<>();
// Set of all tunables, used for leak detection.
private final HashSet<Tunable> mTunables = LeakDetector.ENABLED ? new HashSet<>() : null;
private final Context mContext;
diff --git a/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java b/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java
index 23df991..ccb8699 100644
--- a/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java
+++ b/packages/SystemUI/src/com/android/systemui/wm/SystemWindows.java
@@ -324,7 +324,7 @@
@Override
public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
- boolean sync) {}
+ float zoom, boolean sync) {}
@Override
public void dispatchWallpaperCommand(String action, int x, int y,
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
index ea6cf33..f7daf97 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
@@ -249,7 +249,7 @@
// STOPSHIP(b/130246708) This line makes sure that SubscriptionManager provides the
// same answer as KeyguardUpdateMonitor. Remove when this is addressed
- when(mSubscriptionManager.getActiveAndHiddenSubscriptionInfoList()).thenReturn(
+ when(mSubscriptionManager.getCompleteActiveSubscriptionInfoList()).thenReturn(
new ArrayList<>());
when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index eead120..4f4ce13 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -516,7 +516,7 @@
List<SubscriptionInfo> list = new ArrayList<>();
list.add(TEST_SUBSCRIPTION);
list.add(TEST_SUBSCRIPTION_2);
- when(mSubscriptionManager.getActiveAndHiddenSubscriptionInfoList()).thenReturn(list);
+ when(mSubscriptionManager.getCompleteActiveSubscriptionInfoList()).thenReturn(list);
mKeyguardUpdateMonitor.mPhoneStateListener.onActiveDataSubscriptionIdChanged(
TEST_SUBSCRIPTION_2.getSubscriptionId());
mTestableLooper.processAllMessages();
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java
index 6199181..353fe62 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/clock/ClockManagerTest.java
@@ -50,6 +50,8 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.Arrays;
+
@SmallTest
@RunWith(AndroidTestingRunner.class)
// Need to run tests on main looper because LiveData operations such as setData, observe,
@@ -126,7 +128,7 @@
when(mMockSettingsWrapper.getLockScreenCustomClockFace(anyInt())).thenReturn(null);
when(mMockSettingsWrapper.getDockedClockFace(anyInt())).thenReturn(null);
// WHEN settings change event is fired
- mContentObserver.onChange(false, SETTINGS_URI, MAIN_USER_ID);
+ mContentObserver.onChange(false, Arrays.asList(SETTINGS_URI), 0, MAIN_USER_ID);
// THEN the result is null, indicated the default clock face should be used.
assertThat(mClockManager.getCurrentClock()).isNull();
}
@@ -136,7 +138,7 @@
// GIVEN that settings is set to the bubble clock face
when(mMockSettingsWrapper.getLockScreenCustomClockFace(anyInt())).thenReturn(BUBBLE_CLOCK);
// WHEN settings change event is fired
- mContentObserver.onChange(false, SETTINGS_URI, MAIN_USER_ID);
+ mContentObserver.onChange(false, Arrays.asList(SETTINGS_URI), 0, MAIN_USER_ID);
// THEN the plugin is the bubble clock face.
assertThat(mClockManager.getCurrentClock()).isInstanceOf(BUBBLE_CLOCK_CLASS);
}
@@ -146,7 +148,7 @@
// GIVEN that settings is set to the bubble clock face
when(mMockSettingsWrapper.getLockScreenCustomClockFace(anyInt())).thenReturn(BUBBLE_CLOCK);
// WHEN settings change event is fired
- mContentObserver.onChange(false, SETTINGS_URI, MAIN_USER_ID);
+ mContentObserver.onChange(false, Arrays.asList(SETTINGS_URI), 0, MAIN_USER_ID);
// THEN the plugin is the bubble clock face.
ArgumentCaptor<ClockPlugin> captor = ArgumentCaptor.forClass(ClockPlugin.class);
verify(mMockListener1).onClockChanged(captor.capture());
@@ -158,7 +160,7 @@
// GIVEN that settings is set to the bubble clock face
when(mMockSettingsWrapper.getLockScreenCustomClockFace(anyInt())).thenReturn(BUBBLE_CLOCK);
// WHEN settings change event is fired
- mContentObserver.onChange(false, SETTINGS_URI, MAIN_USER_ID);
+ mContentObserver.onChange(false, Arrays.asList(SETTINGS_URI), 0, MAIN_USER_ID);
// THEN the listeners receive separate instances of the Bubble clock plugin.
ArgumentCaptor<ClockPlugin> captor1 = ArgumentCaptor.forClass(ClockPlugin.class);
ArgumentCaptor<ClockPlugin> captor2 = ArgumentCaptor.forClass(ClockPlugin.class);
@@ -175,7 +177,7 @@
// custom clock face.
when(mMockSettingsWrapper.getLockScreenCustomClockFace(anyInt())).thenReturn("bad value");
// WHEN settings change event is fired
- mContentObserver.onChange(false, SETTINGS_URI, MAIN_USER_ID);
+ mContentObserver.onChange(false, Arrays.asList(SETTINGS_URI), 0, MAIN_USER_ID);
// THEN the result is null.
assertThat(mClockManager.getCurrentClock()).isNull();
}
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 78160c4..6e612d7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -45,7 +45,11 @@
import android.app.Notification;
import android.app.PendingIntent;
import android.content.res.Resources;
+import android.hardware.display.AmbientDisplayConfiguration;
import android.hardware.face.FaceManager;
+import android.os.Handler;
+import android.os.PowerManager;
+import android.service.dreams.IDreamManager;
import android.service.notification.ZenModeConfig;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -61,14 +65,12 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.NotificationRemoveInterceptor;
import com.android.systemui.statusbar.SuperStatusBarViewFactory;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationFilter;
-import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
@@ -227,15 +229,17 @@
mZenModeConfig.suppressedVisualEffects = 0;
when(mZenModeController.getConfig()).thenReturn(mZenModeConfig);
- TestableNotificationInterruptionStateProvider interruptionStateProvider =
- new TestableNotificationInterruptionStateProvider(mContext,
+ TestableNotificationInterruptStateProviderImpl interruptionStateProvider =
+ new TestableNotificationInterruptStateProviderImpl(mContext.getContentResolver(),
+ mock(PowerManager.class),
+ mock(IDreamManager.class),
+ mock(AmbientDisplayConfiguration.class),
mock(NotificationFilter.class),
mock(StatusBarStateController.class),
- mock(BatteryController.class));
- interruptionStateProvider.setUpWithPresenter(
- mock(NotificationPresenter.class),
- mock(HeadsUpManager.class),
- mock(NotificationInterruptionStateProvider.HeadsUpSuppressor.class));
+ mock(BatteryController.class),
+ mock(HeadsUpManager.class),
+ mock(Handler.class)
+ );
mBubbleData = new BubbleData(mContext);
when(mFeatureFlagsOldPipeline.isNewNotifPipelineRenderingEnabled()).thenReturn(false);
mBubbleController = new TestableBubbleController(
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 5ef4cd2..6244644 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java
@@ -41,7 +41,11 @@
import android.app.Notification;
import android.app.PendingIntent;
import android.content.res.Resources;
+import android.hardware.display.AmbientDisplayConfiguration;
import android.hardware.face.FaceManager;
+import android.os.Handler;
+import android.os.PowerManager;
+import android.service.dreams.IDreamManager;
import android.service.notification.ZenModeConfig;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -57,12 +61,10 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.SuperStatusBarViewFactory;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationFilter;
-import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
@@ -212,15 +214,17 @@
mZenModeConfig.suppressedVisualEffects = 0;
when(mZenModeController.getConfig()).thenReturn(mZenModeConfig);
- TestableNotificationInterruptionStateProvider interruptionStateProvider =
- new TestableNotificationInterruptionStateProvider(mContext,
+ TestableNotificationInterruptStateProviderImpl interruptionStateProvider =
+ new TestableNotificationInterruptStateProviderImpl(mContext.getContentResolver(),
+ mock(PowerManager.class),
+ mock(IDreamManager.class),
+ mock(AmbientDisplayConfiguration.class),
mock(NotificationFilter.class),
mock(StatusBarStateController.class),
- mock(BatteryController.class));
- interruptionStateProvider.setUpWithPresenter(
- mock(NotificationPresenter.class),
- mock(HeadsUpManager.class),
- mock(NotificationInterruptionStateProvider.HeadsUpSuppressor.class));
+ mock(BatteryController.class),
+ mock(HeadsUpManager.class),
+ mock(Handler.class)
+ );
mBubbleData = new BubbleData(mContext);
when(mFeatureFlagsNewPipeline.isNewNotifPipelineRenderingEnabled()).thenReturn(true);
mBubbleController = new TestableBubbleController(
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 de1fb41..d3d90c4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java
@@ -23,8 +23,8 @@
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.ShadeController;
@@ -44,7 +44,7 @@
ShadeController shadeController,
BubbleData data,
ConfigurationController configurationController,
- NotificationInterruptionStateProvider interruptionStateProvider,
+ NotificationInterruptStateProvider interruptionStateProvider,
ZenModeController zenModeController,
NotificationLockscreenUserManager lockscreenUserManager,
NotificationGroupManager groupManager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableNotificationInterruptStateProviderImpl.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableNotificationInterruptStateProviderImpl.java
new file mode 100644
index 0000000..17dc76b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableNotificationInterruptStateProviderImpl.java
@@ -0,0 +1,55 @@
+/*
+ * 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.bubbles;
+
+import android.content.ContentResolver;
+import android.hardware.display.AmbientDisplayConfiguration;
+import android.os.Handler;
+import android.os.PowerManager;
+import android.service.dreams.IDreamManager;
+
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.notification.NotificationFilter;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
+
+public class TestableNotificationInterruptStateProviderImpl
+ extends NotificationInterruptStateProviderImpl {
+
+ TestableNotificationInterruptStateProviderImpl(
+ ContentResolver contentResolver,
+ PowerManager powerManager,
+ IDreamManager dreamManager,
+ AmbientDisplayConfiguration ambientDisplayConfiguration,
+ NotificationFilter filter,
+ StatusBarStateController statusBarStateController,
+ BatteryController batteryController,
+ HeadsUpManager headsUpManager,
+ Handler mainHandler) {
+ super(contentResolver,
+ powerManager,
+ dreamManager,
+ ambientDisplayConfiguration,
+ filter,
+ batteryController,
+ statusBarStateController,
+ headsUpManager,
+ mainHandler);
+ mUseHeadsUp = true;
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableNotificationInterruptionStateProvider.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableNotificationInterruptionStateProvider.java
deleted file mode 100644
index 5d192b2..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableNotificationInterruptionStateProvider.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.bubbles;
-
-import android.content.Context;
-
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.notification.NotificationFilter;
-import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
-import com.android.systemui.statusbar.policy.BatteryController;
-
-public class TestableNotificationInterruptionStateProvider
- extends NotificationInterruptionStateProvider {
-
- TestableNotificationInterruptionStateProvider(Context context,
- NotificationFilter filter, StatusBarStateController controller,
- BatteryController batteryController) {
- super(context, filter, controller, batteryController);
- mUseHeadsUp = true;
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt
index eceb1dd..c25d4e2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt
@@ -22,6 +22,8 @@
import android.os.UserHandle
import android.service.controls.Control
import android.service.controls.DeviceTypes
+import android.service.controls.IControlsSubscriber
+import android.service.controls.IControlsSubscription
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -34,6 +36,8 @@
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.Mockito
import org.mockito.Mockito.`when`
@@ -48,6 +52,7 @@
class ControlsBindingControllerImplTest : SysuiTestCase() {
companion object {
+ fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture()
fun <T> any(): T = Mockito.any<T>()
private val TEST_COMPONENT_NAME_1 = ComponentName("TEST_PKG", "TEST_CLS_1")
private val TEST_COMPONENT_NAME_2 = ComponentName("TEST_PKG", "TEST_CLS_2")
@@ -57,6 +62,15 @@
@Mock
private lateinit var mockControlsController: ControlsController
+ @Captor
+ private lateinit var subscriberCaptor: ArgumentCaptor<IControlsSubscriber.Stub>
+
+ @Captor
+ private lateinit var loadSubscriberCaptor: ArgumentCaptor<IControlsSubscriber.Stub>
+
+ @Captor
+ private lateinit var listStringCaptor: ArgumentCaptor<List<String>>
+
private val user = UserHandle.of(mContext.userId)
private val otherUser = UserHandle.of(user.identifier + 1)
@@ -97,6 +111,102 @@
}
@Test
+ fun testBindAndLoad_cancel() {
+ val callback = object : ControlsBindingController.LoadCallback {
+ override fun error(message: String) {}
+
+ override fun accept(t: List<Control>) {}
+ }
+ val subscription = mock(IControlsSubscription::class.java)
+
+ val canceller = controller.bindAndLoad(TEST_COMPONENT_NAME_1, callback)
+
+ verify(providers[0]).maybeBindAndLoad(capture(loadSubscriberCaptor))
+ loadSubscriberCaptor.value.onSubscribe(Binder(), subscription)
+
+ canceller.run()
+ verify(subscription).cancel()
+ }
+
+ @Test
+ fun testBindAndLoad_noCancelAfterOnComplete() {
+ val callback = object : ControlsBindingController.LoadCallback {
+ override fun error(message: String) {}
+
+ override fun accept(t: List<Control>) {}
+ }
+ val subscription = mock(IControlsSubscription::class.java)
+
+ val canceller = controller.bindAndLoad(TEST_COMPONENT_NAME_1, callback)
+
+ verify(providers[0]).maybeBindAndLoad(capture(loadSubscriberCaptor))
+ val b = Binder()
+ loadSubscriberCaptor.value.onSubscribe(b, subscription)
+
+ loadSubscriberCaptor.value.onComplete(b)
+ canceller.run()
+ verify(subscription, never()).cancel()
+ }
+
+ @Test
+ fun testLoad_onCompleteRemovesTimeout() {
+ val callback = object : ControlsBindingController.LoadCallback {
+ override fun error(message: String) {}
+
+ override fun accept(t: List<Control>) {}
+ }
+ val subscription = mock(IControlsSubscription::class.java)
+
+ val canceller = controller.bindAndLoad(TEST_COMPONENT_NAME_1, callback)
+
+ verify(providers[0]).maybeBindAndLoad(capture(subscriberCaptor))
+ val b = Binder()
+ subscriberCaptor.value.onSubscribe(b, subscription)
+
+ subscriberCaptor.value.onComplete(b)
+ verify(providers[0]).cancelLoadTimeout()
+ }
+
+ @Test
+ fun testLoad_onErrorRemovesTimeout() {
+ val callback = object : ControlsBindingController.LoadCallback {
+ override fun error(message: String) {}
+
+ override fun accept(t: List<Control>) {}
+ }
+ val subscription = mock(IControlsSubscription::class.java)
+
+ val canceller = controller.bindAndLoad(TEST_COMPONENT_NAME_1, callback)
+
+ verify(providers[0]).maybeBindAndLoad(capture(subscriberCaptor))
+ val b = Binder()
+ subscriberCaptor.value.onSubscribe(b, subscription)
+
+ subscriberCaptor.value.onError(b, "")
+ verify(providers[0]).cancelLoadTimeout()
+ }
+
+ @Test
+ fun testBindAndLoad_noCancelAfterOnError() {
+ val callback = object : ControlsBindingController.LoadCallback {
+ override fun error(message: String) {}
+
+ override fun accept(t: List<Control>) {}
+ }
+ val subscription = mock(IControlsSubscription::class.java)
+
+ val canceller = controller.bindAndLoad(TEST_COMPONENT_NAME_1, callback)
+
+ verify(providers[0]).maybeBindAndLoad(capture(loadSubscriberCaptor))
+ val b = Binder()
+ loadSubscriberCaptor.value.onSubscribe(b, subscription)
+
+ loadSubscriberCaptor.value.onError(b, "")
+ canceller.run()
+ verify(subscription, never()).cancel()
+ }
+
+ @Test
fun testBindService() {
controller.bindService(TEST_COMPONENT_NAME_1)
executor.runAllReady()
@@ -115,8 +225,13 @@
executor.runAllReady()
+ val subs = mock(IControlsSubscription::class.java)
verify(providers[0]).maybeBindAndSubscribe(
+ capture(listStringCaptor), capture(subscriberCaptor))
+ assertEquals(listStringCaptor.value,
listOf(controlInfo1.controlId, controlInfo2.controlId))
+
+ subscriberCaptor.value.onSubscribe(providers[0].token, subs)
}
@Test
@@ -126,7 +241,7 @@
executor.runAllReady()
- verify(providers[0], never()).unsubscribe()
+ verify(providers[0], never()).cancelSubscription(any())
}
@Test
@@ -137,12 +252,21 @@
StructureInfo(TEST_COMPONENT_NAME_1, "Home", listOf(controlInfo1, controlInfo2))
controller.subscribe(structure)
-
- controller.unsubscribe()
-
executor.runAllReady()
- verify(providers[0]).unsubscribe()
+ val subs = mock(IControlsSubscription::class.java)
+ verify(providers[0]).maybeBindAndSubscribe(
+ capture(listStringCaptor), capture(subscriberCaptor))
+ assertEquals(listStringCaptor.value,
+ listOf(controlInfo1.controlId, controlInfo2.controlId))
+
+ subscriberCaptor.value.onSubscribe(providers[0].token, subs)
+ executor.runAllReady()
+
+ controller.unsubscribe()
+ executor.runAllReady()
+
+ verify(providers[0]).cancelSubscription(subs)
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
index c70c56a..f9c9815 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
@@ -346,6 +346,88 @@
}
@Test
+ fun testCancelLoad() {
+ val canceller = object : Runnable {
+ var ran = false
+ override fun run() {
+ ran = true
+ }
+ }
+ `when`(bindingController.bindAndLoad(any(), any())).thenReturn(canceller)
+
+ var loaded = false
+ controller.replaceFavoritesForStructure(TEST_STRUCTURE_INFO)
+ delayableExecutor.runAllReady()
+ controller.loadForComponent(TEST_COMPONENT, Consumer {
+ loaded = true
+ })
+
+ controller.cancelLoad()
+ delayableExecutor.runAllReady()
+
+ assertFalse(loaded)
+ assertTrue(canceller.ran)
+ }
+
+ @Test
+ fun testCancelLoad_noCancelAfterSuccessfulLoad() {
+ val canceller = object : Runnable {
+ var ran = false
+ override fun run() {
+ ran = true
+ }
+ }
+ `when`(bindingController.bindAndLoad(any(), any())).thenReturn(canceller)
+
+ var loaded = false
+ controller.replaceFavoritesForStructure(TEST_STRUCTURE_INFO)
+ delayableExecutor.runAllReady()
+ controller.loadForComponent(TEST_COMPONENT, Consumer {
+ loaded = true
+ })
+
+ verify(bindingController).bindAndLoad(eq(TEST_COMPONENT),
+ capture(controlLoadCallbackCaptor))
+
+ controlLoadCallbackCaptor.value.accept(emptyList())
+
+ controller.cancelLoad()
+ delayableExecutor.runAllReady()
+
+ assertTrue(loaded)
+ assertFalse(canceller.ran)
+ }
+
+ @Test
+ fun testCancelLoad_noCancelAfterErrorLoad() {
+ val canceller = object : Runnable {
+ var ran = false
+ override fun run() {
+ ran = true
+ }
+ }
+ `when`(bindingController.bindAndLoad(any(), any())).thenReturn(canceller)
+
+ var loaded = false
+ controller.replaceFavoritesForStructure(TEST_STRUCTURE_INFO)
+ delayableExecutor.runAllReady()
+ controller.loadForComponent(TEST_COMPONENT, Consumer {
+ loaded = true
+ })
+
+ verify(bindingController).bindAndLoad(eq(TEST_COMPONENT),
+ capture(controlLoadCallbackCaptor))
+
+ controlLoadCallbackCaptor.value.error("")
+
+ controller.cancelLoad()
+ delayableExecutor.runAllReady()
+
+ assertTrue(loaded)
+ assertFalse(canceller.ran)
+ }
+
+ @Test
fun testFavoriteInformationModifiedOnLoad() {
controller.replaceFavoritesForStructure(TEST_STRUCTURE_INFO)
delayableExecutor.runAllReady()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt
index fd92ad0..2d3757c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
- * Licensed under the Apache License, Version 2.0 (the "License");
+ * Licensed under the Apache License, Version 2.0 (149the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
@@ -43,6 +43,7 @@
import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito.`when`
+import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@@ -83,7 +84,6 @@
context,
executor,
actionCallbackService,
- subscriberService,
UserHandle.of(0),
componentName
)
@@ -144,9 +144,22 @@
}
@Test
+ fun testMaybeBindAndLoad_timeoutCancelled() {
+ manager.maybeBindAndLoad(subscriberService)
+ executor.runAllReady()
+
+ manager.cancelLoadTimeout()
+
+ executor.advanceClockToLast()
+ executor.runAllReady()
+
+ verify(subscriberService, never()).onError(any(), anyString())
+ }
+
+ @Test
fun testMaybeBindAndSubscribe() {
val list = listOf("TEST_ID")
- manager.maybeBindAndSubscribe(list)
+ manager.maybeBindAndSubscribe(list, subscriberService)
executor.runAllReady()
assertTrue(mContext.isBound(componentName))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/StatefulControlSubscriberTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/StatefulControlSubscriberTest.kt
new file mode 100644
index 0000000..ff5c8d4
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/StatefulControlSubscriberTest.kt
@@ -0,0 +1,146 @@
+/*
+ * 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.controls.controller
+
+import android.content.ComponentName
+import android.os.Binder
+import android.service.controls.Control
+import android.service.controls.IControlsSubscription
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.time.FakeSystemClock
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.`when`
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class StatefulControlSubscriberTest : SysuiTestCase() {
+
+ @Mock
+ private lateinit var controller: ControlsController
+
+ @Mock
+ private lateinit var subscription: IControlsSubscription
+
+ @Mock
+ private lateinit var provider: ControlsProviderLifecycleManager
+
+ @Mock
+ private lateinit var control: Control
+
+ private val executor = FakeExecutor(FakeSystemClock())
+ private val token = Binder()
+ private val badToken = Binder()
+
+ private val TEST_COMPONENT = ComponentName("TEST_PKG", "TEST_CLS_1")
+
+ private lateinit var scs: StatefulControlSubscriber
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ `when`(provider.componentName).thenReturn(TEST_COMPONENT)
+ `when`(provider.token).thenReturn(token)
+ scs = StatefulControlSubscriber(controller, provider, executor)
+ }
+
+ @Test
+ fun testOnSubscribe() {
+ scs.onSubscribe(token, subscription)
+
+ executor.runAllReady()
+ verify(provider).startSubscription(subscription)
+ }
+
+ @Test
+ fun testOnSubscribe_badToken() {
+ scs.onSubscribe(badToken, subscription)
+
+ executor.runAllReady()
+ verify(provider, never()).startSubscription(subscription)
+ }
+
+ @Test
+ fun testOnNext() {
+ scs.onSubscribe(token, subscription)
+ scs.onNext(token, control)
+
+ executor.runAllReady()
+ verify(controller).refreshStatus(TEST_COMPONENT, control)
+ }
+
+ @Test
+ fun testOnNext_multiple() {
+ scs.onSubscribe(token, subscription)
+ scs.onNext(token, control)
+ scs.onNext(token, control)
+ scs.onNext(token, control)
+
+ executor.runAllReady()
+ verify(controller, times(3)).refreshStatus(TEST_COMPONENT, control)
+ }
+
+ @Test
+ fun testOnNext_noRefreshBeforeSubscribe() {
+ scs.onNext(token, control)
+
+ executor.runAllReady()
+ verify(controller, never()).refreshStatus(TEST_COMPONENT, control)
+ }
+
+ @Test
+ fun testOnNext_noRefreshAfterCancel() {
+ scs.onSubscribe(token, subscription)
+ executor.runAllReady()
+
+ scs.cancel()
+ scs.onNext(token, control)
+
+ executor.runAllReady()
+ verify(controller, never()).refreshStatus(TEST_COMPONENT, control)
+ }
+
+ @Test
+ fun testOnNext_noRefreshAfterError() {
+ scs.onSubscribe(token, subscription)
+ scs.onError(token, "Error")
+ scs.onNext(token, control)
+
+ executor.runAllReady()
+ verify(controller, never()).refreshStatus(TEST_COMPONENT, control)
+ }
+
+ @Test
+ fun testOnNext_noRefreshAfterComplete() {
+ scs.onSubscribe(token, subscription)
+ scs.onComplete(token)
+ scs.onNext(token, control)
+
+ executor.runAllReady()
+ verify(controller, never()).refreshStatus(TEST_COMPONENT, control)
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
index 9117ea8..f535351 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenBrightnessTest.java
@@ -248,31 +248,6 @@
}
@Test
- public void pausingAod_softBlanks_withSpuriousSensorDuringPause() throws Exception {
- mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
- mScreen.transitionTo(INITIALIZED, DOZE_AOD);
- mScreen.transitionTo(DOZE_AOD, DOZE_AOD_PAUSING);
- mScreen.transitionTo(DOZE_AOD_PAUSING, DOZE_AOD_PAUSED);
-
- reset(mDozeHost);
- mSensor.sendSensorEvent(1);
- verify(mDozeHost).setAodDimmingScrim(eq(1f));
- }
-
- @Test
- public void screenOff_softBlanks() throws Exception {
- mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
- mScreen.transitionTo(INITIALIZED, DOZE_AOD);
- mScreen.transitionTo(DOZE_AOD, DOZE);
- verify(mDozeHost).setAodDimmingScrim(eq(1f));
-
- reset(mDozeHost);
- mScreen.transitionTo(DOZE, DOZE_AOD);
- mSensor.sendSensorEvent(2);
- verify(mDozeHost).setAodDimmingScrim(eq(0f));
- }
-
- @Test
public void pausingAod_unblanksAfterSensor() throws Exception {
mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
mScreen.transitionTo(INITIALIZED, DOZE_AOD);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
index 0098012..73f3ddd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
@@ -22,7 +22,9 @@
import static junit.framework.TestCase.assertFalse;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -137,6 +139,8 @@
return new TestTile1(mQSTileHost);
} else if ("spec2".equals(spec)) {
return new TestTile2(mQSTileHost);
+ } else if ("na".equals(spec)) {
+ return new NotAvailableTile(mQSTileHost);
} else if (CUSTOM_TILE_SPEC.equals(spec)) {
return mCustomTile;
} else {
@@ -283,6 +287,12 @@
assertEquals(1, specs.size());
}
+ @Test
+ public void testNotAvailableTile_specNotNull() {
+ mQSTileHost.onTuningChanged(QSTileHost.TILES_SETTING, "na");
+ verify(mQSLogger, never()).logTileDestroyed(isNull(), anyString());
+ }
+
private static class TestQSTileHost extends QSTileHost {
TestQSTileHost(Context context, StatusBarIconController iconController,
QSFactoryImpl defaultFactory, Handler mainHandler, Looper bgLooper,
@@ -369,4 +379,16 @@
super(host);
}
}
+
+ private class NotAvailableTile extends TestTile {
+
+ protected NotAvailableTile(QSHost host) {
+ super(host);
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return false;
+ }
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInterruptionStateProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
similarity index 63%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInterruptionStateProviderTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
index 1693e7f..f9c62e1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInterruptionStateProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.systemui.statusbar;
+package com.android.systemui.statusbar.notification.interruption;
import static android.app.Notification.FLAG_BUBBLE;
@@ -30,15 +30,14 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Notification;
import android.app.PendingIntent;
-import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Icon;
import android.hardware.display.AmbientDisplayConfiguration;
+import android.os.Handler;
import android.os.PowerManager;
import android.os.RemoteException;
import android.service.dreams.IDreamManager;
@@ -50,7 +49,6 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.notification.NotificationFilter;
-import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.policy.BatteryController;
@@ -68,7 +66,7 @@
*/
@RunWith(AndroidTestingRunner.class)
@SmallTest
-public class NotificationInterruptionStateProviderTest extends SysuiTestCase {
+public class NotificationInterruptStateProviderImplTest extends SysuiTestCase {
@Mock
PowerManager mPowerManager;
@@ -81,38 +79,36 @@
@Mock
StatusBarStateController mStatusBarStateController;
@Mock
- NotificationPresenter mPresenter;
- @Mock
HeadsUpManager mHeadsUpManager;
@Mock
- NotificationInterruptionStateProvider.HeadsUpSuppressor mHeadsUpSuppressor;
- @Mock
BatteryController mBatteryController;
+ @Mock
+ Handler mMockHandler;
- private NotificationInterruptionStateProvider mNotifInterruptionStateProvider;
+ private NotificationInterruptStateProviderImpl mNotifInterruptionStateProvider;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
mNotifInterruptionStateProvider =
- new TestableNotificationInterruptionStateProvider(mContext,
+ new NotificationInterruptStateProviderImpl(
+ mContext.getContentResolver(),
mPowerManager,
mDreamManager,
mAmbientDisplayConfiguration,
mNotificationFilter,
+ mBatteryController,
mStatusBarStateController,
- mBatteryController);
+ mHeadsUpManager,
+ mMockHandler);
- mNotifInterruptionStateProvider.setUpWithPresenter(
- mPresenter,
- mHeadsUpManager,
- mHeadsUpSuppressor);
+ mNotifInterruptionStateProvider.mUseHeadsUp = true;
}
/**
* Sets up the state such that any requests to
- * {@link NotificationInterruptionStateProvider#canAlertCommon(NotificationEntry)} will
+ * {@link NotificationInterruptStateProviderImpl#canAlertCommon(NotificationEntry)} will
* pass as long its provided NotificationEntry fulfills group suppression check.
*/
private void ensureStateForAlertCommon() {
@@ -121,17 +117,16 @@
/**
* Sets up the state such that any requests to
- * {@link NotificationInterruptionStateProvider#canAlertAwakeCommon(NotificationEntry)} will
+ * {@link NotificationInterruptStateProviderImpl#canAlertAwakeCommon(NotificationEntry)} will
* pass as long its provided NotificationEntry fulfills launch fullscreen check.
*/
private void ensureStateForAlertAwakeCommon() {
- when(mPresenter.isDeviceInVrMode()).thenReturn(false);
when(mHeadsUpManager.isSnoozed(any())).thenReturn(false);
}
/**
* Sets up the state such that any requests to
- * {@link NotificationInterruptionStateProvider#shouldHeadsUp(NotificationEntry)} will
+ * {@link NotificationInterruptStateProviderImpl#shouldHeadsUp(NotificationEntry)} will
* pass as long its provided NotificationEntry fulfills importance & DND checks.
*/
private void ensureStateForHeadsUpWhenAwake() throws RemoteException {
@@ -141,12 +136,11 @@
when(mStatusBarStateController.isDozing()).thenReturn(false);
when(mDreamManager.isDreaming()).thenReturn(false);
when(mPowerManager.isScreenOn()).thenReturn(true);
- when(mHeadsUpSuppressor.canHeadsUp(any(), any())).thenReturn(true);
}
/**
* Sets up the state such that any requests to
- * {@link NotificationInterruptionStateProvider#shouldHeadsUp(NotificationEntry)} will
+ * {@link NotificationInterruptStateProviderImpl#shouldHeadsUp(NotificationEntry)} will
* pass as long its provided NotificationEntry fulfills importance & DND checks.
*/
private void ensureStateForHeadsUpWhenDozing() {
@@ -158,7 +152,7 @@
/**
* Sets up the state such that any requests to
- * {@link NotificationInterruptionStateProvider#shouldBubbleUp(NotificationEntry)} will
+ * {@link NotificationInterruptStateProviderImpl#shouldBubbleUp(NotificationEntry)} will
* pass as long its provided NotificationEntry fulfills importance & bubble checks.
*/
private void ensureStateForBubbleUp() {
@@ -166,75 +160,53 @@
ensureStateForAlertAwakeCommon();
}
- /**
- * Ensure that the disabled state is set correctly.
- */
@Test
- public void testDisableNotificationAlerts() {
- // Enabled by default
- assertThat(mNotifInterruptionStateProvider.areNotificationAlertsDisabled()).isFalse();
-
- // Disable alerts
- mNotifInterruptionStateProvider.setDisableNotificationAlerts(true);
- assertThat(mNotifInterruptionStateProvider.areNotificationAlertsDisabled()).isTrue();
-
- // Enable alerts
- mNotifInterruptionStateProvider.setDisableNotificationAlerts(false);
- assertThat(mNotifInterruptionStateProvider.areNotificationAlertsDisabled()).isFalse();
- }
-
- /**
- * Ensure that the disabled alert state effects whether HUNs are enabled.
- */
- @Test
- public void testHunSettingsChange_enabled_butAlertsDisabled() {
- // Set up but without a mock change observer
- mNotifInterruptionStateProvider.setUpWithPresenter(
- mPresenter,
- mHeadsUpManager,
- mHeadsUpSuppressor);
-
- // HUNs enabled by default
- assertThat(mNotifInterruptionStateProvider.getUseHeadsUp()).isTrue();
-
- // Set alerts disabled
- mNotifInterruptionStateProvider.setDisableNotificationAlerts(true);
-
- // No more HUNs
- assertThat(mNotifInterruptionStateProvider.getUseHeadsUp()).isFalse();
- }
-
- /**
- * Alerts can happen.
- */
- @Test
- public void testCanAlertCommon_true() {
- ensureStateForAlertCommon();
+ public void testDefaultSuppressorDoesNotSuppress() {
+ // GIVEN a suppressor without any overrides
+ final NotificationInterruptSuppressor defaultSuppressor =
+ new NotificationInterruptSuppressor() {
+ @Override
+ public String getName() {
+ return "defaultSuppressor";
+ }
+ };
NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
- assertThat(mNotifInterruptionStateProvider.canAlertCommon(entry)).isTrue();
+
+ // THEN this suppressor doesn't suppress anything by default
+ assertThat(defaultSuppressor.suppressAwakeHeadsUp(entry)).isFalse();
+ assertThat(defaultSuppressor.suppressAwakeInterruptions(entry)).isFalse();
+ assertThat(defaultSuppressor.suppressInterruptions(entry)).isFalse();
}
- /**
- * Filtered out notifications don't alert.
- */
@Test
- public void testCanAlertCommon_false_filteredOut() {
- ensureStateForAlertCommon();
- when(mNotificationFilter.shouldFilterOut(any())).thenReturn(true);
+ public void testShouldHeadsUpAwake() throws RemoteException {
+ ensureStateForHeadsUpWhenAwake();
- NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
- assertThat(mNotifInterruptionStateProvider.canAlertCommon(entry)).isFalse();
+ NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
+ assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isTrue();
}
- /**
- * Grouped notifications have different alerting behaviours, sometimes the alert for a
- * grouped notification may be suppressed {@link android.app.Notification#GROUP_ALERT_CHILDREN}.
- */
@Test
- public void testCanAlertCommon_false_suppressedForGroups() {
- ensureStateForAlertCommon();
+ public void testShouldNotHeadsUpAwake_flteredOut() throws RemoteException {
+ // GIVEN state for "heads up when awake" is true
+ ensureStateForHeadsUpWhenAwake();
+ // WHEN this entry should be filtered out
+ NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
+ when(mNotificationFilter.shouldFilterOut(entry)).thenReturn(true);
+
+ // THEN we shouldn't heads up this entry
+ assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
+ }
+
+ @Test
+ public void testShouldNotHeadsUp_suppressedForGroups() throws RemoteException {
+ // GIVEN state for "heads up when awake" is true
+ ensureStateForHeadsUpWhenAwake();
+
+ // WHEN the alert for a grouped notification is suppressed
+ // see {@link android.app.Notification#GROUP_ALERT_CHILDREN}
NotificationEntry entry = new NotificationEntryBuilder()
.setPkg("a")
.setOpPkg("a")
@@ -247,40 +219,40 @@
.setImportance(IMPORTANCE_DEFAULT)
.build();
- assertThat(mNotifInterruptionStateProvider.canAlertCommon(entry)).isFalse();
+ // THEN this entry shouldn't HUN
+ assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
}
- /**
- * HUNs while dozing can happen.
- */
@Test
- public void testShouldHeadsUpWhenDozing_true() {
+ public void testShouldHeadsUpWhenDozing() {
ensureStateForHeadsUpWhenDozing();
NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isTrue();
}
- /**
- * Ambient display can show HUNs for new notifications, this may be disabled.
- */
@Test
- public void testShouldHeadsUpWhenDozing_false_pulseDisabled() {
+ public void testShouldNotHeadsUpWhenDozing_pulseDisabled() {
+ // GIVEN state for "heads up when dozing" is true
ensureStateForHeadsUpWhenDozing();
+
+ // WHEN pulsing (HUNs when dozing) is disabled
when(mAmbientDisplayConfiguration.pulseOnNotificationEnabled(anyInt())).thenReturn(false);
+ // THEN this entry shouldn't HUN
NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
}
- /**
- * If the device is not in ambient display or sleeping then we don't HUN.
- */
@Test
- public void testShouldHeadsUpWhenDozing_false_notDozing() {
+ public void testShouldNotHeadsUpWhenDozing_notDozing() {
+ // GIVEN state for "heads up when dozing" is true
ensureStateForHeadsUpWhenDozing();
+
+ // WHEN we're not dozing (in ambient display or sleeping)
when(mStatusBarStateController.isDozing()).thenReturn(false);
+ // THEN this entry shouldn't HUN
NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
}
@@ -290,7 +262,7 @@
* {@link android.app.NotificationManager.Policy#SUPPRESSED_EFFECT_AMBIENT}.
*/
@Test
- public void testShouldHeadsUpWhenDozing_false_suppressingAmbient() {
+ public void testShouldNotHeadsUpWhenDozing_suppressingAmbient() {
ensureStateForHeadsUpWhenDozing();
NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
@@ -301,23 +273,18 @@
assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
}
- /**
- * Notifications that are < {@link android.app.NotificationManager#IMPORTANCE_DEFAULT} don't
- * get to pulse.
- */
@Test
- public void testShouldHeadsUpWhenDozing_false_lessImportant() {
+ public void testShouldNotHeadsUpWhenDozing_lessImportant() {
ensureStateForHeadsUpWhenDozing();
+ // Notifications that are < {@link android.app.NotificationManager#IMPORTANCE_DEFAULT} don't
+ // get to pulse
NotificationEntry entry = createNotification(IMPORTANCE_LOW);
assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
}
- /**
- * Heads up can happen.
- */
@Test
- public void testShouldHeadsUp_true() throws RemoteException {
+ public void testShouldHeadsUp() throws RemoteException {
ensureStateForHeadsUpWhenAwake();
NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
@@ -325,38 +292,11 @@
}
/**
- * Heads up notifications can be disabled in general.
- */
- @Test
- public void testShouldHeadsUp_false_noHunsAllowed() throws RemoteException {
- ensureStateForHeadsUpWhenAwake();
-
- // Set alerts disabled, this should cause heads up to be false
- mNotifInterruptionStateProvider.setDisableNotificationAlerts(true);
- assertThat(mNotifInterruptionStateProvider.getUseHeadsUp()).isFalse();
-
- NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
- assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
- }
-
- /**
- * If the device is dozing, we don't show as heads up.
- */
- @Test
- public void testShouldHeadsUp_false_dozing() throws RemoteException {
- ensureStateForHeadsUpWhenAwake();
- when(mStatusBarStateController.isDozing()).thenReturn(true);
-
- NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
- assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
- }
-
- /**
* If the notification is a bubble, and the user is not on AOD / lockscreen, then
* the bubble is shown rather than the heads up.
*/
@Test
- public void testShouldHeadsUp_false_bubble() throws RemoteException {
+ public void testShouldNotHeadsUp_bubble() throws RemoteException {
ensureStateForHeadsUpWhenAwake();
// Bubble bit only applies to interruption when we're in the shade
@@ -369,7 +309,7 @@
* If we're not allowed to alert in general, we shouldn't be shown as heads up.
*/
@Test
- public void testShouldHeadsUp_false_alertCommonFalse() throws RemoteException {
+ public void testShouldNotHeadsUp_filtered() throws RemoteException {
ensureStateForHeadsUpWhenAwake();
// Make canAlertCommon false by saying it's filtered out
when(mNotificationFilter.shouldFilterOut(any())).thenReturn(true);
@@ -383,7 +323,7 @@
* {@link android.app.NotificationManager.Policy#SUPPRESSED_EFFECT_PEEK}.
*/
@Test
- public void testShouldHeadsUp_false_suppressPeek() throws RemoteException {
+ public void testShouldNotHeadsUp_suppressPeek() throws RemoteException {
ensureStateForHeadsUpWhenAwake();
NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
@@ -399,7 +339,7 @@
* to show as a heads up.
*/
@Test
- public void testShouldHeadsUp_false_lessImportant() throws RemoteException {
+ public void testShouldNotHeadsUp_lessImportant() throws RemoteException {
ensureStateForHeadsUpWhenAwake();
NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
@@ -410,7 +350,7 @@
* If the device is not in use then we shouldn't be shown as heads up.
*/
@Test
- public void testShouldHeadsUp_false_deviceNotInUse() throws RemoteException {
+ public void testShouldNotHeadsUp_deviceNotInUse() throws RemoteException {
ensureStateForHeadsUpWhenAwake();
NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
@@ -424,61 +364,58 @@
assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
}
- /**
- * If something wants to suppress this heads up, then it shouldn't be shown as a heads up.
- */
@Test
- public void testShouldHeadsUp_false_suppressed() throws RemoteException {
+ public void testShouldNotHeadsUp_headsUpSuppressed() throws RemoteException {
ensureStateForHeadsUpWhenAwake();
- when(mHeadsUpSuppressor.canHeadsUp(any(), any())).thenReturn(false);
+
+ // If a suppressor is suppressing heads up, then it shouldn't be shown as a heads up.
+ mNotifInterruptionStateProvider.addSuppressor(mSuppressAwakeHeadsUp);
NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
- verify(mHeadsUpSuppressor).canHeadsUp(any(), any());
}
- /**
- * On screen alerts don't happen when the device is in VR Mode.
- */
@Test
- public void testCanAlertAwakeCommon__false_vrMode() {
- ensureStateForAlertAwakeCommon();
- when(mPresenter.isDeviceInVrMode()).thenReturn(true);
+ public void testShouldNotHeadsUpAwake_awakeInterruptsSuppressed() throws RemoteException {
+ ensureStateForHeadsUpWhenAwake();
- NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
- assertThat(mNotifInterruptionStateProvider.canAlertAwakeCommon(entry)).isFalse();
+ // If a suppressor is suppressing heads up, then it shouldn't be shown as a heads up.
+ mNotifInterruptionStateProvider.addSuppressor(mSuppressAwakeInterruptions);
+
+ NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
+ assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
}
/**
* On screen alerts don't happen when the notification is snoozed.
*/
@Test
- public void testCanAlertAwakeCommon_false_snoozedPackage() {
- ensureStateForAlertAwakeCommon();
- when(mHeadsUpManager.isSnoozed(any())).thenReturn(true);
-
+ public void testShouldNotHeadsUp_snoozedPackage() {
NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
- assertThat(mNotifInterruptionStateProvider.canAlertAwakeCommon(entry)).isFalse();
+ ensureStateForAlertAwakeCommon();
+
+ when(mHeadsUpManager.isSnoozed(entry.getSbn().getPackageName())).thenReturn(true);
+
+ assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
}
- /**
- * On screen alerts don't happen when that package has just launched fullscreen.
- */
+
@Test
- public void testCanAlertAwakeCommon_false_justLaunchedFullscreen() {
+ public void testShouldNotHeadsUp_justLaunchedFullscreen() {
ensureStateForAlertAwakeCommon();
+ // On screen alerts don't happen when that package has just launched fullscreen.
NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
entry.notifyFullScreenIntentLaunched();
- assertThat(mNotifInterruptionStateProvider.canAlertAwakeCommon(entry)).isFalse();
+ assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
}
/**
* Bubbles can happen.
*/
@Test
- public void testShouldBubbleUp_true() {
+ public void testShouldBubbleUp() {
ensureStateForBubbleUp();
assertThat(mNotifInterruptionStateProvider.shouldBubbleUp(createBubble())).isTrue();
}
@@ -487,7 +424,7 @@
* If the notification doesn't have permission to bubble, it shouldn't bubble.
*/
@Test
- public void shouldBubbleUp_false_notAllowedToBubble() {
+ public void shouldNotBubbleUp_notAllowedToBubble() {
ensureStateForBubbleUp();
NotificationEntry entry = createBubble();
@@ -502,7 +439,7 @@
* If the notification isn't a bubble, it should definitely not show as a bubble.
*/
@Test
- public void shouldBubbleUp_false_notABubble() {
+ public void shouldNotBubbleUp_notABubble() {
ensureStateForBubbleUp();
NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
@@ -517,7 +454,7 @@
* If the notification doesn't have bubble metadata, it shouldn't bubble.
*/
@Test
- public void shouldBubbleUp_false_invalidMetadata() {
+ public void shouldNotBubbleUp_invalidMetadata() {
ensureStateForBubbleUp();
NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
@@ -529,24 +466,18 @@
assertThat(mNotifInterruptionStateProvider.shouldBubbleUp(entry)).isFalse();
}
- /**
- * If the notification can't heads up in general, it shouldn't bubble.
- */
@Test
- public void shouldBubbleUp_false_alertAwakeCommonFalse() {
+ public void shouldNotBubbleUp_suppressedInterruptions() {
ensureStateForBubbleUp();
- // Make alert common return false by pretending we're in VR mode
- when(mPresenter.isDeviceInVrMode()).thenReturn(true);
+ // If the notification can't heads up in general, it shouldn't bubble.
+ mNotifInterruptionStateProvider.addSuppressor(mSuppressInterruptions);
assertThat(mNotifInterruptionStateProvider.shouldBubbleUp(createBubble())).isFalse();
}
- /**
- * If the notification can't heads up in general, it shouldn't bubble.
- */
@Test
- public void shouldBubbleUp_false_alertCommonFalse() {
+ public void shouldNotBubbleUp_filteredOut() {
ensureStateForBubbleUp();
// Make canAlertCommon false by saying it's filtered out
@@ -592,20 +523,45 @@
.build();
}
- /**
- * Testable class overriding constructor.
- */
- public static class TestableNotificationInterruptionStateProvider extends
- NotificationInterruptionStateProvider {
-
- TestableNotificationInterruptionStateProvider(Context context,
- PowerManager powerManager, IDreamManager dreamManager,
- AmbientDisplayConfiguration ambientDisplayConfiguration,
- NotificationFilter notificationFilter,
- StatusBarStateController statusBarStateController,
- BatteryController batteryController) {
- super(context, powerManager, dreamManager, ambientDisplayConfiguration,
- notificationFilter, batteryController, statusBarStateController);
+ private final NotificationInterruptSuppressor
+ mSuppressAwakeHeadsUp =
+ new NotificationInterruptSuppressor() {
+ @Override
+ public String getName() {
+ return "suppressAwakeHeadsUp";
}
- }
+
+ @Override
+ public boolean suppressAwakeHeadsUp(NotificationEntry entry) {
+ return true;
+ }
+ };
+
+ private final NotificationInterruptSuppressor
+ mSuppressAwakeInterruptions =
+ new NotificationInterruptSuppressor() {
+ @Override
+ public String getName() {
+ return "suppressAwakeInterruptions";
+ }
+
+ @Override
+ public boolean suppressAwakeInterruptions(NotificationEntry entry) {
+ return true;
+ }
+ };
+
+ private final NotificationInterruptSuppressor
+ mSuppressInterruptions =
+ new NotificationInterruptSuppressor() {
+ @Override
+ public String getName() {
+ return "suppressInterruptions";
+ }
+
+ @Override
+ public boolean suppressInterruptions(NotificationEntry entry) {
+ return true;
+ }
+ };
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
index 5d0349d..a21a047 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java
@@ -56,12 +56,12 @@
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationEntryManagerLogger;
import com.android.systemui.statusbar.notification.NotificationFilter;
-import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
@@ -108,7 +108,7 @@
@Mock private NotificationEntryListener mEntryListener;
@Mock private NotificationRowBinderImpl.BindRowCallback mBindCallback;
@Mock private HeadsUpManager mHeadsUpManager;
- @Mock private NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
+ @Mock private NotificationInterruptStateProvider mNotificationInterruptionStateProvider;
@Mock private NotificationLockscreenUserManager mLockscreenUserManager;
@Mock private NotificationGutsManager mGutsManager;
@Mock private NotificationRemoteInputManager mRemoteInputManager;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextViewTest.java
new file mode 100644
index 0000000..291c039
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardIndicationTextViewTest.java
@@ -0,0 +1,68 @@
+/*
+ * 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.phone;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.View;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class KeyguardIndicationTextViewTest extends SysuiTestCase {
+
+ private KeyguardIndicationTextView mKeyguardIndicationTextView;
+
+ @Before
+ public void setup() {
+ mKeyguardIndicationTextView = new KeyguardIndicationTextView(mContext);
+ }
+
+ @Test
+ public void switchIndication_null_hideIndication() {
+ mKeyguardIndicationTextView.switchIndication(null /* text */);
+
+ assertThat(mKeyguardIndicationTextView.getVisibility()).isEqualTo(View.INVISIBLE);
+ assertThat(mKeyguardIndicationTextView.getText()).isEqualTo("");
+ }
+
+ @Test
+ public void switchIndication_emptyText_hideIndication() {
+ mKeyguardIndicationTextView.switchIndication("" /* text */);
+
+ assertThat(mKeyguardIndicationTextView.getVisibility()).isEqualTo(View.INVISIBLE);
+ assertThat(mKeyguardIndicationTextView.getText()).isEqualTo("");
+ }
+
+ @Test
+ public void switchIndication_newText_updateProperly() {
+ mKeyguardIndicationTextView.switchIndication("test_indication" /* text */);
+
+ assertThat(mKeyguardIndicationTextView.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mKeyguardIndicationTextView.getText()).isEqualTo("test_indication");
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
index c5b6969..cc2d1c2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationShadeWindowViewTest.java
@@ -37,7 +37,7 @@
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.DragDownHelper;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.NotificationShadeWindowBlurController;
+import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.PulseExpansionHandler;
import com.android.systemui.statusbar.SuperStatusBarViewFactory;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
@@ -81,7 +81,7 @@
@Mock private DockManager mDockManager;
@Mock private NotificationPanelViewController mNotificationPanelViewController;
@Mock private NotificationStackScrollLayout mNotificationStackScrollLayout;
- @Mock private NotificationShadeWindowBlurController mNotificationShadeWindowBlurController;
+ @Mock private NotificationShadeDepthController mNotificationShadeDepthController;
@Mock private SuperStatusBarViewFactory mStatusBarViewFactory;
@Before
@@ -116,7 +116,7 @@
new CommandQueue(mContext),
mShadeController,
mDockManager,
- mNotificationShadeWindowBlurController,
+ mNotificationShadeDepthController,
mView,
mNotificationPanelViewController,
mStatusBarViewFactory);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
index 1e4df27..b9c5b7c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
@@ -67,10 +67,10 @@
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -183,7 +183,7 @@
mock(StatusBarRemoteInputCallback.class), mock(NotificationGroupManager.class),
mock(NotificationLockscreenUserManager.class),
mKeyguardStateController,
- mock(NotificationInterruptionStateProvider.class), mock(MetricsLogger.class),
+ mock(NotificationInterruptStateProvider.class), mock(MetricsLogger.class),
mock(LockPatternUtils.class), mHandler, mHandler, mUiBgExecutor,
mActivityIntentHelper, mBubbleController, mShadeController, mFeatureFlags,
mNotifPipeline, mNotifCollection)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
index b9d2d22..318e9b8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
@@ -16,8 +16,9 @@
import static android.view.Display.DEFAULT_DISPLAY;
-import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Notification;
@@ -35,6 +36,7 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.logging.testing.FakeMetricsLogger;
+import com.android.systemui.ForegroundServiceNotificationListener;
import com.android.systemui.InitController;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -48,12 +50,12 @@
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
-import com.android.systemui.statusbar.notification.NotificationAlertingManager;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptSuppressor;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
@@ -62,6 +64,7 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import java.util.ArrayList;
@@ -72,6 +75,9 @@
private StatusBarNotificationPresenter mStatusBarNotificationPresenter;
+ private NotificationInterruptStateProvider mNotificationInterruptStateProvider =
+ mock(NotificationInterruptStateProvider.class);
+ private NotificationInterruptSuppressor mInterruptSuppressor;
private CommandQueue mCommandQueue;
private FakeMetricsLogger mMetricsLogger;
private ShadeController mShadeController = mock(ShadeController.class);
@@ -95,11 +101,11 @@
mDependency.injectMockDependency(NotificationViewHierarchyManager.class);
mDependency.injectMockDependency(NotificationRemoteInputManager.Callback.class);
mDependency.injectMockDependency(NotificationLockscreenUserManager.class);
- mDependency.injectMockDependency(NotificationInterruptionStateProvider.class);
mDependency.injectMockDependency(NotificationMediaManager.class);
mDependency.injectMockDependency(VisualStabilityManager.class);
mDependency.injectMockDependency(NotificationGutsManager.class);
mDependency.injectMockDependency(NotificationShadeWindowController.class);
+ mDependency.injectMockDependency(ForegroundServiceNotificationListener.class);
NotificationEntryManager entryManager =
mDependency.injectMockDependency(NotificationEntryManager.class);
when(entryManager.getActiveNotificationsForCurrentUser()).thenReturn(new ArrayList<>());
@@ -107,18 +113,25 @@
NotificationShadeWindowView notificationShadeWindowView =
mock(NotificationShadeWindowView.class);
when(notificationShadeWindowView.getResources()).thenReturn(mContext.getResources());
+
mStatusBarNotificationPresenter = new StatusBarNotificationPresenter(mContext,
mock(NotificationPanelViewController.class), mock(HeadsUpManagerPhone.class),
notificationShadeWindowView, mock(NotificationListContainerViewGroup.class),
mock(DozeScrimController.class), mock(ScrimController.class),
mock(ActivityLaunchAnimator.class), mock(DynamicPrivacyController.class),
- mock(NotificationAlertingManager.class), mock(KeyguardStateController.class),
+ mock(KeyguardStateController.class),
mock(KeyguardIndicationController.class), mStatusBar,
- mock(ShadeControllerImpl.class), mCommandQueue, mInitController);
+ mock(ShadeControllerImpl.class), mCommandQueue, mInitController,
+ mNotificationInterruptStateProvider);
+ mInitController.executePostInitTasks();
+ ArgumentCaptor<NotificationInterruptSuppressor> suppressorCaptor =
+ ArgumentCaptor.forClass(NotificationInterruptSuppressor.class);
+ verify(mNotificationInterruptStateProvider).addSuppressor(suppressorCaptor.capture());
+ mInterruptSuppressor = suppressorCaptor.getValue();
}
@Test
- public void testHeadsUp_disabledStatusBar() {
+ public void testSuppressHeadsUp_disabledStatusBar() {
Notification n = new Notification.Builder(getContext(), "a").build();
NotificationEntry entry = new NotificationEntryBuilder()
.setPkg("a")
@@ -130,12 +143,12 @@
false /* animate */);
TestableLooper.get(this).processAllMessages();
- assertFalse("The panel shouldn't allow heads up while disabled",
- mStatusBarNotificationPresenter.canHeadsUp(entry, entry.getSbn()));
+ assertTrue("The panel should suppress heads up while disabled",
+ mInterruptSuppressor.suppressAwakeHeadsUp(entry));
}
@Test
- public void testHeadsUp_disabledNotificationShade() {
+ public void testSuppressHeadsUp_disabledNotificationShade() {
Notification n = new Notification.Builder(getContext(), "a").build();
NotificationEntry entry = new NotificationEntryBuilder()
.setPkg("a")
@@ -147,8 +160,39 @@
false /* animate */);
TestableLooper.get(this).processAllMessages();
- assertFalse("The panel shouldn't allow heads up while notitifcation shade disabled",
- mStatusBarNotificationPresenter.canHeadsUp(entry, entry.getSbn()));
+ assertTrue("The panel should suppress interruptions while notification shade "
+ + "disabled",
+ mInterruptSuppressor.suppressAwakeHeadsUp(entry));
+ }
+
+ @Test
+ public void testSuppressInterruptions_vrMode() {
+ Notification n = new Notification.Builder(getContext(), "a").build();
+ NotificationEntry entry = new NotificationEntryBuilder()
+ .setPkg("a")
+ .setOpPkg("a")
+ .setTag("a")
+ .setNotification(n)
+ .build();
+ mStatusBarNotificationPresenter.mVrMode = true;
+
+ assertTrue("Vr mode should suppress interruptions",
+ mInterruptSuppressor.suppressAwakeInterruptions(entry));
+ }
+
+ @Test
+ public void testSuppressInterruptions_statusBarAlertsDisabled() {
+ Notification n = new Notification.Builder(getContext(), "a").build();
+ NotificationEntry entry = new NotificationEntryBuilder()
+ .setPkg("a")
+ .setOpPkg("a")
+ .setTag("a")
+ .setNotification(n)
+ .build();
+ when(mStatusBar.areNotificationAlertsDisabled()).thenReturn(true);
+
+ assertTrue("StatusBar alerts disabled shouldn't allow interruptions",
+ mInterruptSuppressor.suppressInterruptions(entry));
}
@Test
@@ -172,4 +216,3 @@
}
}
}
-
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index e407927..679ac22 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -42,7 +42,7 @@
import android.app.StatusBarManager;
import android.app.trust.TrustManager;
import android.content.BroadcastReceiver;
-import android.content.Context;
+import android.content.ContentResolver;
import android.content.IntentFilter;
import android.hardware.display.AmbientDisplayConfiguration;
import android.hardware.fingerprint.FingerprintManager;
@@ -109,18 +109,18 @@
import com.android.systemui.statusbar.StatusBarStateControllerImpl;
import com.android.systemui.statusbar.SuperStatusBarViewFactory;
import com.android.systemui.statusbar.VibratorHelper;
-import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
-import com.android.systemui.statusbar.notification.NotificationAlertingManager;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationFilter;
-import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.init.NotificationsController;
+import com.android.systemui.statusbar.notification.interruption.BypassHeadsUpNotifier;
+import com.android.systemui.statusbar.notification.interruption.NotificationAlertingManager;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.logging.NotificationPanelLoggerFake;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
@@ -130,6 +130,7 @@
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.ExtensionController;
+import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
@@ -161,7 +162,7 @@
private StatusBar mStatusBar;
private FakeMetricsLogger mMetricsLogger;
private PowerManager mPowerManager;
- private TestableNotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
+ private TestableNotificationInterruptStateProviderImpl mNotificationInterruptStateProvider;
@Mock private NotificationsController mNotificationsController;
@Mock private LightBarController mLightBarController;
@@ -179,7 +180,6 @@
@Mock private DozeScrimController mDozeScrimController;
@Mock private Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy;
@Mock private BiometricUnlockController mBiometricUnlockController;
- @Mock private NotificationInterruptionStateProvider.HeadsUpSuppressor mHeadsUpSuppressor;
@Mock private VisualStabilityManager mVisualStabilityManager;
@Mock private NotificationListener mNotificationListener;
@Mock private KeyguardViewMediator mKeyguardViewMediator;
@@ -193,9 +193,9 @@
@Mock private NotificationEntryListener mEntryListener;
@Mock private NotificationFilter mNotificationFilter;
@Mock private NotificationAlertingManager mNotificationAlertingManager;
+ @Mock private AmbientDisplayConfiguration mAmbientDisplayConfiguration;
@Mock private NotificationLogger.ExpansionStateLogger mExpansionStateLogger;
@Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
- @Mock private AmbientDisplayConfiguration mAmbientDisplayConfiguration;
@Mock private NotificationShadeWindowView mNotificationShadeWindowView;
@Mock private BroadcastDispatcher mBroadcastDispatcher;
@Mock private AssistManager mAssistManager;
@@ -263,10 +263,12 @@
mPowerManager = new PowerManager(mContext, powerManagerService, thermalService,
Handler.createAsync(Looper.myLooper()));
- mNotificationInterruptionStateProvider =
- new TestableNotificationInterruptionStateProvider(mContext, mPowerManager,
+ mNotificationInterruptStateProvider =
+ new TestableNotificationInterruptStateProviderImpl(mContext.getContentResolver(),
+ mPowerManager,
mDreamManager, mAmbientDisplayConfiguration, mNotificationFilter,
- mStatusBarStateController, mBatteryController);
+ mStatusBarStateController, mBatteryController, mHeadsUpManager,
+ new Handler(TestableLooper.get(this).getLooper()));
mContext.addMockSystemService(TrustManager.class, mock(TrustManager.class));
mContext.addMockSystemService(FingerprintManager.class, mock(FingerprintManager.class));
@@ -299,9 +301,6 @@
return null;
}).when(mStatusBarKeyguardViewManager).addAfterKeyguardGoneRunnable(any());
- mNotificationInterruptionStateProvider.setUpWithPresenter(mNotificationPresenter,
- mHeadsUpManager, mHeadsUpSuppressor);
-
when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController);
WakefulnessLifecycle wakefulnessLifecycle = new WakefulnessLifecycle();
@@ -348,7 +347,7 @@
),
mNotificationGutsManager,
notificationLogger,
- mNotificationInterruptionStateProvider,
+ mNotificationInterruptStateProvider,
mNotificationViewHierarchyManager,
mKeyguardViewMediator,
mNotificationAlertingManager,
@@ -562,7 +561,6 @@
when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
when(mNotificationFilter.shouldFilterOut(any())).thenReturn(false);
when(mDreamManager.isDreaming()).thenReturn(false);
- when(mHeadsUpSuppressor.canHeadsUp(any(), any())).thenReturn(true);
Notification n = new Notification.Builder(getContext(), "a")
.setGroup("a")
@@ -578,7 +576,7 @@
.setImportance(IMPORTANCE_HIGH)
.build();
- assertTrue(mNotificationInterruptionStateProvider.shouldHeadsUp(entry));
+ assertTrue(mNotificationInterruptStateProvider.shouldHeadsUp(entry));
}
@Test
@@ -587,7 +585,6 @@
when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
when(mNotificationFilter.shouldFilterOut(any())).thenReturn(false);
when(mDreamManager.isDreaming()).thenReturn(false);
- when(mHeadsUpSuppressor.canHeadsUp(any(), any())).thenReturn(true);
Notification n = new Notification.Builder(getContext(), "a")
.setGroup("a")
@@ -603,7 +600,7 @@
.setImportance(IMPORTANCE_HIGH)
.build();
- assertFalse(mNotificationInterruptionStateProvider.shouldHeadsUp(entry));
+ assertFalse(mNotificationInterruptStateProvider.shouldHeadsUp(entry));
}
@Test
@@ -612,7 +609,6 @@
when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
when(mNotificationFilter.shouldFilterOut(any())).thenReturn(false);
when(mDreamManager.isDreaming()).thenReturn(false);
- when(mHeadsUpSuppressor.canHeadsUp(any(), any())).thenReturn(true);
Notification n = new Notification.Builder(getContext(), "a").build();
@@ -625,7 +621,7 @@
.setSuppressedVisualEffects(SUPPRESSED_EFFECT_PEEK)
.build();
- assertFalse(mNotificationInterruptionStateProvider.shouldHeadsUp(entry));
+ assertFalse(mNotificationInterruptStateProvider.shouldHeadsUp(entry));
}
@Test
@@ -634,7 +630,6 @@
when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false);
when(mNotificationFilter.shouldFilterOut(any())).thenReturn(false);
when(mDreamManager.isDreaming()).thenReturn(false);
- when(mHeadsUpSuppressor.canHeadsUp(any(), any())).thenReturn(true);
Notification n = new Notification.Builder(getContext(), "a").build();
@@ -646,7 +641,7 @@
.setImportance(IMPORTANCE_HIGH)
.build();
- assertTrue(mNotificationInterruptionStateProvider.shouldHeadsUp(entry));
+ assertTrue(mNotificationInterruptStateProvider.shouldHeadsUp(entry));
}
@Test
@@ -872,19 +867,21 @@
verify(mDozeServiceHost).setDozeSuppressed(false);
}
- public static class TestableNotificationInterruptionStateProvider extends
- NotificationInterruptionStateProvider {
+ public static class TestableNotificationInterruptStateProviderImpl extends
+ NotificationInterruptStateProviderImpl {
- TestableNotificationInterruptionStateProvider(
- Context context,
+ TestableNotificationInterruptStateProviderImpl(
+ ContentResolver contentResolver,
PowerManager powerManager,
IDreamManager dreamManager,
AmbientDisplayConfiguration ambientDisplayConfiguration,
NotificationFilter filter,
StatusBarStateController controller,
- BatteryController batteryController) {
- super(context, powerManager, dreamManager, ambientDisplayConfiguration, filter,
- batteryController, controller);
+ BatteryController batteryController,
+ HeadsUpManager headsUpManager,
+ Handler mainHandler) {
+ super(contentResolver, powerManager, dreamManager, ambientDisplayConfiguration, filter,
+ batteryController, controller, headsUpManager, mainHandler);
mUseHeadsUp = true;
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index a0d551c..cddbb9f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -207,7 +207,7 @@
protected void setupNetworkController() {
// For now just pretend to be the data sim, so we can test that too.
mSubId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
- when(mMockTm.isDataConnectionEnabled()).thenReturn(true);
+ when(mMockTm.isDataConnectionAllowed()).thenReturn(true);
setDefaultSubId(mSubId);
setSubscriptions(mSubId);
mMobileSignalController = mNetworkController.mMobileSignalControllers.get(mSubId);
@@ -235,7 +235,7 @@
subs.add(subscription);
}
when(mMockSm.getActiveSubscriptionInfoList()).thenReturn(subs);
- when(mMockSm.getActiveAndHiddenSubscriptionInfoList()).thenReturn(subs);
+ when(mMockSm.getCompleteActiveSubscriptionInfoList()).thenReturn(subs);
mNetworkController.doUpdateMobileControllers();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
index 3eb0c44..d8b6aac 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
@@ -119,7 +119,7 @@
@Test
public void testNoInternetIcon_withDefaultSub() {
setupNetworkController();
- when(mMockTm.isDataConnectionEnabled()).thenReturn(false);
+ when(mMockTm.isDataConnectionAllowed()).thenReturn(false);
setupDefaultSignal();
updateDataConnectionState(TelephonyManager.DATA_CONNECTED, 0);
setConnectivityViaBroadcast(NetworkCapabilities.TRANSPORT_CELLULAR, false, false);
@@ -133,7 +133,7 @@
@Test
public void testDataDisabledIcon_withDefaultSub() {
setupNetworkController();
- when(mMockTm.isDataConnectionEnabled()).thenReturn(false);
+ when(mMockTm.isDataConnectionAllowed()).thenReturn(false);
setupDefaultSignal();
updateDataConnectionState(TelephonyManager.DATA_DISCONNECTED, 0);
setConnectivityViaBroadcast(NetworkCapabilities.TRANSPORT_CELLULAR, false, false);
@@ -147,7 +147,7 @@
@Test
public void testNonDefaultSIM_showsFullSignal_connected() {
setupNetworkController();
- when(mMockTm.isDataConnectionEnabled()).thenReturn(false);
+ when(mMockTm.isDataConnectionAllowed()).thenReturn(false);
setupDefaultSignal();
setDefaultSubId(mSubId + 1);
updateDataConnectionState(TelephonyManager.DATA_CONNECTED, 0);
@@ -162,7 +162,7 @@
@Test
public void testNonDefaultSIM_showsFullSignal_disconnected() {
setupNetworkController();
- when(mMockTm.isDataConnectionEnabled()).thenReturn(false);
+ when(mMockTm.isDataConnectionAllowed()).thenReturn(false);
setupDefaultSignal();
setDefaultSubId(mSubId + 1);
updateDataConnectionState(TelephonyManager.DATA_DISCONNECTED, 0);
@@ -177,7 +177,7 @@
@Test
public void testDataDisabledIcon_UserNotSetup() {
setupNetworkController();
- when(mMockTm.isDataConnectionEnabled()).thenReturn(false);
+ when(mMockTm.isDataConnectionAllowed()).thenReturn(false);
setupDefaultSignal();
updateDataConnectionState(TelephonyManager.DATA_DISCONNECTED, 0);
setConnectivityViaBroadcast(NetworkCapabilities.TRANSPORT_CELLULAR, false, false);
@@ -192,7 +192,7 @@
@Test
public void testAlwaysShowDataRatIcon() {
setupDefaultSignal();
- when(mMockTm.isDataConnectionEnabled()).thenReturn(false);
+ when(mMockTm.isDataConnectionAllowed()).thenReturn(false);
updateDataConnectionState(TelephonyManager.DATA_DISCONNECTED,
TelephonyManager.NETWORK_TYPE_GSM);
diff --git a/packages/Tethering/common/TetheringLib/Android.bp b/packages/Tethering/common/TetheringLib/Android.bp
index 5b73dd5..2fbba68 100644
--- a/packages/Tethering/common/TetheringLib/Android.bp
+++ b/packages/Tethering/common/TetheringLib/Android.bp
@@ -62,26 +62,14 @@
apex_available: ["com.android.tethering"],
}
-droidstubs {
- name: "framework-tethering-stubs-sources",
- defaults: ["framework-module-stubs-defaults-module_libs_api"],
+stubs_defaults {
+ name: "framework-tethering-stubs-defaults",
srcs: [
"src/android/net/TetheredClient.java",
"src/android/net/TetheringManager.java",
"src/android/net/TetheringConstants.java",
],
- libs: [
- "tethering-aidl-interfaces-java",
- "framework-all",
- ],
- sdk_version: "core_platform",
-}
-
-java_library {
- name: "framework-tethering-stubs",
- srcs: [":framework-tethering-stubs-sources"],
- libs: ["framework-all"],
- sdk_version: "core_platform",
+ libs: ["tethering-aidl-interfaces-java"],
}
filegroup {
@@ -101,3 +89,53 @@
],
path: "src"
}
+
+droidstubs {
+ name: "framework-tethering-stubs-srcs-publicapi",
+ defaults: [
+ "framework-module-stubs-defaults-publicapi",
+ "framework-tethering-stubs-defaults",
+ ],
+}
+
+droidstubs {
+ name: "framework-tethering-stubs-srcs-systemapi",
+ defaults: [
+ "framework-module-stubs-defaults-systemapi",
+ "framework-tethering-stubs-defaults",
+ ],
+}
+
+droidstubs {
+ name: "framework-tethering-api-module_libs_api",
+ defaults: [
+ "framework-module-api-defaults-module_libs_api",
+ "framework-tethering-stubs-defaults",
+ ],
+}
+
+droidstubs {
+ name: "framework-tethering-stubs-srcs-module_libs_api",
+ defaults: [
+ "framework-module-stubs-defaults-module_libs_api",
+ "framework-tethering-stubs-defaults",
+ ],
+}
+
+java_library {
+ name: "framework-tethering-stubs-publicapi",
+ srcs: [":framework-tethering-stubs-srcs-publicapi"],
+ sdk_version: "current",
+}
+
+java_library {
+ name: "framework-tethering-stubs-systemapi",
+ srcs: [":framework-tethering-stubs-srcs-systemapi"],
+ sdk_version: "system_current",
+}
+
+java_library {
+ name: "framework-tethering-stubs-module_libs_api",
+ srcs: [":framework-tethering-stubs-srcs-module_libs_api"],
+ sdk_version: "module_current",
+}
diff --git a/services/Android.bp b/services/Android.bp
index ef47867..c4be003 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -78,7 +78,7 @@
libs: [
"android.hidl.manager-V1.0-java",
- "framework-tethering-stubs",
+ "framework-tethering-stubs-module_libs_api",
],
plugins: [
diff --git a/services/api/current.txt b/services/api/current.txt
index 8c90165..9bbb3ef 100644
--- a/services/api/current.txt
+++ b/services/api/current.txt
@@ -3,9 +3,9 @@
public interface RuntimePermissionsPersistence {
method @NonNull public static com.android.permission.persistence.RuntimePermissionsPersistence createInstance();
- method public void deleteAsUser(@NonNull android.os.UserHandle);
- method @Nullable public com.android.permission.persistence.RuntimePermissionsState readAsUser(@NonNull android.os.UserHandle);
- method public void writeAsUser(@NonNull com.android.permission.persistence.RuntimePermissionsState, @NonNull android.os.UserHandle);
+ method public void deleteForUser(@NonNull android.os.UserHandle);
+ method @Nullable public com.android.permission.persistence.RuntimePermissionsState readForUser(@NonNull android.os.UserHandle);
+ method public void writeForUser(@NonNull com.android.permission.persistence.RuntimePermissionsState, @NonNull android.os.UserHandle);
}
public final class RuntimePermissionsState {
@@ -17,7 +17,7 @@
field public static final int NO_VERSION = -1; // 0xffffffff
}
- public static class RuntimePermissionsState.PermissionState {
+ public static final class RuntimePermissionsState.PermissionState {
ctor public RuntimePermissionsState.PermissionState(@NonNull String, boolean, int);
method public int getFlags();
method @NonNull public String getName();
@@ -30,9 +30,9 @@
public interface RolesPersistence {
method @NonNull public static com.android.role.persistence.RolesPersistence createInstance();
- method public void deleteAsUser(@NonNull android.os.UserHandle);
- method @Nullable public com.android.role.persistence.RolesState readAsUser(@NonNull android.os.UserHandle);
- method public void writeAsUser(@NonNull com.android.role.persistence.RolesState, @NonNull android.os.UserHandle);
+ method public void deleteForUser(@NonNull android.os.UserHandle);
+ method @Nullable public com.android.role.persistence.RolesState readForUser(@NonNull android.os.UserHandle);
+ method public void writeForUser(@NonNull com.android.role.persistence.RolesState, @NonNull android.os.UserHandle);
}
public final class RolesState {
diff --git a/services/autofill/java/com/android/server/autofill/InlineSuggestionSession.java b/services/autofill/java/com/android/server/autofill/InlineSuggestionSession.java
index 7fe086d..3376f2b 100644
--- a/services/autofill/java/com/android/server/autofill/InlineSuggestionSession.java
+++ b/services/autofill/java/com/android/server/autofill/InlineSuggestionSession.java
@@ -23,6 +23,7 @@
import android.annotation.Nullable;
import android.content.ComponentName;
import android.os.Bundle;
+import android.os.Handler;
import android.os.RemoteException;
import android.util.Log;
import android.util.Slog;
@@ -38,11 +39,8 @@
import java.util.Collections;
import java.util.Optional;
-import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
+import java.util.function.Consumer;
/**
* Maintains an autofill inline suggestion session that communicates with the IME.
@@ -69,7 +67,7 @@
final class InlineSuggestionSession {
private static final String TAG = "AfInlineSuggestionSession";
- private static final int INLINE_REQUEST_TIMEOUT_MS = 1000;
+ private static final int INLINE_REQUEST_TIMEOUT_MS = 200;
@NonNull
private final InputMethodManagerInternal mInputMethodManagerInternal;
@@ -80,6 +78,8 @@
private final Object mLock;
@NonNull
private final ImeStatusListener mImeStatusListener;
+ @NonNull
+ private final Handler mHandler;
/**
* To avoid the race condition, one should not access {@code mPendingImeResponse} without
@@ -105,10 +105,11 @@
private boolean mImeInputViewStarted = false;
InlineSuggestionSession(InputMethodManagerInternal inputMethodManagerInternal,
- int userId, ComponentName componentName) {
+ int userId, ComponentName componentName, Handler handler) {
mInputMethodManagerInternal = inputMethodManagerInternal;
mUserId = userId;
mComponentName = componentName;
+ mHandler = handler;
mLock = new Object();
mImeStatusListener = new ImeStatusListener() {
@Override
@@ -137,7 +138,8 @@
};
}
- public void onCreateInlineSuggestionsRequest(@NonNull AutofillId autofillId) {
+ public void onCreateInlineSuggestionsRequest(@NonNull AutofillId autofillId,
+ @NonNull Consumer<InlineSuggestionsRequest> requestConsumer) {
if (sDebug) Log.d(TAG, "onCreateInlineSuggestionsRequest called for " + autofillId);
synchronized (mLock) {
@@ -154,26 +156,16 @@
mUserId,
new InlineSuggestionsRequestInfo(mComponentName, autofillId, new Bundle()),
new InlineSuggestionsRequestCallbackImpl(mPendingImeResponse,
- mImeStatusListener));
+ mImeStatusListener, requestConsumer, mHandler, mLock));
}
}
- public Optional<InlineSuggestionsRequest> waitAndGetInlineSuggestionsRequest() {
+ public Optional<InlineSuggestionsRequest> getInlineSuggestionsRequest() {
final CompletableFuture<ImeResponse> pendingImeResponse = getPendingImeResponse();
- if (pendingImeResponse == null) {
+ if (pendingImeResponse == null || !pendingImeResponse.isDone()) {
return Optional.empty();
}
- try {
- return Optional.ofNullable(pendingImeResponse.get(INLINE_REQUEST_TIMEOUT_MS,
- TimeUnit.MILLISECONDS)).map(ImeResponse::getRequest);
- } catch (TimeoutException e) {
- Log.w(TAG, "Exception getting inline suggestions request in time: " + e);
- } catch (CancellationException e) {
- Log.w(TAG, "Inline suggestions request cancelled");
- } catch (InterruptedException | ExecutionException e) {
- throw new RuntimeException(e);
- }
- return Optional.empty();
+ return Optional.ofNullable(pendingImeResponse.getNow(null)).map(ImeResponse::getRequest);
}
public boolean hideInlineSuggestionsUi(@NonNull AutofillId autofillId) {
@@ -200,8 +192,7 @@
if (sDebug) Log.d(TAG, "onInlineSuggestionsResponseLocked without IMS request");
return false;
}
- // There is no need to wait on the CompletableFuture since it should have been completed
- // when {@link #waitAndGetInlineSuggestionsRequest()} was called.
+ // There is no need to wait on the CompletableFuture since it should have been completed.
ImeResponse imeResponse = completedImsResponse.getNow(null);
if (imeResponse == null) {
if (sDebug) Log.d(TAG, "onInlineSuggestionsResponseLocked with pending IMS response");
@@ -249,20 +240,50 @@
private static final class InlineSuggestionsRequestCallbackImpl
extends IInlineSuggestionsRequestCallback.Stub {
+ private final Object mLock;
+ @GuardedBy("mLock")
private final CompletableFuture<ImeResponse> mResponse;
+ @GuardedBy("mLock")
+ private final Consumer<InlineSuggestionsRequest> mRequestConsumer;
private final ImeStatusListener mImeStatusListener;
+ private final Handler mHandler;
+ private final Runnable mTimeoutCallback;
private InlineSuggestionsRequestCallbackImpl(CompletableFuture<ImeResponse> response,
- ImeStatusListener imeStatusListener) {
+ ImeStatusListener imeStatusListener,
+ Consumer<InlineSuggestionsRequest> requestConsumer,
+ Handler handler, Object lock) {
mResponse = response;
mImeStatusListener = imeStatusListener;
+ mRequestConsumer = requestConsumer;
+ mLock = lock;
+
+ mHandler = handler;
+ mTimeoutCallback = () -> {
+ Log.w(TAG, "Timed out waiting for IME callback InlineSuggestionsRequest.");
+ synchronized (mLock) {
+ completeIfNotLocked(null);
+ }
+ };
+ mHandler.postDelayed(mTimeoutCallback, INLINE_REQUEST_TIMEOUT_MS);
+ }
+
+ private void completeIfNotLocked(@Nullable ImeResponse response) {
+ if (mResponse.isDone()) {
+ return;
+ }
+ mResponse.complete(response);
+ mRequestConsumer.accept(response == null ? null : response.mRequest);
+ mHandler.removeCallbacks(mTimeoutCallback);
}
@BinderThread
@Override
public void onInlineSuggestionsUnsupported() throws RemoteException {
if (sDebug) Log.d(TAG, "onInlineSuggestionsUnsupported() called.");
- mResponse.complete(null);
+ synchronized (mLock) {
+ completeIfNotLocked(null);
+ }
}
@BinderThread
@@ -281,9 +302,13 @@
mImeStatusListener.onInputMethodFinishInputView(imeFieldId);
}
if (request != null && callback != null) {
- mResponse.complete(new ImeResponse(request, callback));
+ synchronized (mLock) {
+ completeIfNotLocked(new ImeResponse(request, callback));
+ }
} else {
- mResponse.complete(null);
+ synchronized (mLock) {
+ completeIfNotLocked(null);
+ }
}
}
diff --git a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
index e73f9ce..53afa6e 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
@@ -57,6 +57,7 @@
import com.android.internal.os.IResultReceiver;
import com.android.server.autofill.ui.InlineSuggestionFactory;
+import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CancellationException;
import java.util.concurrent.TimeUnit;
@@ -255,8 +256,12 @@
mCallbacks.logAugmentedAutofillSelected(sessionId,
dataset.getId());
try {
- client.autofill(sessionId, dataset.getFieldIds(),
- dataset.getFieldValues());
+ final ArrayList<AutofillId> fieldIds = dataset.getFieldIds();
+ final int size = fieldIds.size();
+ final boolean hideHighlight = size == 1
+ && fieldIds.get(0).equals(focusedId);
+ client.autofill(sessionId, fieldIds, dataset.getFieldValues(),
+ hideHighlight);
} catch (RemoteException e) {
Slog.w(TAG, "Encounter exception autofilling the values");
}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 538082d..5064663 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -18,6 +18,7 @@
import static android.service.autofill.AutofillFieldClassificationService.EXTRA_SCORES;
import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
+import static android.service.autofill.FillRequest.FLAG_PASSWORD_INPUT_TYPE;
import static android.service.autofill.FillRequest.INVALID_REQUEST_ID;
import static android.view.autofill.AutofillManager.ACTION_RESPONSE_EXPIRED;
import static android.view.autofill.AutofillManager.ACTION_START_SESSION;
@@ -113,7 +114,9 @@
import java.util.List;
import java.util.Objects;
import java.util.Optional;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Consumer;
/**
* A session for a given activity.
@@ -306,7 +309,47 @@
/**
* Receiver of assist data from the app's {@link Activity}.
*/
- private final IAssistDataReceiver mAssistReceiver = new IAssistDataReceiver.Stub() {
+ private final AssistDataReceiverImpl mAssistReceiver = new AssistDataReceiverImpl();
+
+ private final class AssistDataReceiverImpl extends IAssistDataReceiver.Stub {
+
+ @GuardedBy("mLock")
+ private InlineSuggestionsRequest mPendingInlineSuggestionsRequest;
+ @GuardedBy("mLock")
+ private FillRequest mPendingFillRequest;
+ @GuardedBy("mLock")
+ private CountDownLatch mCountDownLatch;
+
+ @Nullable Consumer<InlineSuggestionsRequest> newAutofillRequestLocked(
+ boolean isInlineRequest) {
+ mCountDownLatch = new CountDownLatch(isInlineRequest ? 2 : 1);
+ mPendingFillRequest = null;
+ mPendingInlineSuggestionsRequest = null;
+ return isInlineRequest ? (inlineSuggestionsRequest) -> {
+ synchronized (mLock) {
+ mPendingInlineSuggestionsRequest = inlineSuggestionsRequest;
+ mCountDownLatch.countDown();
+ maybeRequestFillLocked();
+ }
+ } : null;
+ }
+
+ void maybeRequestFillLocked() {
+ if (mCountDownLatch == null || mCountDownLatch.getCount() > 0
+ || mPendingFillRequest == null) {
+ return;
+ }
+ if (mPendingInlineSuggestionsRequest != null) {
+ mPendingFillRequest = new FillRequest(mPendingFillRequest.getId(),
+ mPendingFillRequest.getFillContexts(), mPendingFillRequest.getClientState(),
+ mPendingFillRequest.getFlags(), mPendingInlineSuggestionsRequest);
+ }
+ mRemoteFillService.onFillRequest(mPendingFillRequest);
+ mPendingInlineSuggestionsRequest = null;
+ mPendingFillRequest = null;
+ mCountDownLatch = null;
+ }
+
@Override
public void onHandleAssistData(Bundle resultData) throws RemoteException {
if (mRemoteFillService == null) {
@@ -401,17 +444,17 @@
final ArrayList<FillContext> contexts =
mergePreviousSessionLocked(/* forSave= */ false);
-
- final Optional<InlineSuggestionsRequest> inlineSuggestionsRequest =
- mInlineSuggestionSession.waitAndGetInlineSuggestionsRequest();
request = new FillRequest(requestId, contexts, mClientState, flags,
- inlineSuggestionsRequest.orElse(null));
+ /*inlineSuggestionsRequest=*/null);
+
+ mPendingFillRequest = request;
+ mCountDownLatch.countDown();
+ maybeRequestFillLocked();
}
if (mActivityToken != null) {
mService.sendActivityAssistDataToContentCapture(mActivityToken, resultData);
}
- mRemoteFillService.onFillRequest(request);
}
@Override
@@ -604,9 +647,15 @@
private void maybeRequestInlineSuggestionsRequestThenFillLocked(@NonNull ViewState viewState,
int newState, int flags) {
if (isInlineSuggestionsEnabledLocked()) {
- mInlineSuggestionSession.onCreateInlineSuggestionsRequest(mCurrentViewId);
+ Consumer<InlineSuggestionsRequest> inlineSuggestionsRequestConsumer =
+ mAssistReceiver.newAutofillRequestLocked(/*isInlineRequest=*/ true);
+ if (inlineSuggestionsRequestConsumer != null) {
+ mInlineSuggestionSession.onCreateInlineSuggestionsRequest(mCurrentViewId,
+ inlineSuggestionsRequestConsumer);
+ }
+ } else {
+ mAssistReceiver.newAutofillRequestLocked(/*isInlineRequest=*/ false);
}
-
requestNewFillResponseLocked(viewState, newState, flags);
}
@@ -624,7 +673,7 @@
+ ", flags=" + flags + ")");
}
mForAugmentedAutofillOnly = true;
- triggerAugmentedAutofillLocked();
+ triggerAugmentedAutofillLocked(flags);
return;
}
@@ -707,7 +756,7 @@
setClientLocked(client);
mInlineSuggestionSession = new InlineSuggestionSession(inputMethodManagerInternal, userId,
- componentName);
+ componentName, handler);
mMetricsLogger.write(newLogMaker(MetricsEvent.AUTOFILL_SESSION_STARTED)
.addTaggedData(MetricsEvent.FIELD_AUTOFILL_FLAGS, flags));
@@ -834,7 +883,7 @@
}
// Although "standard" autofill is disabled, it might still trigger augmented autofill
- if (triggerAugmentedAutofillLocked() != null) {
+ if (triggerAugmentedAutofillLocked(requestFlags) != null) {
mForAugmentedAutofillOnly = true;
if (sDebug) {
Slog.d(TAG, "Service disabled autofill for " + mComponentName
@@ -2465,7 +2514,7 @@
// triggered augmented autofill
if (!isSameViewEntered) {
if (sDebug) Slog.d(TAG, "trigger augmented autofill.");
- triggerAugmentedAutofillLocked();
+ triggerAugmentedAutofillLocked(flags);
} else {
if (sDebug) Slog.d(TAG, "skip augmented autofill for same view.");
}
@@ -2662,7 +2711,7 @@
private boolean requestShowInlineSuggestionsLocked(@NonNull FillResponse response,
@Nullable String filterText) {
final Optional<InlineSuggestionsRequest> inlineSuggestionsRequest =
- mInlineSuggestionSession.waitAndGetInlineSuggestionsRequest();
+ mInlineSuggestionSession.getInlineSuggestionsRequest();
if (!inlineSuggestionsRequest.isPresent()) {
Log.w(TAG, "InlineSuggestionsRequest unavailable");
return false;
@@ -2863,8 +2912,8 @@
// The default autofill service cannot fullfill the request, let's check if the augmented
// autofill service can.
- mAugmentedAutofillDestroyer = triggerAugmentedAutofillLocked();
- if (mAugmentedAutofillDestroyer == null) {
+ mAugmentedAutofillDestroyer = triggerAugmentedAutofillLocked(flags);
+ if (mAugmentedAutofillDestroyer == null && ((flags & FLAG_PASSWORD_INPUT_TYPE) == 0)) {
if (sVerbose) {
Slog.v(TAG, "canceling session " + id + " when service returned null and it cannot "
+ "be augmented. AutofillableIds: " + autofillableIds);
@@ -2874,8 +2923,14 @@
removeSelf();
} else {
if (sVerbose) {
- Slog.v(TAG, "keeping session " + id + " when service returned null but "
- + "it can be augmented. AutofillableIds: " + autofillableIds);
+ if ((flags & FLAG_PASSWORD_INPUT_TYPE) != 0) {
+ Slog.v(TAG, "keeping session " + id + " when service returned null and "
+ + "augmented service is disabled for password fields. "
+ + "AutofillableIds: " + autofillableIds);
+ } else {
+ Slog.v(TAG, "keeping session " + id + " when service returned null but "
+ + "it can be augmented. AutofillableIds: " + autofillableIds);
+ }
}
mAugmentedAutofillableIds = autofillableIds;
try {
@@ -2889,12 +2944,20 @@
/**
* Tries to trigger Augmented Autofill when the standard service could not fulfill a request.
*
+ * <p> The request may not have been sent when this method returns as it may be waiting for
+ * the inline suggestion request asynchronously.
+ *
* @return callback to destroy the autofill UI, or {@code null} if not supported.
*/
// TODO(b/123099468): might need to call it in other places, like when the service returns a
// non-null response but without datasets (for example, just SaveInfo)
@GuardedBy("mLock")
- private Runnable triggerAugmentedAutofillLocked() {
+ private Runnable triggerAugmentedAutofillLocked(int flags) {
+ // (TODO: b/141703197) Fix later by passing info to service.
+ if ((flags & FLAG_PASSWORD_INPUT_TYPE) != 0) {
+ return null;
+ }
+
// Check if Smart Suggestions is supported...
final @SmartSuggestionMode int supportedModes = mService
.getSupportedSmartSuggestionModesLocked();
@@ -2966,6 +3029,21 @@
final AutofillId focusedId = AutofillId.withoutSession(mCurrentViewId);
+ final Consumer<InlineSuggestionsRequest> requestAugmentedAutofill =
+ (inlineSuggestionsRequest) -> {
+ remoteService.onRequestAutofillLocked(id, mClient, taskId, mComponentName,
+ focusedId,
+ currentValue, inlineSuggestionsRequest,
+ /*inlineSuggestionsCallback=*/
+ response -> mInlineSuggestionSession.onInlineSuggestionsResponse(
+ mCurrentViewId, response),
+ /*onErrorCallback=*/ () -> {
+ synchronized (mLock) {
+ cancelAugmentedAutofillLocked();
+ }
+ }, mService.getRemoteInlineSuggestionRenderServiceLocked());
+ };
+
// There are 3 cases when augmented autofill should ask IME for a new request:
// 1. standard autofill provider is None
// 2. standard autofill provider doesn't support inline (and returns null response)
@@ -2973,21 +3051,12 @@
// doesn't want autofill
if (mForAugmentedAutofillOnly || !isInlineSuggestionsEnabledLocked()) {
if (sDebug) Slog.d(TAG, "Create inline request for augmented autofill");
- mInlineSuggestionSession.onCreateInlineSuggestionsRequest(mCurrentViewId);
+ mInlineSuggestionSession.onCreateInlineSuggestionsRequest(mCurrentViewId,
+ /*requestConsumer=*/ requestAugmentedAutofill);
+ } else {
+ requestAugmentedAutofill.accept(
+ mInlineSuggestionSession.getInlineSuggestionsRequest().orElse(null));
}
-
- Optional<InlineSuggestionsRequest> inlineSuggestionsRequest =
- mInlineSuggestionSession.waitAndGetInlineSuggestionsRequest();
- remoteService.onRequestAutofillLocked(id, mClient, taskId, mComponentName, focusedId,
- currentValue, inlineSuggestionsRequest.orElse(null),
- response -> mInlineSuggestionSession.onInlineSuggestionsResponse(
- mCurrentViewId, response),
- () -> {
- synchronized (mLock) {
- cancelAugmentedAutofillLocked();
- }
- }, mService.getRemoteInlineSuggestionRenderServiceLocked());
-
if (mAugmentedAutofillDestroyer == null) {
mAugmentedAutofillDestroyer = () -> remoteService.onDestroyAutofillWindowsRequest();
}
@@ -3370,6 +3439,8 @@
final List<AutofillId> ids = new ArrayList<>(entryCount);
final List<AutofillValue> values = new ArrayList<>(entryCount);
boolean waitingDatasetAuth = false;
+ boolean hideHighlight = (entryCount == 1
+ && dataset.getFieldIds().get(0).equals(mCurrentViewId));
for (int i = 0; i < entryCount; i++) {
if (dataset.getFieldValues().get(i) == null) {
continue;
@@ -3393,7 +3464,7 @@
}
if (sDebug) Slog.d(TAG, "autoFillApp(): the buck is on the app: " + dataset);
- mClient.autofill(id, ids, values);
+ mClient.autofill(id, ids, values, hideHighlight);
if (dataset.getId() != null) {
if (mSelectedDatasetIds == null) {
mSelectedDatasetIds = new ArrayList<>();
diff --git a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
index ee59d89..0ca9dd9 100644
--- a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
+++ b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
@@ -329,8 +329,14 @@
@NonNull Runnable onErrorCallback) {
return new IInlineSuggestionUiCallback.Stub() {
@Override
- public void onAutofill() throws RemoteException {
+ public void onClick() throws RemoteException {
onAutofillCallback.run();
+ callback.onClick();
+ }
+
+ @Override
+ public void onLongClick() throws RemoteException {
+ callback.onLongClick();
}
@Override
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 4cc65900..942d563 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -99,7 +99,7 @@
"android.hardware.tv.cec-V1.0-java",
"android.hardware.vibrator-java",
"app-compat-annotations",
- "framework-tethering-stubs",
+ "framework-tethering-stubs-module_libs_api",
"ike-stubs",
],
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 7840b19..9b04e79 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -1672,7 +1672,7 @@
| Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND
| Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
| Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
- intent.putExtra("time-zone", zone.getID());
+ intent.putExtra(Intent.EXTRA_TIMEZONE, zone.getID());
getContext().sendBroadcastAsUser(intent, UserHandle.ALL);
}
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 7287a44..ecf1f13 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -7803,12 +7803,15 @@
private void handleNetworkTestedWithExtras(
@NonNull ConnectivityReportEvent reportEvent, @NonNull PersistableBundle extras) {
final NetworkAgentInfo nai = reportEvent.mNai;
+ final NetworkCapabilities networkCapabilities =
+ new NetworkCapabilities(nai.networkCapabilities);
+ clearNetworkCapabilitiesUids(networkCapabilities);
final ConnectivityReport report =
new ConnectivityReport(
reportEvent.mNai.network,
reportEvent.mTimestampMillis,
nai.linkProperties,
- nai.networkCapabilities,
+ networkCapabilities,
extras);
final List<IConnectivityDiagnosticsCallback> results =
getMatchingPermissionedCallbacks(nai);
@@ -7824,13 +7827,16 @@
private void handleDataStallSuspected(
@NonNull NetworkAgentInfo nai, long timestampMillis, int detectionMethod,
@NonNull PersistableBundle extras) {
+ final NetworkCapabilities networkCapabilities =
+ new NetworkCapabilities(nai.networkCapabilities);
+ clearNetworkCapabilitiesUids(networkCapabilities);
final DataStallReport report =
new DataStallReport(
nai.network,
timestampMillis,
detectionMethod,
nai.linkProperties,
- nai.networkCapabilities,
+ networkCapabilities,
extras);
final List<IConnectivityDiagnosticsCallback> results =
getMatchingPermissionedCallbacks(nai);
@@ -7856,6 +7862,12 @@
}
}
+ private void clearNetworkCapabilitiesUids(@NonNull NetworkCapabilities nc) {
+ nc.setUids(null);
+ nc.setAdministratorUids(Collections.EMPTY_LIST);
+ nc.setOwnerUid(Process.INVALID_UID);
+ }
+
private List<IConnectivityDiagnosticsCallback> getMatchingPermissionedCallbacks(
@NonNull NetworkAgentInfo nai) {
final List<IConnectivityDiagnosticsCallback> results = new ArrayList<>();
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index acd4039..d814b9c 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -200,7 +200,7 @@
// time
private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
- private static final String FEATURE_ID = "LocationService";
+ private static final String ATTRIBUTION_TAG = "LocationService";
private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
@@ -246,7 +246,7 @@
private int mBatterySaverMode;
private LocationManagerService(Context context) {
- mContext = context.createFeatureContext(FEATURE_ID);
+ mContext = context.createAttributionContext(ATTRIBUTION_TAG);
mHandler = FgThread.getHandler();
mLocalService = new LocalService();
diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
index 2cfe404..b464422 100644
--- a/services/core/java/com/android/server/PackageWatchdog.java
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -161,9 +161,6 @@
private final Runnable mSaveToFile = this::saveToFile;
private final SystemClock mSystemClock;
private final BootThreshold mBootThreshold;
- // The set of packages that have been synced with the ExplicitHealthCheckController
- @GuardedBy("mLock")
- private Set<String> mRequestedHealthCheckPackages = new ArraySet<>();
@GuardedBy("mLock")
private boolean mIsPackagesReady;
// Flag to control whether explicit health checks are supported or not
@@ -627,22 +624,17 @@
* @see #syncRequestsAsync
*/
private void syncRequests() {
- boolean syncRequired = false;
+ Set<String> packages = null;
synchronized (mLock) {
if (mIsPackagesReady) {
- Set<String> packages = getPackagesPendingHealthChecksLocked();
- if (!packages.equals(mRequestedHealthCheckPackages)) {
- syncRequired = true;
- mRequestedHealthCheckPackages = packages;
- }
+ packages = getPackagesPendingHealthChecksLocked();
} // else, we will sync requests when packages become ready
}
// Call outside lock to avoid holding lock when calling into the controller.
- if (syncRequired) {
- Slog.i(TAG, "Syncing health check requests for packages: "
- + mRequestedHealthCheckPackages);
- mHealthCheckController.syncRequests(mRequestedHealthCheckPackages);
+ if (packages != null) {
+ Slog.i(TAG, "Syncing health check requests for packages: " + packages);
+ mHealthCheckController.syncRequests(packages);
}
}
diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java
index 80036bb..808d322 100644
--- a/services/core/java/com/android/server/RescueParty.java
+++ b/services/core/java/com/android/server/RescueParty.java
@@ -99,6 +99,8 @@
private static final String PROP_DISABLE_RESCUE = "persist.sys.disable_rescue";
private static final String PROP_VIRTUAL_DEVICE = "ro.hardware.virtual_device";
+ private static final String DEVICE_CONFIG_DISABLE_FLAG = "disable_rescue_party";
+
private static final int PERSISTENT_MASK = ApplicationInfo.FLAG_PERSISTENT
| ApplicationInfo.FLAG_SYSTEM;
@@ -114,6 +116,14 @@
return false;
}
+ // We're disabled if the DeviceConfig disable flag is set to true.
+ // This is in case that an emergency rollback of the feature is needed.
+ if (DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_CONFIGURATION, DEVICE_CONFIG_DISABLE_FLAG, false)) {
+ Slog.v(TAG, "Disabled because of DeviceConfig flag");
+ return true;
+ }
+
// We're disabled on all engineering devices
if (Build.IS_ENG) {
Slog.v(TAG, "Disabled because of eng build");
diff --git a/services/core/java/com/android/server/SensorNotificationService.java b/services/core/java/com/android/server/SensorNotificationService.java
index 9082dca..db3db0c 100644
--- a/services/core/java/com/android/server/SensorNotificationService.java
+++ b/services/core/java/com/android/server/SensorNotificationService.java
@@ -48,7 +48,7 @@
private static final long MILLIS_2010_1_1 = 1262358000000l;
- private static final String FEATURE_ID = "SensorNotificationService";
+ private static final String ATTRIBUTION_TAG = "SensorNotificationService";
private Context mContext;
private SensorManager mSensorManager;
@@ -59,7 +59,7 @@
private long mLocalGeomagneticFieldUpdateTime = -LOCATION_MIN_TIME;
public SensorNotificationService(Context context) {
- super(context.createFeatureContext(FEATURE_ID));
+ super(context.createAttributionContext(ATTRIBUTION_TAG));
mContext = getContext();
}
diff --git a/services/core/java/com/android/server/ServiceWatcher.java b/services/core/java/com/android/server/ServiceWatcher.java
index b43ae36..cfb79aa 100644
--- a/services/core/java/com/android/server/ServiceWatcher.java
+++ b/services/core/java/com/android/server/ServiceWatcher.java
@@ -100,7 +100,7 @@
@Nullable public final ComponentName component;
@UserIdInt public final int userId;
- private ServiceInfo(ResolveInfo resolveInfo, int currentUserId) {
+ ServiceInfo(ResolveInfo resolveInfo, int currentUserId) {
Preconditions.checkArgument(resolveInfo.serviceInfo.getComponentName() != null);
Bundle metadata = resolveInfo.serviceInfo.metaData;
@@ -316,6 +316,7 @@
}
mContext.unbindService(this);
+ onServiceDisconnected(mServiceInfo.component);
mServiceInfo = ServiceInfo.NONE;
}
@@ -339,15 +340,13 @@
@Override
public final void onServiceConnected(ComponentName component, IBinder binder) {
Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
+ Preconditions.checkState(mBinder == null);
if (D) {
Log.i(TAG, getLogPrefix() + " connected to " + component.toShortString());
}
mBinder = binder;
-
- // we always run the on bind callback even if we know that the binder is dead already so
- // that there are always balance pairs of bind/unbind callbacks
if (mOnBind != null) {
try {
mOnBind.run(binder);
@@ -357,19 +356,16 @@
Log.e(TAG, getLogPrefix() + " exception running on " + mServiceInfo, e);
}
}
-
- try {
- // setting the binder to null lets us skip queued transactions
- binder.linkToDeath(() -> mBinder = null, 0);
- } catch (RemoteException e) {
- mBinder = null;
- }
}
@Override
public final void onServiceDisconnected(ComponentName component) {
Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
+ if (mBinder == null) {
+ return;
+ }
+
if (D) {
Log.i(TAG, getLogPrefix() + " disconnected from " + component.toShortString());
}
@@ -391,18 +387,18 @@
onBestServiceChanged(true);
}
- private void onUserSwitched(@UserIdInt int userId) {
+ void onUserSwitched(@UserIdInt int userId) {
mCurrentUserId = userId;
onBestServiceChanged(false);
}
- private void onUserUnlocked(@UserIdInt int userId) {
+ void onUserUnlocked(@UserIdInt int userId) {
if (userId == mCurrentUserId) {
onBestServiceChanged(false);
}
}
- private void onPackageChanged(String packageName) {
+ void onPackageChanged(String packageName) {
// force a rebind if the changed package was the currently connected package
String currentPackageName =
mServiceInfo.component != null ? mServiceInfo.component.getPackageName() : null;
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 7c833fa..12a1a95 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -75,7 +75,9 @@
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
+import java.util.Arrays;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -293,7 +295,7 @@
public void onChange(boolean selfChange, Uri uri) {
synchronized (mLock) {
// setup wizard is done now so we can unblock
- if (setupWizardCompleteForCurrentUser()) {
+ if (setupWizardCompleteForCurrentUser() && !selfChange) {
mSetupWizardComplete = true;
getContext().getContentResolver()
.unregisterContentObserver(mSetupWizardObserver);
@@ -348,6 +350,9 @@
IntentFilter batteryFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
context.registerReceiver(mBatteryReceiver, batteryFilter);
+ context.registerReceiver(mSettingsRestored,
+ new IntentFilter(Intent.ACTION_SETTING_RESTORED), null, mHandler);
+
mLocalPowerManager =
LocalServices.getService(PowerManagerInternal.class);
initPowerSave();
@@ -395,6 +400,22 @@
mHandler.post(() -> updateSystemProperties());
}
+ private final BroadcastReceiver mSettingsRestored = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ List<String> settings = Arrays.asList(
+ Secure.UI_NIGHT_MODE, Secure.DARK_THEME_CUSTOM_START_TIME,
+ Secure.DARK_THEME_CUSTOM_END_TIME);
+ if (settings.contains(intent.getExtras().getCharSequence(Intent.EXTRA_SETTING_NAME))) {
+ synchronized (mLock) {
+ updateNightModeFromSettingsLocked(context, context.getResources(),
+ UserHandle.getCallingUserId());
+ updateConfigurationLocked();
+ }
+ }
+ }
+ };
+
private void initPowerSave() {
mPowerSave =
mLocalPowerManager.getLowPowerState(ServiceType.NIGHT_MODE)
@@ -1297,9 +1318,9 @@
if (Sandman.shouldStartDockApp(getContext(), homeIntent)) {
try {
int result = ActivityTaskManager.getService().startActivityWithConfig(
- null, getContext().getBasePackageName(), getContext().getFeatureId(),
- homeIntent, null, null, null, 0, 0, mConfiguration, null,
- UserHandle.USER_CURRENT);
+ null, getContext().getBasePackageName(),
+ getContext().getAttributionTag(), homeIntent, null, null, null, 0, 0,
+ mConfiguration, null, UserHandle.USER_CURRENT);
if (ActivityManager.isStartResultSuccessful(result)) {
dockAppStarted = true;
} else if (result != ActivityManager.START_INTENT_NOT_RESOLVED) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 59f64ac..8f5fbf7 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -2931,25 +2931,35 @@
final PlatformCompat platformCompat = (PlatformCompat)
ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE);
String toggleValue = getNextArgRequired();
- if (toggleValue.equals("reset-all")) {
- final String packageName = getNextArgRequired();
- pw.println("Reset all changes for " + packageName + " to default value.");
- platformCompat.clearOverrides(packageName);
- return 0;
- }
- long changeId;
- String changeIdString = getNextArgRequired();
- try {
- changeId = Long.parseLong(changeIdString);
- } catch (NumberFormatException e) {
- changeId = platformCompat.lookupChangeId(changeIdString);
- }
- if (changeId == -1) {
- pw.println("Unknown or invalid change: '" + changeIdString + "'.");
- return -1;
+ boolean toggleAll = false;
+ int targetSdkVersion = -1;
+ long changeId = -1;
+
+ if (toggleValue.endsWith("-all")) {
+ toggleValue = toggleValue.substring(0, toggleValue.lastIndexOf("-all"));
+ toggleAll = true;
+ if (!toggleValue.equals("reset")) {
+ try {
+ targetSdkVersion = Integer.parseInt(getNextArgRequired());
+ } catch (NumberFormatException e) {
+ pw.println("Invalid targetSdkVersion!");
+ return -1;
+ }
+ }
+ } else {
+ String changeIdString = getNextArgRequired();
+ try {
+ changeId = Long.parseLong(changeIdString);
+ } catch (NumberFormatException e) {
+ changeId = platformCompat.lookupChangeId(changeIdString);
+ }
+ if (changeId == -1) {
+ pw.println("Unknown or invalid change: '" + changeIdString + "'.");
+ return -1;
+ }
}
String packageName = getNextArgRequired();
- if (!platformCompat.isKnownChangeId(changeId)) {
+ if (!toggleAll && !platformCompat.isKnownChangeId(changeId)) {
pw.println("Warning! Change " + changeId + " is not known yet. Enabling/disabling it"
+ " could have no effect.");
}
@@ -2958,22 +2968,49 @@
try {
switch (toggleValue) {
case "enable":
- enabled.add(changeId);
- CompatibilityChangeConfig overrides =
- new CompatibilityChangeConfig(
- new Compatibility.ChangeConfig(enabled, disabled));
- platformCompat.setOverrides(overrides, packageName);
- pw.println("Enabled change " + changeId + " for " + packageName + ".");
+ if (toggleAll) {
+ int numChanges = platformCompat.enableTargetSdkChanges(packageName,
+ targetSdkVersion);
+ if (numChanges == 0) {
+ pw.println("No changes were enabled.");
+ return -1;
+ }
+ pw.println("Enabled " + numChanges + " changes gated by targetSdkVersion "
+ + targetSdkVersion + " for " + packageName + ".");
+ } else {
+ enabled.add(changeId);
+ CompatibilityChangeConfig overrides =
+ new CompatibilityChangeConfig(
+ new Compatibility.ChangeConfig(enabled, disabled));
+ platformCompat.setOverrides(overrides, packageName);
+ pw.println("Enabled change " + changeId + " for " + packageName + ".");
+ }
return 0;
case "disable":
- disabled.add(changeId);
- overrides =
- new CompatibilityChangeConfig(
- new Compatibility.ChangeConfig(enabled, disabled));
- platformCompat.setOverrides(overrides, packageName);
- pw.println("Disabled change " + changeId + " for " + packageName + ".");
+ if (toggleAll) {
+ int numChanges = platformCompat.disableTargetSdkChanges(packageName,
+ targetSdkVersion);
+ if (numChanges == 0) {
+ pw.println("No changes were disabled.");
+ return -1;
+ }
+ pw.println("Disabled " + numChanges + " changes gated by targetSdkVersion "
+ + targetSdkVersion + " for " + packageName + ".");
+ } else {
+ disabled.add(changeId);
+ CompatibilityChangeConfig overrides =
+ new CompatibilityChangeConfig(
+ new Compatibility.ChangeConfig(enabled, disabled));
+ platformCompat.setOverrides(overrides, packageName);
+ pw.println("Disabled change " + changeId + " for " + packageName + ".");
+ }
return 0;
case "reset":
+ if (toggleAll) {
+ platformCompat.clearOverrides(packageName);
+ pw.println("Reset all changes for " + packageName + " to default value.");
+ return 0;
+ }
if (platformCompat.clearOverride(changeId, packageName)) {
pw.println("Reset change " + changeId + " for " + packageName
+ " to default value.");
@@ -3304,6 +3341,8 @@
pw.println(" enable|disable|reset <CHANGE_ID|CHANGE_NAME> <PACKAGE_NAME>");
pw.println(" Toggles a change either by id or by name for <PACKAGE_NAME>.");
pw.println(" It kills <PACKAGE_NAME> (to allow the toggle to take effect).");
+ pw.println(" enable-all|disable-all <targetSdkVersion> <PACKAGE_NAME");
+ pw.println(" Toggles all changes that are gated by <targetSdkVersion>.");
pw.println(" reset-all <PACKAGE_NAME>");
pw.println(" Removes all existing overrides for all changes for ");
pw.println(" <PACKAGE_NAME> (back to default behaviour).");
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index 3a6065e..86d9028 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -121,6 +121,7 @@
static final int COMPACT_PROCESS_MSG = 1;
static final int COMPACT_SYSTEM_MSG = 2;
static final int SET_FROZEN_PROCESS_MSG = 3;
+ static final int REPORT_UNFREEZE_MSG = 4;
//TODO:change this static definition into a configurable flag.
static final int FREEZE_TIMEOUT_MS = 500;
@@ -613,30 +614,6 @@
FREEZE_TIMEOUT_MS);
}
- private final class UnfreezeStats {
- final int mPid;
- final String mName;
- final long mFrozenDuration;
-
- UnfreezeStats(int pid, String name, long frozenDuration) {
- mPid = pid;
- mName = name;
- mFrozenDuration = frozenDuration;
- }
-
- public int getPid() {
- return mPid;
- }
-
- public String getName() {
- return mName;
- }
-
- public long getFrozenDuration() {
- return mFrozenDuration;
- }
- }
-
@GuardedBy("mAm")
void unfreezeAppLocked(ProcessRecord app) {
mFreezeHandler.removeMessages(SET_FROZEN_PROCESS_MSG, app);
@@ -667,12 +644,11 @@
Slog.d(TAG_AM, "sync unfroze " + app.pid + " " + app.processName);
}
- UnfreezeStats stats = new UnfreezeStats(app.pid, app.processName,
- app.freezeUnfreezeTime - freezeTime);
-
mFreezeHandler.sendMessage(
- mFreezeHandler.obtainMessage(SET_FROZEN_PROCESS_MSG, REPORT_UNFREEZE, 0,
- stats));
+ mFreezeHandler.obtainMessage(REPORT_UNFREEZE_MSG,
+ app.pid,
+ (int) Math.min(app.freezeUnfreezeTime - freezeTime, Integer.MAX_VALUE),
+ app.processName));
}
}
@@ -945,14 +921,19 @@
@Override
public void handleMessage(Message msg) {
- if (msg.what != SET_FROZEN_PROCESS_MSG) {
- return;
- }
+ switch (msg.what) {
+ case SET_FROZEN_PROCESS_MSG:
+ freezeProcess((ProcessRecord) msg.obj);
+ break;
+ case REPORT_UNFREEZE_MSG:
+ int pid = msg.arg1;
+ int frozenDuration = msg.arg2;
+ String processName = (String) msg.obj;
- if (msg.arg1 == DO_FREEZE) {
- freezeProcess((ProcessRecord) msg.obj);
- } else if (msg.arg1 == REPORT_UNFREEZE) {
- reportUnfreeze((UnfreezeStats) msg.obj);
+ reportUnfreeze(pid, frozenDuration, processName);
+ break;
+ default:
+ return;
}
}
@@ -1015,18 +996,18 @@
}
}
- private void reportUnfreeze(UnfreezeStats stats) {
+ private void reportUnfreeze(int pid, int frozenDuration, String processName) {
- EventLog.writeEvent(EventLogTags.AM_UNFREEZE, stats.getPid(), stats.getName());
+ EventLog.writeEvent(EventLogTags.AM_UNFREEZE, pid, processName);
// See above for why we're not taking mPhenotypeFlagLock here
if (mRandom.nextFloat() < mFreezerStatsdSampleRate) {
FrameworkStatsLog.write(
FrameworkStatsLog.APP_FREEZE_CHANGED,
FrameworkStatsLog.APP_FREEZE_CHANGED__ACTION__UNFREEZE_APP,
- stats.getPid(),
- stats.getName(),
- stats.getFrozenDuration());
+ pid,
+ processName,
+ frozenDuration);
}
}
}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 6b16513..0e9970e 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -61,6 +61,7 @@
import android.app.IApplicationThread;
import android.app.IUidObserver;
import android.compat.annotation.ChangeId;
+import android.compat.annotation.Disabled;
import android.compat.annotation.EnabledAfter;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -70,6 +71,7 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManagerInternal;
+import android.content.pm.ProcessInfo;
import android.content.res.Resources;
import android.graphics.Point;
import android.net.LocalSocket;
@@ -345,6 +347,14 @@
private static final long NATIVE_HEAP_POINTER_TAGGING = 135754954; // This is a bug id.
/**
+ * Enable sampled memory bug detection in the app.
+ * @see <a href="https://source.android.com/devices/tech/debug/gwp-asan">GWP-ASan</a>.
+ */
+ @ChangeId
+ @Disabled
+ private static final long GWP_ASAN = 135634846; // This is a bug id.
+
+ /**
* Apps have no access to the private data directories of any other app, even if the other
* app has made them world-readable.
*/
@@ -1634,6 +1644,28 @@
return gidArray;
}
+ private int decideGwpAsanLevel(ProcessRecord app) {
+ // Look at the process attribute first.
+ if (app.processInfo != null && app.processInfo.enableGwpAsan != null) {
+ return app.processInfo.enableGwpAsan ? Zygote.GWP_ASAN_LEVEL_ALWAYS
+ : Zygote.GWP_ASAN_LEVEL_NEVER;
+ }
+ // Then at the applicaton attribute.
+ if (app.info.isGwpAsanEnabled() != null) {
+ return app.info.isGwpAsanEnabled() ? Zygote.GWP_ASAN_LEVEL_ALWAYS
+ : Zygote.GWP_ASAN_LEVEL_NEVER;
+ }
+ // If the app does not specify enableGwpAsan, the default behavior is lottery among the
+ // system apps, and disabled for user apps, unless overwritten by the compat feature.
+ if (mPlatformCompat.isChangeEnabled(GWP_ASAN, app.info)) {
+ return Zygote.GWP_ASAN_LEVEL_ALWAYS;
+ }
+ if ((app.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+ return Zygote.GWP_ASAN_LEVEL_LOTTERY;
+ }
+ return Zygote.GWP_ASAN_LEVEL_NEVER;
+ }
+
/**
* @return {@code true} if process start is successful, false otherwise.
*/
@@ -1803,6 +1835,8 @@
runtimeFlags |= Zygote.MEMORY_TAG_LEVEL_TBI;
}
+ runtimeFlags |= decideGwpAsanLevel(app);
+
String invokeWith = null;
if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
// Debuggable apps may include a wrapper script with their library directory.
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index c029811..a78caac 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -384,6 +384,9 @@
pw.println(processInfo.deniedPermissions.valueAt(i));
}
}
+ if (processInfo.enableGwpAsan != null) {
+ pw.print(prefix); pw.println(" enableGwpAsan=" + processInfo.enableGwpAsan);
+ }
}
pw.print(prefix); pw.print("mRequiredAbi="); pw.print(mRequiredAbi);
pw.print(" instructionSet="); pw.println(instructionSet);
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index 0a8e70c..bac7565 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -80,6 +80,7 @@
@VisibleForTesting
static final String[] sDeviceConfigScopes = new String[] {
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER_NATIVE_BOOT,
+ DeviceConfig.NAMESPACE_CONFIGURATION,
DeviceConfig.NAMESPACE_INPUT_NATIVE_BOOT,
DeviceConfig.NAMESPACE_INTELLIGENCE_CONTENT_SUGGESTIONS,
DeviceConfig.NAMESPACE_MEDIA_NATIVE,
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 7774633..310664e 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -19,8 +19,8 @@
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_CAMERA;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
-import static android.app.AppOpsManager.CALL_BACK_ON_CHANGED_LISTENER_WITH_SWITCHED_OP_CHANGE;
-import static android.app.AppOpsManager.FILTER_BY_FEATURE_ID;
+import static android.app.AppOpsManager.CALL_BACK_ON_SWITCHED_OP;
+import static android.app.AppOpsManager.FILTER_BY_ATTRIBUTION_TAG;
import static android.app.AppOpsManager.FILTER_BY_OP_NAMES;
import static android.app.AppOpsManager.FILTER_BY_PACKAGE_NAME;
import static android.app.AppOpsManager.FILTER_BY_UID;
@@ -40,6 +40,7 @@
import static android.app.AppOpsManager.OP_PLAY_AUDIO;
import static android.app.AppOpsManager.OP_RECORD_AUDIO;
import static android.app.AppOpsManager.OpEventProxyInfo;
+import static android.app.AppOpsManager.RestrictionBypass;
import static android.app.AppOpsManager.SAMPLING_STRATEGY_RARELY_USED;
import static android.app.AppOpsManager.SAMPLING_STRATEGY_UNIFORM;
import static android.app.AppOpsManager.UID_STATE_BACKGROUND;
@@ -55,6 +56,7 @@
import static android.app.AppOpsManager.extractUidStateFromKey;
import static android.app.AppOpsManager.makeKey;
import static android.app.AppOpsManager.modeToName;
+import static android.app.AppOpsManager.opAllowSystemBypassRestriction;
import static android.app.AppOpsManager.opToName;
import static android.app.AppOpsManager.opToPublicName;
import static android.app.AppOpsManager.resolveFirstUnrestrictedUidState;
@@ -73,33 +75,29 @@
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
-import android.app.ActivityThread;
import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.AppOpsManager.HistoricalOps;
import android.app.AppOpsManager.Mode;
import android.app.AppOpsManager.OpEntry;
-import android.app.AppOpsManager.OpFeatureEntry;
+import android.app.AppOpsManager.AttributedOpEntry;
import android.app.AppOpsManager.OpFlags;
import android.app.AppOpsManagerInternal;
import android.app.AppOpsManagerInternal.CheckOpsDelegate;
import android.app.AsyncNotedAppOp;
import android.app.RuntimeAppOpAccessMessage;
import android.app.SyncNotedAppOp;
-import android.compat.Compatibility;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.PermissionInfo;
import android.content.pm.UserInfo;
-import android.content.pm.parsing.component.ParsedFeature;
+import android.content.pm.parsing.component.ParsedAttribution;
import android.database.ContentObserver;
import android.hardware.camera2.CameraDevice.CAMERA_AUDIO_RESTRICTION;
import android.net.Uri;
@@ -373,14 +371,14 @@
}
OpEventProxyInfo acquire(@IntRange(from = 0) int uid, @Nullable String packageName,
- @Nullable String featureId) {
+ @Nullable String attributionTag) {
OpEventProxyInfo recycled = acquire();
if (recycled != null) {
- recycled.reinit(uid, packageName, featureId);
+ recycled.reinit(uid, packageName, attributionTag);
return recycled;
}
- return new OpEventProxyInfo(uid, packageName, featureId);
+ return new OpEventProxyInfo(uid, packageName, attributionTag);
}
}
@@ -666,15 +664,19 @@
final static class Ops extends SparseArray<Op> {
final String packageName;
final UidState uidState;
- final boolean isPrivileged;
- /** Lazily populated cache of featureIds of this package */
- final @NonNull ArraySet<String> knownFeatureIds = new ArraySet<>();
+ /**
+ * The restriction properties of the package. If {@code null} it could not have been read
+ * yet and has to be refreshed.
+ */
+ @Nullable RestrictionBypass bypass;
- Ops(String _packageName, UidState _uidState, boolean _isPrivileged) {
+ /** Lazily populated cache of attributionTags of this package */
+ final @NonNull ArraySet<String> knownAttributionTags = new ArraySet<>();
+
+ Ops(String _packageName, UidState _uidState) {
packageName = _packageName;
uidState = _uidState;
- isPrivileged = _isPrivileged;
}
}
@@ -774,8 +776,8 @@
}
}
- private final class FeatureOp {
- public final @Nullable String featureId;
+ private final class AttributedOp {
+ public final @Nullable String tag;
public final @NonNull Op parent;
/**
@@ -802,8 +804,8 @@
@GuardedBy("AppOpsService.this")
private @Nullable ArrayMap<IBinder, InProgressStartOpEvent> mInProgressEvents;
- FeatureOp(@Nullable String featureId, @NonNull Op parent) {
- this.featureId = featureId;
+ AttributedOp(@Nullable String tag, @NonNull Op parent) {
+ this.tag = tag;
this.parent = parent;
}
@@ -812,18 +814,18 @@
*
* @param proxyUid The uid of the proxy
* @param proxyPackageName The package name of the proxy
- * @param proxyFeatureId the featureId in the proxies package
+ * @param proxyAttributionTag the attributionTag in the proxies package
* @param uidState UID state of the app noteOp/startOp was called for
* @param flags OpFlags of the call
*/
public void accessed(int proxyUid, @Nullable String proxyPackageName,
- @Nullable String proxyFeatureId, @AppOpsManager.UidState int uidState,
+ @Nullable String proxyAttributionTag, @AppOpsManager.UidState int uidState,
@OpFlags int flags) {
accessed(System.currentTimeMillis(), -1, proxyUid, proxyPackageName,
- proxyFeatureId, uidState, flags);
+ proxyAttributionTag, uidState, flags);
mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid, parent.packageName,
- featureId, uidState, flags);
+ tag, uidState, flags);
}
/**
@@ -833,12 +835,12 @@
* @param duration The duration of the event
* @param proxyUid The uid of the proxy
* @param proxyPackageName The package name of the proxy
- * @param proxyFeatureId the featureId in the proxies package
+ * @param proxyAttributionTag the attributionTag in the proxies package
* @param uidState UID state of the app noteOp/startOp was called for
* @param flags OpFlags of the call
*/
public void accessed(long noteTime, long duration, int proxyUid,
- @Nullable String proxyPackageName, @Nullable String proxyFeatureId,
+ @Nullable String proxyPackageName, @Nullable String proxyAttributionTag,
@AppOpsManager.UidState int uidState, @OpFlags int flags) {
long key = makeKey(uidState, flags);
@@ -849,7 +851,7 @@
OpEventProxyInfo proxyInfo = null;
if (proxyUid != Process.INVALID_UID) {
proxyInfo = mOpEventProxyInfoPool.acquire(proxyUid, proxyPackageName,
- proxyFeatureId);
+ proxyAttributionTag);
}
NoteOpEvent existingEvent = mAccessEvents.get(key);
@@ -870,7 +872,7 @@
rejected(System.currentTimeMillis(), uidState, flags);
mHistoricalRegistry.incrementOpRejected(parent.op, parent.uid, parent.packageName,
- featureId, uidState, flags);
+ tag, uidState, flags);
}
/**
@@ -936,7 +938,7 @@
// startOp events don't support proxy, hence use flags==SELF
mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid, parent.packageName,
- featureId, uidState, OP_FLAG_SELF);
+ tag, uidState, OP_FLAG_SELF);
}
/**
@@ -976,7 +978,7 @@
mAccessEvents.put(makeKey(event.getUidState(), OP_FLAG_SELF), finishedEvent);
mHistoricalRegistry.increaseOpAccessDuration(parent.op, parent.uid,
- parent.packageName, featureId, event.getUidState(),
+ parent.packageName, tag, event.getUidState(),
AppOpsManager.OP_FLAG_SELF, finishedEvent.getDuration());
mInProgressStartOpEventPool.release(event);
@@ -984,7 +986,7 @@
if (mInProgressEvents.isEmpty()) {
mInProgressEvents = null;
- // TODO moltmann: Also callback for single feature activity changes
+ // TODO moltmann: Also callback for single attribution tag activity changes
if (triggerCallbackIfNeeded && !parent.isRunning()) {
scheduleOpActiveChangedIfNeededLocked(parent.op, parent.uid,
parent.packageName, false);
@@ -1075,14 +1077,14 @@
}
/**
- * Add all data from the {@code featureToAdd} to this op.
+ * Add all data from the {@code opToAdd} to this op.
*
* <p>If there is an event for the same key in both the later event is retained.
* <p>{@code opToAdd} should not be used after this method is called.
*
* @param opToAdd The op to add
*/
- public void add(@NonNull FeatureOp opToAdd) {
+ public void add(@NonNull AttributedOp opToAdd) {
if (opToAdd.mInProgressEvents != null) {
Slog.w(TAG, "Ignoring " + opToAdd.mInProgressEvents.size() + " running app-ops");
@@ -1126,7 +1128,7 @@
return clone;
}
- @NonNull OpFeatureEntry createFeatureEntryLocked() {
+ @NonNull AttributedOpEntry createAttributedOpEntryLocked() {
LongSparseArray<NoteOpEvent> accessEvents = deepClone(mAccessEvents);
// Add in progress events as access events
@@ -1150,7 +1152,7 @@
LongSparseArray<NoteOpEvent> rejectEvents = deepClone(mRejectEvents);
- return new OpFeatureEntry(parent.op, isRunning(), accessEvents, rejectEvents);
+ return new AttributedOpEntry(parent.op, isRunning(), accessEvents, rejectEvents);
}
}
@@ -1162,8 +1164,8 @@
private @Mode int mode;
- /** featureId -> FeatureOp */
- final ArrayMap<String, FeatureOp> mFeatures = new ArrayMap<>(1);
+ /** attributionTag -> AttributedOp */
+ final ArrayMap<String, AttributedOp> mAttributions = new ArrayMap<>(1);
Op(UidState uidState, String packageName, int op, int uid) {
this.op = op;
@@ -1181,58 +1183,59 @@
return uidState.evalMode(op, mode);
}
- void removeFeaturesWithNoTime() {
- for (int i = mFeatures.size() - 1; i >= 0; i--) {
- if (!mFeatures.valueAt(i).hasAnyTime()) {
- mFeatures.removeAt(i);
+ void removeAttributionsWithNoTime() {
+ for (int i = mAttributions.size() - 1; i >= 0; i--) {
+ if (!mAttributions.valueAt(i).hasAnyTime()) {
+ mAttributions.removeAt(i);
}
}
}
- private @NonNull FeatureOp getOrCreateFeature(@NonNull Op parent,
- @Nullable String featureId) {
- FeatureOp featureOp;
+ private @NonNull AttributedOp getOrCreateAttribution(@NonNull Op parent,
+ @Nullable String attributionTag) {
+ AttributedOp attributedOp;
- featureOp = mFeatures.get(featureId);
- if (featureOp == null) {
- featureOp = new FeatureOp(featureId, parent);
- mFeatures.put(featureId, featureOp);
+ attributedOp = mAttributions.get(attributionTag);
+ if (attributedOp == null) {
+ attributedOp = new AttributedOp(attributionTag, parent);
+ mAttributions.put(attributionTag, attributedOp);
}
- return featureOp;
+ return attributedOp;
}
@NonNull OpEntry createEntryLocked() {
- final int numFeatures = mFeatures.size();
+ final int numAttributions = mAttributions.size();
- final ArrayMap<String, OpFeatureEntry> featureEntries = new ArrayMap<>(numFeatures);
- for (int i = 0; i < numFeatures; i++) {
- featureEntries.put(mFeatures.keyAt(i),
- mFeatures.valueAt(i).createFeatureEntryLocked());
+ final ArrayMap<String, AppOpsManager.AttributedOpEntry> attributionEntries =
+ new ArrayMap<>(numAttributions);
+ for (int i = 0; i < numAttributions; i++) {
+ attributionEntries.put(mAttributions.keyAt(i),
+ mAttributions.valueAt(i).createAttributedOpEntryLocked());
}
- return new OpEntry(op, mode, featureEntries);
+ return new OpEntry(op, mode, attributionEntries);
}
- @NonNull OpEntry createSingleFeatureEntryLocked(@Nullable String featureId) {
- final int numFeatures = mFeatures.size();
+ @NonNull OpEntry createSingleAttributionEntryLocked(@Nullable String attributionTag) {
+ final int numAttributions = mAttributions.size();
- final ArrayMap<String, OpFeatureEntry> featureEntries = new ArrayMap<>(1);
- for (int i = 0; i < numFeatures; i++) {
- if (Objects.equals(mFeatures.keyAt(i), featureId)) {
- featureEntries.put(mFeatures.keyAt(i),
- mFeatures.valueAt(i).createFeatureEntryLocked());
+ final ArrayMap<String, AttributedOpEntry> attributionEntries = new ArrayMap<>(1);
+ for (int i = 0; i < numAttributions; i++) {
+ if (Objects.equals(mAttributions.keyAt(i), attributionTag)) {
+ attributionEntries.put(mAttributions.keyAt(i),
+ mAttributions.valueAt(i).createAttributedOpEntryLocked());
break;
}
}
- return new OpEntry(op, mode, featureEntries);
+ return new OpEntry(op, mode, attributionEntries);
}
boolean isRunning() {
- final int numFeatures = mFeatures.size();
- for (int i = 0; i < numFeatures; i++) {
- if (mFeatures.valueAt(i).isRunning()) {
+ final int numAttributions = mAttributions.size();
+ for (int i = 0; i < numAttributions; i++) {
+ if (mAttributions.valueAt(i).isRunning()) {
return true;
}
}
@@ -1405,10 +1408,11 @@
}
/**
- * Call {@link FeatureOp#onClientDeath featureOp.onClientDeath(clientId)}.
+ * Call {@link AttributedOp#onClientDeath attributedOp.onClientDeath(clientId)}.
*/
- private static void onClientDeath(@NonNull FeatureOp featureOp, @NonNull IBinder clientId) {
- featureOp.onClientDeath(clientId);
+ private static void onClientDeath(@NonNull AttributedOp attributedOp,
+ @NonNull IBinder clientId) {
+ attributedOp.onClientDeath(clientId);
}
@@ -1490,20 +1494,21 @@
return;
}
- ArrayMap<String, String> dstFeatureIds = new ArrayMap<>();
- ArraySet<String> featureIds = new ArraySet<>();
- featureIds.add(null);
- if (pkg.getFeatures() != null) {
- int numFeatures = pkg.getFeatures().size();
- for (int featureNum = 0; featureNum < numFeatures; featureNum++) {
- ParsedFeature feature = pkg.getFeatures().get(featureNum);
- featureIds.add(feature.id);
+ ArrayMap<String, String> dstAttributionTags = new ArrayMap<>();
+ ArraySet<String> attributionTags = new ArraySet<>();
+ attributionTags.add(null);
+ if (pkg.getAttributions() != null) {
+ int numAttributions = pkg.getAttributions().size();
+ for (int attributionNum = 0; attributionNum < numAttributions;
+ attributionNum++) {
+ ParsedAttribution attribution = pkg.getAttributions().get(attributionNum);
+ attributionTags.add(attribution.tag);
- int numInheritFrom = feature.inheritFrom.size();
+ int numInheritFrom = attribution.inheritFrom.size();
for (int inheritFromNum = 0; inheritFromNum < numInheritFrom;
inheritFromNum++) {
- dstFeatureIds.put(feature.inheritFrom.get(inheritFromNum),
- feature.id);
+ dstAttributionTags.put(attribution.inheritFrom.get(inheritFromNum),
+ attribution.tag);
}
}
}
@@ -1519,25 +1524,32 @@
return;
}
- ops.knownFeatureIds.clear();
+ // Reset cached package properties to re-initialize when needed
+ ops.bypass = null;
+ ops.knownAttributionTags.clear();
+
+ // Merge data collected for removed attributions into their successor
+ // attributions
int numOps = ops.size();
for (int opNum = 0; opNum < numOps; opNum++) {
Op op = ops.valueAt(opNum);
- int numFeatures = op.mFeatures.size();
- for (int featureNum = numFeatures - 1; featureNum >= 0; featureNum--) {
- String featureId = op.mFeatures.keyAt(featureNum);
+ int numAttributions = op.mAttributions.size();
+ for (int attributionNum = numAttributions - 1; attributionNum >= 0;
+ attributionNum--) {
+ String attributionTag = op.mAttributions.keyAt(attributionNum);
- if (featureIds.contains(featureId)) {
- // feature still exist after upgrade
+ if (attributionTags.contains(attributionTag)) {
+ // attribution still exist after upgrade
continue;
}
- String newFeatureId = dstFeatureIds.get(featureId);
+ String newAttributionTag = dstAttributionTags.get(attributionTag);
- FeatureOp newFeatureOp = op.getOrCreateFeature(op, newFeatureId);
- newFeatureOp.add(op.mFeatures.valueAt(featureNum));
- op.mFeatures.removeAt(featureNum);
+ AttributedOp newAttributedOp = op.getOrCreateAttribution(op,
+ newAttributionTag);
+ newAttributedOp.add(op.mAttributions.valueAt(attributionNum));
+ op.mAttributions.removeAt(attributionNum);
scheduleFastWriteLocked();
}
@@ -1737,12 +1749,13 @@
for (int opNum = 0; opNum < numOps; opNum++) {
final Op op = ops.valueAt(opNum);
- final int numFeatures = op.mFeatures.size();
- for (int featureNum = 0; featureNum < numFeatures; featureNum++) {
- FeatureOp featureOp = op.mFeatures.valueAt(featureNum);
+ final int numAttributions = op.mAttributions.size();
+ for (int attributionNum = 0; attributionNum < numAttributions;
+ attributionNum++) {
+ AttributedOp attributedOp = op.mAttributions.valueAt(attributionNum);
- while (featureOp.mInProgressEvents != null) {
- featureOp.finished(featureOp.mInProgressEvents.keyAt(0));
+ while (attributedOp.mInProgressEvents != null) {
+ attributedOp.finished(attributedOp.mInProgressEvents.keyAt(0));
}
}
}
@@ -1822,11 +1835,13 @@
for (int opNum = 0; opNum < numOps; opNum++) {
Op op = ops.valueAt(opNum);
- int numFeatures = op.mFeatures.size();
- for (int featureNum = 0; featureNum < numFeatures; featureNum++) {
- FeatureOp featureOp = op.mFeatures.valueAt(featureNum);
+ int numAttributions = op.mAttributions.size();
+ for (int attributionNum = 0; attributionNum < numAttributions;
+ attributionNum++) {
+ AttributedOp attributedOp = op.mAttributions.valueAt(
+ attributionNum);
- featureOp.onUidStateChanged(newState);
+ attributedOp.onUidStateChanged(newState);
}
}
}
@@ -1953,8 +1968,7 @@
return Collections.emptyList();
}
synchronized (this) {
- Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, null, false /* isPrivileged */,
- false /* edit */);
+ Ops pkgOps = getOpsLocked(uid, resolvedPackageName, null, null, false /* edit */);
if (pkgOps == null) {
return null;
}
@@ -1973,9 +1987,9 @@
/**
* Verify that historical appop request arguments are valid.
*/
- private void ensureHistoricalOpRequestIsValid(int uid, String packageName, String featureId,
- List<String> opNames, int filter, long beginTimeMillis, long endTimeMillis,
- int flags) {
+ private void ensureHistoricalOpRequestIsValid(int uid, String packageName,
+ String attributionTag, List<String> opNames, int filter, long beginTimeMillis,
+ long endTimeMillis, int flags) {
if ((filter & FILTER_BY_UID) != 0) {
Preconditions.checkArgument(uid != Process.INVALID_UID);
} else {
@@ -1988,8 +2002,8 @@
Preconditions.checkArgument(packageName == null);
}
- if ((filter & FILTER_BY_FEATURE_ID) == 0) {
- Preconditions.checkArgument(featureId == null);
+ if ((filter & FILTER_BY_ATTRIBUTION_TAG) == 0) {
+ Preconditions.checkArgument(attributionTag == null);
}
if ((filter & FILTER_BY_OP_NAMES) != 0) {
@@ -1999,17 +2013,18 @@
}
Preconditions.checkFlagsArgument(filter,
- FILTER_BY_UID | FILTER_BY_PACKAGE_NAME | FILTER_BY_FEATURE_ID | FILTER_BY_OP_NAMES);
+ FILTER_BY_UID | FILTER_BY_PACKAGE_NAME | FILTER_BY_ATTRIBUTION_TAG
+ | FILTER_BY_OP_NAMES);
Preconditions.checkArgumentNonnegative(beginTimeMillis);
Preconditions.checkArgument(endTimeMillis > beginTimeMillis);
Preconditions.checkFlagsArgument(flags, OP_FLAGS_ALL);
}
@Override
- public void getHistoricalOps(int uid, String packageName, String featureId,
+ public void getHistoricalOps(int uid, String packageName, String attributionTag,
List<String> opNames, int filter, long beginTimeMillis, long endTimeMillis,
int flags, RemoteCallback callback) {
- ensureHistoricalOpRequestIsValid(uid, packageName, featureId, opNames, filter,
+ ensureHistoricalOpRequestIsValid(uid, packageName, attributionTag, opNames, filter,
beginTimeMillis, endTimeMillis, flags);
Objects.requireNonNull(callback, "callback cannot be null");
@@ -2030,15 +2045,15 @@
// Must not hold the appops lock
mHandler.post(PooledLambda.obtainRunnable(HistoricalRegistry::getHistoricalOps,
- mHistoricalRegistry, uid, packageName, featureId, opNamesArray, filter,
+ mHistoricalRegistry, uid, packageName, attributionTag, opNamesArray, filter,
beginTimeMillis, endTimeMillis, flags, callback).recycleOnUse());
}
@Override
- public void getHistoricalOpsFromDiskRaw(int uid, String packageName, String featureId,
+ public void getHistoricalOpsFromDiskRaw(int uid, String packageName, String attributionTag,
List<String> opNames, int filter, long beginTimeMillis, long endTimeMillis,
int flags, RemoteCallback callback) {
- ensureHistoricalOpRequestIsValid(uid, packageName, featureId, opNames, filter,
+ ensureHistoricalOpRequestIsValid(uid, packageName, attributionTag, opNames, filter,
beginTimeMillis, endTimeMillis, flags);
Objects.requireNonNull(callback, "callback cannot be null");
@@ -2050,7 +2065,7 @@
// Must not hold the appops lock
mHandler.post(PooledLambda.obtainRunnable(HistoricalRegistry::getHistoricalOpsFromDiskRaw,
- mHistoricalRegistry, uid, packageName, featureId, opNamesArray,
+ mHistoricalRegistry, uid, packageName, attributionTag, opNamesArray,
filter, beginTimeMillis, endTimeMillis, flags, callback).recycleOnUse());
}
@@ -2084,11 +2099,10 @@
}
private void pruneOpLocked(Op op, int uid, String packageName) {
- op.removeFeaturesWithNoTime();
+ op.removeAttributionsWithNoTime();
- if (op.mFeatures.size() == 0) {
- Ops ops = getOpsRawLocked(uid, packageName, null, false /* isPrivileged */,
- false /* edit */);
+ if (op.mAttributions.isEmpty()) {
+ Ops ops = getOpsLocked(uid, packageName, null, null, false /* edit */);
if (ops != null) {
ops.remove(op.op);
if (ops.size() <= 0) {
@@ -2390,9 +2404,9 @@
ArraySet<ModeCallback> repCbs = null;
code = AppOpsManager.opToSwitch(code);
- boolean isPrivileged;
+ RestrictionBypass bypass;
try {
- isPrivileged = verifyAndGetIsPrivileged(uid, packageName, null);
+ bypass = verifyAndGetBypass(uid, packageName, null);
} catch (SecurityException e) {
Slog.e(TAG, "Cannot setMode", e);
return;
@@ -2400,7 +2414,7 @@
synchronized (this) {
UidState uidState = getUidStateLocked(uid, false);
- Op op = getOpLocked(code, uid, packageName, null, isPrivileged, true);
+ Op op = getOpLocked(code, uid, packageName, null, bypass, true);
if (op != null) {
if (op.mode != mode) {
op.mode = mode;
@@ -2606,8 +2620,8 @@
callbacks = addCallbacks(callbacks, curOp.op, uid, packageName,
mPackageModeWatchers.get(packageName));
- curOp.removeFeaturesWithNoTime();
- if (curOp.mFeatures.size() == 0) {
+ curOp.removeAttributionsWithNoTime();
+ if (curOp.mAttributions.isEmpty()) {
pkgOps.removeAt(j);
}
}
@@ -2674,10 +2688,8 @@
synchronized (this) {
int switchOp = (op != AppOpsManager.OP_NONE) ? AppOpsManager.opToSwitch(op) : op;
- // See CALL_BACK_ON_CHANGED_LISTENER_WITH_SWITCHED_OP_CHANGE
int notifiedOps;
- if (Compatibility.isChangeEnabled(
- CALL_BACK_ON_CHANGED_LISTENER_WITH_SWITCHED_OP_CHANGE)) {
+ if ((flags & CALL_BACK_ON_SWITCHED_OP) == 0) {
if (op == OP_NONE) {
notifiedOps = ALL_OPS;
} else {
@@ -2798,10 +2810,9 @@
*/
private @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName,
boolean raw) {
- boolean isPrivileged;
-
+ RestrictionBypass bypass;
try {
- isPrivileged = verifyAndGetIsPrivileged(uid, packageName, null);
+ bypass = verifyAndGetBypass(uid, packageName, null);
} catch (SecurityException e) {
Slog.e(TAG, "checkOperation", e);
return AppOpsManager.opToDefaultMode(code);
@@ -2811,7 +2822,7 @@
return AppOpsManager.MODE_IGNORED;
}
synchronized (this) {
- if (isOpRestrictedLocked(uid, code, packageName, null, isPrivileged)) {
+ if (isOpRestrictedLocked(uid, code, packageName, bypass)) {
return AppOpsManager.MODE_IGNORED;
}
code = AppOpsManager.opToSwitch(code);
@@ -2821,7 +2832,7 @@
final int rawMode = uidState.opModes.get(code);
return raw ? rawMode : uidState.evalMode(code, rawMode);
}
- Op op = getOpLocked(code, uid, packageName, null, false, false);
+ Op op = getOpLocked(code, uid, packageName, null, bypass, false);
if (op == null) {
return AppOpsManager.opToDefaultMode(code);
}
@@ -2884,7 +2895,7 @@
public int checkPackage(int uid, String packageName) {
Objects.requireNonNull(packageName);
try {
- verifyAndGetIsPrivileged(uid, packageName, null);
+ verifyAndGetBypass(uid, packageName, null);
return AppOpsManager.MODE_ALLOWED;
} catch (SecurityException ignored) {
@@ -2894,8 +2905,8 @@
@Override
public int noteProxyOperation(int code, int proxiedUid, String proxiedPackageName,
- String proxiedFeatureId, int proxyUid, String proxyPackageName,
- String proxyFeatureId, boolean shouldCollectAsyncNotedOp, String message) {
+ String proxiedAttributionTag, int proxyUid, String proxyPackageName,
+ String proxyAttributionTag, boolean shouldCollectAsyncNotedOp, String message) {
verifyIncomingUid(proxyUid);
verifyIncomingOp(code);
@@ -2911,7 +2922,7 @@
final int proxyFlags = isProxyTrusted ? AppOpsManager.OP_FLAG_TRUSTED_PROXY
: AppOpsManager.OP_FLAG_UNTRUSTED_PROXY;
final int proxyMode = noteOperationUnchecked(code, proxyUid, resolveProxyPackageName,
- proxyFeatureId, Process.INVALID_UID, null, null, proxyFlags,
+ proxyAttributionTag, Process.INVALID_UID, null, null, proxyFlags,
!isProxyTrusted, "proxy " + message);
if (proxyMode != AppOpsManager.MODE_ALLOWED || Binder.getCallingUid() == proxiedUid) {
return proxyMode;
@@ -2924,27 +2935,27 @@
final int proxiedFlags = isProxyTrusted ? AppOpsManager.OP_FLAG_TRUSTED_PROXIED
: AppOpsManager.OP_FLAG_UNTRUSTED_PROXIED;
return noteOperationUnchecked(code, proxiedUid, resolveProxiedPackageName,
- proxiedFeatureId, proxyUid, resolveProxyPackageName, proxyFeatureId,
+ proxiedAttributionTag, proxyUid, resolveProxyPackageName, proxyAttributionTag,
proxiedFlags, shouldCollectAsyncNotedOp, message);
}
@Override
- public int noteOperation(int code, int uid, String packageName, String featureId,
+ public int noteOperation(int code, int uid, String packageName, String attributionTag,
boolean shouldCollectAsyncNotedOp, String message) {
final CheckOpsDelegate delegate;
synchronized (this) {
delegate = mCheckOpsDelegate;
}
if (delegate == null) {
- return noteOperationImpl(code, uid, packageName, featureId, shouldCollectAsyncNotedOp,
- message);
+ return noteOperationImpl(code, uid, packageName, attributionTag,
+ shouldCollectAsyncNotedOp, message);
}
- return delegate.noteOperation(code, uid, packageName, featureId, shouldCollectAsyncNotedOp,
- message, AppOpsService.this::noteOperationImpl);
+ return delegate.noteOperation(code, uid, packageName, attributionTag,
+ shouldCollectAsyncNotedOp, message, AppOpsService.this::noteOperationImpl);
}
private int noteOperationImpl(int code, int uid, @Nullable String packageName,
- @Nullable String featureId, boolean shouldCollectAsyncNotedOp,
+ @Nullable String attributionTag, boolean shouldCollectAsyncNotedOp,
@Nullable String message) {
verifyIncomingUid(uid);
verifyIncomingOp(code);
@@ -2952,25 +2963,25 @@
if (resolvedPackageName == null) {
return AppOpsManager.MODE_IGNORED;
}
- return noteOperationUnchecked(code, uid, resolvedPackageName, featureId,
+ return noteOperationUnchecked(code, uid, resolvedPackageName, attributionTag,
Process.INVALID_UID, null, null, AppOpsManager.OP_FLAG_SELF,
shouldCollectAsyncNotedOp, message);
}
private int noteOperationUnchecked(int code, int uid, @NonNull String packageName,
- @Nullable String featureId, int proxyUid, String proxyPackageName,
- @Nullable String proxyFeatureId, @OpFlags int flags, boolean shouldCollectAsyncNotedOp,
- @Nullable String message) {
- boolean isPrivileged;
+ @Nullable String attributionTag, int proxyUid, String proxyPackageName,
+ @Nullable String proxyAttributionTag, @OpFlags int flags,
+ boolean shouldCollectAsyncNotedOp, @Nullable String message) {
+ RestrictionBypass bypass;
try {
- isPrivileged = verifyAndGetIsPrivileged(uid, packageName, featureId);
+ bypass = verifyAndGetBypass(uid, packageName, attributionTag);
} catch (SecurityException e) {
Slog.e(TAG, "noteOperation", e);
return AppOpsManager.MODE_ERRORED;
}
synchronized (this) {
- final Ops ops = getOpsRawLocked(uid, packageName, featureId, isPrivileged,
+ final Ops ops = getOpsLocked(uid, packageName, attributionTag, bypass,
true /* edit */);
if (ops == null) {
scheduleOpNotedIfNeededLocked(code, uid, packageName,
@@ -2980,17 +2991,17 @@
return AppOpsManager.MODE_ERRORED;
}
final Op op = getOpLocked(ops, code, uid, true);
- final FeatureOp featureOp = op.getOrCreateFeature(op, featureId);
- if (isOpRestrictedLocked(uid, code, packageName, featureId, isPrivileged)) {
+ final AttributedOp attributedOp = op.getOrCreateAttribution(op, attributionTag);
+ if (isOpRestrictedLocked(uid, code, packageName, bypass)) {
scheduleOpNotedIfNeededLocked(code, uid, packageName,
AppOpsManager.MODE_IGNORED);
return AppOpsManager.MODE_IGNORED;
}
final UidState uidState = ops.uidState;
- if (featureOp.isRunning()) {
+ if (attributedOp.isRunning()) {
Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName + " code "
+ code + " startTime of in progress event="
- + featureOp.mInProgressEvents.valueAt(0).getStartTime());
+ + attributedOp.mInProgressEvents.valueAt(0).getStartTime());
}
final int switchCode = AppOpsManager.opToSwitch(code);
@@ -3002,7 +3013,7 @@
if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
+ switchCode + " (" + code + ") uid " + uid + " package "
+ packageName);
- featureOp.rejected(uidState.state, flags);
+ attributedOp.rejected(uidState.state, flags);
scheduleOpNotedIfNeededLocked(code, uid, packageName, uidMode);
return uidMode;
}
@@ -3014,26 +3025,31 @@
if (DEBUG) Slog.d(TAG, "noteOperation: reject #" + mode + " for code "
+ switchCode + " (" + code + ") uid " + uid + " package "
+ packageName);
- featureOp.rejected(uidState.state, flags);
+ attributedOp.rejected(uidState.state, flags);
scheduleOpNotedIfNeededLocked(code, uid, packageName, mode);
return mode;
}
}
- if (DEBUG) Slog.d(TAG, "noteOperation: allowing code " + code + " uid " + uid
- + " package " + packageName + (featureId == null ? "" : "." + featureId));
- featureOp.accessed(proxyUid, proxyPackageName, proxyFeatureId, uidState.state, flags);
+ if (DEBUG) {
+ Slog.d(TAG,
+ "noteOperation: allowing code " + code + " uid " + uid + " package "
+ + packageName + (attributionTag == null ? ""
+ : "." + attributionTag));
+ }
+ attributedOp.accessed(proxyUid, proxyPackageName, proxyAttributionTag, uidState.state,
+ flags);
scheduleOpNotedIfNeededLocked(code, uid, packageName,
AppOpsManager.MODE_ALLOWED);
if (shouldCollectAsyncNotedOp) {
- collectAsyncNotedOp(uid, packageName, code, featureId, message);
+ collectAsyncNotedOp(uid, packageName, code, attributionTag, message);
}
return AppOpsManager.MODE_ALLOWED;
}
}
- // TODO moltmann: Allow watching for feature ops
+ // TODO moltmann: Allow watching for attribution ops
@Override
public void startWatchingActive(int[] ops, IAppOpsActiveCallback callback) {
int watchedUid = -1;
@@ -3131,11 +3147,11 @@
* @param uid The uid the op was noted for
* @param packageName The package the op was noted for
* @param opCode The code of the op noted
- * @param featureId The id of the feature to op was noted for
+ * @param attributionTag attribution tag the op was noted for
* @param message The message for the op noting
*/
private void collectAsyncNotedOp(int uid, @NonNull String packageName, int opCode,
- @Nullable String featureId, @NonNull String message) {
+ @Nullable String attributionTag, @NonNull String message) {
Objects.requireNonNull(message);
int callingUid = Binder.getCallingUid();
@@ -3147,10 +3163,10 @@
RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key);
AsyncNotedAppOp asyncNotedOp = new AsyncNotedAppOp(opCode, callingUid,
- featureId, message, System.currentTimeMillis());
+ attributionTag, message, System.currentTimeMillis());
final boolean[] wasNoteForwarded = {false};
- reportRuntimeAppOpAccessMessageAsyncLocked(uid, packageName, opCode, featureId,
+ reportRuntimeAppOpAccessMessageAsyncLocked(uid, packageName, opCode, attributionTag,
message);
if (callbacks != null) {
@@ -3161,7 +3177,7 @@
} catch (RemoteException e) {
Slog.e(TAG,
"Could not forward noteOp of " + opCode + " to " + packageName
- + "/" + uid + "(" + featureId + ")", e);
+ + "/" + uid + "(" + attributionTag + ")", e);
}
});
}
@@ -3205,7 +3221,7 @@
int uid = Binder.getCallingUid();
Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid);
- verifyAndGetIsPrivileged(uid, packageName, null);
+ verifyAndGetBypass(uid, packageName, null);
synchronized (this) {
RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key);
@@ -3235,7 +3251,7 @@
int uid = Binder.getCallingUid();
Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid);
- verifyAndGetIsPrivileged(uid, packageName, null);
+ verifyAndGetBypass(uid, packageName, null);
synchronized (this) {
RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key);
@@ -3254,7 +3270,7 @@
int uid = Binder.getCallingUid();
- verifyAndGetIsPrivileged(uid, packageName, null);
+ verifyAndGetBypass(uid, packageName, null);
synchronized (this) {
return mUnforwardedAsyncNotedOps.remove(getAsyncNotedOpsKey(packageName, uid));
@@ -3263,7 +3279,7 @@
@Override
public int startOperation(IBinder clientId, int code, int uid, String packageName,
- String featureId, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp,
+ String attributionTag, boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp,
String message) {
verifyIncomingUid(uid);
verifyIncomingOp(code);
@@ -3272,16 +3288,16 @@
return AppOpsManager.MODE_IGNORED;
}
- boolean isPrivileged;
+ RestrictionBypass bypass;
try {
- isPrivileged = verifyAndGetIsPrivileged(uid, packageName, featureId);
+ bypass = verifyAndGetBypass(uid, packageName, attributionTag);
} catch (SecurityException e) {
Slog.e(TAG, "startOperation", e);
return AppOpsManager.MODE_ERRORED;
}
synchronized (this) {
- final Ops ops = getOpsRawLocked(uid, resolvedPackageName, featureId, isPrivileged,
+ final Ops ops = getOpsLocked(uid, resolvedPackageName, attributionTag, bypass,
true /* edit */);
if (ops == null) {
if (DEBUG) Slog.d(TAG, "startOperation: no op for code " + code + " uid " + uid
@@ -3289,10 +3305,10 @@
return AppOpsManager.MODE_ERRORED;
}
final Op op = getOpLocked(ops, code, uid, true);
- if (isOpRestrictedLocked(uid, code, resolvedPackageName, featureId, isPrivileged)) {
+ if (isOpRestrictedLocked(uid, code, resolvedPackageName, bypass)) {
return AppOpsManager.MODE_IGNORED;
}
- final FeatureOp featureOp = op.getOrCreateFeature(op, featureId);
+ final AttributedOp attributedOp = op.getOrCreateAttribution(op, attributionTag);
final int switchCode = AppOpsManager.opToSwitch(code);
final UidState uidState = ops.uidState;
// If there is a non-default per UID policy (we set UID op mode only if
@@ -3305,7 +3321,7 @@
if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
+ switchCode + " (" + code + ") uid " + uid + " package "
+ resolvedPackageName);
- featureOp.rejected(uidState.state, AppOpsManager.OP_FLAG_SELF);
+ attributedOp.rejected(uidState.state, AppOpsManager.OP_FLAG_SELF);
return uidMode;
}
} else {
@@ -3317,21 +3333,21 @@
if (DEBUG) Slog.d(TAG, "startOperation: reject #" + mode + " for code "
+ switchCode + " (" + code + ") uid " + uid + " package "
+ resolvedPackageName);
- featureOp.rejected(uidState.state, AppOpsManager.OP_FLAG_SELF);
+ attributedOp.rejected(uidState.state, AppOpsManager.OP_FLAG_SELF);
return mode;
}
}
if (DEBUG) Slog.d(TAG, "startOperation: allowing code " + code + " uid " + uid
+ " package " + resolvedPackageName);
try {
- featureOp.started(clientId, uidState.state);
+ attributedOp.started(clientId, uidState.state);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
}
if (shouldCollectAsyncNotedOp) {
- collectAsyncNotedOp(uid, packageName, code, featureId, message);
+ collectAsyncNotedOp(uid, packageName, code, attributionTag, message);
}
return AppOpsManager.MODE_ALLOWED;
@@ -3339,7 +3355,7 @@
@Override
public void finishOperation(IBinder clientId, int code, int uid, String packageName,
- String featureId) {
+ String attributionTag) {
verifyIncomingUid(uid);
verifyIncomingOp(code);
String resolvedPackageName = resolvePackageName(uid, packageName);
@@ -3347,26 +3363,26 @@
return;
}
- boolean isPrivileged;
+ RestrictionBypass bypass;
try {
- isPrivileged = verifyAndGetIsPrivileged(uid, packageName, featureId);
+ bypass = verifyAndGetBypass(uid, packageName, attributionTag);
} catch (SecurityException e) {
Slog.e(TAG, "Cannot finishOperation", e);
return;
}
synchronized (this) {
- Op op = getOpLocked(code, uid, resolvedPackageName, featureId, isPrivileged, true);
+ Op op = getOpLocked(code, uid, resolvedPackageName, attributionTag, bypass, true);
if (op == null) {
return;
}
- final FeatureOp featureOp = op.mFeatures.get(featureId);
- if (featureOp == null) {
+ final AttributedOp attributedOp = op.mAttributions.get(attributionTag);
+ if (attributedOp == null) {
return;
}
try {
- featureOp.finished(clientId);
+ attributedOp.finished(clientId);
} catch (IllegalStateException e) {
Slog.e(TAG, "Operation not started: uid=" + uid + " pkg="
+ packageName + " op=" + AppOpsManager.opToName(code), e);
@@ -3617,50 +3633,66 @@
}
/**
- * Verify that package belongs to uid and return whether the package is privileged.
+ * Create a restriction description matching the properties of the package.
+ *
+ * @param context A context to use
+ * @param pkg The package to create the restriction description for
+ *
+ * @return The restriction matching the package
+ */
+ private RestrictionBypass getBypassforPackage(@NonNull AndroidPackage pkg) {
+ return new RestrictionBypass(pkg.isPrivileged(), mContext.checkPermission(
+ android.Manifest.permission.EXEMPT_FROM_AUDIO_RECORD_RESTRICTIONS, -1, pkg.getUid())
+ == PackageManager.PERMISSION_GRANTED);
+ }
+
+ /**
+ * Verify that package belongs to uid and return the {@link RestrictionBypass bypass
+ * description} for the package.
*
* @param uid The uid the package belongs to
* @param packageName The package the might belong to the uid
- * @param featureId The feature in the package or {@code null} if no need to verify
+ * @param attributionTag attribution tag or {@code null} if no need to verify
*
* @return {@code true} iff the package is privileged
*/
- private boolean verifyAndGetIsPrivileged(int uid, String packageName,
- @Nullable String featureId) {
+ private @Nullable RestrictionBypass verifyAndGetBypass(int uid, String packageName,
+ @Nullable String attributionTag) {
if (uid == Process.ROOT_UID) {
// For backwards compatibility, don't check package name for root UID.
- return false;
+ return null;
}
- // Do not check if uid/packageName/featureId is already known
+ // Do not check if uid/packageName/attributionTag is already known
synchronized (this) {
UidState uidState = mUidStates.get(uid);
if (uidState != null && uidState.pkgOps != null) {
Ops ops = uidState.pkgOps.get(packageName);
- if (ops != null && (featureId == null || ops.knownFeatureIds.contains(featureId))) {
- return ops.isPrivileged;
+ if (ops != null && (attributionTag == null || ops.knownAttributionTags.contains(
+ attributionTag)) && ops.bypass != null) {
+ return ops.bypass;
}
}
}
- boolean isPrivileged = false;
+ RestrictionBypass bypass = null;
final long ident = Binder.clearCallingIdentity();
try {
int pkgUid;
AndroidPackage pkg = LocalServices.getService(PackageManagerInternal.class).getPackage(
packageName);
- boolean isFeatureIdValid = false;
+ boolean isAttributionTagValid = false;
if (pkg != null) {
- if (featureId == null) {
- isFeatureIdValid = true;
+ if (attributionTag == null) {
+ isAttributionTagValid = true;
} else {
- if (pkg.getFeatures() != null) {
- int numFeatures = pkg.getFeatures().size();
- for (int i = 0; i < numFeatures; i++) {
- if (pkg.getFeatures().get(i).id.equals(featureId)) {
- isFeatureIdValid = true;
+ if (pkg.getAttributions() != null) {
+ int numAttributions = pkg.getAttributions().size();
+ for (int i = 0; i < numAttributions; i++) {
+ if (pkg.getAttributions().get(i).tag.equals(attributionTag)) {
+ isAttributionTagValid = true;
}
}
}
@@ -3668,14 +3700,14 @@
pkgUid = UserHandle.getUid(
UserHandle.getUserId(uid), UserHandle.getAppId(pkg.getUid()));
- isPrivileged = pkg.isPrivileged();
+ bypass = getBypassforPackage(pkg);
} else {
- // Allow any feature id for resolvable uids
- isFeatureIdValid = true;
+ // Allow any attribution tag for resolvable uids
+ isAttributionTagValid = true;
pkgUid = resolveUid(packageName);
if (pkgUid >= 0) {
- isPrivileged = false;
+ bypass = RestrictionBypass.UNRESTRICTED;
}
}
if (pkgUid != uid) {
@@ -3683,16 +3715,16 @@
+ " but it is really " + pkgUid);
}
- if (!isFeatureIdValid) {
+ if (!isAttributionTagValid) {
// TODO moltmann: Switch from logging to enforcement
- Slog.e(TAG, "featureId " + featureId + " not declared in manifest of "
+ Slog.e(TAG, "attributionTag " + attributionTag + " not declared in manifest of "
+ packageName);
}
} finally {
Binder.restoreCallingIdentity(ident);
}
- return isPrivileged;
+ return bypass;
}
/**
@@ -3700,14 +3732,14 @@
*
* @param uid The uid the package belongs to
* @param packageName The name of the package
- * @param featureId The feature in the package
- * @param isPrivileged If the package is privilidged (ignored if {@code edit} is false)
+ * @param attributionTag attribution tag
+ * @param bypass When to bypass certain op restrictions (can be null if edit == false)
* @param edit If an ops does not exist, create the ops?
- * @return
+ * @return The ops
*/
- private Ops getOpsRawLocked(int uid, String packageName, @Nullable String featureId,
- boolean isPrivileged, boolean edit) {
+ private Ops getOpsLocked(int uid, String packageName, @Nullable String attributionTag,
+ @Nullable RestrictionBypass bypass, boolean edit) {
UidState uidState = getUidStateLocked(uid, edit);
if (uidState == null) {
return null;
@@ -3725,53 +3757,18 @@
if (!edit) {
return null;
}
- ops = new Ops(packageName, uidState, isPrivileged);
- uidState.pkgOps.put(packageName, ops);
- }
- if (edit && featureId != null) {
- ops.knownFeatureIds.add(featureId);
- }
- return ops;
- }
-
- /**
- * Get the state of all ops for a package.
- *
- * <p>Usually callers should use {@link #getOpLocked} and not call this directly.
- *
- * @param uid The uid the of the package
- * @param packageName The package name for which to get the state for
- * @param featureId The feature in the package
- * @param edit Iff {@code true} create the {@link Ops} object if not yet created
- * @param isPrivileged Whether the package is privileged or not
- *
- * @return The {@link Ops state} of all ops for the package
- */
- private @Nullable Ops getOpsRawNoVerifyLocked(int uid, @NonNull String packageName,
- @Nullable String featureId, boolean edit, boolean isPrivileged) {
- UidState uidState = getUidStateLocked(uid, edit);
- if (uidState == null) {
- return null;
- }
-
- if (uidState.pkgOps == null) {
- if (!edit) {
- return null;
- }
- uidState.pkgOps = new ArrayMap<>();
- }
-
- Ops ops = uidState.pkgOps.get(packageName);
- if (ops == null) {
- if (!edit) {
- return null;
- }
- ops = new Ops(packageName, uidState, isPrivileged);
+ ops = new Ops(packageName, uidState);
uidState.pkgOps.put(packageName, ops);
}
- if (edit && featureId != null) {
- ops.knownFeatureIds.add(featureId);
+ if (edit) {
+ if (bypass != null) {
+ ops.bypass = bypass;
+ }
+
+ if (attributionTag != null) {
+ ops.knownAttributionTags.add(attributionTag);
+ }
}
return ops;
@@ -3799,16 +3796,15 @@
* @param code The code of the op
* @param uid The uid the of the package
* @param packageName The package name for which to get the state for
- * @param featureId The feature in the package
- * @param isPrivileged Whether the package is privileged or not (only used if {@code edit
- * == true})
+ * @param attributionTag The attribution tag
+ * @param bypass When to bypass certain op restrictions (can be null if edit == false)
* @param edit Iff {@code true} create the {@link Op} object if not yet created
*
* @return The {@link Op state} of the op
*/
private @Nullable Op getOpLocked(int code, int uid, @NonNull String packageName,
- @Nullable String featureId, boolean isPrivileged, boolean edit) {
- Ops ops = getOpsRawNoVerifyLocked(uid, packageName, featureId, edit, isPrivileged);
+ @Nullable String attributionTag, @Nullable RestrictionBypass bypass, boolean edit) {
+ Ops ops = getOpsLocked(uid, packageName, attributionTag, bypass, edit);
if (ops == null) {
return null;
}
@@ -3839,7 +3835,7 @@
}
private boolean isOpRestrictedLocked(int uid, int code, String packageName,
- @Nullable String featureId, boolean isPrivileged) {
+ @Nullable RestrictionBypass appBypass) {
int userHandle = UserHandle.getUserId(uid);
final int restrictionSetCount = mOpUserRestrictions.size();
@@ -3848,12 +3844,15 @@
// package is exempt from the restriction.
ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
if (restrictionState.hasRestriction(code, packageName, userHandle)) {
- if (AppOpsManager.opAllowSystemBypassRestriction(code)) {
+ RestrictionBypass opBypass = opAllowSystemBypassRestriction(code);
+ if (opBypass != null) {
// If we are the system, bypass user restrictions for certain codes
synchronized (this) {
- Ops ops = getOpsRawLocked(uid, packageName, featureId, isPrivileged,
- true /* edit */);
- if ((ops != null) && ops.isPrivileged) {
+ if (opBypass.isPrivileged && appBypass != null && appBypass.isPrivileged) {
+ return false;
+ }
+ if (opBypass.isRecordAudioRestrictionExcept && appBypass != null
+ && appBypass.isRecordAudioRestrictionExcept) {
return false;
}
}
@@ -4043,28 +4042,6 @@
throws NumberFormatException, XmlPullParserException, IOException {
int uid = Integer.parseInt(parser.getAttributeValue(null, "n"));
final UidState uidState = getUidStateLocked(uid, true);
- String isPrivilegedString = parser.getAttributeValue(null, "p");
- boolean isPrivileged = false;
- if (isPrivilegedString == null) {
- try {
- IPackageManager packageManager = ActivityThread.getPackageManager();
- if (packageManager != null) {
- ApplicationInfo appInfo = ActivityThread.getPackageManager()
- .getApplicationInfo(pkgName, 0, UserHandle.getUserId(uid));
- if (appInfo != null) {
- isPrivileged = (appInfo.privateFlags
- & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
- }
- } else {
- // Could not load data, don't add to cache so it will be loaded later.
- return;
- }
- } catch (RemoteException e) {
- Slog.w(TAG, "Could not contact PackageManager", e);
- }
- } else {
- isPrivileged = Boolean.parseBoolean(isPrivilegedString);
- }
int outerDepth = parser.getDepth();
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
@@ -4074,7 +4051,7 @@
}
String tagName = parser.getName();
if (tagName.equals("op")) {
- readOp(parser, uidState, pkgName, isPrivileged);
+ readOp(parser, uidState, pkgName);
} else {
Slog.w(TAG, "Unknown element under <pkg>: "
+ parser.getName());
@@ -4084,9 +4061,9 @@
uidState.evalForegroundOps(mOpModeWatchers);
}
- private void readFeatureOp(XmlPullParser parser, @NonNull Op parent,
- @Nullable String feature) throws NumberFormatException, IOException {
- final FeatureOp featureOp = parent.getOrCreateFeature(parent, feature);
+ private void readAttributionOp(XmlPullParser parser, @NonNull Op parent,
+ @Nullable String attribution) throws NumberFormatException, IOException {
+ final AttributedOp attributedOp = parent.getOrCreateAttribution(parent, attribution);
final long key = XmlUtils.readLongAttribute(parser, "n");
final int uidState = extractUidStateFromKey(key);
@@ -4097,19 +4074,19 @@
final long accessDuration = XmlUtils.readLongAttribute(parser, "d", -1);
final String proxyPkg = XmlUtils.readStringAttribute(parser, "pp");
final int proxyUid = XmlUtils.readIntAttribute(parser, "pu", Process.INVALID_UID);
- final String proxyFeatureId = XmlUtils.readStringAttribute(parser, "pc");
+ final String proxyAttributionTag = XmlUtils.readStringAttribute(parser, "pc");
if (accessTime > 0) {
- featureOp.accessed(accessTime, accessDuration, proxyUid, proxyPkg, proxyFeatureId,
- uidState, opFlags);
+ attributedOp.accessed(accessTime, accessDuration, proxyUid, proxyPkg,
+ proxyAttributionTag, uidState, opFlags);
}
if (rejectTime > 0) {
- featureOp.rejected(rejectTime, uidState, opFlags);
+ attributedOp.rejected(rejectTime, uidState, opFlags);
}
}
- private void readOp(XmlPullParser parser, @NonNull UidState uidState,
- @NonNull String pkgName, boolean isPrivileged) throws NumberFormatException,
+ private void readOp(XmlPullParser parser, @NonNull UidState uidState, @NonNull String pkgName)
+ throws NumberFormatException,
XmlPullParserException, IOException {
int opCode = Integer.parseInt(parser.getAttributeValue(null, "n"));
if (isIgnoredAppOp(opCode)) {
@@ -4130,7 +4107,7 @@
}
String tagName = parser.getName();
if (tagName.equals("st")) {
- readFeatureOp(parser, op, XmlUtils.readStringAttribute(parser, "id"));
+ readAttributionOp(parser, op, XmlUtils.readStringAttribute(parser, "id"));
} else {
Slog.w(TAG, "Unknown element under <op>: "
+ parser.getName());
@@ -4143,7 +4120,7 @@
}
Ops ops = uidState.pkgOps.get(pkgName);
if (ops == null) {
- ops = new Ops(pkgName, uidState, isPrivileged);
+ ops = new Ops(pkgName, uidState);
uidState.pkgOps.put(pkgName, ops);
}
ops.put(op.op, op);
@@ -4235,17 +4212,6 @@
}
out.startTag(null, "uid");
out.attribute(null, "n", Integer.toString(pkg.getUid()));
- synchronized (this) {
- Ops ops = getOpsRawLocked(pkg.getUid(), pkg.getPackageName(), null,
- false /* isPrivileged */, false /* edit */);
- // Should always be present as the list of PackageOps is generated
- // from Ops.
- if (ops != null) {
- out.attribute(null, "p", Boolean.toString(ops.isPrivileged));
- } else {
- out.attribute(null, "p", Boolean.toString(false));
- }
- }
List<AppOpsManager.OpEntry> ops = pkg.getOps();
for (int j=0; j<ops.size(); j++) {
AppOpsManager.OpEntry op = ops.get(j);
@@ -4255,11 +4221,11 @@
out.attribute(null, "m", Integer.toString(op.getMode()));
}
- for (String featureId : op.getFeatures().keySet()) {
- final OpFeatureEntry feature = op.getFeatures().get(
- featureId);
+ for (String attributionTag : op.getAttributedOpEntries().keySet()) {
+ final AttributedOpEntry attribution =
+ op.getAttributedOpEntries().get(attributionTag);
- final ArraySet<Long> keys = feature.collectKeys();
+ final ArraySet<Long> keys = attribution.collectKeys();
final int keyCount = keys.size();
for (int k = 0; k < keyCount; k++) {
@@ -4268,14 +4234,14 @@
final int uidState = AppOpsManager.extractUidStateFromKey(key);
final int flags = AppOpsManager.extractFlagsFromKey(key);
- final long accessTime = feature.getLastAccessTime(uidState,
+ final long accessTime = attribution.getLastAccessTime(uidState,
uidState, flags);
- final long rejectTime = feature.getLastRejectTime(uidState,
+ final long rejectTime = attribution.getLastRejectTime(uidState,
uidState, flags);
- final long accessDuration = feature.getLastDuration(uidState,
- uidState, flags);
+ final long accessDuration = attribution.getLastDuration(
+ uidState, uidState, flags);
// Proxy information for rejections is not backed up
- final OpEventProxyInfo proxy = feature.getLastProxyInfo(
+ final OpEventProxyInfo proxy = attribution.getLastProxyInfo(
uidState, uidState, flags);
if (accessTime <= 0 && rejectTime <= 0 && accessDuration <= 0
@@ -4284,17 +4250,17 @@
}
String proxyPkg = null;
- String proxyFeatureId = null;
+ String proxyAttributionTag = null;
int proxyUid = Process.INVALID_UID;
if (proxy != null) {
proxyPkg = proxy.getPackageName();
- proxyFeatureId = proxy.getFeatureId();
+ proxyAttributionTag = proxy.getAttributionTag();
proxyUid = proxy.getUid();
}
out.startTag(null, "st");
- if (featureId != null) {
- out.attribute(null, "id", featureId);
+ if (attributionTag != null) {
+ out.attribute(null, "id", attributionTag);
}
out.attribute(null, "n", Long.toString(key));
if (accessTime > 0) {
@@ -4309,8 +4275,8 @@
if (proxyPkg != null) {
out.attribute(null, "pp", proxyPkg);
}
- if (proxyFeatureId != null) {
- out.attribute(null, "pc", proxyFeatureId);
+ if (proxyAttributionTag != null) {
+ out.attribute(null, "pc", proxyAttributionTag);
}
if (proxyUid >= 0) {
out.attribute(null, "pu", Integer.toString(proxyUid));
@@ -4344,7 +4310,7 @@
int userId = UserHandle.USER_SYSTEM;
String packageName;
- String featureId;
+ String attributionTag;
String opStr;
String modeStr;
int op;
@@ -4446,8 +4412,8 @@
userId = UserHandle.parseUserArg(getNextArgRequired());
} else if ("--uid".equals(argument)) {
targetsUid = true;
- } else if ("--feature".equals(argument)) {
- featureId = getNextArgRequired();
+ } else if ("--attribution".equals(argument)) {
+ attributionTag = getNextArgRequired();
} else {
if (packageName == null) {
packageName = argument;
@@ -4542,13 +4508,16 @@
pw.println("AppOps service (appops) commands:");
pw.println(" help");
pw.println(" Print this help text.");
- pw.println(" start [--user <USER_ID>] [--feature <FEATURE_ID>] <PACKAGE | UID> <OP> ");
+ pw.println(" start [--user <USER_ID>] [--attribution <ATTRIBUTION_TAG>] <PACKAGE | UID> "
+ + "<OP> ");
pw.println(" Starts a given operation for a particular application.");
- pw.println(" stop [--user <USER_ID>] [--feature <FEATURE_ID>] <PACKAGE | UID> <OP> ");
+ pw.println(" stop [--user <USER_ID>] [--attribution <ATTRIBUTION_TAG>] <PACKAGE | UID> "
+ + "<OP> ");
pw.println(" Stops a given operation for a particular application.");
pw.println(" set [--user <USER_ID>] <[--uid] PACKAGE | UID> <OP> <MODE>");
pw.println(" Set the mode for a particular application and operation.");
- pw.println(" get [--user <USER_ID>] [--feature <FEATURE_ID>] <PACKAGE | UID> [<OP>]");
+ pw.println(" get [--user <USER_ID>] [--attribution <ATTRIBUTION_TAG>] <PACKAGE | UID> "
+ + "[<OP>]");
pw.println(" Return the mode for a particular application and optional operation.");
pw.println(" query-op [--user <USER_ID>] <OP> [<MODE>]");
pw.println(" Print all packages that currently have the given op in the given mode.");
@@ -4562,8 +4531,8 @@
pw.println(" <PACKAGE> an Android package name or its UID if prefixed by --uid");
pw.println(" <OP> an AppOps operation.");
pw.println(" <MODE> one of allow, ignore, deny, or default");
- pw.println(" <USER_ID> the user id under which the package is installed. If --user is not");
- pw.println(" specified, the current user is assumed.");
+ pw.println(" <USER_ID> the user id under which the package is installed. If --user is");
+ pw.println(" not specified, the current user is assumed.");
}
static int onShellCommand(Shell shell, String cmd) {
@@ -4652,7 +4621,7 @@
pw.print(AppOpsManager.opToName(ent.getOp()));
pw.print(": ");
pw.print(AppOpsManager.modeToName(ent.getMode()));
- if (shell.featureId == null) {
+ if (shell.attributionTag == null) {
if (ent.getLastAccessTime(OP_FLAGS_ALL) != -1) {
pw.print("; time=");
TimeUtils.formatDuration(
@@ -4672,29 +4641,30 @@
TimeUtils.formatDuration(ent.getLastDuration(OP_FLAGS_ALL), pw);
}
} else {
- final OpFeatureEntry featureEnt = ent.getFeatures().get(
- shell.featureId);
- if (featureEnt != null) {
- if (featureEnt.getLastAccessTime(OP_FLAGS_ALL) != -1) {
+ final AppOpsManager.AttributedOpEntry attributionEnt =
+ ent.getAttributedOpEntries().get(shell.attributionTag);
+ if (attributionEnt != null) {
+ if (attributionEnt.getLastAccessTime(OP_FLAGS_ALL) != -1) {
pw.print("; time=");
- TimeUtils.formatDuration(now - featureEnt.getLastAccessTime(
- OP_FLAGS_ALL), pw);
+ TimeUtils.formatDuration(
+ now - attributionEnt.getLastAccessTime(
+ OP_FLAGS_ALL), pw);
pw.print(" ago");
}
- if (featureEnt.getLastRejectTime(OP_FLAGS_ALL) != -1) {
+ if (attributionEnt.getLastRejectTime(OP_FLAGS_ALL) != -1) {
pw.print("; rejectTime=");
TimeUtils.formatDuration(
- now - featureEnt.getLastRejectTime(OP_FLAGS_ALL),
- pw);
+ now - attributionEnt.getLastRejectTime(
+ OP_FLAGS_ALL), pw);
pw.print(" ago");
}
- if (featureEnt.isRunning()) {
+ if (attributionEnt.isRunning()) {
pw.print(" (running)");
- } else if (featureEnt.getLastDuration(OP_FLAGS_ALL)
+ } else if (attributionEnt.getLastDuration(OP_FLAGS_ALL)
!= -1) {
pw.print("; duration=");
TimeUtils.formatDuration(
- featureEnt.getLastDuration(OP_FLAGS_ALL), pw);
+ attributionEnt.getLastDuration(OP_FLAGS_ALL), pw);
}
}
}
@@ -4802,7 +4772,7 @@
if (shell.packageName != null) {
shell.mInterface.startOperation(shell.mToken, shell.op, shell.packageUid,
- shell.packageName, shell.featureId, true, true,
+ shell.packageName, shell.attributionTag, true, true,
"appops start shell command");
} else {
return -1;
@@ -4816,8 +4786,8 @@
}
if (shell.packageName != null) {
- shell.mInterface.finishOperation(shell.mToken,
- shell.op, shell.packageUid, shell.packageName, shell.featureId);
+ shell.mInterface.finishOperation(shell.mToken, shell.op, shell.packageUid,
+ shell.packageName, shell.attributionTag);
} else {
return -1;
}
@@ -4842,35 +4812,35 @@
pw.println(" Limit output to data associated with the given app op mode.");
pw.println(" --package [PACKAGE]");
pw.println(" Limit output to data associated with the given package name.");
- pw.println(" --featureId [featureId]");
- pw.println(" Limit output to data associated with the given feature id.");
+ pw.println(" --attributionTag [attributionTag]");
+ pw.println(" Limit output to data associated with the given attribution tag.");
pw.println(" --watchers");
pw.println(" Only output the watcher sections.");
}
- private void dumpStatesLocked(@NonNull PrintWriter pw, @Nullable String filterFeatureId,
+ private void dumpStatesLocked(@NonNull PrintWriter pw, @Nullable String filterAttributionTag,
@HistoricalOpsRequestFilter int filter, long nowElapsed, @NonNull Op op, long now,
@NonNull SimpleDateFormat sdf, @NonNull Date date, @NonNull String prefix) {
- final int numFeatures = op.mFeatures.size();
- for (int i = 0; i < numFeatures; i++) {
- if ((filter & FILTER_BY_FEATURE_ID) != 0 && !Objects.equals(op.mFeatures.keyAt(i),
- filterFeatureId)) {
+ final int numAttributions = op.mAttributions.size();
+ for (int i = 0; i < numAttributions; i++) {
+ if ((filter & FILTER_BY_ATTRIBUTION_TAG) != 0 && !Objects.equals(
+ op.mAttributions.keyAt(i), filterAttributionTag)) {
continue;
}
- pw.print(prefix + op.mFeatures.keyAt(i) + "=[\n");
- dumpStatesLocked(pw, nowElapsed, op, op.mFeatures.keyAt(i), now, sdf, date,
+ pw.print(prefix + op.mAttributions.keyAt(i) + "=[\n");
+ dumpStatesLocked(pw, nowElapsed, op, op.mAttributions.keyAt(i), now, sdf, date,
prefix + " ");
pw.print(prefix + "]\n");
}
}
private void dumpStatesLocked(@NonNull PrintWriter pw, long nowElapsed, @NonNull Op op,
- @Nullable String featureId, long now, @NonNull SimpleDateFormat sdf,
+ @Nullable String attributionTag, long now, @NonNull SimpleDateFormat sdf,
@NonNull Date date, @NonNull String prefix) {
- final OpFeatureEntry entry = op.createSingleFeatureEntryLocked(
- featureId).getFeatures().get(featureId);
+ final AttributedOpEntry entry = op.createSingleAttributionEntryLocked(
+ attributionTag).getAttributedOpEntries().get(attributionTag);
final ArraySet<Long> keys = entry.collectKeys();
@@ -4887,11 +4857,11 @@
final OpEventProxyInfo proxy = entry.getLastProxyInfo(uidState, uidState, flags);
String proxyPkg = null;
- String proxyFeatureId = null;
+ String proxyAttributionTag = null;
int proxyUid = Process.INVALID_UID;
if (proxy != null) {
proxyPkg = proxy.getPackageName();
- proxyFeatureId = proxy.getFeatureId();
+ proxyAttributionTag = proxy.getAttributionTag();
proxyUid = proxy.getUid();
}
@@ -4915,8 +4885,8 @@
pw.print(proxyUid);
pw.print(", pkg=");
pw.print(proxyPkg);
- pw.print(", feature=");
- pw.print(proxyFeatureId);
+ pw.print(", attributionTag=");
+ pw.print(proxyAttributionTag);
pw.print("]");
}
pw.println();
@@ -4937,21 +4907,21 @@
pw.print(proxyUid);
pw.print(", pkg=");
pw.print(proxyPkg);
- pw.print(", feature=");
- pw.print(proxyFeatureId);
+ pw.print(", attributionTag=");
+ pw.print(proxyAttributionTag);
pw.print("]");
}
pw.println();
}
}
- final FeatureOp featureOp = op.mFeatures.get(featureId);
- if (featureOp.isRunning()) {
+ final AttributedOp attributedOp = op.mAttributions.get(attributionTag);
+ if (attributedOp.isRunning()) {
long earliestElapsedTime = Long.MAX_VALUE;
long maxNumStarts = 0;
- int numInProgressEvents = featureOp.mInProgressEvents.size();
+ int numInProgressEvents = attributedOp.mInProgressEvents.size();
for (int i = 0; i < numInProgressEvents; i++) {
- InProgressStartOpEvent event = featureOp.mInProgressEvents.valueAt(i);
+ InProgressStartOpEvent event = attributedOp.mInProgressEvents.valueAt(i);
earliestElapsedTime = Math.min(earliestElapsedTime, event.getStartElapsedTime());
maxNumStarts = Math.max(maxNumStarts, event.numUnfinishedStarts);
@@ -4974,7 +4944,7 @@
int dumpOp = OP_NONE;
String dumpPackage = null;
- String dumpFeatureId = null;
+ String dumpAttributionTag = null;
int dumpUid = Process.INVALID_UID;
int dumpMode = -1;
boolean dumpWatchers = false;
@@ -5021,14 +4991,14 @@
}
dumpUid = UserHandle.getAppId(dumpUid);
dumpFilter |= FILTER_BY_UID;
- } else if ("--featureId".equals(arg)) {
+ } else if ("--attributionTag".equals(arg)) {
i++;
if (i >= args.length) {
- pw.println("No argument for --featureId option");
+ pw.println("No argument for --attributionTag option");
return;
}
- dumpFeatureId = args[i];
- dumpFilter |= FILTER_BY_FEATURE_ID;
+ dumpAttributionTag = args[i];
+ dumpFilter |= FILTER_BY_ATTRIBUTION_TAG;
} else if ("--mode".equals(arg)) {
i++;
if (i >= args.length) {
@@ -5367,8 +5337,8 @@
pw.print("="); pw.print(AppOpsManager.modeToName(mode));
}
pw.println("): ");
- dumpStatesLocked(pw, dumpFeatureId, dumpFilter, nowElapsed, op, now, sdf,
- date, " ");
+ dumpStatesLocked(pw, dumpAttributionTag, dumpFilter, nowElapsed, op, now,
+ sdf, date, " ");
}
}
}
@@ -5467,7 +5437,7 @@
// Must not hold the appops lock
if (dumpHistory && !dumpWatchers) {
- mHistoricalRegistry.dump(" ", pw, dumpUid, dumpPackage, dumpFeatureId, dumpOp,
+ mHistoricalRegistry.dump(" ", pw, dumpUid, dumpPackage, dumpAttributionTag, dumpOp,
dumpFilter);
}
}
@@ -5572,9 +5542,9 @@
if (resolvedPackageName == null) {
return false;
}
- // TODO moltmann: Allow to check for feature op activeness
+ // TODO moltmann: Allow to check for attribution op activeness
synchronized (AppOpsService.this) {
- Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, null, false, false);
+ Ops pkgOps = getOpsLocked(uid, resolvedPackageName, null, null, false);
if (pkgOps == null) {
return false;
}
@@ -5633,7 +5603,7 @@
* Report runtime access to AppOp together with message (including stack trace)
*
* @param packageName The package which reported the op
- * @param notedAppOp contains code of op and featureId provided by developer
+ * @param notedAppOp contains code of op and attributionTag provided by developer
* @param message Message describing AppOp access (can be stack trace)
*
* @return Config for future sampling to reduce amount of reporting
@@ -5655,7 +5625,7 @@
reportRuntimeAppOpAccessMessageInternalLocked(uid, packageName,
AppOpsManager.strOpToOp(notedAppOp.getOp()),
- notedAppOp.getFeatureId(), message);
+ notedAppOp.getAttributionTag(), message);
return new MessageSamplingConfig(mSampledAppOpCode, mAcceptableLeftDistance,
Instant.now().plus(1, ChronoUnit.HOURS).toEpochMilli());
@@ -5668,17 +5638,18 @@
* @param uid Uid of the package which reported the op
* @param packageName The package which reported the op
* @param opCode Code of AppOp
- * @param featureId FeautreId of AppOp reported
+ * @param attributionTag FeautreId of AppOp reported
* @param message Message describing AppOp access (can be stack trace)
*/
private void reportRuntimeAppOpAccessMessageAsyncLocked(int uid,
- @NonNull String packageName, int opCode, @Nullable String featureId,
+ @NonNull String packageName, int opCode, @Nullable String attributionTag,
@NonNull String message) {
switchPackageIfRarelyUsedLocked(packageName);
if (!Objects.equals(mSampledPackage, packageName)) {
return;
}
- reportRuntimeAppOpAccessMessageInternalLocked(uid, packageName, opCode, featureId, message);
+ reportRuntimeAppOpAccessMessageInternalLocked(uid, packageName, opCode, attributionTag,
+ message);
}
/**
@@ -5686,7 +5657,7 @@
* reporting uniformly at random across all received messages.
*/
private void reportRuntimeAppOpAccessMessageInternalLocked(int uid,
- @NonNull String packageName, int opCode, @Nullable String featureId,
+ @NonNull String packageName, int opCode, @Nullable String attributionTag,
@NonNull String message) {
int newLeftDistance = AppOpsManager.leftCircularDistance(opCode,
mSampledAppOpCode, _NUM_OP);
@@ -5703,7 +5674,7 @@
mMessagesCollectedCount += 1.0f;
if (ThreadLocalRandom.current().nextFloat() <= 1.0f / mMessagesCollectedCount) {
mCollectedRuntimePermissionMessage = new RuntimeAppOpAccessMessage(uid, opCode,
- packageName, featureId, message, mSamplingStrategy);
+ packageName, attributionTag, message, mSamplingStrategy);
}
return;
}
diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java
index cd450d4..ed45069 100644
--- a/services/core/java/com/android/server/appop/HistoricalRegistry.java
+++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java
@@ -15,7 +15,7 @@
*/
package com.android.server.appop;
-import static android.app.AppOpsManager.FILTER_BY_FEATURE_ID;
+import static android.app.AppOpsManager.FILTER_BY_ATTRIBUTION_TAG;
import static android.app.AppOpsManager.FILTER_BY_OP_NAMES;
import static android.app.AppOpsManager.FILTER_BY_PACKAGE_NAME;
import static android.app.AppOpsManager.FILTER_BY_UID;
@@ -23,7 +23,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AppOpsManager;
-import android.app.AppOpsManager.HistoricalFeatureOps;
import android.app.AppOpsManager.HistoricalMode;
import android.app.AppOpsManager.HistoricalOp;
import android.app.AppOpsManager.HistoricalOps;
@@ -282,7 +281,7 @@
}
void dump(String prefix, PrintWriter pw, int filterUid, @Nullable String filterPackage,
- @Nullable String filterFeatureId, int filterOp,
+ @Nullable String filterAttributionTag, int filterOp,
@HistoricalOpsRequestFilter int filter) {
if (!isApiEnabled()) {
return;
@@ -298,7 +297,7 @@
pw.println(AppOpsManager.historicalModeToString(mMode));
final StringDumpVisitor visitor = new StringDumpVisitor(prefix + " ",
- pw, filterUid, filterPackage, filterFeatureId, filterOp, filter);
+ pw, filterUid, filterPackage, filterAttributionTag, filterOp, filter);
final long nowMillis = System.currentTimeMillis();
// Dump in memory state first
@@ -338,7 +337,7 @@
}
void getHistoricalOpsFromDiskRaw(int uid, @NonNull String packageName,
- @Nullable String featureId, @Nullable String[] opNames,
+ @Nullable String attributionTag, @Nullable String[] opNames,
@HistoricalOpsRequestFilter int filter, long beginTimeMillis, long endTimeMillis,
@OpFlags int flags, @NonNull RemoteCallback callback) {
if (!isApiEnabled()) {
@@ -354,7 +353,7 @@
return;
}
final HistoricalOps result = new HistoricalOps(beginTimeMillis, endTimeMillis);
- mPersistence.collectHistoricalOpsDLocked(result, uid, packageName, featureId,
+ mPersistence.collectHistoricalOpsDLocked(result, uid, packageName, attributionTag,
opNames, filter, beginTimeMillis, endTimeMillis, flags);
final Bundle payload = new Bundle();
payload.putParcelable(AppOpsManager.KEY_HISTORICAL_OPS, result);
@@ -363,7 +362,7 @@
}
}
- void getHistoricalOps(int uid, @NonNull String packageName, @Nullable String featureId,
+ void getHistoricalOps(int uid, @NonNull String packageName, @Nullable String attributionTag,
@Nullable String[] opNames, @HistoricalOpsRequestFilter int filter,
long beginTimeMillis, long endTimeMillis, @OpFlags int flags,
@NonNull RemoteCallback callback) {
@@ -401,7 +400,7 @@
|| inMemoryAdjEndTimeMillis <= currentOps.getBeginTimeMillis())) {
// Some of the current batch falls into the query, so extract that.
final HistoricalOps currentOpsCopy = new HistoricalOps(currentOps);
- currentOpsCopy.filter(uid, packageName, featureId, opNames, filter,
+ currentOpsCopy.filter(uid, packageName, attributionTag, opNames, filter,
inMemoryAdjBeginTimeMillis, inMemoryAdjEndTimeMillis);
result.merge(currentOpsCopy);
}
@@ -421,7 +420,7 @@
- onDiskAndInMemoryOffsetMillis, 0);
final long onDiskAdjEndTimeMillis = Math.max(inMemoryAdjEndTimeMillis
- onDiskAndInMemoryOffsetMillis, 0);
- mPersistence.collectHistoricalOpsDLocked(result, uid, packageName, featureId,
+ mPersistence.collectHistoricalOpsDLocked(result, uid, packageName, attributionTag,
opNames, filter, onDiskAdjBeginTimeMillis, onDiskAdjEndTimeMillis, flags);
}
@@ -436,7 +435,7 @@
}
void incrementOpAccessedCount(int op, int uid, @NonNull String packageName,
- @Nullable String featureId, @UidState int uidState, @OpFlags int flags) {
+ @Nullable String attributionTag, @UidState int uidState, @OpFlags int flags) {
synchronized (mInMemoryLock) {
if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) {
if (!isPersistenceInitializedMLocked()) {
@@ -445,13 +444,13 @@
}
getUpdatedPendingHistoricalOpsMLocked(
System.currentTimeMillis()).increaseAccessCount(op, uid, packageName,
- featureId, uidState, flags, 1);
+ attributionTag, uidState, flags, 1);
}
}
}
void incrementOpRejected(int op, int uid, @NonNull String packageName,
- @Nullable String featureId, @UidState int uidState, @OpFlags int flags) {
+ @Nullable String attributionTag, @UidState int uidState, @OpFlags int flags) {
synchronized (mInMemoryLock) {
if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) {
if (!isPersistenceInitializedMLocked()) {
@@ -460,13 +459,13 @@
}
getUpdatedPendingHistoricalOpsMLocked(
System.currentTimeMillis()).increaseRejectCount(op, uid, packageName,
- featureId, uidState, flags, 1);
+ attributionTag, uidState, flags, 1);
}
}
}
void increaseOpAccessDuration(int op, int uid, @NonNull String packageName,
- @Nullable String featureId, @UidState int uidState, @OpFlags int flags,
+ @Nullable String attributionTag, @UidState int uidState, @OpFlags int flags,
long increment) {
synchronized (mInMemoryLock) {
if (mMode == AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE) {
@@ -476,7 +475,7 @@
}
getUpdatedPendingHistoricalOpsMLocked(
System.currentTimeMillis()).increaseAccessDuration(op, uid, packageName,
- featureId, uidState, flags, increment);
+ attributionTag, uidState, flags, increment);
}
}
}
@@ -728,7 +727,7 @@
private static final String TAG_OPS = "ops";
private static final String TAG_UID = "uid";
private static final String TAG_PACKAGE = "pkg";
- private static final String TAG_FEATURE = "ftr";
+ private static final String TAG_ATTRIBUTION = "ftr";
private static final String TAG_OP = "op";
private static final String TAG_STATE = "st";
@@ -807,9 +806,9 @@
@Nullable List<HistoricalOps> readHistoryRawDLocked() {
return collectHistoricalOpsBaseDLocked(Process.INVALID_UID /*filterUid*/,
- null /*filterPackageName*/, null /*filterFeatureId*/, null /*filterOpNames*/,
- 0 /*filter*/, 0 /*filterBeginTimeMills*/, Long.MAX_VALUE /*filterEndTimeMills*/,
- AppOpsManager.OP_FLAGS_ALL);
+ null /*filterPackageName*/, null /*filterAttributionTag*/,
+ null /*filterOpNames*/, 0 /*filter*/, 0 /*filterBeginTimeMills*/,
+ Long.MAX_VALUE /*filterEndTimeMills*/, AppOpsManager.OP_FLAGS_ALL);
}
@Nullable List<HistoricalOps> readHistoryDLocked() {
@@ -861,13 +860,13 @@
return 0;
}
- private void collectHistoricalOpsDLocked(@NonNull HistoricalOps currentOps,
- int filterUid, @Nullable String filterPackageName, @Nullable String filterFeatureId,
+ private void collectHistoricalOpsDLocked(@NonNull HistoricalOps currentOps, int filterUid,
+ @Nullable String filterPackageName, @Nullable String filterAttributionTag,
@Nullable String[] filterOpNames, @HistoricalOpsRequestFilter int filter,
long filterBeingMillis, long filterEndMillis, @OpFlags int filterFlags) {
final List<HistoricalOps> readOps = collectHistoricalOpsBaseDLocked(filterUid,
- filterPackageName, filterFeatureId, filterOpNames, filter, filterBeingMillis,
- filterEndMillis, filterFlags);
+ filterPackageName, filterAttributionTag, filterOpNames, filter,
+ filterBeingMillis, filterEndMillis, filterFlags);
if (readOps != null) {
final int readCount = readOps.size();
for (int i = 0; i < readCount; i++) {
@@ -877,8 +876,8 @@
}
}
- private @Nullable LinkedList<HistoricalOps> collectHistoricalOpsBaseDLocked(
- int filterUid, @Nullable String filterPackageName, @Nullable String filterFeatureId,
+ private @Nullable LinkedList<HistoricalOps> collectHistoricalOpsBaseDLocked(int filterUid,
+ @Nullable String filterPackageName, @Nullable String filterAttributionTag,
@Nullable String[] filterOpNames, @HistoricalOpsRequestFilter int filter,
long filterBeginTimeMillis, long filterEndTimeMillis, @OpFlags int filterFlags) {
File baseDir = null;
@@ -892,7 +891,7 @@
final Set<String> historyFiles = getHistoricalFileNames(baseDir);
final long[] globalContentOffsetMillis = {0};
final LinkedList<HistoricalOps> ops = collectHistoricalOpsRecursiveDLocked(
- baseDir, filterUid, filterPackageName, filterFeatureId, filterOpNames,
+ baseDir, filterUid, filterPackageName, filterAttributionTag, filterOpNames,
filter, filterBeginTimeMillis, filterEndTimeMillis, filterFlags,
globalContentOffsetMillis, null /*outOps*/, 0 /*depth*/, historyFiles);
if (DEBUG) {
@@ -909,7 +908,7 @@
private @Nullable LinkedList<HistoricalOps> collectHistoricalOpsRecursiveDLocked(
@NonNull File baseDir, int filterUid, @Nullable String filterPackageName,
- @Nullable String filterFeatureId, @Nullable String[] filterOpNames,
+ @Nullable String filterAttributionTag, @Nullable String[] filterOpNames,
@HistoricalOpsRequestFilter int filter, long filterBeginTimeMillis,
long filterEndTimeMillis, @OpFlags int filterFlags,
@NonNull long[] globalContentOffsetMillis,
@@ -927,7 +926,7 @@
// Read historical data at this level
final List<HistoricalOps> readOps = readHistoricalOpsLocked(baseDir,
previousIntervalEndMillis, currentIntervalEndMillis, filterUid,
- filterPackageName, filterFeatureId, filterOpNames, filter,
+ filterPackageName, filterAttributionTag, filterOpNames, filter,
filterBeginTimeMillis, filterEndTimeMillis, filterFlags,
globalContentOffsetMillis, depth, historyFiles);
// Empty is a special signal to stop diving
@@ -937,7 +936,7 @@
// Collect older historical data from subsequent levels
outOps = collectHistoricalOpsRecursiveDLocked(baseDir, filterUid, filterPackageName,
- filterFeatureId, filterOpNames, filter, filterBeginTimeMillis,
+ filterAttributionTag, filterOpNames, filter, filterBeginTimeMillis,
filterEndTimeMillis, filterFlags, globalContentOffsetMillis, outOps, depth + 1,
historyFiles);
@@ -1006,7 +1005,7 @@
final List<HistoricalOps> existingOps = readHistoricalOpsLocked(oldBaseDir,
previousIntervalEndMillis, currentIntervalEndMillis,
Process.INVALID_UID /*filterUid*/, null /*filterPackageName*/,
- null /*filterFeatureId*/, null /*filterOpNames*/, 0 /*filter*/,
+ null /*filterAttributionTag*/, null /*filterOpNames*/, 0 /*filter*/,
Long.MIN_VALUE /*filterBeginTimeMillis*/,
Long.MAX_VALUE /*filterEndTimeMillis*/, AppOpsManager.OP_FLAGS_ALL, null, depth,
null /*historyFiles*/);
@@ -1120,7 +1119,7 @@
private @Nullable List<HistoricalOps> readHistoricalOpsLocked(File baseDir,
long intervalBeginMillis, long intervalEndMillis, int filterUid,
- @Nullable String filterPackageName, @Nullable String filterFeatureId,
+ @Nullable String filterPackageName, @Nullable String filterAttributionTag,
@Nullable String[] filterOpNames, @HistoricalOpsRequestFilter int filter,
long filterBeginTimeMillis, long filterEndTimeMillis, @OpFlags int filterFlags,
@Nullable long[] cumulativeOverflowMillis, int depth,
@@ -1147,15 +1146,16 @@
return null;
}
}
- return readHistoricalOpsLocked(file, filterUid, filterPackageName, filterFeatureId,
+ return readHistoricalOpsLocked(file, filterUid, filterPackageName, filterAttributionTag,
filterOpNames, filter, filterBeginTimeMillis, filterEndTimeMillis, filterFlags,
cumulativeOverflowMillis);
}
- private @Nullable List<HistoricalOps> readHistoricalOpsLocked(@NonNull File file,
- int filterUid, @Nullable String filterPackageName, @Nullable String filterFeatureId,
- @Nullable String[] filterOpNames, @HistoricalOpsRequestFilter int filter,
- long filterBeginTimeMillis, long filterEndTimeMillis, @OpFlags int filterFlags,
+ private @Nullable List<HistoricalOps> readHistoricalOpsLocked(@NonNull File file,
+ int filterUid, @Nullable String filterPackageName,
+ @Nullable String filterAttributionTag, @Nullable String[] filterOpNames,
+ @HistoricalOpsRequestFilter int filter, long filterBeginTimeMillis,
+ long filterEndTimeMillis, @OpFlags int filterFlags,
@Nullable long[] cumulativeOverflowMillis)
throws IOException, XmlPullParserException {
if (DEBUG) {
@@ -1180,7 +1180,7 @@
while (XmlUtils.nextElementWithin(parser, depth)) {
if (TAG_OPS.equals(parser.getName())) {
final HistoricalOps ops = readeHistoricalOpsDLocked(parser, filterUid,
- filterPackageName, filterFeatureId, filterOpNames, filter,
+ filterPackageName, filterAttributionTag, filterOpNames, filter,
filterBeginTimeMillis, filterEndTimeMillis, filterFlags,
cumulativeOverflowMillis);
if (ops == null) {
@@ -1215,7 +1215,7 @@
private @Nullable HistoricalOps readeHistoricalOpsDLocked(
@NonNull XmlPullParser parser, int filterUid, @Nullable String filterPackageName,
- @Nullable String filterFeatureId, @Nullable String[] filterOpNames,
+ @Nullable String filterAttributionTag, @Nullable String[] filterOpNames,
@HistoricalOpsRequestFilter int filter, long filterBeginTimeMillis,
long filterEndTimeMillis, @OpFlags int filterFlags,
@Nullable long[] cumulativeOverflowMillis)
@@ -1245,8 +1245,8 @@
while (XmlUtils.nextElementWithin(parser, depth)) {
if (TAG_UID.equals(parser.getName())) {
final HistoricalOps returnedOps = readHistoricalUidOpsDLocked(ops, parser,
- filterUid, filterPackageName, filterFeatureId, filterOpNames, filter,
- filterFlags, filterScale);
+ filterUid, filterPackageName, filterAttributionTag, filterOpNames,
+ filter, filterFlags, filterScale);
if (ops == null) {
ops = returnedOps;
}
@@ -1260,7 +1260,7 @@
private @Nullable HistoricalOps readHistoricalUidOpsDLocked(
@Nullable HistoricalOps ops, @NonNull XmlPullParser parser, int filterUid,
- @Nullable String filterPackageName, @Nullable String filterFeatureId,
+ @Nullable String filterPackageName, @Nullable String filterAttributionTag,
@Nullable String[] filterOpNames, @HistoricalOpsRequestFilter int filter,
@OpFlags int filterFlags, double filterScale)
throws IOException, XmlPullParserException {
@@ -1272,8 +1272,8 @@
final int depth = parser.getDepth();
while (XmlUtils.nextElementWithin(parser, depth)) {
if (TAG_PACKAGE.equals(parser.getName())) {
- final HistoricalOps returnedOps = readHistoricalPackageOpsDLocked(ops,
- uid, parser, filterPackageName, filterFeatureId, filterOpNames, filter,
+ final HistoricalOps returnedOps = readHistoricalPackageOpsDLocked(ops, uid,
+ parser, filterPackageName, filterAttributionTag, filterOpNames, filter,
filterFlags, filterScale);
if (ops == null) {
ops = returnedOps;
@@ -1285,7 +1285,7 @@
private @Nullable HistoricalOps readHistoricalPackageOpsDLocked(
@Nullable HistoricalOps ops, int uid, @NonNull XmlPullParser parser,
- @Nullable String filterPackageName, @Nullable String filterFeatureId,
+ @Nullable String filterPackageName, @Nullable String filterAttributionTag,
@Nullable String[] filterOpNames, @HistoricalOpsRequestFilter int filter,
@OpFlags int filterFlags, double filterScale)
throws IOException, XmlPullParserException {
@@ -1296,9 +1296,9 @@
}
final int depth = parser.getDepth();
while (XmlUtils.nextElementWithin(parser, depth)) {
- if (TAG_FEATURE.equals(parser.getName())) {
- final HistoricalOps returnedOps = readHistoricalFeatureOpsDLocked(ops, uid,
- packageName, parser, filterFeatureId, filterOpNames, filter,
+ if (TAG_ATTRIBUTION.equals(parser.getName())) {
+ final HistoricalOps returnedOps = readHistoricalAttributionOpsDLocked(ops, uid,
+ packageName, parser, filterAttributionTag, filterOpNames, filter,
filterFlags, filterScale);
if (ops == null) {
ops = returnedOps;
@@ -1308,15 +1308,15 @@
return ops;
}
- private @Nullable HistoricalOps readHistoricalFeatureOpsDLocked(@Nullable HistoricalOps ops,
- int uid, String packageName, @NonNull XmlPullParser parser,
- @Nullable String filterFeatureId, @Nullable String[] filterOpNames,
- @HistoricalOpsRequestFilter int filter, @OpFlags int filterFlags,
- double filterScale)
+ private @Nullable HistoricalOps readHistoricalAttributionOpsDLocked(
+ @Nullable HistoricalOps ops, int uid, String packageName,
+ @NonNull XmlPullParser parser, @Nullable String filterAttributionTag,
+ @Nullable String[] filterOpNames, @HistoricalOpsRequestFilter int filter,
+ @OpFlags int filterFlags, double filterScale)
throws IOException, XmlPullParserException {
- final String featureId = XmlUtils.readStringAttribute(parser, ATTR_NAME);
- if ((filter & FILTER_BY_FEATURE_ID) != 0 && !Objects.equals(filterFeatureId,
- featureId)) {
+ final String attributionTag = XmlUtils.readStringAttribute(parser, ATTR_NAME);
+ if ((filter & FILTER_BY_ATTRIBUTION_TAG) != 0 && !Objects.equals(filterAttributionTag,
+ attributionTag)) {
XmlUtils.skipCurrentTag(parser);
return null;
}
@@ -1324,7 +1324,8 @@
while (XmlUtils.nextElementWithin(parser, depth)) {
if (TAG_OP.equals(parser.getName())) {
final HistoricalOps returnedOps = readHistoricalOpDLocked(ops, uid, packageName,
- featureId, parser, filterOpNames, filter, filterFlags, filterScale);
+ attributionTag, parser, filterOpNames, filter, filterFlags,
+ filterScale);
if (ops == null) {
ops = returnedOps;
}
@@ -1334,7 +1335,7 @@
}
private @Nullable HistoricalOps readHistoricalOpDLocked(@Nullable HistoricalOps ops,
- int uid, @NonNull String packageName, @Nullable String featureId,
+ int uid, @NonNull String packageName, @Nullable String attributionTag,
@NonNull XmlPullParser parser, @Nullable String[] filterOpNames,
@HistoricalOpsRequestFilter int filter, @OpFlags int filterFlags,
double filterScale)
@@ -1349,7 +1350,7 @@
while (XmlUtils.nextElementWithin(parser, depth)) {
if (TAG_STATE.equals(parser.getName())) {
final HistoricalOps returnedOps = readStateDLocked(ops, uid,
- packageName, featureId, op, parser, filterFlags, filterScale);
+ packageName, attributionTag, op, parser, filterFlags, filterScale);
if (ops == null) {
ops = returnedOps;
}
@@ -1359,7 +1360,7 @@
}
private @Nullable HistoricalOps readStateDLocked(@Nullable HistoricalOps ops,
- int uid, @NonNull String packageName, @Nullable String featureId, int op,
+ int uid, @NonNull String packageName, @Nullable String attributionTag, int op,
@NonNull XmlPullParser parser, @OpFlags int filterFlags, double filterScale)
throws IOException {
final long key = XmlUtils.readLongAttribute(parser, ATTR_NAME);
@@ -1377,7 +1378,7 @@
if (ops == null) {
ops = new HistoricalOps(0, 0);
}
- ops.increaseAccessCount(op, uid, packageName, featureId, uidState, flags,
+ ops.increaseAccessCount(op, uid, packageName, attributionTag, uidState, flags,
accessCount);
}
long rejectCount = XmlUtils.readLongAttribute(parser, ATTR_REJECT_COUNT, 0);
@@ -1389,7 +1390,7 @@
if (ops == null) {
ops = new HistoricalOps(0, 0);
}
- ops.increaseRejectCount(op, uid, packageName, featureId, uidState, flags,
+ ops.increaseRejectCount(op, uid, packageName, attributionTag, uidState, flags,
rejectCount);
}
long accessDuration = XmlUtils.readLongAttribute(parser, ATTR_ACCESS_DURATION, 0);
@@ -1401,7 +1402,7 @@
if (ops == null) {
ops = new HistoricalOps(0, 0);
}
- ops.increaseAccessDuration(op, uid, packageName, featureId, uidState, flags,
+ ops.increaseAccessDuration(op, uid, packageName, attributionTag, uidState, flags,
accessDuration);
}
return ops;
@@ -1467,24 +1468,25 @@
@NonNull XmlSerializer serializer) throws IOException {
serializer.startTag(null, TAG_PACKAGE);
serializer.attribute(null, ATTR_NAME, packageOps.getPackageName());
- final int numFeatures = packageOps.getFeatureCount();
- for (int i = 0; i < numFeatures; i++) {
- final HistoricalFeatureOps op = packageOps.getFeatureOpsAt(i);
- writeHistoricalFeatureOpsDLocked(op, serializer);
+ final int numAttributions = packageOps.getAttributedOpsCount();
+ for (int i = 0; i < numAttributions; i++) {
+ final AppOpsManager.AttributedHistoricalOps op = packageOps.getAttributedOpsAt(i);
+ writeHistoricalAttributionOpsDLocked(op, serializer);
}
serializer.endTag(null, TAG_PACKAGE);
}
- private void writeHistoricalFeatureOpsDLocked(@NonNull HistoricalFeatureOps featureOps,
+ private void writeHistoricalAttributionOpsDLocked(
+ @NonNull AppOpsManager.AttributedHistoricalOps attributionOps,
@NonNull XmlSerializer serializer) throws IOException {
- serializer.startTag(null, TAG_FEATURE);
- XmlUtils.writeStringAttribute(serializer, ATTR_NAME, featureOps.getFeatureId());
- final int opCount = featureOps.getOpCount();
+ serializer.startTag(null, TAG_ATTRIBUTION);
+ XmlUtils.writeStringAttribute(serializer, ATTR_NAME, attributionOps.getTag());
+ final int opCount = attributionOps.getOpCount();
for (int i = 0; i < opCount; i++) {
- final HistoricalOp op = featureOps.getOpAt(i);
+ final HistoricalOp op = attributionOps.getOpAt(i);
writeHistoricalOpDLocked(op, serializer);
}
- serializer.endTag(null, TAG_FEATURE);
+ serializer.endTag(null, TAG_ATTRIBUTION);
}
private void writeHistoricalOpDLocked(@NonNull HistoricalOp op,
@@ -1718,29 +1720,29 @@
private final @NonNull String mOpsPrefix;
private final @NonNull String mUidPrefix;
private final @NonNull String mPackagePrefix;
- private final @NonNull String mFeaturePrefix;
+ private final @NonNull String mAttributionPrefix;
private final @NonNull String mEntryPrefix;
private final @NonNull String mUidStatePrefix;
private final @NonNull PrintWriter mWriter;
private final int mFilterUid;
private final String mFilterPackage;
- private final String mFilterFeatureId;
+ private final String mFilterAttributionTag;
private final int mFilterOp;
private final @HistoricalOpsRequestFilter int mFilter;
StringDumpVisitor(@NonNull String prefix, @NonNull PrintWriter writer, int filterUid,
- @Nullable String filterPackage, @Nullable String filterFeatureId, int filterOp,
+ @Nullable String filterPackage, @Nullable String filterAttributionTag, int filterOp,
@HistoricalOpsRequestFilter int filter) {
mOpsPrefix = prefix + " ";
mUidPrefix = mOpsPrefix + " ";
mPackagePrefix = mUidPrefix + " ";
- mFeaturePrefix = mPackagePrefix + " ";
- mEntryPrefix = mFeaturePrefix + " ";
+ mAttributionPrefix = mPackagePrefix + " ";
+ mEntryPrefix = mAttributionPrefix + " ";
mUidStatePrefix = mEntryPrefix + " ";
mWriter = writer;
mFilterUid = filterUid;
mFilterPackage = filterPackage;
- mFilterFeatureId = filterFeatureId;
+ mFilterAttributionTag = filterAttributionTag;
mFilterOp = filterOp;
mFilter = filter;
}
@@ -1791,14 +1793,14 @@
}
@Override
- public void visitHistoricalFeatureOps(HistoricalFeatureOps ops) {
- if ((mFilter & FILTER_BY_FEATURE_ID) != 0 && !Objects.equals(mFilterPackage,
- ops.getFeatureId())) {
+ public void visitHistoricalAttributionOps(AppOpsManager.AttributedHistoricalOps ops) {
+ if ((mFilter & FILTER_BY_ATTRIBUTION_TAG) != 0 && !Objects.equals(mFilterPackage,
+ ops.getTag())) {
return;
}
- mWriter.print(mFeaturePrefix);
- mWriter.print("Feature ");
- mWriter.print(ops.getFeatureId());
+ mWriter.print(mAttributionPrefix);
+ mWriter.print("Attribution ");
+ mWriter.print(ops.getTag());
mWriter.println(":");
}
diff --git a/services/core/java/com/android/server/compat/CompatChange.java b/services/core/java/com/android/server/compat/CompatChange.java
index 7bdeb59..2e9818d 100644
--- a/services/core/java/com/android/server/compat/CompatChange.java
+++ b/services/core/java/com/android/server/compat/CompatChange.java
@@ -151,6 +151,15 @@
return true;
}
+ /**
+ * Checks whether a change has an override for a package.
+ * @param packageName name of the package
+ * @return true if there is such override
+ */
+ boolean hasOverride(String packageName) {
+ return mPackageOverrides != null && mPackageOverrides.containsKey(packageName);
+ }
+
@Override
public String toString() {
StringBuilder sb = new StringBuilder("ChangeId(")
diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java
index 61bede9..aeaa1fe 100644
--- a/services/core/java/com/android/server/compat/CompatConfig.java
+++ b/services/core/java/com/android/server/compat/CompatConfig.java
@@ -247,11 +247,13 @@
CompatChange c = mChanges.get(changeId);
try {
if (c != null) {
- OverrideAllowedState allowedState =
- mOverrideValidator.getOverrideAllowedState(changeId, packageName);
- allowedState.enforce(changeId, packageName);
- overrideExists = true;
- c.removePackageOverride(packageName);
+ overrideExists = c.hasOverride(packageName);
+ if (overrideExists) {
+ OverrideAllowedState allowedState =
+ mOverrideValidator.getOverrideAllowedState(changeId, packageName);
+ allowedState.enforce(changeId, packageName);
+ c.removePackageOverride(packageName);
+ }
}
} catch (RemoteException e) {
// Should never occur, since validator is in the same process.
@@ -298,12 +300,14 @@
for (int i = 0; i < mChanges.size(); ++i) {
try {
CompatChange change = mChanges.valueAt(i);
- OverrideAllowedState allowedState =
- mOverrideValidator.getOverrideAllowedState(change.getId(),
- packageName);
- allowedState.enforce(change.getId(), packageName);
- if (change != null) {
- mChanges.valueAt(i).removePackageOverride(packageName);
+ if (change.hasOverride(packageName)) {
+ OverrideAllowedState allowedState =
+ mOverrideValidator.getOverrideAllowedState(change.getId(),
+ packageName);
+ allowedState.enforce(change.getId(), packageName);
+ if (change != null) {
+ mChanges.valueAt(i).removePackageOverride(packageName);
+ }
}
} catch (RemoteException e) {
// Should never occur, since validator is in the same process.
@@ -314,6 +318,63 @@
}
}
+ private long[] getAllowedChangesAfterTargetSdkForPackage(String packageName,
+ int targetSdkVersion)
+ throws RemoteException {
+ LongArray allowed = new LongArray();
+ synchronized (mChanges) {
+ for (int i = 0; i < mChanges.size(); ++i) {
+ try {
+ CompatChange change = mChanges.valueAt(i);
+ if (change.getEnableAfterTargetSdk() != targetSdkVersion) {
+ continue;
+ }
+ OverrideAllowedState allowedState =
+ mOverrideValidator.getOverrideAllowedState(change.getId(),
+ packageName);
+ if (allowedState.state == OverrideAllowedState.ALLOWED) {
+ allowed.add(change.getId());
+ }
+ } catch (RemoteException e) {
+ // Should never occur, since validator is in the same process.
+ throw new RuntimeException("Unable to call override validator!", e);
+ }
+ }
+ }
+ return allowed.toArray();
+ }
+
+ /**
+ * Enables all changes with enabledAfterTargetSdk == {@param targetSdkVersion} for
+ * {@param packageName}.
+ *
+ * @return The number of changes that were toggled.
+ */
+ int enableTargetSdkChangesForPackage(String packageName, int targetSdkVersion)
+ throws RemoteException {
+ long[] changes = getAllowedChangesAfterTargetSdkForPackage(packageName, targetSdkVersion);
+ for (long changeId : changes) {
+ addOverride(changeId, packageName, true);
+ }
+ return changes.length;
+ }
+
+
+ /**
+ * Disables all changes with enabledAfterTargetSdk == {@param targetSdkVersion} for
+ * {@param packageName}.
+ *
+ * @return The number of changes that were toggled.
+ */
+ int disableTargetSdkChangesForPackage(String packageName, int targetSdkVersion)
+ throws RemoteException {
+ long[] changes = getAllowedChangesAfterTargetSdkForPackage(packageName, targetSdkVersion);
+ for (long changeId : changes) {
+ addOverride(changeId, packageName, false);
+ }
+ return changes.length;
+ }
+
boolean registerListener(long changeId, CompatChange.ChangeListener listener) {
boolean alreadyKnown = true;
synchronized (mChanges) {
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index 821653a..8519b00 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -166,6 +166,26 @@
}
@Override
+ public int enableTargetSdkChanges(String packageName, int targetSdkVersion)
+ throws RemoteException, SecurityException {
+ checkCompatChangeOverridePermission();
+ int numChanges = mCompatConfig.enableTargetSdkChangesForPackage(packageName,
+ targetSdkVersion);
+ killPackage(packageName);
+ return numChanges;
+ }
+
+ @Override
+ public int disableTargetSdkChanges(String packageName, int targetSdkVersion)
+ throws RemoteException, SecurityException {
+ checkCompatChangeOverridePermission();
+ int numChanges = mCompatConfig.disableTargetSdkChangesForPackage(packageName,
+ targetSdkVersion);
+ killPackage(packageName);
+ return numChanges;
+ }
+
+ @Override
public void clearOverrides(String packageName) throws RemoteException, SecurityException {
checkCompatChangeOverridePermission();
mCompatConfig.removePackageOverrides(packageName);
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 7c3cab1..20ffd9f 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -2563,7 +2563,7 @@
public void exitIfOuterInterfaceIs(String interfaze) {
if (interfaze.equals(mOuterInterface)) {
Log.i(TAG, "Legacy VPN is going down with " + interfaze);
- exit();
+ exitVpnRunner();
}
}
@@ -2572,6 +2572,10 @@
public void exitVpnRunner() {
// We assume that everything is reset after stopping the daemons.
interrupt();
+
+ // Always disconnect. This may be called again in cleanupVpnStateLocked() if
+ // exitVpnRunner() was called from exit(), but it will be a no-op.
+ agentDisconnect();
try {
mContext.unregisterReceiver(mBroadcastReceiver);
} catch (IllegalArgumentException e) {}
@@ -2794,7 +2798,7 @@
} catch (Exception e) {
Log.i(TAG, "Aborting", e);
updateState(DetailedState.FAILED, e.getMessage());
- exit();
+ exitVpnRunner();
}
}
diff --git a/services/core/java/com/android/server/location/CountryDetectorBase.java b/services/core/java/com/android/server/location/CountryDetectorBase.java
index b158388..682b104 100644
--- a/services/core/java/com/android/server/location/CountryDetectorBase.java
+++ b/services/core/java/com/android/server/location/CountryDetectorBase.java
@@ -31,7 +31,7 @@
* @hide
*/
public abstract class CountryDetectorBase {
- private static final String FEATURE_ID = "CountryDetector";
+ private static final String ATTRIBUTION_TAG = "CountryDetector";
protected final Handler mHandler;
protected final Context mContext;
@@ -39,7 +39,7 @@
protected Country mDetectedCountry;
public CountryDetectorBase(Context context) {
- mContext = context.createFeatureContext(FEATURE_ID);
+ mContext = context.createAttributionContext(ATTRIBUTION_TAG);
mHandler = new Handler();
}
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
index b456737..2aa53cc 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
@@ -60,6 +60,8 @@
private Connection mActiveConnection;
private boolean mConnectionReady;
+ private RouteDiscoveryPreference mPendingDiscoveryPreference = null;
+
MediaRoute2ProviderServiceProxy(@NonNull Context context, @NonNull ComponentName componentName,
int userId) {
super(componentName);
@@ -99,6 +101,8 @@
if (mConnectionReady) {
mActiveConnection.updateDiscoveryPreference(discoveryPreference);
updateBinding();
+ } else {
+ mPendingDiscoveryPreference = discoveryPreference;
}
}
@@ -271,6 +275,10 @@
private void onConnectionReady(Connection connection) {
if (mActiveConnection == connection) {
mConnectionReady = true;
+ if (mPendingDiscoveryPreference != null) {
+ updateDiscoveryPreference(mPendingDiscoveryPreference);
+ mPendingDiscoveryPreference = null;
+ }
}
}
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index ee5a4fe..4af31b0 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -306,9 +306,8 @@
/** Data layer operation counters for splicing into other structures. */
private NetworkStats mUidOperations = new NetworkStats(0L, 10);
- /** Must be set in factory by calling #setHandler. */
- private Handler mHandler;
- private Handler.Callback mHandlerCallback;
+ @NonNull
+ private final Handler mHandler;
private volatile boolean mSystemReady;
private long mPersistThreshold = 2 * MB_IN_BYTES;
@@ -324,6 +323,9 @@
private final static int DUMP_STATS_SESSION_COUNT = 20;
+ @NonNull
+ private final Dependencies mDeps;
+
private static @NonNull File getDefaultSystemDir() {
return new File(Environment.getDataDirectory(), "system");
}
@@ -339,9 +341,24 @@
Clock.systemUTC());
}
- private static final class NetworkStatsHandler extends Handler {
- NetworkStatsHandler(Looper looper, Handler.Callback callback) {
- super(looper, callback);
+ private final class NetworkStatsHandler extends Handler {
+ NetworkStatsHandler(@NonNull Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_PERFORM_POLL: {
+ performPoll(FLAG_PERSIST_ALL);
+ break;
+ }
+ case MSG_PERFORM_POLL_REGISTER_ALERT: {
+ performPoll(FLAG_PERSIST_NETWORK);
+ registerGlobalAlert();
+ break;
+ }
+ }
}
}
@@ -355,14 +372,10 @@
NetworkStatsService service = new NetworkStatsService(context, networkManager, alarmManager,
wakeLock, getDefaultClock(), context.getSystemService(TelephonyManager.class),
new DefaultNetworkStatsSettings(context), new NetworkStatsFactory(),
- new NetworkStatsObservers(), getDefaultSystemDir(), getDefaultBaseDir());
+ new NetworkStatsObservers(), getDefaultSystemDir(), getDefaultBaseDir(),
+ new Dependencies());
service.registerLocalService();
- HandlerThread handlerThread = new HandlerThread(TAG);
- Handler.Callback callback = new HandlerCallback(service);
- handlerThread.start();
- Handler handler = new NetworkStatsHandler(handlerThread.getLooper(), callback);
- service.setHandler(handler, callback);
return service;
}
@@ -373,7 +386,7 @@
AlarmManager alarmManager, PowerManager.WakeLock wakeLock, Clock clock,
TelephonyManager teleManager, NetworkStatsSettings settings,
NetworkStatsFactory factory, NetworkStatsObservers statsObservers, File systemDir,
- File baseDir) {
+ File baseDir, @NonNull Dependencies deps) {
mContext = Objects.requireNonNull(context, "missing Context");
mNetworkManager = Objects.requireNonNull(networkManager,
"missing INetworkManagementService");
@@ -387,6 +400,26 @@
mSystemDir = Objects.requireNonNull(systemDir, "missing systemDir");
mBaseDir = Objects.requireNonNull(baseDir, "missing baseDir");
mUseBpfTrafficStats = new File("/sys/fs/bpf/map_netd_app_uid_stats_map").exists();
+ mDeps = Objects.requireNonNull(deps, "missing Dependencies");
+
+ final HandlerThread handlerThread = mDeps.makeHandlerThread();
+ handlerThread.start();
+ mHandler = new NetworkStatsHandler(handlerThread.getLooper());
+ }
+
+ /**
+ * Dependencies of NetworkStatsService, for injection in tests.
+ */
+ // TODO: Move more stuff into dependencies object.
+ @VisibleForTesting
+ public static class Dependencies {
+ /**
+ * Create a HandlerThread to use in NetworkStatsService.
+ */
+ @NonNull
+ public HandlerThread makeHandlerThread() {
+ return new HandlerThread(TAG);
+ }
}
private void registerLocalService() {
@@ -394,12 +427,6 @@
new NetworkStatsManagerInternalImpl());
}
- @VisibleForTesting
- void setHandler(Handler handler, Handler.Callback callback) {
- mHandler = handler;
- mHandlerCallback = callback;
- }
-
public void systemReady() {
synchronized (mStatsLock) {
mSystemReady = true;
@@ -1920,33 +1947,6 @@
}
- @VisibleForTesting
- static class HandlerCallback implements Handler.Callback {
- private final NetworkStatsService mService;
-
- HandlerCallback(NetworkStatsService service) {
- this.mService = service;
- }
-
- @Override
- public boolean handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_PERFORM_POLL: {
- mService.performPoll(FLAG_PERSIST_ALL);
- return true;
- }
- case MSG_PERFORM_POLL_REGISTER_ALERT: {
- mService.performPoll(FLAG_PERSIST_NETWORK);
- mService.registerGlobalAlert();
- return true;
- }
- default: {
- return false;
- }
- }
- }
- }
-
private void assertSystemReady() {
if (!mSystemReady) {
throw new IllegalStateException("System not ready");
diff --git a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
index ec9b37d..83da381 100644
--- a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
+++ b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
@@ -45,6 +45,7 @@
import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
import android.os.Binder;
+import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -183,7 +184,8 @@
String callingFeatureId,
Intent intent,
@UserIdInt int userId,
- IBinder callingActivity) throws RemoteException {
+ IBinder callingActivity,
+ Bundle options) throws RemoteException {
Objects.requireNonNull(callingPackage);
Objects.requireNonNull(intent);
Objects.requireNonNull(intent.getComponent(), "The intent must have a Component set");
@@ -226,7 +228,7 @@
launchIntent,
callingActivity,
/* startFlags= */ 0,
- /* options= */ null,
+ options,
userId);
logStartActivityByIntent(callingPackage);
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 33ef2d4..cdc3736 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -805,26 +805,30 @@
public SessionInfo getSessionInfo(int sessionId) {
synchronized (mSessions) {
final PackageInstallerSession session = mSessions.get(sessionId);
- return session != null ? session.generateInfo() : null;
+
+ return session != null
+ ? session.generateInfoForCaller(true /*withIcon*/, Binder.getCallingUid())
+ : null;
}
}
@Override
public ParceledListSlice<SessionInfo> getStagedSessions() {
- return mStagingManager.getSessions();
+ return mStagingManager.getSessions(Binder.getCallingUid());
}
@Override
public ParceledListSlice<SessionInfo> getAllSessions(int userId) {
+ final int callingUid = Binder.getCallingUid();
mPermissionManager.enforceCrossUserPermission(
- Binder.getCallingUid(), userId, true, false, "getAllSessions");
+ callingUid, userId, true, false, "getAllSessions");
final List<SessionInfo> result = new ArrayList<>();
synchronized (mSessions) {
for (int i = 0; i < mSessions.size(); i++) {
final PackageInstallerSession session = mSessions.valueAt(i);
if (session.userId == userId && !session.hasParentSessionId()) {
- result.add(session.generateInfo(false));
+ result.add(session.generateInfoForCaller(false, callingUid));
}
}
}
@@ -842,7 +846,8 @@
for (int i = 0; i < mSessions.size(); i++) {
final PackageInstallerSession session = mSessions.valueAt(i);
- SessionInfo info = session.generateInfo(false);
+ SessionInfo info =
+ session.generateInfoForCaller(false /*withIcon*/, Process.SYSTEM_UID);
if (Objects.equals(info.getInstallerPackageName(), installerPackageName)
&& session.userId == userId && !session.hasParentSessionId()) {
result.add(info);
@@ -1302,7 +1307,10 @@
session.markUpdated();
writeSessionsAsync();
if (mOkToSendBroadcasts) {
- mPm.sendSessionUpdatedBroadcast(session.generateInfo(false),
+ // we don't scrub the data here as this is sent only to the installer several
+ // privileged system packages
+ mPm.sendSessionUpdatedBroadcast(
+ session.generateInfoForCaller(false/*icon*/, Process.SYSTEM_UID),
session.userId);
}
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 97aa79d..483f83e 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -557,11 +557,41 @@
}
}
- public SessionInfo generateInfo() {
- return generateInfo(true);
+ /**
+ * Returns {@code true} if the {@link SessionInfo} object should be produced with potentially
+ * sensitive data scrubbed from its fields.
+ *
+ * @param callingUid the uid of the caller; the recipient of the {@link SessionInfo} that may
+ * need to be scrubbed
+ */
+ private boolean shouldScrubData(int callingUid) {
+ return !(callingUid < Process.FIRST_APPLICATION_UID || getInstallerUid() == callingUid);
}
- public SessionInfo generateInfo(boolean includeIcon) {
+ /**
+ * Generates a {@link SessionInfo} object for the provided uid. This may result in some fields
+ * that may contain sensitive info being filtered.
+ *
+ * @param includeIcon true if the icon should be included in the object
+ * @param callingUid the uid of the caller; the recipient of the {@link SessionInfo} that may
+ * need to be scrubbed
+ * @see #shouldScrubData(int)
+ */
+ public SessionInfo generateInfoForCaller(boolean includeIcon, int callingUid) {
+ return generateInfoInternal(includeIcon, shouldScrubData(callingUid));
+ }
+
+ /**
+ * Generates a {@link SessionInfo} object to ensure proper hiding of sensitive fields.
+ *
+ * @param includeIcon true if the icon should be included in the object
+ * @see #generateInfoForCaller(boolean, int)
+ */
+ public SessionInfo generateInfoScrubbed(boolean includeIcon) {
+ return generateInfoInternal(includeIcon, true /*scrubData*/);
+ }
+
+ private SessionInfo generateInfoInternal(boolean includeIcon, boolean scrubData) {
final SessionInfo info = new SessionInfo();
synchronized (mLock) {
info.sessionId = sessionId;
@@ -584,9 +614,13 @@
info.appLabel = params.appLabel;
info.installLocation = params.installLocation;
- info.originatingUri = params.originatingUri;
+ if (!scrubData) {
+ info.originatingUri = params.originatingUri;
+ }
info.originatingUid = params.originatingUid;
- info.referrerUri = params.referrerUri;
+ if (!scrubData) {
+ info.referrerUri = params.referrerUri;
+ }
info.grantedRuntimePermissions = params.grantedRuntimePermissions;
info.whitelistedRestrictedPermissions = params.whitelistedRestrictedPermissions;
info.installFlags = params.installFlags;
@@ -2664,7 +2698,7 @@
final boolean isNewInstall = extras == null || !extras.getBoolean(Intent.EXTRA_REPLACING);
if (success && isNewInstall && mPm.mInstallerService.okToSendBroadcasts()
&& (params.installFlags & PackageManager.INSTALL_DRY_RUN) == 0) {
- mPm.sendSessionCommitBroadcast(generateInfo(), userId);
+ mPm.sendSessionCommitBroadcast(generateInfoScrubbed(true /*icon*/), userId);
}
mCallback.onSessionFinished(this, success);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 799ce65..61bf5f0 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -11514,8 +11514,8 @@
"Static shared libs cannot declare permission groups");
}
- // Static shared libs cannot declare features
- if (!pkg.getFeatures().isEmpty()) {
+ // Static shared libs cannot declare attributions
+ if (!pkg.getAttributions().isEmpty()) {
throw new PackageManagerException(
"Static shared libs cannot declare features");
}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 2d16854..62541ab 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -5450,7 +5450,7 @@
packagePermissions, sharedUserPermissions);
}
- mPersistence.writeAsUser(runtimePermissions, UserHandle.of(userId));
+ mPersistence.writeForUser(runtimePermissions, UserHandle.of(userId));
}
@NonNull
@@ -5504,12 +5504,12 @@
}
public void deleteUserRuntimePermissionsFile(int userId) {
- mPersistence.deleteAsUser(UserHandle.of(userId));
+ mPersistence.deleteForUser(UserHandle.of(userId));
}
@GuardedBy("Settings.this.mLock")
public void readStateForUserSyncLPr(int userId) {
- RuntimePermissionsState runtimePermissions = mPersistence.readAsUser(UserHandle.of(
+ RuntimePermissionsState runtimePermissions = mPersistence.readForUser(UserHandle.of(
userId));
if (runtimePermissions == null) {
readLegacyStateForUserSyncLPr(userId);
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 83fe556..342c907 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -128,11 +128,12 @@
}
}
- ParceledListSlice<PackageInstaller.SessionInfo> getSessions() {
+ ParceledListSlice<PackageInstaller.SessionInfo> getSessions(int callingUid) {
final List<PackageInstaller.SessionInfo> result = new ArrayList<>();
synchronized (mStagedSessions) {
for (int i = 0; i < mStagedSessions.size(); i++) {
- result.add(mStagedSessions.valueAt(i).generateInfo(false));
+ final PackageInstallerSession stagedSession = mStagedSessions.valueAt(i);
+ result.add(stagedSession.generateInfoForCaller(false /*icon*/, callingUid));
}
}
return new ParceledListSlice<>(result);
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 d3f668c..0e294f70 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
@@ -391,8 +391,9 @@
ArrayMap<String, ProcessInfo> retProcs = new ArrayMap<>(numProcs);
for (String key : procs.keySet()) {
ParsedProcess proc = procs.get(key);
- retProcs.put(proc.getName(), new ProcessInfo(proc.getName(),
- new ArraySet<>(proc.getDeniedPermissions())));
+ retProcs.put(proc.getName(),
+ new ProcessInfo(proc.getName(), new ArraySet<>(proc.getDeniedPermissions()),
+ proc.getEnableGwpAsan()));
}
return retProcs;
}
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java
index 7929579..46b08df 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java
@@ -25,7 +25,7 @@
import android.content.pm.PermissionGroupInfo;
import android.content.pm.SharedLibraryInfo;
import android.content.pm.parsing.ParsingPackageRead;
-import android.content.pm.parsing.component.ParsedFeature;
+import android.content.pm.parsing.component.ParsedAttribution;
import android.content.pm.parsing.component.ParsedIntentInfo;
import android.content.pm.parsing.component.ParsedPermissionGroup;
import android.os.Bundle;
@@ -147,7 +147,7 @@
List<ParsedPermissionGroup> getPermissionGroups();
@NonNull
- List<ParsedFeature> getFeatures();
+ List<ParsedAttribution> getAttributions();
/**
* Used to determine the default preferred handler of an {@link Intent}.
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index d589353..161f304 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -32,6 +32,7 @@
import android.app.AppOpsManagerInternal;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
@@ -173,6 +174,65 @@
} catch (RemoteException doesNotHappen) {
Slog.wtf(LOG_TAG, "Cannot set up app-ops listener");
}
+
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+ intentFilter.addDataScheme("package");
+
+
+ /* TODO ntmyren: enable receiver when test flakes are fixed
+ getContext().registerReceiverAsUser(new BroadcastReceiver() {
+ final List<Integer> mUserSetupUids = new ArrayList<>(200);
+ final Map<UserHandle, PermissionControllerManager> mPermControllerManagers =
+ new HashMap<>();
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ boolean hasSetupRun = true;
+ try {
+ hasSetupRun = Settings.Secure.getInt(getContext().getContentResolver(),
+ Settings.Secure.USER_SETUP_COMPLETE) != 0;
+ } catch (Settings.SettingNotFoundException e) {
+ // Ignore error, assume setup has run
+ }
+ int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
+ // If there is no valid package for the given UID, return immediately
+ if (packageManagerInternal.getPackage(uid) == null) {
+ return;
+ }
+
+ if (hasSetupRun) {
+ if (!mUserSetupUids.isEmpty()) {
+ synchronized (mUserSetupUids) {
+ for (int i = mUserSetupUids.size() - 1; i >= 0; i--) {
+ updateUid(mUserSetupUids.get(i));
+ }
+ mUserSetupUids.clear();
+ }
+ }
+ updateUid(uid);
+ } else {
+ synchronized (mUserSetupUids) {
+ if (!mUserSetupUids.contains(uid)) {
+ mUserSetupUids.add(uid);
+ }
+ }
+ }
+ }
+
+ private void updateUid(int uid) {
+ UserHandle user = UserHandle.getUserHandleForUid(uid);
+ PermissionControllerManager manager = mPermControllerManagers.get(user);
+ if (manager == null) {
+ manager = new PermissionControllerManager(
+ getUserContext(getContext(), user), FgThread.getHandler());
+ mPermControllerManagers.put(user, manager);
+ }
+ manager.updateUserSensitiveForApp(uid);
+ }
+ }, UserHandle.ALL, intentFilter, null, null);
+ */
}
/**
@@ -182,7 +242,6 @@
* {@link AppOpsManager#sOpToSwitch share an op} to control the access.
*
* @param permission The permission
- *
* @return The op that controls the access of the permission
*/
private static int getSwitchOp(@NonNull String permission) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 1b5cc6a..64edacd43 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -5202,7 +5202,7 @@
if (dock != null) {
int result = ActivityTaskManager.getService()
.startActivityAsUser(null, mContext.getBasePackageName(),
- mContext.getFeatureId(), dock,
+ mContext.getAttributionTag(), dock,
dock.resolveTypeIfNeeded(mContext.getContentResolver()),
null, null, 0,
ActivityManager.START_FLAG_ONLY_IF_NEEDED,
@@ -5214,7 +5214,7 @@
}
int result = ActivityTaskManager.getService()
.startActivityAsUser(null, mContext.getBasePackageName(),
- mContext.getFeatureId(), mHomeIntent,
+ mContext.getAttributionTag(), mHomeIntent,
mHomeIntent.resolveTypeIfNeeded(mContext.getContentResolver()),
null, null, 0,
ActivityManager.START_FLAG_ONLY_IF_NEEDED,
diff --git a/services/core/java/com/android/server/role/RoleUserState.java b/services/core/java/com/android/server/role/RoleUserState.java
index 97ce6bd..b33dc8f 100644
--- a/services/core/java/com/android/server/role/RoleUserState.java
+++ b/services/core/java/com/android/server/role/RoleUserState.java
@@ -364,12 +364,12 @@
(Map<String, Set<String>>) (Map<String, ?>) snapshotRolesLocked());
}
- mPersistence.writeAsUser(roles, UserHandle.of(mUserId));
+ mPersistence.writeForUser(roles, UserHandle.of(mUserId));
}
private void readFile() {
synchronized (mLock) {
- RolesState roles = mPersistence.readAsUser(UserHandle.of(mUserId));
+ RolesState roles = mPersistence.readForUser(UserHandle.of(mUserId));
if (roles == null) {
readLegacyFileLocked();
scheduleWriteFileLocked();
@@ -545,7 +545,7 @@
throw new IllegalStateException("This RoleUserState has already been destroyed");
}
mWriteHandler.removeCallbacksAndMessages(null);
- mPersistence.deleteAsUser(UserHandle.of(mUserId));
+ mPersistence.deleteForUser(UserHandle.of(mUserId));
mDestroyed = true;
}
}
diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
index 98579af5..7f7d668 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -406,8 +406,8 @@
case FrameworkStatsLog.BATTERY_VOLTAGE:
case FrameworkStatsLog.BATTERY_CYCLE_COUNT:
return pullHealthHal(atomTag, data);
- case FrameworkStatsLog.APP_FEATURES_OPS:
- return pullAppFeaturesOps(atomTag, data);
+ case FrameworkStatsLog.ATTRIBUTED_APP_OPS:
+ return pullAttributedAppOps(atomTag, data);
default:
throw new UnsupportedOperationException("Unknown tagId=" + atomTag);
}
@@ -562,7 +562,7 @@
registerAppsOnExternalStorageInfo();
registerFaceSettings();
registerAppOps();
- registerAppFeaturesOps();
+ registerAttributedAppOps();
registerRuntimeAppOpAccessMessage();
registerNotificationRemoteViews();
registerDangerousPermissionState();
@@ -2898,8 +2898,8 @@
return StatsManager.PULL_SUCCESS;
}
- private void registerAppFeaturesOps() {
- int tagId = FrameworkStatsLog.APP_FEATURES_OPS;
+ private void registerAttributedAppOps() {
+ int tagId = FrameworkStatsLog.ATTRIBUTED_APP_OPS;
mStatsManager.setPullAtomCallback(
tagId,
null, // use default PullAtomMetadata values
@@ -2908,7 +2908,7 @@
);
}
- int pullAppFeaturesOps(int atomTag, List<StatsEvent> pulledData) {
+ int pullAttributedAppOps(int atomTag, List<StatsEvent> pulledData) {
final long token = Binder.clearCallingIdentity();
try {
AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
@@ -2946,7 +2946,7 @@
appOps.getHistoricalOps(histOpsRequest, mContext.getMainExecutor(), ops::complete);
HistoricalOps histOps = ops.get(EXTERNAL_STATS_SYNC_TIMEOUT_MILLIS,
TimeUnit.MILLISECONDS);
- return processHistoricalOps(histOps, FrameworkStatsLog.APP_FEATURES_OPS, null);
+ return processHistoricalOps(histOps, FrameworkStatsLog.ATTRIBUTED_APP_OPS, null);
}
int processHistoricalOps(HistoricalOps histOps, int atomTag, List<StatsEvent> pulledData) {
@@ -2956,15 +2956,15 @@
final int uid = uidOps.getUid();
for (int pkgIdx = 0; pkgIdx < uidOps.getPackageCount(); pkgIdx++) {
final HistoricalPackageOps packageOps = uidOps.getPackageOpsAt(pkgIdx);
- if (atomTag == FrameworkStatsLog.APP_FEATURES_OPS) {
- for (int featureIdx = 0; featureIdx < packageOps.getFeatureCount();
- featureIdx++) {
- final AppOpsManager.HistoricalFeatureOps featureOps =
- packageOps.getFeatureOpsAt(featureIdx);
- for (int opIdx = 0; opIdx < featureOps.getOpCount(); opIdx++) {
- final AppOpsManager.HistoricalOp op = featureOps.getOpAt(opIdx);
+ if (atomTag == FrameworkStatsLog.ATTRIBUTED_APP_OPS) {
+ for (int attributionIdx = 0;
+ attributionIdx < packageOps.getAttributedOpsCount(); attributionIdx++) {
+ final AppOpsManager.AttributedHistoricalOps attributedOps =
+ packageOps.getAttributedOpsAt(attributionIdx);
+ for (int opIdx = 0; opIdx < attributedOps.getOpCount(); opIdx++) {
+ final AppOpsManager.HistoricalOp op = attributedOps.getOpAt(opIdx);
counter += processHistoricalOp(op, atomTag, pulledData, uid,
- packageOps.getPackageName(), featureOps.getFeatureId());
+ packageOps.getPackageName(), attributedOps.getTag());
}
}
} else if (atomTag == FrameworkStatsLog.APP_OPS) {
@@ -2981,18 +2981,19 @@
private int processHistoricalOp(AppOpsManager.HistoricalOp op, int atomTag,
@Nullable List<StatsEvent> pulledData, int uid, String packageName,
- @Nullable String feature) {
- if (atomTag == FrameworkStatsLog.APP_FEATURES_OPS) {
+ @Nullable String attributionTag) {
+ if (atomTag == FrameworkStatsLog.ATTRIBUTED_APP_OPS) {
if (pulledData == null) { // this is size estimation call
if (op.getForegroundAccessCount(OP_FLAGS_PULLED) + op.getBackgroundAccessCount(
OP_FLAGS_PULLED) == 0) {
return 0;
} else {
- return 32 + packageName.length() + (feature == null ? 1 : feature.length());
+ return 32 + packageName.length() + (attributionTag == null ? 1
+ : attributionTag.length());
}
} else {
- if (abs((op.getOpCode() + feature + packageName).hashCode() + RANDOM_SEED) % 100
- >= mAppOpsSamplingRate) {
+ if (abs((op.getOpCode() + attributionTag + packageName).hashCode() + RANDOM_SEED)
+ % 100 >= mAppOpsSamplingRate) {
return 0;
}
}
@@ -3002,10 +3003,10 @@
e.setAtomId(atomTag);
e.writeInt(uid);
e.writeString(packageName);
- if (atomTag == FrameworkStatsLog.APP_FEATURES_OPS) {
- e.writeString(feature);
+ if (atomTag == FrameworkStatsLog.ATTRIBUTED_APP_OPS) {
+ e.writeString(attributionTag);
}
- if (atomTag == FrameworkStatsLog.APP_FEATURES_OPS) {
+ if (atomTag == FrameworkStatsLog.ATTRIBUTED_APP_OPS) {
e.writeString(op.getOpName());
} else {
e.writeInt(op.getOpCode());
@@ -3032,7 +3033,7 @@
e.writeBoolean(false);
}
}
- if (atomTag == FrameworkStatsLog.APP_FEATURES_OPS) {
+ if (atomTag == FrameworkStatsLog.ATTRIBUTED_APP_OPS) {
e.writeInt(mAppOpsSamplingRate);
}
pulledData.add(e.build());
@@ -3055,10 +3056,10 @@
e.writeInt(message.getUid());
e.writeString(message.getPackageName());
e.writeString(message.getOp());
- if (message.getFeatureId() == null) {
+ if (message.getAttributionTag() == null) {
e.writeString("");
} else {
- e.writeString(message.getFeatureId());
+ e.writeString(message.getAttributionTag());
}
e.writeString(message.getMessage());
e.writeInt(message.getSamplingStrategy());
diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
index 8164526..74a6383 100644
--- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
+++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
@@ -41,6 +41,7 @@
import android.util.SparseArray;
import android.view.textclassifier.ConversationActions;
import android.view.textclassifier.SelectionEvent;
+import android.view.textclassifier.SystemTextClassifierMetadata;
import android.view.textclassifier.TextClassification;
import android.view.textclassifier.TextClassificationConstants;
import android.view.textclassifier.TextClassificationContext;
@@ -179,12 +180,12 @@
TextSelection.Request request, ITextClassifierCallback callback)
throws RemoteException {
Objects.requireNonNull(request);
+ Objects.requireNonNull(request.getSystemTextClassifierMetadata());
handleRequest(
- request.getUserId(),
- request.getCallingPackageName(),
+ request.getSystemTextClassifierMetadata(),
+ /* verifyCallingPackage= */ true,
/* attemptToBind= */ true,
- request.getUseDefaultTextClassifier(),
service -> service.onSuggestSelection(sessionId, request, callback),
"onSuggestSelection",
callback);
@@ -196,12 +197,12 @@
TextClassification.Request request, ITextClassifierCallback callback)
throws RemoteException {
Objects.requireNonNull(request);
+ Objects.requireNonNull(request.getSystemTextClassifierMetadata());
handleRequest(
- request.getUserId(),
- request.getCallingPackageName(),
+ request.getSystemTextClassifierMetadata(),
+ /* verifyCallingPackage= */ true,
/* attemptToBind= */ true,
- request.getUseDefaultTextClassifier(),
service -> service.onClassifyText(sessionId, request, callback),
"onClassifyText",
callback);
@@ -213,12 +214,12 @@
TextLinks.Request request, ITextClassifierCallback callback)
throws RemoteException {
Objects.requireNonNull(request);
+ Objects.requireNonNull(request.getSystemTextClassifierMetadata());
handleRequest(
- request.getUserId(),
- request.getCallingPackageName(),
+ request.getSystemTextClassifierMetadata(),
+ /* verifyCallingPackage= */ true,
/* attemptToBind= */ true,
- request.getUseDefaultTextClassifier(),
service -> service.onGenerateLinks(sessionId, request, callback),
"onGenerateLinks",
callback);
@@ -229,12 +230,12 @@
@Nullable TextClassificationSessionId sessionId, SelectionEvent event)
throws RemoteException {
Objects.requireNonNull(event);
+ Objects.requireNonNull(event.getSystemTextClassifierMetadata());
handleRequest(
- event.getUserId(),
- /* callingPackageName= */ null,
+ event.getSystemTextClassifierMetadata(),
+ /* verifyCallingPackage= */ false,
/* attemptToBind= */ false,
- event.getUseDefaultTextClassifier(),
service -> service.onSelectionEvent(sessionId, event),
"onSelectionEvent",
NO_OP_CALLBACK);
@@ -246,18 +247,14 @@
TextClassifierEvent event) throws RemoteException {
Objects.requireNonNull(event);
- final int userId = event.getEventContext() == null
- ? UserHandle.getCallingUserId()
- : event.getEventContext().getUserId();
- final boolean useDefaultTextClassifier =
- event.getEventContext() != null
- ? event.getEventContext().getUseDefaultTextClassifier()
- : true;
+ final TextClassificationContext eventContext = event.getEventContext();
+ final SystemTextClassifierMetadata systemTcMetadata =
+ eventContext != null ? eventContext.getSystemTextClassifierMetadata() : null;
+
handleRequest(
- userId,
- /* callingPackageName= */ null,
+ systemTcMetadata,
+ /* verifyCallingPackage= */ false,
/* attemptToBind= */ false,
- useDefaultTextClassifier,
service -> service.onTextClassifierEvent(sessionId, event),
"onTextClassifierEvent",
NO_OP_CALLBACK);
@@ -269,12 +266,12 @@
TextLanguage.Request request,
ITextClassifierCallback callback) throws RemoteException {
Objects.requireNonNull(request);
+ Objects.requireNonNull(request.getSystemTextClassifierMetadata());
handleRequest(
- request.getUserId(),
- request.getCallingPackageName(),
+ request.getSystemTextClassifierMetadata(),
+ /* verifyCallingPackage= */ true,
/* attemptToBind= */ true,
- request.getUseDefaultTextClassifier(),
service -> service.onDetectLanguage(sessionId, request, callback),
"onDetectLanguage",
callback);
@@ -286,12 +283,12 @@
ConversationActions.Request request,
ITextClassifierCallback callback) throws RemoteException {
Objects.requireNonNull(request);
+ Objects.requireNonNull(request.getSystemTextClassifierMetadata());
handleRequest(
- request.getUserId(),
- request.getCallingPackageName(),
+ request.getSystemTextClassifierMetadata(),
+ /* verifyCallingPackage= */ true,
/* attemptToBind= */ true,
- request.getUseDefaultTextClassifier(),
service -> service.onSuggestConversationActions(sessionId, request, callback),
"onSuggestConversationActions",
callback);
@@ -303,13 +300,12 @@
throws RemoteException {
Objects.requireNonNull(sessionId);
Objects.requireNonNull(classificationContext);
+ Objects.requireNonNull(classificationContext.getSystemTextClassifierMetadata());
- final int userId = classificationContext.getUserId();
handleRequest(
- userId,
- classificationContext.getPackageName(),
+ classificationContext.getSystemTextClassifierMetadata(),
+ /* verifyCallingPackage= */ true,
/* attemptToBind= */ false,
- classificationContext.getUseDefaultTextClassifier(),
service -> {
service.onCreateTextClassificationSession(classificationContext, sessionId);
mSessionCache.put(sessionId, classificationContext);
@@ -333,11 +329,13 @@
textClassificationContext != null
? textClassificationContext.useDefaultTextClassifier
: true;
+ final SystemTextClassifierMetadata sysTcMetadata = new SystemTextClassifierMetadata(
+ "", userId, useDefaultTextClassifier);
+
handleRequest(
- userId,
- /* callingPackageName= */ null,
+ sysTcMetadata,
+ /* verifyCallingPackage= */ false,
/* attemptToBind= */ false,
- useDefaultTextClassifier,
service -> {
service.onDestroyTextClassificationSession(sessionId);
mSessionCache.remove(sessionId);
@@ -412,10 +410,9 @@
}
private void handleRequest(
- @UserIdInt int userId,
- @Nullable String callingPackageName,
+ @Nullable SystemTextClassifierMetadata sysTcMetadata,
+ boolean verifyCallingPackage,
boolean attemptToBind,
- boolean useDefaultTextClassifier,
@NonNull ThrowingConsumer<ITextClassifierService> textClassifierServiceConsumer,
@NonNull String methodName,
@NonNull ITextClassifierCallback callback) throws RemoteException {
@@ -423,8 +420,17 @@
Objects.requireNonNull(methodName);
Objects.requireNonNull(callback);
+ final int userId =
+ sysTcMetadata == null ? UserHandle.getCallingUserId() : sysTcMetadata.getUserId();
+ final String callingPackageName =
+ sysTcMetadata == null ? null : sysTcMetadata.getCallingPackageName();
+ final boolean useDefaultTextClassifier =
+ sysTcMetadata == null ? true : sysTcMetadata.useDefaultTextClassifier();
+
try {
- validateCallingPackage(callingPackageName);
+ if (verifyCallingPackage) {
+ validateCallingPackage(callingPackageName);
+ }
validateUser(userId);
} catch (Exception e) {
throw new RemoteException("Invalid request: " + e.getMessage(), e,
@@ -636,8 +642,10 @@
public final boolean useDefaultTextClassifier;
StrippedTextClassificationContext(TextClassificationContext textClassificationContext) {
- userId = textClassificationContext.getUserId();
- useDefaultTextClassifier = textClassificationContext.getUseDefaultTextClassifier();
+ SystemTextClassifierMetadata sysTcMetadata =
+ textClassificationContext.getSystemTextClassifierMetadata();
+ userId = sysTcMetadata.getUserId();
+ useDefaultTextClassifier = sysTcMetadata.useDefaultTextClassifier();
}
}
diff --git a/services/core/java/com/android/server/tv/UinputBridge.java b/services/core/java/com/android/server/tv/UinputBridge.java
index 752aa66..a2fe5fc 100644
--- a/services/core/java/com/android/server/tv/UinputBridge.java
+++ b/services/core/java/com/android/server/tv/UinputBridge.java
@@ -28,7 +28,7 @@
public final class UinputBridge {
private final CloseGuard mCloseGuard = CloseGuard.get();
private long mPtr;
- private IBinder mToken = null;
+ private IBinder mToken;
private static native long nativeOpen(String name, String uniqueId, int width, int height,
int maxPointers);
@@ -39,6 +39,25 @@
private static native void nativeSendPointerUp(long ptr, int pointerId);
private static native void nativeSendPointerSync(long ptr);
+ /** Opens a gamepad - will support gamepad key and axis sending */
+ private static native long nativeGamepadOpen(String name, String uniqueId);
+
+ /** Marks the specified key up/down for a gamepad */
+ private static native void nativeSendGamepadKey(long ptr, int keyIndex, boolean down);
+
+ /**
+ * Gamepads pre-define the following axes:
+ * - Left joystick X, axis == ABS_X == 0, range [0, 254]
+ * - Left joystick Y, axis == ABS_Y == 1, range [0, 254]
+ * - Right joystick X, axis == ABS_RX == 3, range [0, 254]
+ * - Right joystick Y, axis == ABS_RY == 4, range [0, 254]
+ * - Left trigger, axis == ABS_Z == 2, range [0, 254]
+ * - Right trigger, axis == ABS_RZ == 5, range [0, 254]
+ * - DPad X, axis == ABS_HAT0X == 0x10, range [-1, 1]
+ * - DPad Y, axis == ABS_HAT0Y == 0x11, range [-1, 1]
+ */
+ private static native void nativeSendGamepadAxisValue(long ptr, int axis, int value);
+
public UinputBridge(IBinder token, String name, int width, int height, int maxPointers)
throws IOException {
if (width < 1 || height < 1) {
@@ -58,12 +77,31 @@
mCloseGuard.open("close");
}
+ /** Constructor used by static factory methods */
+ private UinputBridge(IBinder token, long ptr) {
+ mPtr = ptr;
+ mToken = token;
+ mCloseGuard.open("close");
+ }
+
+ /** Opens a UinputBridge that supports gamepad buttons and axes. */
+ public static UinputBridge openGamepad(IBinder token, String name)
+ throws IOException {
+ if (token == null) {
+ throw new IllegalArgumentException("Token cannot be null");
+ }
+ long ptr = nativeGamepadOpen(name, token.toString());
+ if (ptr == 0) {
+ throw new IOException("Could not open uinput device " + name);
+ }
+
+ return new UinputBridge(token, ptr);
+ }
+
@Override
protected void finalize() throws Throwable {
try {
- if (mCloseGuard != null) {
- mCloseGuard.warnIfOpen();
- }
+ mCloseGuard.warnIfOpen();
close(mToken);
} finally {
mToken = null;
@@ -119,7 +157,35 @@
if (isTokenValid(token)) {
nativeSendPointerSync(mPtr);
}
+ }
+ /** Send a gamepad key
+ * @param keyIndex - the index of the w3-spec key
+ * @param down - is the key pressed ?
+ */
+ public void sendGamepadKey(IBinder token, int keyIndex, boolean down) {
+ if (isTokenValid(token)) {
+ nativeSendGamepadKey(mPtr, keyIndex, down);
+ }
+ }
+
+ /** Send a gamepad axis value.
+ * - Left joystick X, axis == ABS_X == 0, range [0, 254]
+ * - Left joystick Y, axis == ABS_Y == 1, range [0, 254]
+ * - Right joystick X, axis == ABS_RX == 3, range [0, 254]
+ * - Right joystick Y, axis == ABS_RY == 4, range [0, 254]
+ * - Left trigger, axis == ABS_Z == 2, range [0, 254]
+ * - Right trigger, axis == ABS_RZ == 5, range [0, 254]
+ * - DPad X, axis == ABS_HAT0X == 0x10, range [-1, 1]
+ * - DPad Y, axis == ABS_HAT0Y == 0x11, range [-1, 1]
+ *
+ * @param axis is the axis index
+ * @param value is the value to set for that axis
+ */
+ public void sendGamepadAxisValue(IBinder token, int axis, int value) {
+ if (isTokenValid(token)) {
+ nativeSendGamepadAxisValue(mPtr, axis, value);
+ }
}
public void clear(IBinder token) {
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
index 04d551d..b43d8b7 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
@@ -24,6 +24,8 @@
import android.media.tv.tunerresourcemanager.IResourcesReclaimListener;
import android.media.tv.tunerresourcemanager.ITunerResourceManager;
import android.media.tv.tunerresourcemanager.ResourceClientProfile;
+import android.media.tv.tunerresourcemanager.TunerDemuxRequest;
+import android.media.tv.tunerresourcemanager.TunerDescramblerRequest;
import android.media.tv.tunerresourcemanager.TunerFrontendInfo;
import android.media.tv.tunerresourcemanager.TunerFrontendRequest;
import android.media.tv.tunerresourcemanager.TunerLnbRequest;
@@ -189,6 +191,24 @@
}
@Override
+ public boolean requestDemux(@NonNull TunerDemuxRequest request,
+ @NonNull int[] demuxHandle) {
+ if (DEBUG) {
+ Slog.d(TAG, "requestDemux(request=" + request + ")");
+ }
+ return true;
+ }
+
+ @Override
+ public boolean requestDescrambler(@NonNull TunerDescramblerRequest request,
+ @NonNull int[] descrambleHandle) {
+ if (DEBUG) {
+ Slog.d(TAG, "requestDescrambler(request=" + request + ")");
+ }
+ return true;
+ }
+
+ @Override
public boolean requestCasSession(
@NonNull CasSessionRequest request, @NonNull int[] sessionResourceId) {
if (DEBUG) {
@@ -214,6 +234,20 @@
}
@Override
+ public void releaseDemux(int demuxHandle) {
+ if (DEBUG) {
+ Slog.d(TAG, "releaseDemux(demuxHandle=" + demuxHandle + ")");
+ }
+ }
+
+ @Override
+ public void releaseDescrambler(int descramblerHandle) {
+ if (DEBUG) {
+ Slog.d(TAG, "releaseDescrambler(descramblerHandle=" + descramblerHandle + ")");
+ }
+ }
+
+ @Override
public void releaseCasSession(int sessionResourceId) {
if (DEBUG) {
Slog.d(TAG, "releaseCasSession(sessionResourceId=" + sessionResourceId + ")");
diff --git a/services/core/java/com/android/server/twilight/TwilightService.java b/services/core/java/com/android/server/twilight/TwilightService.java
index 761fbf8..88a60dd 100644
--- a/services/core/java/com/android/server/twilight/TwilightService.java
+++ b/services/core/java/com/android/server/twilight/TwilightService.java
@@ -50,7 +50,7 @@
implements AlarmManager.OnAlarmListener, Handler.Callback, LocationListener {
private static final String TAG = "TwilightService";
- private static final String FEATURE_ID = "TwilightService";
+ private static final String ATTRIBUTION_TAG = "TwilightService";
private static final boolean DEBUG = false;
private static final int MSG_START_LISTENING = 1;
@@ -74,7 +74,7 @@
protected TwilightState mLastTwilightState;
public TwilightService(Context context) {
- super(context.createFeatureContext(FEATURE_ID));
+ super(context.createAttributionContext(ATTRIBUTION_TAG));
mHandler = new Handler(Looper.getMainLooper(), this);
}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 6eb3c0f..a298b89 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -2184,47 +2184,6 @@
}
}
- /**
- * Called when the wallpaper needs to zoom out.
- *
- * @param zoom from 0 to 1 (inclusive) where 1 means fully zoomed out, 0 means fully zoomed in.
- * @param callingPackage package name calling this API.
- * @param displayId id of the display whose zoom is updating.
- */
- public void setWallpaperZoomOut(float zoom, String callingPackage, int displayId) {
- if (!isWallpaperSupported(callingPackage)) {
- return;
- }
- synchronized (mLock) {
- if (!isValidDisplay(displayId)) {
- throw new IllegalArgumentException("Cannot find display with id=" + displayId);
- }
- int userId = UserHandle.getCallingUserId();
- if (mCurrentUserId != userId) {
- return; // Don't change the properties now
- }
- WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM);
- if (zoom < 0 || zoom > 1f) {
- throw new IllegalArgumentException("zoom must be between 0 and one: " + zoom);
- }
-
- if (wallpaper.connection != null) {
- final WallpaperConnection.DisplayConnector connector = wallpaper.connection
- .getDisplayConnectorOrCreate(displayId);
- final IWallpaperEngine engine = connector != null ? connector.mEngine : null;
- if (engine != null) {
- try {
- engine.setZoomOut(zoom);
- } catch (RemoteException e) {
- if (DEBUG) {
- Slog.w(TAG, "Couldn't set wallpaper zoom", e);
- }
- }
- }
- }
- }
- }
-
@Deprecated
@Override
public ParcelFileDescriptor getWallpaper(String callingPkg, IWallpaperManagerCallback cb,
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index b6ad241..e73c928 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -1589,6 +1589,11 @@
info.taskAffinity = uid + ":" + info.taskAffinity;
}
taskAffinity = info.taskAffinity;
+ if (info.windowLayout != null && info.windowLayout.windowLayoutAffinity != null
+ && !info.windowLayout.windowLayoutAffinity.startsWith(uid)) {
+ info.windowLayout.windowLayoutAffinity =
+ uid + ":" + info.windowLayout.windowLayoutAffinity;
+ }
stateNotNeeded = (aInfo.flags & FLAG_STATE_NOT_NEEDED) != 0;
nonLocalizedLabel = aInfo.nonLocalizedLabel;
labelRes = aInfo.labelRes;
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 9bad799..4ebb423 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -153,7 +153,6 @@
import android.util.proto.ProtoOutputStream;
import android.view.Display;
import android.view.DisplayInfo;
-import android.view.ITaskOrganizer;
import android.view.SurfaceControl;
import com.android.internal.annotations.GuardedBy;
@@ -307,8 +306,6 @@
// TODO(task-hierarchy): remove when tiles can be actual parents
TaskTile mTile = null;
- private int mLastTaskOrganizerWindowingMode = -1;
-
private final Handler mHandler;
private class ActivityStackHandler extends Handler {
@@ -635,8 +632,6 @@
super.onConfigurationChanged(newParentConfig);
- updateTaskOrganizerState();
-
// Only need to update surface size here since the super method will handle updating
// surface position.
updateSurfaceSize(getPendingTransaction());
@@ -692,30 +687,6 @@
}
}
- void updateTaskOrganizerState() {
- if (!isRootTask()) {
- return;
- }
-
- final int windowingMode = getWindowingMode();
- if (windowingMode == mLastTaskOrganizerWindowingMode) {
- // If our windowing mode hasn't actually changed, then just stick
- // with our old organizer. This lets us implement the semantic
- // where SysUI can continue to manage it's old tasks
- // while CTS temporarily takes over the registration.
- return;
- }
- /*
- * Different windowing modes may be managed by different task organizers. If
- * getTaskOrganizer returns null, we still call setTaskOrganizer to
- * make sure we clear it.
- */
- final ITaskOrganizer org =
- mWmService.mAtmService.mTaskOrganizerController.getTaskOrganizer(windowingMode);
- setTaskOrganizer(org);
- mLastTaskOrganizerWindowingMode = windowingMode;
- }
-
@Override
public void setWindowingMode(int windowingMode) {
// Calling Task#setWindowingMode() for leaf task since this is the a specialization of
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 688c9ae..c7a1391 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -29,7 +29,6 @@
import static android.app.ActivityManager.START_TASK_TO_FRONT;
import static android.app.WaitResult.LAUNCH_STATE_COLD;
import static android.app.WaitResult.LAUNCH_STATE_HOT;
-import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
@@ -178,6 +177,9 @@
private Intent mNewTaskIntent;
private ActivityStack mSourceStack;
private ActivityStack mTargetStack;
+ // The task that the last activity was started into. We currently reset the actual start
+ // activity's task and as a result may not have a reference to the task in all cases
+ private Task mTargetTask;
private boolean mMovedToFront;
private boolean mNoAnimation;
private boolean mKeepCurTransition;
@@ -545,6 +547,7 @@
mNewTaskIntent = starter.mNewTaskIntent;
mSourceStack = starter.mSourceStack;
+ mTargetTask = starter.mTargetTask;
mTargetStack = starter.mTargetStack;
mMovedToFront = starter.mMovedToFront;
mNoAnimation = starter.mNoAnimation;
@@ -1368,7 +1371,10 @@
// it waits for the new activity to become visible instead, {@link #waitResultIfNeeded}.
mSupervisor.reportWaitingActivityLaunchedIfNeeded(r, result);
- if (startedActivityStack == null) {
+ final Task targetTask = r.getTask() != null
+ ? r.getTask()
+ : mTargetTask;
+ if (startedActivityStack == null || targetTask == null) {
return;
}
@@ -1379,19 +1385,10 @@
// The activity was already running so it wasn't started, but either brought to the
// front or the new intent was delivered to it since it was already in front. Notify
// anyone interested in this piece of information.
- switch (startedActivityStack.getWindowingMode()) {
- case WINDOWING_MODE_PINNED:
- mService.getTaskChangeNotificationController().notifyPinnedActivityRestartAttempt(
- clearedTask);
- break;
- case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY:
- final ActivityStack homeStack =
- startedActivityStack.getDisplay().getOrCreateRootHomeTask();
- if (homeStack != null && homeStack.shouldBeVisible(null /* starting */)) {
- mService.mWindowManager.showRecentApps();
- }
- break;
- }
+ final ActivityStack homeStack = targetTask.getDisplayContent().getRootHomeTask();
+ final boolean homeTaskVisible = homeStack != null && homeStack.shouldBeVisible(null);
+ mService.getTaskChangeNotificationController().notifyActivityRestartAttempt(
+ targetTask.getTaskInfo(), homeTaskVisible, clearedTask);
}
}
@@ -1517,6 +1514,7 @@
// Compute if there is an existing task that should be used for.
final Task targetTask = reusedTask != null ? reusedTask : computeTargetTask();
final boolean newTask = targetTask == null;
+ mTargetTask = targetTask;
computeLaunchParams(r, sourceRecord, targetTask);
@@ -2018,6 +2016,7 @@
mSourceStack = null;
mTargetStack = null;
+ mTargetTask = null;
mMovedToFront = false;
mNoAnimation = false;
mKeepCurTransition = false;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 21d300a..7bacc42 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -356,6 +356,8 @@
ActivityManagerInternal mAmInternal;
UriGrantsManagerInternal mUgmInternal;
private PackageManagerInternal mPmInternal;
+ /** The cached sys ui service component name from package manager. */
+ private ComponentName mSysUiServiceComponent;
private PermissionPolicyInternal mPermissionPolicyInternal;
@VisibleForTesting
final ActivityTaskManagerInternal mInternal;
@@ -5869,6 +5871,14 @@
return mPmInternal;
}
+ ComponentName getSysUiServiceComponentLocked() {
+ if (mSysUiServiceComponent == null) {
+ final PackageManagerInternal pm = getPackageManagerInternalLocked();
+ mSysUiServiceComponent = pm.getSystemUiServiceComponent();
+ }
+ return mSysUiServiceComponent;
+ }
+
PermissionPolicyInternal getPermissionPolicyInternal() {
if (mPermissionPolicyInternal == null) {
mPermissionPolicyInternal = LocalServices.getService(PermissionPolicyInternal.class);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 3352bd5..98e3d07 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -2224,9 +2224,7 @@
.addTaggedData(MetricsEvent.FIELD_DISPLAY_ID, getDisplayId()));
}
- // If there was no pinned stack, we still need to notify the controller of the display info
- // update as a result of the config change.
- if (mPinnedStackControllerLocked != null && !hasPinnedTask()) {
+ if (mPinnedStackControllerLocked != null) {
mPinnedStackControllerLocked.onDisplayInfoChanged(getDisplayInfo());
}
}
@@ -4934,6 +4932,12 @@
scheduleAnimation();
}
}
+
+ @Override
+ boolean shouldMagnify() {
+ // Omitted from Screen-Magnification
+ return false;
+ }
}
/**
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index d5a0d05..ba61667 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -28,6 +28,7 @@
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_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;
@@ -439,10 +440,12 @@
updateDreamingSleepToken(msg.arg1 != 0);
break;
case MSG_REQUEST_TRANSIENT_BARS:
- WindowState targetBar = (msg.arg1 == MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS)
- ? mStatusBar : mNavigationBar;
- if (targetBar != null) {
- requestTransientBars(targetBar);
+ synchronized (mLock) {
+ WindowState targetBar = (msg.arg1 == MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS)
+ ? mStatusBar : mNavigationBar;
+ if (targetBar != null) {
+ requestTransientBars(targetBar);
+ }
}
break;
case MSG_DISPOSE_INPUT_CONSUMER:
@@ -498,15 +501,20 @@
new SystemGesturesPointerEventListener.Callbacks() {
@Override
public void onSwipeFromTop() {
- if (mStatusBar != null) {
- requestTransientBars(mStatusBar);
+ synchronized (mLock) {
+ if (mStatusBar != null) {
+ requestTransientBars(mStatusBar);
+ }
}
}
@Override
public void onSwipeFromBottom() {
- if (mNavigationBar != null && mNavigationBarPosition == NAV_BAR_BOTTOM) {
- requestTransientBars(mNavigationBar);
+ synchronized (mLock) {
+ if (mNavigationBar != null
+ && mNavigationBarPosition == NAV_BAR_BOTTOM) {
+ requestTransientBars(mNavigationBar);
+ }
}
}
@@ -516,12 +524,13 @@
synchronized (mLock) {
mDisplayContent.calculateSystemGestureExclusion(
excludedRegion, null /* outUnrestricted */);
- }
- final boolean sideAllowed = mNavigationBarAlwaysShowOnSideGesture
- || mNavigationBarPosition == NAV_BAR_RIGHT;
- if (mNavigationBar != null && sideAllowed
- && !mSystemGestures.currentGestureStartedInRegion(excludedRegion)) {
- requestTransientBars(mNavigationBar);
+ final boolean sideAllowed = mNavigationBarAlwaysShowOnSideGesture
+ || mNavigationBarPosition == NAV_BAR_RIGHT;
+ if (mNavigationBar != null && sideAllowed
+ && !mSystemGestures.currentGestureStartedInRegion(
+ excludedRegion)) {
+ requestTransientBars(mNavigationBar);
+ }
}
excludedRegion.recycle();
}
@@ -532,12 +541,13 @@
synchronized (mLock) {
mDisplayContent.calculateSystemGestureExclusion(
excludedRegion, null /* outUnrestricted */);
- }
- final boolean sideAllowed = mNavigationBarAlwaysShowOnSideGesture
- || mNavigationBarPosition == NAV_BAR_LEFT;
- if (mNavigationBar != null && sideAllowed
- && !mSystemGestures.currentGestureStartedInRegion(excludedRegion)) {
- requestTransientBars(mNavigationBar);
+ final boolean sideAllowed = mNavigationBarAlwaysShowOnSideGesture
+ || mNavigationBarPosition == NAV_BAR_LEFT;
+ if (mNavigationBar != null && sideAllowed
+ && !mSystemGestures.currentGestureStartedInRegion(
+ excludedRegion)) {
+ requestTransientBars(mNavigationBar);
+ }
}
excludedRegion.recycle();
}
@@ -1469,8 +1479,14 @@
*/
public void beginLayoutLw(DisplayFrames displayFrames, int uiMode) {
displayFrames.onBeginLayout();
- updateInsetsStateForDisplayCutout(displayFrames,
- mDisplayContent.getInsetsStateController().getRawInsetsState());
+ 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);
mSystemGestures.screenWidth = displayFrames.mUnrestricted.width();
mSystemGestures.screenHeight = displayFrames.mUnrestricted.height();
@@ -3149,47 +3165,46 @@
}
private void requestTransientBars(WindowState swipeTarget) {
- synchronized (mLock) {
- if (!mService.mPolicy.isUserSetupComplete()) {
- // Swipe-up for navigation bar is disabled during setup
+ if (!mService.mPolicy.isUserSetupComplete()) {
+ // Swipe-up for navigation bar is disabled during setup
+ return;
+ }
+ if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL) {
+ if (swipeTarget == mNavigationBar
+ && !getInsetsPolicy().isHidden(ITYPE_NAVIGATION_BAR)) {
+ // Don't show status bar when swiping on already visible navigation bar
return;
}
- if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_FULL) {
- if (swipeTarget == mNavigationBar
- && !getInsetsPolicy().isHidden(ITYPE_NAVIGATION_BAR)) {
- // Don't show status bar when swiping on already visible navigation bar
- return;
- }
- final InsetsControlTarget controlTarget =
- swipeTarget.getControllableInsetProvider().getControlTarget();
+ final InsetsSourceProvider provider = swipeTarget.getControllableInsetProvider();
+ final InsetsControlTarget controlTarget = provider != null
+ ? provider.getControlTarget() : null;
- // No transient mode on lockscreen (in notification shade window).
- if (controlTarget == null || controlTarget == getNotificationShade()) {
+ // No transient mode on lockscreen (in notification shade window).
+ if (controlTarget == null || controlTarget == getNotificationShade()) {
+ return;
+ }
+ if (controlTarget.canShowTransient()) {
+ mDisplayContent.getInsetsPolicy().showTransient(IntArray.wrap(
+ new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR}));
+ } else {
+ controlTarget.showInsets(Type.systemBars(), false);
+ }
+ } else {
+ boolean sb = mStatusBarController.checkShowTransientBarLw();
+ boolean nb = mNavigationBarController.checkShowTransientBarLw()
+ && !isNavBarEmpty(mLastSystemUiFlags);
+ if (sb || nb) {
+ // Don't show status bar when swiping on already visible navigation bar
+ if (!nb && swipeTarget == mNavigationBar) {
+ if (DEBUG) Slog.d(TAG, "Not showing transient bar, wrong swipe target");
return;
}
- if (controlTarget.canShowTransient()) {
- mDisplayContent.getInsetsPolicy().showTransient(IntArray.wrap(
- new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR}));
- } else {
- controlTarget.showInsets(Type.systemBars(), false);
- }
- } else {
- boolean sb = mStatusBarController.checkShowTransientBarLw();
- boolean nb = mNavigationBarController.checkShowTransientBarLw()
- && !isNavBarEmpty(mLastSystemUiFlags);
- if (sb || nb) {
- // Don't show status bar when swiping on already visible navigation bar
- if (!nb && swipeTarget == mNavigationBar) {
- if (DEBUG) Slog.d(TAG, "Not showing transient bar, wrong swipe target");
- return;
- }
- if (sb) mStatusBarController.showTransient();
- if (nb) mNavigationBarController.showTransient();
- updateSystemUiVisibilityLw();
- }
+ if (sb) mStatusBarController.showTransient();
+ if (nb) mNavigationBarController.showTransient();
+ updateSystemUiVisibilityLw();
}
- mImmersiveModeConfirmation.confirmCurrentPrompt();
}
+ mImmersiveModeConfirmation.confirmCurrentPrompt();
}
private void disposeInputConsumer(InputConsumer inputConsumer) {
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index 01f9888..30912e5 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -36,6 +36,7 @@
import android.util.SparseArray;
import android.view.InsetsAnimationControlCallbacks;
import android.view.InsetsAnimationControlImpl;
+import android.view.InsetsAnimationControlRunner;
import android.view.InsetsController;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
@@ -44,6 +45,7 @@
import android.view.SyncRtSurfaceTransactionApplier;
import android.view.ViewRootImpl;
import android.view.WindowInsetsAnimation;
+import android.view.WindowInsetsAnimation.Bounds;
import android.view.WindowInsetsAnimationControlListener;
import com.android.internal.annotations.VisibleForTesting;
@@ -327,7 +329,7 @@
InsetsPolicyAnimationControlCallbacks mControlCallbacks;
InsetsPolicyAnimationControlListener(boolean show, Runnable finishCallback) {
- super(show);
+ super(show, true /* useSfVsync */);
mFinishCallback = finishCallback;
mControlCallbacks = new InsetsPolicyAnimationControlCallbacks(this);
}
@@ -360,8 +362,6 @@
mFocusedWin.getDisplayContent().getBounds(), getState(),
mListener, typesReady, this, mListener.getDurationMs(),
InsetsController.INTERPOLATOR, true,
- show ? LAYOUT_INSETS_DURING_ANIMATION_SHOWN
- : LAYOUT_INSETS_DURING_ANIMATION_HIDDEN,
show ? ANIMATION_TYPE_SHOW : ANIMATION_TYPE_HIDE);
SurfaceAnimationThread.getHandler().post(
() -> mListener.onReady(mAnimationControl, typesReady));
@@ -377,7 +377,7 @@
}
@Override
- public void notifyFinished(InsetsAnimationControlImpl controller, boolean shown) {
+ public void notifyFinished(InsetsAnimationControlRunner runner, boolean shown) {
// Nothing's needed here. Finish steps is handled in the listener
// onAnimationFinished callback.
}
@@ -406,14 +406,21 @@
applyParams(t, surfaceParams, mTmpFloat9);
}
t.apply();
+ t.close();
+ }
+
+ // Since we don't push applySurfaceParams to a Handler-queue we don't need
+ // to push release in this case.
+ @Override
+ public void releaseSurfaceControlFromRt(SurfaceControl sc) {
+ sc.release();
}
@Override
public void startAnimation(InsetsAnimationControlImpl controller,
WindowInsetsAnimationControlListener listener, int types,
WindowInsetsAnimation animation,
- WindowInsetsAnimation.Bounds bounds,
- int layoutDuringAnimation) {
+ Bounds bounds) {
}
}
}
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index 6ff029b..ee36db9 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.InsetsState.ITYPE_CAPTION_BAR;
import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.ITYPE_INVALID;
@@ -29,6 +30,8 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.WindowConfiguration;
+import android.app.WindowConfiguration.WindowingMode;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.SparseArray;
@@ -74,30 +77,28 @@
/**
* When dispatching window state to the client, we'll need to exclude the source that represents
- * the window that is being dispatched.
+ * the window that is being dispatched. We also need to exclude certain types of insets source
+ * for client within specific windowing modes.
*
* @param target The client we dispatch the state to.
* @return The state stripped of the necessary information.
*/
InsetsState getInsetsForDispatch(@NonNull WindowState target) {
final InsetsSourceProvider provider = target.getControllableInsetProvider();
- if (provider == null) {
- return mState;
- }
- final @InternalInsetsType int type = provider.getSource().getType();
- return getInsetsForType(type);
+ final @InternalInsetsType int type = provider != null
+ ? provider.getSource().getType() : ITYPE_INVALID;
+ return getInsetsForTypeAndWindowingMode(type, target.getWindowingMode());
}
InsetsState getInsetsForWindowMetrics(@NonNull WindowManager.LayoutParams attrs) {
final @InternalInsetsType int type = getInsetsTypeForWindowType(attrs.type);
- if (type == ITYPE_INVALID) {
- return mState;
- }
- return getInsetsForType(type);
+ final WindowToken token = mDisplayContent.getWindowToken(attrs.token);
+ final @WindowingMode int windowingMode = token != null
+ ? token.getWindowingMode() : WINDOWING_MODE_UNDEFINED;
+ return getInsetsForTypeAndWindowingMode(type, windowingMode);
}
- @InternalInsetsType
- private static int getInsetsTypeForWindowType(int type) {
+ private static @InternalInsetsType int getInsetsTypeForWindowType(int type) {
switch(type) {
case TYPE_STATUS_BAR:
return ITYPE_STATUS_BAR;
@@ -110,36 +111,48 @@
}
}
- private InsetsState getInsetsForType(@InternalInsetsType int type) {
- final InsetsState state = new InsetsState();
- state.set(mState);
- state.removeSource(type);
+ /** @see #getInsetsForDispatch */
+ private InsetsState getInsetsForTypeAndWindowingMode(@InternalInsetsType int type,
+ @WindowingMode int windowingMode) {
+ InsetsState state = mState;
- // Navigation bar doesn't get influenced by anything else
- if (type == ITYPE_NAVIGATION_BAR) {
- state.removeSource(ITYPE_IME);
- state.removeSource(ITYPE_STATUS_BAR);
- state.removeSource(ITYPE_CAPTION_BAR);
- }
+ if (type != ITYPE_INVALID) {
+ state = new InsetsState(state);
+ state.removeSource(type);
- // Status bar doesn't get influenced by caption bar
- if (type == ITYPE_STATUS_BAR) {
- state.removeSource(ITYPE_CAPTION_BAR);
- }
+ // Navigation bar doesn't get influenced by anything else
+ if (type == ITYPE_NAVIGATION_BAR) {
+ state.removeSource(ITYPE_IME);
+ state.removeSource(ITYPE_STATUS_BAR);
+ state.removeSource(ITYPE_CAPTION_BAR);
+ }
- // IME needs different frames for certain cases (e.g. navigation bar in gesture nav).
- if (type == ITYPE_IME) {
- for (int i = mProviders.size() - 1; i >= 0; i--) {
- InsetsSourceProvider otherProvider = mProviders.valueAt(i);
- if (otherProvider.overridesImeFrame()) {
- InsetsSource override =
- new InsetsSource(state.getSource(otherProvider.getSource().getType()));
- override.setFrame(otherProvider.getImeOverrideFrame());
- state.addSource(override);
+ // Status bar doesn't get influenced by caption bar
+ if (type == ITYPE_STATUS_BAR) {
+ state.removeSource(ITYPE_CAPTION_BAR);
+ }
+
+ // IME needs different frames for certain cases (e.g. navigation bar in gesture nav).
+ if (type == ITYPE_IME) {
+ for (int i = mProviders.size() - 1; i >= 0; i--) {
+ InsetsSourceProvider otherProvider = mProviders.valueAt(i);
+ if (otherProvider.overridesImeFrame()) {
+ InsetsSource override =
+ new InsetsSource(
+ state.getSource(otherProvider.getSource().getType()));
+ override.setFrame(otherProvider.getImeOverrideFrame());
+ state.addSource(override);
+ }
}
}
}
+ if (WindowConfiguration.isFloating(windowingMode)) {
+ state = new InsetsState(state);
+ state.removeSource(ITYPE_STATUS_BAR);
+ state.removeSource(ITYPE_NAVIGATION_BAR);
+ }
+
return state;
}
diff --git a/services/core/java/com/android/server/wm/LaunchParamsPersister.java b/services/core/java/com/android/server/wm/LaunchParamsPersister.java
index 660706e..9371c0e 100644
--- a/services/core/java/com/android/server/wm/LaunchParamsPersister.java
+++ b/services/core/java/com/android/server/wm/LaunchParamsPersister.java
@@ -16,7 +16,9 @@
package com.android.server.wm;
+import android.annotation.Nullable;
import android.content.ComponentName;
+import android.content.pm.ActivityInfo;
import android.content.pm.PackageManagerInternal;
import android.graphics.Rect;
import android.os.Environment;
@@ -87,9 +89,17 @@
* launching activity of tasks) to {@link PersistableLaunchParams} that stores launch metadata
* that are stable across reboots.
*/
- private final SparseArray<ArrayMap<ComponentName, PersistableLaunchParams>> mMap =
+ private final SparseArray<ArrayMap<ComponentName, PersistableLaunchParams>> mLaunchParamsMap =
new SparseArray<>();
+ /**
+ * A map from {@link android.content.pm.ActivityInfo.WindowLayout#windowLayoutAffinity} to
+ * activity's component name for reverse queries from window layout affinities to activities.
+ * Used to decide if we should use another activity's record with the same affinity.
+ */
+ private final ArrayMap<String, ArraySet<ComponentName>> mWindowLayoutAffinityMap =
+ new ArrayMap<>();
+
LaunchParamsPersister(PersisterQueue persisterQueue, ActivityStackSupervisor supervisor) {
this(persisterQueue, supervisor, Environment::getDataSystemCeDirectory);
}
@@ -112,7 +122,7 @@
}
void onCleanupUser(int userId) {
- mMap.remove(userId);
+ mLaunchParamsMap.remove(userId);
}
private void loadLaunchParams(int userId) {
@@ -128,7 +138,7 @@
final File[] paramsFiles = launchParamsFolder.listFiles();
final ArrayMap<ComponentName, PersistableLaunchParams> map =
new ArrayMap<>(paramsFiles.length);
- mMap.put(userId, map);
+ mLaunchParamsMap.put(userId, map);
for (File paramsFile : paramsFiles) {
if (!paramsFile.isFile()) {
@@ -179,10 +189,12 @@
continue;
}
- params.restoreFromXml(parser);
+ params.restore(paramsFile, parser);
}
map.put(name, params);
+ addComponentNameToLaunchParamAffinityMapIfNotNull(
+ name, params.mWindowLayoutAffinity);
} catch (Exception e) {
Slog.w(TAG, "Failed to restore launch params for " + name, e);
filesToDelete.add(paramsFile);
@@ -204,19 +216,17 @@
final ComponentName name = task.realActivity;
final int userId = task.mUserId;
PersistableLaunchParams params;
- ArrayMap<ComponentName, PersistableLaunchParams> map = mMap.get(userId);
+ ArrayMap<ComponentName, PersistableLaunchParams> map = mLaunchParamsMap.get(userId);
if (map == null) {
map = new ArrayMap<>();
- mMap.put(userId, map);
+ mLaunchParamsMap.put(userId, map);
}
- params = map.get(name);
- if (params == null) {
- params = new PersistableLaunchParams();
- map.put(name, params);
- }
+ params = map.computeIfAbsent(name, componentName -> new PersistableLaunchParams());
final boolean changed = saveTaskToLaunchParam(task, display, params);
+ addComponentNameToLaunchParamAffinityMapIfNotNull(name, params.mWindowLayoutAffinity);
+
if (changed) {
mPersisterQueue.updateLastOrAddItem(
new LaunchParamsWriteQueueItem(userId, name, params),
@@ -243,19 +253,63 @@
params.mBounds.setEmpty();
}
+ String launchParamAffinity = task.mWindowLayoutAffinity;
+ changed |= Objects.equals(launchParamAffinity, params.mWindowLayoutAffinity);
+ params.mWindowLayoutAffinity = launchParamAffinity;
+
+ if (changed) {
+ params.mTimestamp = System.currentTimeMillis();
+ }
+
return changed;
}
+ private void addComponentNameToLaunchParamAffinityMapIfNotNull(
+ ComponentName name, String launchParamAffinity) {
+ if (launchParamAffinity == null) {
+ return;
+ }
+ mWindowLayoutAffinityMap.computeIfAbsent(launchParamAffinity, affinity -> new ArraySet<>())
+ .add(name);
+ }
+
void getLaunchParams(Task task, ActivityRecord activity, LaunchParams outParams) {
final ComponentName name = task != null ? task.realActivity : activity.mActivityComponent;
final int userId = task != null ? task.mUserId : activity.mUserId;
+ final String windowLayoutAffinity;
+ if (task != null) {
+ windowLayoutAffinity = task.mWindowLayoutAffinity;
+ } else {
+ ActivityInfo.WindowLayout layout = activity.info.windowLayout;
+ windowLayoutAffinity = layout == null ? null : layout.windowLayoutAffinity;
+ }
outParams.reset();
- Map<ComponentName, PersistableLaunchParams> map = mMap.get(userId);
+ Map<ComponentName, PersistableLaunchParams> map = mLaunchParamsMap.get(userId);
if (map == null) {
return;
}
- final PersistableLaunchParams persistableParams = map.get(name);
+
+ // First use its own record as a reference.
+ PersistableLaunchParams persistableParams = map.get(name);
+ // Next we'll compare these params against all existing params with the same affinity and
+ // use the newest one.
+ if (windowLayoutAffinity != null
+ && mWindowLayoutAffinityMap.get(windowLayoutAffinity) != null) {
+ ArraySet<ComponentName> candidates = mWindowLayoutAffinityMap.get(windowLayoutAffinity);
+ for (int i = 0; i < candidates.size(); ++i) {
+ ComponentName candidate = candidates.valueAt(i);
+ final PersistableLaunchParams candidateParams = map.get(candidate);
+ if (candidateParams == null) {
+ continue;
+ }
+
+ if (persistableParams == null
+ || candidateParams.mTimestamp > persistableParams.mTimestamp) {
+ persistableParams = candidateParams;
+ }
+ }
+ }
if (persistableParams == null) {
return;
@@ -272,10 +326,10 @@
void removeRecordForPackage(String packageName) {
final List<File> fileToDelete = new ArrayList<>();
- for (int i = 0; i < mMap.size(); ++i) {
- int userId = mMap.keyAt(i);
+ for (int i = 0; i < mLaunchParamsMap.size(); ++i) {
+ int userId = mLaunchParamsMap.keyAt(i);
final File launchParamsFolder = getLaunchParamFolder(userId);
- ArrayMap<ComponentName, PersistableLaunchParams> map = mMap.valueAt(i);
+ ArrayMap<ComponentName, PersistableLaunchParams> map = mLaunchParamsMap.valueAt(i);
for (int j = map.size() - 1; j >= 0; --j) {
final ComponentName name = map.keyAt(j);
if (name.getPackageName().equals(packageName)) {
@@ -409,6 +463,7 @@
private static final String ATTR_WINDOWING_MODE = "windowing_mode";
private static final String ATTR_DISPLAY_UNIQUE_ID = "display_unique_id";
private static final String ATTR_BOUNDS = "bounds";
+ private static final String ATTR_WINDOW_LAYOUT_AFFINITY = "window_layout_affinity";
/** The bounds within the parent container. */
final Rect mBounds = new Rect();
@@ -419,14 +474,29 @@
/** The windowing mode to be in. */
int mWindowingMode;
+ /**
+ * Last {@link android.content.pm.ActivityInfo.WindowLayout#windowLayoutAffinity} of the
+ * window.
+ */
+ @Nullable String mWindowLayoutAffinity;
+
+ /**
+ * Timestamp from {@link System#currentTimeMillis()} when this record is captured, or last
+ * modified time when the record is restored from storage.
+ */
+ long mTimestamp;
+
void saveToXml(XmlSerializer serializer) throws IOException {
serializer.attribute(null, ATTR_DISPLAY_UNIQUE_ID, mDisplayUniqueId);
serializer.attribute(null, ATTR_WINDOWING_MODE,
Integer.toString(mWindowingMode));
serializer.attribute(null, ATTR_BOUNDS, mBounds.flattenToString());
+ if (mWindowLayoutAffinity != null) {
+ serializer.attribute(null, ATTR_WINDOW_LAYOUT_AFFINITY, mWindowLayoutAffinity);
+ }
}
- void restoreFromXml(XmlPullParser parser) {
+ void restore(File xmlFile, XmlPullParser parser) {
for (int i = 0; i < parser.getAttributeCount(); ++i) {
final String attrValue = parser.getAttributeValue(i);
switch (parser.getAttributeName(i)) {
@@ -443,16 +513,28 @@
}
break;
}
+ case ATTR_WINDOW_LAYOUT_AFFINITY:
+ mWindowLayoutAffinity = attrValue;
+ break;
}
}
+
+ // The modified time could be a few seconds later than the timestamp when the record is
+ // captured, which is a good enough estimate to the capture time after a reboot or a
+ // user switch.
+ mTimestamp = xmlFile.lastModified();
}
@Override
public String toString() {
final StringBuilder builder = new StringBuilder("PersistableLaunchParams{");
- builder.append("windowingMode=" + mWindowingMode);
+ builder.append(" windowingMode=" + mWindowingMode);
builder.append(" displayUniqueId=" + mDisplayUniqueId);
builder.append(" bounds=" + mBounds);
+ if (mWindowLayoutAffinity != null) {
+ builder.append(" launchParamsAffinity=" + mWindowLayoutAffinity);
+ }
+ builder.append(" timestamp=" + mTimestamp);
builder.append(" }");
return builder.toString();
}
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 9df4248..5f3732a 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -356,6 +356,31 @@
}
@Override
+ public void setWallpaperZoomOut(IBinder window, float zoom) {
+ if (Float.compare(0f, zoom) > 0 || Float.compare(1f, zoom) < 0 || Float.isNaN(zoom)) {
+ throw new IllegalArgumentException("Zoom must be a valid float between 0 and 1: "
+ + zoom);
+ }
+ synchronized (mService.mGlobalLock) {
+ long ident = Binder.clearCallingIdentity();
+ try {
+ actionOnWallpaper(window, (wpController, windowState) ->
+ wpController.setWallpaperZoomOut(windowState, zoom));
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
+ @Override
+ public void setShouldZoomOutWallpaper(IBinder window, boolean shouldZoom) {
+ synchronized (mService.mGlobalLock) {
+ actionOnWallpaper(window, (wpController, windowState) ->
+ wpController.setShouldZoomOutWallpaper(windowState, shouldZoom));
+ }
+ }
+
+ @Override
public void wallpaperOffsetsComplete(IBinder window) {
synchronized (mService.mGlobalLock) {
actionOnWallpaper(window, (wpController, windowState) ->
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index b2db99b..5ab5fbc 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -199,6 +199,7 @@
private static final String ATTR_MIN_WIDTH = "min_width";
private static final String ATTR_MIN_HEIGHT = "min_height";
private static final String ATTR_PERSIST_TASK_VERSION = "persist_task_version";
+ private static final String ATTR_WINDOW_LAYOUT_AFFINITY = "window_layout_affinity";
// Current version of the task record we persist. Used to check if we need to run any upgrade
// code.
@@ -233,6 +234,8 @@
String affinity; // The affinity name for this task, or null; may change identity.
String rootAffinity; // Initial base affinity, or null; does not change from initial root.
+ String mWindowLayoutAffinity; // Launch param affinity of this task or null. Used when saving
+ // launch params of this task.
IVoiceInteractionSession voiceSession; // Voice interaction session driving task
IVoiceInteractor voiceInteractor; // Associated interactor to provide to app
Intent intent; // The original intent that started the task. Note that this value can
@@ -474,6 +477,7 @@
* taskAppeared callback, and emit a taskRemoved callback when the Task is vanished.
*/
ITaskOrganizer mTaskOrganizer;
+ private int mLastTaskOrganizerWindowingMode = -1;
/**
* Last Picture-in-Picture params applicable to the task. Updated when the app
@@ -1000,6 +1004,8 @@
origActivity = new ComponentName(info.packageName, info.name);
}
}
+ mWindowLayoutAffinity =
+ info.windowLayout == null ? null : info.windowLayout.windowLayoutAffinity;
final int intentFlags = intent == null ? 0 : intent.getFlags();
if ((intentFlags & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
@@ -1929,6 +1935,7 @@
// TODO: Should also take care of Pip mode changes here.
saveLaunchingStateIfNeeded();
+ updateTaskOrganizerState(false /* forceUpdate */);
}
/**
@@ -3408,6 +3415,9 @@
pw.println();
}
}
+ if (mWindowLayoutAffinity != null) {
+ pw.print(prefix); pw.print("windowLayoutAffinity="); pw.println(mWindowLayoutAffinity);
+ }
if (voiceSession != null || voiceInteractor != null) {
pw.print(prefix); pw.print("VOICE: session=0x");
pw.print(Integer.toHexString(System.identityHashCode(voiceSession)));
@@ -3589,6 +3599,9 @@
} else if (rootAffinity != null) {
out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@");
}
+ if (mWindowLayoutAffinity != null) {
+ out.attribute(null, ATTR_WINDOW_LAYOUT_AFFINITY, mWindowLayoutAffinity);
+ }
out.attribute(null, ATTR_ROOTHASRESET, String.valueOf(rootWasReset));
out.attribute(null, ATTR_AUTOREMOVERECENTS, String.valueOf(autoRemoveRecents));
out.attribute(null, ATTR_ASKEDCOMPATMODE, String.valueOf(askedCompatMode));
@@ -3746,6 +3759,7 @@
String affinity = null;
String rootAffinity = null;
boolean hasRootAffinity = false;
+ String windowLayoutAffinity = null;
boolean rootHasReset = false;
boolean autoRemoveRecents = false;
boolean askedCompatMode = false;
@@ -3798,6 +3812,9 @@
rootAffinity = attrValue;
hasRootAffinity = true;
break;
+ case ATTR_WINDOW_LAYOUT_AFFINITY:
+ windowLayoutAffinity = attrValue;
+ break;
case ATTR_ROOTHASRESET:
rootHasReset = Boolean.parseBoolean(attrValue);
break;
@@ -3953,6 +3970,7 @@
realActivitySuspended, userSetupComplete, minWidth, minHeight, null /*stack*/);
task.mLastNonFullscreenBounds = lastNonFullscreenBounds;
task.setBounds(lastNonFullscreenBounds);
+ task.mWindowLayoutAffinity = windowLayoutAffinity;
for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
task.addChild(activities.get(activityNdx));
@@ -4018,6 +4036,39 @@
// Called on Binder death.
void taskOrganizerDied() {
mTaskOrganizer = null;
+ mLastTaskOrganizerWindowingMode = -1;
+ }
+
+ /**
+ * Called when the task state changes (ie. from windowing mode change) an the task organizer
+ * state should also be updated.
+ *
+ * @param forceUpdate Updates the task organizer to the one currently specified in the task
+ * org controller for the task's windowing mode, ignoring the cached
+ * windowing mode checks.
+ */
+ void updateTaskOrganizerState(boolean forceUpdate) {
+ if (!isRootTask()) {
+ return;
+ }
+
+ final int windowingMode = getWindowingMode();
+ if (!forceUpdate && windowingMode == mLastTaskOrganizerWindowingMode) {
+ // If our windowing mode hasn't actually changed, then just stick
+ // with our old organizer. This lets us implement the semantic
+ // where SysUI can continue to manage it's old tasks
+ // while CTS temporarily takes over the registration.
+ return;
+ }
+ /*
+ * Different windowing modes may be managed by different task organizers. If
+ * getTaskOrganizer returns null, we still call setTaskOrganizer to
+ * make sure we clear it.
+ */
+ final ITaskOrganizer org =
+ mWmService.mAtmService.mTaskOrganizerController.getTaskOrganizer(windowingMode);
+ setTaskOrganizer(org);
+ mLastTaskOrganizerWindowingMode = windowingMode;
}
@Override
@@ -4123,8 +4174,16 @@
return mMainWindowSizeChangeTransaction;
}
+ void setActivityWindowingMode(int windowingMode) {
+ PooledConsumer c = PooledLambda.obtainConsumer(ActivityRecord::setWindowingMode,
+ PooledLambda.__(ActivityRecord.class), windowingMode);
+ forAllActivities(c);
+ c.recycle();
+ }
+
@Override
long getProtoFieldId() {
return TASK;
}
+
}
diff --git a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
index 96a9127..e4f10d9 100644
--- a/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
+++ b/services/core/java/com/android/server/wm/TaskChangeNotificationController.java
@@ -30,13 +30,15 @@
import android.os.RemoteCallbackList;
import android.os.RemoteException;
+import com.android.internal.os.SomeArgs;
+
import java.util.ArrayList;
class TaskChangeNotificationController {
private static final int LOG_STACK_STATE_MSG = 1;
private static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_MSG = 2;
private static final int NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG = 3;
- private static final int NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG = 4;
+ private static final int NOTIFY_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG = 4;
private static final int NOTIFY_FORCED_RESIZABLE_MSG = 6;
private static final int NOTIFY_ACTIVITY_DISMISSING_DOCKED_STACK_MSG = 7;
private static final int NOTIFY_TASK_ADDED_LISTENERS_MSG = 8;
@@ -118,8 +120,10 @@
l.onActivityUnpinned();
};
- private final TaskStackConsumer mNotifyPinnedActivityRestartAttempt = (l, m) -> {
- l.onPinnedActivityRestartAttempt(m.arg1 != 0);
+ private final TaskStackConsumer mNotifyActivityRestartAttempt = (l, m) -> {
+ SomeArgs args = (SomeArgs) m.obj;
+ l.onActivityRestartAttempt((RunningTaskInfo) args.arg1, args.argi1 != 0,
+ args.argi2 != 0);
};
private final TaskStackConsumer mNotifyActivityForcedResizable = (l, m) -> {
@@ -220,8 +224,8 @@
case NOTIFY_ACTIVITY_UNPINNED_LISTENERS_MSG:
forAllRemoteListeners(mNotifyActivityUnpinned, msg);
break;
- case NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG:
- forAllRemoteListeners(mNotifyPinnedActivityRestartAttempt, msg);
+ case NOTIFY_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG:
+ forAllRemoteListeners(mNotifyActivityRestartAttempt, msg);
break;
case NOTIFY_FORCED_RESIZABLE_MSG:
forAllRemoteListeners(mNotifyActivityForcedResizable, msg);
@@ -266,6 +270,9 @@
forAllRemoteListeners(mNotifyTaskFocusChanged, msg);
break;
}
+ if (msg.obj instanceof SomeArgs) {
+ ((SomeArgs) msg.obj).recycle();
+ }
}
}
@@ -358,15 +365,18 @@
/**
* Notifies all listeners when an attempt was made to start an an activity that is already
- * running in the pinned stack and the activity was not actually started, but the task is
- * either brought to the front or a new Intent is delivered to it.
+ * running, but the task is either brought to the front or a new Intent is delivered to it.
*/
- void notifyPinnedActivityRestartAttempt(boolean clearedTask) {
- mHandler.removeMessages(NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG);
- final Message msg =
- mHandler.obtainMessage(NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG,
- clearedTask ? 1 : 0, 0);
- forAllLocalListeners(mNotifyPinnedActivityRestartAttempt, msg);
+ void notifyActivityRestartAttempt(RunningTaskInfo task, boolean homeTaskVisible,
+ boolean clearedTask) {
+ mHandler.removeMessages(NOTIFY_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG);
+ final SomeArgs args = SomeArgs.obtain();
+ args.arg1 = task;
+ args.argi1 = homeTaskVisible ? 1 : 0;
+ args.argi2 = clearedTask ? 1 : 0;
+ final Message msg = mHandler.obtainMessage(NOTIFY_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG,
+ args);
+ forAllLocalListeners(mNotifyActivityRestartAttempt, msg);
msg.sendToTarget();
}
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 4093fe5..9cbc9ee 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -105,7 +105,7 @@
TaskOrganizerState(ITaskOrganizer organizer, int windowingMode,
- TaskOrganizerState replacing) {
+ @Nullable TaskOrganizerState replacing) {
mOrganizer = organizer;
mDeathRecipient = new DeathRecipient(organizer, windowingMode);
try {
@@ -203,10 +203,27 @@
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
+ if (getTaskOrganizer(windowingMode) != null) {
+ Slog.w(TAG, "Task organizer already exists for windowing mode: "
+ + windowingMode);
+ }
+ final TaskOrganizerState previousState =
+ mTaskOrganizersForWindowingMode.get(windowingMode);
final TaskOrganizerState state = new TaskOrganizerState(organizer, windowingMode,
- mTaskOrganizersForWindowingMode.get(windowingMode));
+ previousState);
mTaskOrganizersForWindowingMode.put(windowingMode, state);
mTaskOrganizerStates.put(organizer.asBinder(), state);
+
+ if (previousState == null) {
+ // Only in the case where this is the root task organizer for the given
+ // windowing mode, we add report all existing tasks in that mode to the new
+ // task organizer.
+ mService.mRootWindowContainer.forAllTasks((task) -> {
+ if (task.getWindowingMode() == windowingMode) {
+ task.updateTaskOrganizerState(true /* forceUpdate */);
+ }
+ });
+ }
}
} finally {
Binder.restoreCallingIdentity(origId);
@@ -553,18 +570,28 @@
WindowContainerTransaction.Change c) {
int effects = sanitizeAndApplyChange(wc, c);
+ final Task tr = wc.asTask();
+
final SurfaceControl.Transaction t = c.getBoundsChangeTransaction();
if (t != null) {
- Task tr = (Task) wc;
tr.setMainWindowSizeChangeTransaction(t);
}
Rect enterPipBounds = c.getEnterPipBounds();
if (enterPipBounds != null) {
- Task tr = (Task) wc;
mService.mStackSupervisor.updatePictureInPictureMode(tr,
enterPipBounds, true);
}
+
+ final int windowingMode = c.getWindowingMode();
+ if (windowingMode > -1) {
+ tr.setWindowingMode(windowingMode);
+ }
+ final int childWindowingMode = c.getActivityWindowingMode();
+ if (childWindowingMode > -1) {
+ tr.setActivityWindowingMode(childWindowingMode);
+ }
+
return effects;
}
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 669eb78..57d0a33 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -41,6 +41,7 @@
import android.os.RemoteException;
import android.os.SystemClock;
import android.util.ArraySet;
+import android.util.MathUtils;
import android.util.Slog;
import android.view.DisplayInfo;
import android.view.SurfaceControl;
@@ -52,6 +53,7 @@
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.function.Consumer;
/**
* Controls wallpaper windows visibility, ordering, and so on.
@@ -75,8 +77,10 @@
private float mLastWallpaperY = -1;
private float mLastWallpaperXStep = -1;
private float mLastWallpaperYStep = -1;
+ private float mLastWallpaperZoomOut = 0;
private int mLastWallpaperDisplayOffsetX = Integer.MIN_VALUE;
private int mLastWallpaperDisplayOffsetY = Integer.MIN_VALUE;
+ private final float mMaxWallpaperScale;
// This is set when we are waiting for a wallpaper to tell us it is done
// changing its scroll position.
@@ -191,9 +195,21 @@
return false;
};
+ /**
+ * @see #computeLastWallpaperZoomOut()
+ */
+ private Consumer<WindowState> mComputeMaxZoomOutFunction = windowState -> {
+ if (!windowState.mIsWallpaper
+ && Float.compare(windowState.mWallpaperZoomOut, mLastWallpaperZoomOut) > 0) {
+ mLastWallpaperZoomOut = windowState.mWallpaperZoomOut;
+ }
+ };
+
WallpaperController(WindowManagerService service, DisplayContent displayContent) {
mService = service;
mDisplayContent = displayContent;
+ mMaxWallpaperScale = service.mContext.getResources()
+ .getFloat(com.android.internal.R.dimen.config_wallpaperMaxScale);
}
WindowState getWallpaperTarget() {
@@ -325,20 +341,30 @@
rawChanged = true;
}
- boolean changed = wallpaperWin.mWinAnimator.setWallpaperOffset(xOffset, yOffset);
+ if (Float.compare(wallpaperWin.mWallpaperZoomOut, mLastWallpaperZoomOut) != 0) {
+ wallpaperWin.mWallpaperZoomOut = mLastWallpaperZoomOut;
+ rawChanged = true;
+ }
+
+ boolean changed = wallpaperWin.mWinAnimator.setWallpaperOffset(xOffset, yOffset,
+ wallpaperWin.mShouldScaleWallpaper
+ ? zoomOutToScale(wallpaperWin.mWallpaperZoomOut) : 1);
if (rawChanged && (wallpaperWin.mAttrs.privateFlags &
WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS) != 0) {
try {
if (DEBUG_WALLPAPER) Slog.v(TAG, "Report new wp offset "
+ wallpaperWin + " x=" + wallpaperWin.mWallpaperX
- + " y=" + wallpaperWin.mWallpaperY);
+ + " y=" + wallpaperWin.mWallpaperY
+ + " zoom=" + wallpaperWin.mWallpaperZoomOut);
if (sync) {
mWaitingOnWallpaper = wallpaperWin;
}
wallpaperWin.mClient.dispatchWallpaperOffsets(
wallpaperWin.mWallpaperX, wallpaperWin.mWallpaperY,
- wallpaperWin.mWallpaperXStep, wallpaperWin.mWallpaperYStep, sync);
+ wallpaperWin.mWallpaperXStep, wallpaperWin.mWallpaperYStep,
+ wallpaperWin.mWallpaperZoomOut, sync);
+
if (sync) {
if (mWaitingOnWallpaper != null) {
long start = SystemClock.uptimeMillis();
@@ -378,6 +404,20 @@
}
}
+ void setWallpaperZoomOut(WindowState window, float zoom) {
+ if (Float.compare(window.mWallpaperZoomOut, zoom) != 0) {
+ window.mWallpaperZoomOut = zoom;
+ updateWallpaperOffsetLocked(window, false);
+ }
+ }
+
+ void setShouldZoomOutWallpaper(WindowState window, boolean shouldZoom) {
+ if (shouldZoom != window.mShouldScaleWallpaper) {
+ window.mShouldScaleWallpaper = shouldZoom;
+ updateWallpaperOffsetLocked(window, false);
+ }
+ }
+
void setWindowWallpaperDisplayOffset(WindowState window, int x, int y) {
if (window.mWallpaperDisplayOffsetX != x || window.mWallpaperDisplayOffsetY != y) {
window.mWallpaperDisplayOffsetX = x;
@@ -420,6 +460,7 @@
} else if (changingTarget.mWallpaperY >= 0) {
mLastWallpaperY = changingTarget.mWallpaperY;
}
+ computeLastWallpaperZoomOut();
if (target.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
mLastWallpaperDisplayOffsetX = target.mWallpaperDisplayOffsetX;
} else if (changingTarget.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
@@ -593,6 +634,9 @@
mLastWallpaperX = mWallpaperTarget.mWallpaperX;
mLastWallpaperXStep = mWallpaperTarget.mWallpaperXStep;
}
+ if (mWallpaperTarget.mWallpaperZoomOut >= 0) {
+ mLastWallpaperZoomOut = mWallpaperTarget.mWallpaperZoomOut;
+ }
if (mWallpaperTarget.mWallpaperY >= 0) {
mLastWallpaperY = mWallpaperTarget.mWallpaperY;
mLastWallpaperYStep = mWallpaperTarget.mWallpaperYStep;
@@ -762,6 +806,23 @@
return mTmpTopWallpaper;
}
+ /**
+ * Each window can request a zoom, example:
+ * - User is in overview, zoomed out.
+ * - User also pulls down the shade.
+ *
+ * This means that we always have to choose the largest zoom out that we have, otherwise
+ * we'll have conflicts and break the "depth system" mental model.
+ */
+ private void computeLastWallpaperZoomOut() {
+ mLastWallpaperZoomOut = 0;
+ mDisplayContent.forAllWindows(mComputeMaxZoomOutFunction, true);
+ }
+
+ private float zoomOutToScale(float zoom) {
+ return MathUtils.lerp(1, mMaxWallpaperScale, 1 - zoom);
+ }
+
void dump(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("displayId="); pw.println(mDisplayContent.getDisplayId());
pw.print(prefix); pw.print("mWallpaperTarget="); pw.println(mWallpaperTarget);
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index e8897e1..ec90097 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -275,7 +275,7 @@
RemoteToken mRemoteToken = null;
BLASTSyncEngine mBLASTSyncEngine = new BLASTSyncEngine();
- SurfaceControl.Transaction mBLASTSyncTransaction = new SurfaceControl.Transaction();
+ SurfaceControl.Transaction mBLASTSyncTransaction;
boolean mUsingBLASTSyncTransaction = false;
BLASTSyncEngine.TransactionReadyListener mWaitingListener;
int mWaitingSyncId;
@@ -283,6 +283,7 @@
WindowContainer(WindowManagerService wms) {
mWmService = wms;
mPendingTransaction = wms.mTransactionFactory.get();
+ mBLASTSyncTransaction = wms.mTransactionFactory.get();
mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished, wms);
mSurfaceFreezer = new SurfaceFreezer(this, wms);
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 42a66ad..ecbbb03 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2447,10 +2447,6 @@
// of a transaction to avoid artifacts.
win.mAnimatingExit = true;
} else {
- final DisplayContent displayContent = win.getDisplayContent();
- if (displayContent.mInputMethodWindow == win) {
- displayContent.setInputMethodWindowLocked(null);
- }
boolean stopped = win.mActivityRecord != null ? win.mActivityRecord.mAppStopped : true;
// We set mDestroying=true so ActivityRecord#notifyAppStopped in-to destroy surfaces
// will later actually destroy the surface if we do not do so here. Normally we leave
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 833bb83..32eb932 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -53,6 +53,7 @@
import android.content.res.Configuration;
import android.os.Build;
import android.os.Message;
+import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.util.ArraySet;
@@ -200,6 +201,9 @@
/** Whether our process is currently running a {@link IRemoteAnimationRunner} */
private boolean mRunningRemoteAnimation;
+ /** Whether this process is owned by the System UI package. */
+ final boolean mIsSysUiPackage;
+
public WindowProcessController(@NonNull ActivityTaskManagerService atm, ApplicationInfo info,
String name, int uid, int userId, Object owner, WindowProcessListener listener) {
mInfo = info;
@@ -210,6 +214,10 @@
mListener = listener;
mAtm = atm;
mDisplayId = INVALID_DISPLAY;
+
+ mIsSysUiPackage = info.packageName.equals(
+ mAtm.getSysUiServiceComponentLocked().getPackageName());
+
onConfigurationChanged(atm.getGlobalConfiguration());
}
@@ -1077,6 +1085,12 @@
* always track the configuration of the non-finishing activity last added to the process.
*/
private void updateActivityConfigurationListener() {
+ if (mIsSysUiPackage || mUid == Process.SYSTEM_UID) {
+ // This is a system owned process and should not use an activity config.
+ // TODO(b/151161907): Remove after support for display-independent (raw) SysUi configs.
+ return;
+ }
+
for (int i = mActivities.size() - 1; i >= 0; i--) {
final ActivityRecord activityRecord = mActivities.get(i);
if (!activityRecord.finishing && !activityRecord.containsListener(this)) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index fc28cd5..c44be4d 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -415,6 +415,7 @@
float mHScale=1, mVScale=1;
float mLastHScale=1, mLastVScale=1;
final Matrix mTmpMatrix = new Matrix();
+ final float[] mTmpMatrixArray = new float[9];
private final WindowFrames mWindowFrames = new WindowFrames();
@@ -446,6 +447,14 @@
float mWallpaperX = -1;
float mWallpaperY = -1;
+ // If a window showing a wallpaper: the requested zoom out for the
+ // wallpaper; if a wallpaper window: the currently applied zoom.
+ float mWallpaperZoomOut = -1;
+
+ // If a wallpaper window: whether the wallpaper should be scaled when zoomed, if set
+ // to false, mWallpaperZoom will be ignored here and just passed to the WallpaperService.
+ boolean mShouldScaleWallpaper;
+
// If a window showing a wallpaper: what fraction of the offset
// range corresponds to a full virtual screen.
float mWallpaperXStep = -1;
@@ -3923,6 +3932,9 @@
pw.println(prefix + "mWallpaperXStep=" + mWallpaperXStep
+ " mWallpaperYStep=" + mWallpaperYStep);
}
+ if (mWallpaperZoomOut != -1) {
+ pw.println(prefix + "mWallpaperZoomOut=" + mWallpaperZoomOut);
+ }
if (mWallpaperDisplayOffsetX != Integer.MIN_VALUE
|| mWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
pw.println(prefix + "mWallpaperDisplayOffsetX=" + mWallpaperDisplayOffsetX
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 79dc536..563710b 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -16,6 +16,12 @@
package com.android.server.wm;
+import static android.graphics.Matrix.MSCALE_X;
+import static android.graphics.Matrix.MSCALE_Y;
+import static android.graphics.Matrix.MSKEW_X;
+import static android.graphics.Matrix.MSKEW_Y;
+import static android.graphics.Matrix.MTRANS_X;
+import static android.graphics.Matrix.MTRANS_Y;
import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
import static android.view.WindowManager.LayoutParams.FLAG_SCALED;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY;
@@ -217,6 +223,10 @@
int mXOffset = 0;
int mYOffset = 0;
+ // A scale factor for the surface contents, that will be applied from the center of the visible
+ // region.
+ float mWallpaperScale = 1f;
+
/**
* A flag to determine if the WSA needs to offset its position to compensate for the stack's
* position update before the WSA surface has resized.
@@ -1034,7 +1044,12 @@
}
}
}
- mSurfaceController.setPositionInTransaction(xOffset, yOffset, recoveringMemory);
+ if (!mIsWallpaper) {
+ mSurfaceController.setPositionInTransaction(xOffset, yOffset, recoveringMemory);
+ } else {
+ setWallpaperPositionAndScale(
+ xOffset, yOffset, mWallpaperScale, recoveringMemory);
+ }
}
}
@@ -1051,11 +1066,15 @@
if (!w.mSeamlesslyRotated) {
- applyCrop(clipRect, recoveringMemory);
- mSurfaceController.setMatrixInTransaction(mDsDx * w.mHScale * mExtraHScale,
- mDtDx * w.mVScale * mExtraVScale,
- mDtDy * w.mHScale * mExtraHScale,
- mDsDy * w.mVScale * mExtraVScale, recoveringMemory);
+ if (!mIsWallpaper) {
+ applyCrop(clipRect, recoveringMemory);
+ mSurfaceController.setMatrixInTransaction(mDsDx * w.mHScale * mExtraHScale,
+ mDtDx * w.mVScale * mExtraVScale,
+ mDtDy * w.mHScale * mExtraHScale,
+ mDsDy * w.mVScale * mExtraVScale, recoveringMemory);
+ } else {
+ setWallpaperPositionAndScale(mXOffset, mYOffset, mWallpaperScale, recoveringMemory);
+ }
}
if (mSurfaceResized) {
@@ -1202,18 +1221,18 @@
mSurfaceController.setTransparentRegionHint(region);
}
- boolean setWallpaperOffset(int dx, int dy) {
- if (mXOffset == dx && mYOffset == dy) {
+ boolean setWallpaperOffset(int dx, int dy, float scale) {
+ if (mXOffset == dx && mYOffset == dy && Float.compare(mWallpaperScale, scale) == 0) {
return false;
}
mXOffset = dx;
mYOffset = dy;
+ mWallpaperScale = scale;
try {
if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setWallpaperOffset");
mService.openSurfaceTransaction();
- mSurfaceController.setPositionInTransaction(dx, dy, false);
- applyCrop(null, false);
+ setWallpaperPositionAndScale(dx, dy, scale, false);
} catch (RuntimeException e) {
Slog.w(TAG, "Error positioning surface of " + mWin
+ " pos=(" + dx + "," + dy + ")", e);
@@ -1225,6 +1244,27 @@
}
}
+ private void setWallpaperPositionAndScale(int dx, int dy, float scale,
+ boolean recoveringMemory) {
+ DisplayInfo displayInfo = mWin.getDisplayInfo();
+ Matrix matrix = mWin.mTmpMatrix;
+ matrix.setTranslate(dx, dy);
+ matrix.postScale(scale, scale, displayInfo.logicalWidth / 2f,
+ displayInfo.logicalHeight / 2f);
+ matrix.getValues(mWin.mTmpMatrixArray);
+ matrix.reset();
+
+ mSurfaceController.setPositionInTransaction(mWin.mTmpMatrixArray[MTRANS_X],
+ mWin.mTmpMatrixArray[MTRANS_Y], recoveringMemory);
+ mSurfaceController.setMatrixInTransaction(
+ mDsDx * mWin.mTmpMatrixArray[MSCALE_X] * mWin.mHScale * mExtraHScale,
+ mDtDx * mWin.mTmpMatrixArray[MSKEW_Y] * mWin.mVScale * mExtraVScale,
+ mDtDy * mWin.mTmpMatrixArray[MSKEW_X] * mWin.mHScale * mExtraHScale,
+ mDsDy * mWin.mTmpMatrixArray[MSCALE_Y] * mWin.mVScale * mExtraVScale,
+ recoveringMemory);
+ applyCrop(null, recoveringMemory);
+ }
+
/**
* Try to change the pixel format without recreating the surface. This
* will be common in the case of changing from PixelFormat.OPAQUE to
diff --git a/services/core/jni/com_android_server_tv_GamepadKeys.h b/services/core/jni/com_android_server_tv_GamepadKeys.h
new file mode 100644
index 0000000..11fc903
--- /dev/null
+++ b/services/core/jni/com_android_server_tv_GamepadKeys.h
@@ -0,0 +1,79 @@
+#ifndef ANDROIDTVREMOTE_SERVICE_JNI_GAMEPAD_KEYS_H_
+#define ANDROIDTVREMOTE_SERVICE_JNI_GAMEPAD_KEYS_H_
+
+#include <linux/input.h>
+
+namespace android {
+
+// Follows the W3 spec for gamepad buttons and their corresponding mapping into
+// Linux keycodes. Note that gamepads are generally not very well standardized
+// and various controllers will result in different buttons. This mapping tries
+// to be reasonable.
+//
+// W3 Button spec: https://www.w3.org/TR/gamepad/#remapping
+//
+// Standard gamepad keycodes are added plus 2 additional buttons (e.g. Stadia
+// has "Assistant" and "Share", PS4 has the touchpad button).
+//
+// To generate this list, PS4, XBox, Stadia and Nintendo Switch Pro were tested.
+static const int GAMEPAD_KEY_CODES[19] = {
+ // Right-side buttons. A/B/X/Y or circle/triangle/square/X or similar
+ BTN_A, // "South", A, GAMEPAD and SOUTH have the same constant
+ BTN_B, // "East", BTN_B, BTN_EAST have the same constant
+ BTN_X, // "West", Note that this maps to X and NORTH in constants
+ BTN_Y, // "North", Note that this maps to Y and WEST in constants
+
+ BTN_TL, // "Left Bumper" / "L1" - Nintendo sends BTN_WEST instead
+ BTN_TR, // "Right Bumper" / "R1" - Nintendo sends BTN_Z instead
+
+ // For triggers, gamepads vary:
+ // - Stadia sends analog values over ABS_GAS/ABS_BRAKE and sends
+ // TriggerHappy3/4 as digital presses
+ // - PS4 and Xbox send analog values as ABS_Z/ABS_RZ
+ // - Nintendo Pro sends BTN_TL/BTN_TR (since bumpers behave differently)
+ // As placeholders we chose the stadia trigger-happy values since TL/TR are
+ // sent for bumper button presses
+ BTN_TRIGGER_HAPPY4, // "Left Trigger" / "L2"
+ BTN_TRIGGER_HAPPY3, // "Right Trigger" / "R2"
+
+ BTN_SELECT, // "Select/Back". Often "options" or similar
+ BTN_START, // "Start/forward". Often "hamburger" icon
+
+ BTN_THUMBL, // "Left Joystick Pressed"
+ BTN_THUMBR, // "Right Joystick Pressed"
+
+ // For DPads, gamepads generally only send axis changes
+ // on ABS_HAT0X and ABS_HAT0Y.
+ KEY_UP, // "Digital Pad up"
+ KEY_DOWN, // "Digital Pad down"
+ KEY_LEFT, // "Digital Pad left"
+ KEY_RIGHT, // "Digital Pad right"
+
+ BTN_MODE, // "Main button" (Stadia/PS/XBOX/Home)
+
+ BTN_TRIGGER_HAPPY1, // Extra button: "Assistant" for Stadia
+ BTN_TRIGGER_HAPPY2, // Extra button: "Share" for Stadia
+};
+
+// Defines information for an axis.
+struct Axis {
+ int number;
+ int rangeMin;
+ int rangeMax;
+};
+
+// List of all axes supported by a gamepad
+static const Axis GAMEPAD_AXES[] = {
+ {ABS_X, 0, 254}, // Left joystick X
+ {ABS_Y, 0, 254}, // Left joystick Y
+ {ABS_RX, 0, 254}, // Right joystick X
+ {ABS_RY, 0, 254}, // Right joystick Y
+ {ABS_Z, 0, 254}, // Left trigger
+ {ABS_RZ, 0, 254}, // Right trigger
+ {ABS_HAT0X, -1, 1}, // DPad X
+ {ABS_HAT0Y, -1, 1}, // DPad Y
+};
+
+} // namespace android
+
+#endif // ANDROIDTVREMOTE_SERVICE_JNI_GAMEPAD_KEYS_H_
diff --git a/services/core/jni/com_android_server_tv_TvKeys.h b/services/core/jni/com_android_server_tv_TvKeys.h
index 4895f34..7eacdf6 100644
--- a/services/core/jni/com_android_server_tv_TvKeys.h
+++ b/services/core/jni/com_android_server_tv_TvKeys.h
@@ -110,4 +110,4 @@
} // namespace android
-#endif // SERVICE_JNI_KEYS_H_
+#endif // ANDROIDTVREMOTE_SERVICE_JNI_KEYS_H_
diff --git a/services/core/jni/com_android_server_tv_TvUinputBridge.cpp b/services/core/jni/com_android_server_tv_TvUinputBridge.cpp
index c832c18..0e96bd7 100644
--- a/services/core/jni/com_android_server_tv_TvUinputBridge.cpp
+++ b/services/core/jni/com_android_server_tv_TvUinputBridge.cpp
@@ -16,6 +16,7 @@
#define LOG_TAG "TvRemote-native-uiBridge"
+#include "com_android_server_tv_GamepadKeys.h"
#include "com_android_server_tv_TvKeys.h"
#include "jni.h"
@@ -92,27 +93,156 @@
}
}
+static const int kInvalidFileDescriptor = -1;
+
+// Convenience class to manage an opened /dev/uinput device
+class UInputDescriptor {
+public:
+ UInputDescriptor() : mFd(kInvalidFileDescriptor) {
+ memset(&mUinputDescriptor, 0, sizeof(mUinputDescriptor));
+ }
+
+ // Auto-closes any open /dev/uinput descriptor unless detached.
+ ~UInputDescriptor();
+
+ // Open /dev/uinput and prepare to register
+ // the device with the given name and unique Id
+ bool Open(const char* name, const char* uniqueId);
+
+ // Checks if the current file descriptor is valid
+ bool IsValid() const { return mFd != kInvalidFileDescriptor; }
+
+ void EnableKey(int keyCode);
+
+ void EnableAxesEvents();
+ void EnableAxis(int axis, int rangeMin, int rangeMax);
+
+ bool Create();
+
+ // Detaches from the current file descriptor
+ // Returns the file descriptor for /dev/uniput
+ int Detach();
+
+private:
+ int mFd;
+ struct uinput_user_dev mUinputDescriptor;
+};
+
+UInputDescriptor::~UInputDescriptor() {
+ if (mFd != kInvalidFileDescriptor) {
+ close(mFd);
+ mFd = kInvalidFileDescriptor;
+ }
+}
+
+int UInputDescriptor::Detach() {
+ int fd = mFd;
+ mFd = kInvalidFileDescriptor;
+ return fd;
+}
+
+bool UInputDescriptor::Open(const char* name, const char* uniqueId) {
+ if (IsValid()) {
+ ALOGE("UInput device already open");
+ return false;
+ }
+
+ mFd = ::open("/dev/uinput", O_WRONLY | O_NDELAY);
+ if (mFd < 0) {
+ ALOGE("Cannot open /dev/uinput: %s.", strerror(errno));
+ mFd = kInvalidFileDescriptor;
+ return false;
+ }
+
+ // write device unique id to the phys property
+ ioctl(mFd, UI_SET_PHYS, uniqueId);
+
+ memset(&mUinputDescriptor, 0, sizeof(mUinputDescriptor));
+ strlcpy(mUinputDescriptor.name, name, UINPUT_MAX_NAME_SIZE);
+ mUinputDescriptor.id.version = 1;
+ mUinputDescriptor.id.bustype = BUS_VIRTUAL;
+
+ // All UInput devices we use process keys
+ ioctl(mFd, UI_SET_EVBIT, EV_KEY);
+
+ return true;
+}
+
+void UInputDescriptor::EnableKey(int keyCode) {
+ ioctl(mFd, UI_SET_KEYBIT, keyCode);
+}
+
+void UInputDescriptor::EnableAxesEvents() {
+ ioctl(mFd, UI_SET_EVBIT, EV_ABS);
+}
+
+void UInputDescriptor::EnableAxis(int axis, int rangeMin, int rangeMax) {
+ if ((axis < 0) || (axis >= NELEM(mUinputDescriptor.absmin))) {
+ ALOGE("Invalid axis number: %d", axis);
+ return;
+ }
+
+ if (ioctl(mFd, UI_SET_ABSBIT, axis) != 0) {
+ ALOGE("Failed to set absbit for %d", axis);
+ }
+
+ mUinputDescriptor.absmin[axis] = rangeMin;
+ mUinputDescriptor.absmax[axis] = rangeMax;
+ mUinputDescriptor.absfuzz[axis] = 0;
+ mUinputDescriptor.absflat[axis] = 0;
+}
+
+bool UInputDescriptor::Create() {
+ // register the input device
+ if (write(mFd, &mUinputDescriptor, sizeof(mUinputDescriptor)) != sizeof(mUinputDescriptor)) {
+ ALOGE("Cannot write uinput_user_dev to fd %d: %s.", mFd, strerror(errno));
+ return false;
+ }
+
+ if (ioctl(mFd, UI_DEV_CREATE) != 0) {
+ ALOGE("Unable to create uinput device: %s.", strerror(errno));
+ return false;
+ }
+
+ ALOGV("Created uinput device, fd=%d.", mFd);
+
+ return true;
+}
+
class NativeConnection {
public:
+ enum class ConnectionType {
+ kRemoteDevice,
+ kGamepadDevice,
+ };
+
~NativeConnection();
static NativeConnection* open(const char* name, const char* uniqueId,
int32_t width, int32_t height, int32_t maxPointerId);
+ static NativeConnection* openGamepad(const char* name, const char* uniqueId);
+
void sendEvent(int32_t type, int32_t code, int32_t value);
int32_t getMaxPointers() const { return mMaxPointers; }
+ ConnectionType getType() const { return mType; }
+
+ bool IsGamepad() const { return getType() == ConnectionType::kGamepadDevice; }
+
+ bool IsRemote() const { return getType() == ConnectionType::kRemoteDevice; }
+
private:
- NativeConnection(int fd, int32_t maxPointers);
+ NativeConnection(int fd, int32_t maxPointers, ConnectionType type);
const int mFd;
const int32_t mMaxPointers;
+ const ConnectionType mType;
};
-NativeConnection::NativeConnection(int fd, int32_t maxPointers) :
- mFd(fd), mMaxPointers(maxPointers) {
-}
+NativeConnection::NativeConnection(int fd, int32_t maxPointers, ConnectionType type)
+ : mFd(fd), mMaxPointers(maxPointers), mType(type) {}
NativeConnection::~NativeConnection() {
ALOGI("Un-Registering uinput device %d.", mFd);
@@ -125,44 +255,50 @@
ALOGI("Registering uinput device %s: touch pad size %dx%d, "
"max pointers %d.", name, width, height, maxPointers);
- int fd = ::open("/dev/uinput", O_WRONLY | O_NDELAY);
- if (fd < 0) {
- ALOGE("Cannot open /dev/uinput: %s.", strerror(errno));
- return nullptr;
- }
-
- struct uinput_user_dev uinp;
- memset(&uinp, 0, sizeof(struct uinput_user_dev));
- strlcpy(uinp.name, name, UINPUT_MAX_NAME_SIZE);
- uinp.id.version = 1;
- uinp.id.bustype = BUS_VIRTUAL;
-
- // initialize keymap
initKeysMap();
- // write device unique id to the phys property
- ioctl(fd, UI_SET_PHYS, uniqueId);
-
- // set the keys mapped
- ioctl(fd, UI_SET_EVBIT, EV_KEY);
- for (size_t i = 0; i < NELEM(KEYS); i++) {
- ioctl(fd, UI_SET_KEYBIT, KEYS[i].linuxKeyCode);
- }
-
- // register the input device
- if (write(fd, &uinp, sizeof(uinp)) != sizeof(uinp)) {
- ALOGE("Cannot write uinput_user_dev to fd %d: %s.", fd, strerror(errno));
- close(fd);
- return NULL;
- }
- if (ioctl(fd, UI_DEV_CREATE) != 0) {
- ALOGE("Unable to create uinput device: %s.", strerror(errno));
- close(fd);
+ UInputDescriptor descriptor;
+ if (!descriptor.Open(name, uniqueId)) {
return nullptr;
}
- ALOGV("Created uinput device, fd=%d.", fd);
- return new NativeConnection(fd, maxPointers);
+ // set the keys mapped
+ for (size_t i = 0; i < NELEM(KEYS); i++) {
+ descriptor.EnableKey(KEYS[i].linuxKeyCode);
+ }
+
+ if (!descriptor.Create()) {
+ return nullptr;
+ }
+
+ return new NativeConnection(descriptor.Detach(), maxPointers, ConnectionType::kRemoteDevice);
+}
+
+NativeConnection* NativeConnection::openGamepad(const char* name, const char* uniqueId) {
+ ALOGI("Registering uinput device %s: gamepad", name);
+
+ UInputDescriptor descriptor;
+ if (!descriptor.Open(name, uniqueId)) {
+ return nullptr;
+ }
+
+ // set the keys mapped for gamepads
+ for (size_t i = 0; i < NELEM(GAMEPAD_KEY_CODES); i++) {
+ descriptor.EnableKey(GAMEPAD_KEY_CODES[i]);
+ }
+
+ // define the axes that are required
+ descriptor.EnableAxesEvents();
+ for (size_t i = 0; i < NELEM(GAMEPAD_AXES); i++) {
+ const Axis& axis = GAMEPAD_AXES[i];
+ descriptor.EnableAxis(axis.number, axis.rangeMin, axis.rangeMax);
+ }
+
+ if (!descriptor.Create()) {
+ return nullptr;
+ }
+
+ return new NativeConnection(descriptor.Detach(), 0, ConnectionType::kGamepadDevice);
}
void NativeConnection::sendEvent(int32_t type, int32_t code, int32_t value) {
@@ -174,7 +310,6 @@
write(mFd, &iev, sizeof(iev));
}
-
static jlong nativeOpen(JNIEnv* env, jclass clazz,
jstring nameStr, jstring uniqueIdStr,
jint width, jint height, jint maxPointers) {
@@ -186,6 +321,14 @@
return reinterpret_cast<jlong>(connection);
}
+static jlong nativeGamepadOpen(JNIEnv* env, jclass clazz, jstring nameStr, jstring uniqueIdStr) {
+ ScopedUtfChars name(env, nameStr);
+ ScopedUtfChars uniqueId(env, uniqueIdStr);
+
+ NativeConnection* connection = NativeConnection::openGamepad(name.c_str(), uniqueId.c_str());
+ return reinterpret_cast<jlong>(connection);
+}
+
static void nativeClose(JNIEnv* env, jclass clazz, jlong ptr) {
NativeConnection* connection = reinterpret_cast<NativeConnection*>(ptr);
delete connection;
@@ -194,6 +337,12 @@
static void nativeSendKey(JNIEnv* env, jclass clazz, jlong ptr, jint keyCode, jboolean down) {
int32_t code = getLinuxKeyCode(keyCode);
NativeConnection* connection = reinterpret_cast<NativeConnection*>(ptr);
+
+ if (connection->IsGamepad()) {
+ ALOGE("Invalid key even for a gamepad - need to send gamepad events");
+ return;
+ }
+
if (code != KEY_UNKNOWN) {
connection->sendEvent(EV_KEY, code, down ? 1 : 0);
} else {
@@ -201,10 +350,44 @@
}
}
+static void nativeSendGamepadKey(JNIEnv* env, jclass clazz, jlong ptr, jint keyIndex,
+ jboolean down) {
+ NativeConnection* connection = reinterpret_cast<NativeConnection*>(ptr);
+
+ if (!connection->IsGamepad()) {
+ ALOGE("Invalid gamepad key for non-gamepad device");
+ return;
+ }
+
+ if ((keyIndex < 0) || (keyIndex >= NELEM(GAMEPAD_KEY_CODES))) {
+ ALOGE("Invalid gamepad key index: %d", keyIndex);
+ return;
+ }
+
+ connection->sendEvent(EV_KEY, GAMEPAD_KEY_CODES[keyIndex], down ? 1 : 0);
+}
+
+static void nativeSendGamepadAxisValue(JNIEnv* env, jclass clazz, jlong ptr, jint axis,
+ jint value) {
+ NativeConnection* connection = reinterpret_cast<NativeConnection*>(ptr);
+
+ if (!connection->IsGamepad()) {
+ ALOGE("Invalid axis send for non-gamepad device");
+ return;
+ }
+
+ connection->sendEvent(EV_ABS, axis, value);
+}
+
static void nativeSendPointerDown(JNIEnv* env, jclass clazz, jlong ptr,
jint pointerId, jint x, jint y) {
NativeConnection* connection = reinterpret_cast<NativeConnection*>(ptr);
+ if (connection->IsGamepad()) {
+ ALOGE("Invalid pointer down event for a gamepad.");
+ return;
+ }
+
int32_t slot = findSlot(pointerId);
if (slot == SLOT_UNKNOWN) {
slot = assignSlot(pointerId);
@@ -221,6 +404,11 @@
jint pointerId) {
NativeConnection* connection = reinterpret_cast<NativeConnection*>(ptr);
+ if (connection->IsGamepad()) {
+ ALOGE("Invalid pointer up event for a gamepad.");
+ return;
+ }
+
int32_t slot = findSlot(pointerId);
if (slot != SLOT_UNKNOWN) {
connection->sendEvent(EV_ABS, ABS_MT_SLOT, slot);
@@ -238,17 +426,34 @@
NativeConnection* connection = reinterpret_cast<NativeConnection*>(ptr);
// Clear keys.
- for (size_t i = 0; i < NELEM(KEYS); i++) {
- connection->sendEvent(EV_KEY, KEYS[i].linuxKeyCode, 0);
- }
+ if (connection->IsRemote()) {
+ for (size_t i = 0; i < NELEM(KEYS); i++) {
+ connection->sendEvent(EV_KEY, KEYS[i].linuxKeyCode, 0);
+ }
- // Clear pointers.
- int32_t slot = SLOT_UNKNOWN;
- for (int32_t i = 0; i < connection->getMaxPointers(); i++) {
- slot = findSlot(i);
- if (slot != SLOT_UNKNOWN) {
- connection->sendEvent(EV_ABS, ABS_MT_SLOT, slot);
- connection->sendEvent(EV_ABS, ABS_MT_TRACKING_ID, -1);
+ // Clear pointers.
+ int32_t slot = SLOT_UNKNOWN;
+ for (int32_t i = 0; i < connection->getMaxPointers(); i++) {
+ slot = findSlot(i);
+ if (slot != SLOT_UNKNOWN) {
+ connection->sendEvent(EV_ABS, ABS_MT_SLOT, slot);
+ connection->sendEvent(EV_ABS, ABS_MT_TRACKING_ID, -1);
+ }
+ }
+ } else {
+ for (size_t i = 0; i < NELEM(GAMEPAD_KEY_CODES); i++) {
+ connection->sendEvent(EV_KEY, GAMEPAD_KEY_CODES[i], 0);
+ }
+
+ for (size_t i = 0; i < NELEM(GAMEPAD_AXES); i++) {
+ const Axis& axis = GAMEPAD_AXES[i];
+ if ((axis.number == ABS_Z) || (axis.number == ABS_RZ)) {
+ // Mark triggers unpressed
+ connection->sendEvent(EV_ABS, axis.number, 0);
+ } else {
+ // Joysticks and dpad rests on center
+ connection->sendEvent(EV_ABS, axis.number, (axis.rangeMin + axis.rangeMax) / 2);
+ }
}
}
@@ -261,20 +466,16 @@
*/
static JNINativeMethod gUinputBridgeMethods[] = {
- { "nativeOpen", "(Ljava/lang/String;Ljava/lang/String;III)J",
- (void*)nativeOpen },
- { "nativeClose", "(J)V",
- (void*)nativeClose },
- { "nativeSendKey", "(JIZ)V",
- (void*)nativeSendKey },
- { "nativeSendPointerDown", "(JIII)V",
- (void*)nativeSendPointerDown },
- { "nativeSendPointerUp", "(JI)V",
- (void*)nativeSendPointerUp },
- { "nativeClear", "(J)V",
- (void*)nativeClear },
- { "nativeSendPointerSync", "(J)V",
- (void*)nativeSendPointerSync },
+ {"nativeOpen", "(Ljava/lang/String;Ljava/lang/String;III)J", (void*)nativeOpen},
+ {"nativeGamepadOpen", "(Ljava/lang/String;Ljava/lang/String;)J", (void*)nativeGamepadOpen},
+ {"nativeClose", "(J)V", (void*)nativeClose},
+ {"nativeSendKey", "(JIZ)V", (void*)nativeSendKey},
+ {"nativeSendPointerDown", "(JIII)V", (void*)nativeSendPointerDown},
+ {"nativeSendPointerUp", "(JI)V", (void*)nativeSendPointerUp},
+ {"nativeClear", "(J)V", (void*)nativeClear},
+ {"nativeSendPointerSync", "(J)V", (void*)nativeSendPointerSync},
+ {"nativeSendGamepadKey", "(JIZ)V", (void*)nativeSendGamepadKey},
+ {"nativeSendGamepadAxisValue", "(JII)V", (void*)nativeSendGamepadAxisValue},
};
int register_android_server_tv_TvUinputBridge(JNIEnv* env) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 312d2d2..6f41631 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -86,6 +86,7 @@
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
+import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
import static android.provider.Settings.Global.PRIVATE_DNS_MODE;
import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER;
import static android.provider.Telephony.Carriers.DPC_URI;
@@ -1198,7 +1199,7 @@
// Whether the admin explicitly requires personal apps to be suspended
boolean mSuspendPersonalApps = false;
// Maximum time the profile owned by this admin can be off.
- long mProfileMaximumTimeOff = 0;
+ long mProfileMaximumTimeOffMillis = 0;
// Time by which the profile should be turned on according to System.currentTimeMillis().
long mProfileOffDeadline = 0;
@@ -1439,10 +1440,11 @@
if (mSuspendPersonalApps) {
writeAttributeValueToXml(out, TAG_SUSPEND_PERSONAL_APPS, mSuspendPersonalApps);
}
- if (mProfileMaximumTimeOff != 0) {
- writeAttributeValueToXml(out, TAG_PROFILE_MAXIMUM_TIME_OFF, mProfileMaximumTimeOff);
+ if (mProfileMaximumTimeOffMillis != 0) {
+ writeAttributeValueToXml(out, TAG_PROFILE_MAXIMUM_TIME_OFF,
+ mProfileMaximumTimeOffMillis);
}
- if (mProfileMaximumTimeOff != 0) {
+ if (mProfileMaximumTimeOffMillis != 0) {
writeAttributeValueToXml(out, TAG_PROFILE_OFF_DEADLINE, mProfileOffDeadline);
}
if (!TextUtils.isEmpty(mAlwaysOnVpnPackage)) {
@@ -1691,7 +1693,7 @@
mSuspendPersonalApps = Boolean.parseBoolean(
parser.getAttributeValue(null, ATTR_VALUE));
} else if (TAG_PROFILE_MAXIMUM_TIME_OFF.equals(tag)) {
- mProfileMaximumTimeOff =
+ mProfileMaximumTimeOffMillis =
Long.parseLong(parser.getAttributeValue(null, ATTR_VALUE));
} else if (TAG_PROFILE_OFF_DEADLINE.equals(tag)) {
mProfileOffDeadline =
@@ -1929,8 +1931,8 @@
pw.println(mCrossProfilePackages);
pw.print("mSuspendPersonalApps=");
pw.println(mSuspendPersonalApps);
- pw.print("mProfileMaximumTimeOff=");
- pw.println(mProfileMaximumTimeOff);
+ pw.print("mProfileMaximumTimeOffMillis=");
+ pw.println(mProfileMaximumTimeOffMillis);
pw.print("mProfileOffDeadline=");
pw.println(mProfileOffDeadline);
pw.print("mAlwaysOnVpnPackage=");
@@ -5874,6 +5876,14 @@
}
}
+ private void enforceNetworkStackOrProfileOrDeviceOwner(ComponentName who) {
+ if (mContext.checkCallingPermission(PERMISSION_MAINLINE_NETWORK_STACK)
+ == PackageManager.PERMISSION_GRANTED) {
+ return;
+ }
+ enforceProfileOrDeviceOwner(who);
+ }
+
private void enforceDeviceOwnerOrProfileOwnerOnOrganizationOwnedDevice(ComponentName who) {
synchronized (getLockObject()) {
getActiveAdminForCallerLocked(
@@ -6870,7 +6880,7 @@
@Override
public boolean isAlwaysOnVpnLockdownEnabled(ComponentName admin) throws SecurityException {
- enforceProfileOrDeviceOwner(admin);
+ enforceNetworkStackOrProfileOrDeviceOwner(admin);
final int userId = mInjector.userHandleGetCallingUserId();
return mInjector.binderWithCleanCallingIdentity(
@@ -7786,7 +7796,7 @@
* Set whether auto time is enabled on the device.
*/
@Override
- public void setAutoTime(ComponentName who, boolean enabled) {
+ public void setAutoTimeEnabled(ComponentName who, boolean enabled) {
if (!mHasFeature) {
return;
}
@@ -7807,7 +7817,7 @@
* Returns whether auto time is used on the device or not.
*/
@Override
- public boolean getAutoTime(ComponentName who) {
+ public boolean getAutoTimeEnabled(ComponentName who) {
if (!mHasFeature) {
return false;
}
@@ -7821,7 +7831,7 @@
* Set whether auto time zone is enabled on the device.
*/
@Override
- public void setAutoTimeZone(ComponentName who, boolean enabled) {
+ public void setAutoTimeZoneEnabled(ComponentName who, boolean enabled) {
if (!mHasFeature) {
return;
}
@@ -7842,7 +7852,7 @@
* Returns whether auto time zone is used on the device or not.
*/
@Override
- public boolean getAutoTimeZone(ComponentName who) {
+ public boolean getAutoTimeZoneEnabled(ComponentName who) {
if (!mHasFeature) {
return false;
}
@@ -15716,18 +15726,18 @@
}
boolean shouldSaveSettings = false;
if (profileOwner.mProfileOffDeadline != 0
- && (profileOwner.mProfileMaximumTimeOff == 0 || unlocked)) {
+ && (profileOwner.mProfileMaximumTimeOffMillis == 0 || unlocked)) {
// There is a deadline but either there is no policy or the profile is unlocked -> clear
// the deadline.
Slog.i(LOG_TAG, "Profile off deadline is reset to zero");
profileOwner.mProfileOffDeadline = 0;
shouldSaveSettings = true;
} else if (profileOwner.mProfileOffDeadline == 0
- && (profileOwner.mProfileMaximumTimeOff != 0 && !unlocked)) {
+ && (profileOwner.mProfileMaximumTimeOffMillis != 0 && !unlocked)) {
// There profile is locked and there is a policy, but the deadline is not set -> set the
// deadline.
Slog.i(LOG_TAG, "Profile off deadline is set.");
- profileOwner.mProfileOffDeadline = now + profileOwner.mProfileMaximumTimeOff;
+ profileOwner.mProfileOffDeadline = now + profileOwner.mProfileMaximumTimeOffMillis;
shouldSaveSettings = true;
}
@@ -15828,7 +15838,7 @@
}
@Override
- public void setManagedProfileMaximumTimeOff(ComponentName who, long timeoutMs) {
+ public void setManagedProfileMaximumTimeOff(ComponentName who, long timeoutMillis) {
final int userId = mInjector.userHandleGetCallingUserId();
synchronized (getLockObject()) {
final ActiveAdmin admin = getActiveAdminForCallerLocked(who,
@@ -15837,10 +15847,10 @@
// DO shouldn't be able to use this method.
enforceProfileOwnerOfOrganizationOwnedDevice(admin);
enforceHandlesCheckPolicyComplianceIntent(userId, admin.info.getPackageName());
- if (admin.mProfileMaximumTimeOff == timeoutMs) {
+ if (admin.mProfileMaximumTimeOffMillis == timeoutMillis) {
return;
}
- admin.mProfileMaximumTimeOff = timeoutMs;
+ admin.mProfileMaximumTimeOffMillis = timeoutMillis;
saveSettingsLocked(userId);
}
@@ -15850,7 +15860,7 @@
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.SET_MANAGED_PROFILE_MAXIMUM_TIME_OFF)
.setAdmin(who)
- .setTimePeriod(timeoutMs)
+ .setTimePeriod(timeoutMillis)
.write();
}
@@ -15874,7 +15884,7 @@
false /* parent */);
// DO shouldn't be able to use this method.
enforceProfileOwnerOfOrganizationOwnedDevice(admin);
- return admin.mProfileMaximumTimeOff;
+ return admin.mProfileMaximumTimeOffMillis;
}
}
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index 2426e8f..cccd0133 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -28,6 +28,7 @@
#include <androidfw/ZipFileRO.h>
#include <androidfw/ZipUtils.h>
#include <binder/BinderService.h>
+#include <binder/Nullable.h>
#include <binder/ParcelFileDescriptor.h>
#include <binder/Status.h>
#include <sys/stat.h>
@@ -917,19 +918,23 @@
}
bool IncrementalService::startLoading(StorageId storage) const {
- const auto ifs = getIfs(storage);
- if (!ifs) {
- return false;
- }
- std::unique_lock l(ifs->lock);
- if (ifs->dataLoaderStatus != IDataLoaderStatusListener::DATA_LOADER_CREATED) {
- if (ifs->dataLoaderReady.wait_for(l, Seconds(5)) == std::cv_status::timeout) {
- LOG(ERROR) << "Timeout waiting for data loader to be ready";
+ {
+ std::unique_lock l(mLock);
+ const auto& ifs = getIfsLocked(storage);
+ if (!ifs) {
return false;
}
+ if (ifs->dataLoaderStatus != IDataLoaderStatusListener::DATA_LOADER_CREATED) {
+ ifs->dataLoaderStartRequested = true;
+ return true;
+ }
}
+ return startDataLoader(storage);
+}
+
+bool IncrementalService::startDataLoader(MountId mountId) const {
sp<IDataLoader> dataloader;
- auto status = mDataLoaderManager->getDataLoader(ifs->mountId, &dataloader);
+ auto status = mDataLoaderManager->getDataLoader(mountId, &dataloader);
if (!status.isOk()) {
return false;
}
@@ -1065,15 +1070,9 @@
}
return true; // eventually...
}
- if (base::GetBoolProperty("incremental.skip_loader", false)) {
- LOG(INFO) << "Skipped data loader because of incremental.skip_loader property";
- std::unique_lock l(ifs.lock);
- ifs.savedDataLoaderParams.reset();
- return true;
- }
std::unique_lock l(ifs.lock);
- if (ifs.dataLoaderStatus == IDataLoaderStatusListener::DATA_LOADER_CREATED) {
+ if (ifs.dataLoaderStatus != -1) {
LOG(INFO) << "Skipped data loader preparation because it already exists";
return true;
}
@@ -1085,7 +1084,7 @@
return false;
}
FileSystemControlParcel fsControlParcel;
- fsControlParcel.incremental = std::make_unique<IncrementalFileSystemControlParcel>();
+ fsControlParcel.incremental = aidl::make_nullable<IncrementalFileSystemControlParcel>();
fsControlParcel.incremental->cmd.reset(base::unique_fd(::dup(ifs.control.cmd)));
fsControlParcel.incremental->pendingReads.reset(
base::unique_fd(::dup(ifs.control.pendingReads)));
@@ -1226,30 +1225,42 @@
externalListener->onStatusChanged(mountId, newStatus);
}
- std::unique_lock l(incrementalService.mLock);
- const auto& ifs = incrementalService.getIfsLocked(mountId);
- if (!ifs) {
- LOG(WARNING) << "Received data loader status " << int(newStatus) << " for unknown mount "
- << mountId;
- return binder::Status::ok();
+ bool startRequested = false;
+ {
+ std::unique_lock l(incrementalService.mLock);
+ const auto& ifs = incrementalService.getIfsLocked(mountId);
+ if (!ifs) {
+ LOG(WARNING) << "Received data loader status " << int(newStatus) << " for unknown mount "
+ << mountId;
+ return binder::Status::ok();
+ }
+ ifs->dataLoaderStatus = newStatus;
+
+ if (newStatus == IDataLoaderStatusListener::DATA_LOADER_DESTROYED) {
+ ifs->dataLoaderStatus = IDataLoaderStatusListener::DATA_LOADER_STOPPED;
+ incrementalService.deleteStorageLocked(*ifs, std::move(l));
+ return binder::Status::ok();
+ }
+
+ startRequested = ifs->dataLoaderStartRequested;
}
- ifs->dataLoaderStatus = newStatus;
+
switch (newStatus) {
case IDataLoaderStatusListener::DATA_LOADER_NO_CONNECTION: {
// TODO(b/150411019): handle data loader connection loss
break;
}
case IDataLoaderStatusListener::DATA_LOADER_CONNECTION_OK: {
- ifs->dataLoaderStatus = IDataLoaderStatusListener::DATA_LOADER_STARTED;
+ // TODO(b/150411019): handle data loader connection loss
break;
}
case IDataLoaderStatusListener::DATA_LOADER_CREATED: {
- ifs->dataLoaderReady.notify_one();
+ if (startRequested) {
+ incrementalService.startDataLoader(mountId);
+ }
break;
}
case IDataLoaderStatusListener::DATA_LOADER_DESTROYED: {
- ifs->dataLoaderStatus = IDataLoaderStatusListener::DATA_LOADER_STOPPED;
- incrementalService.deleteStorageLocked(*ifs, std::move(l));
break;
}
case IDataLoaderStatusListener::DATA_LOADER_STARTED: {
diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h
index 8ff441b..406b32e 100644
--- a/services/incremental/IncrementalService.h
+++ b/services/incremental/IncrementalService.h
@@ -170,7 +170,7 @@
std::optional<DataLoaderParamsParcel> savedDataLoaderParams;
std::atomic<int> nextStorageDirNo{0};
std::atomic<int> dataLoaderStatus = -1;
- std::condition_variable dataLoaderReady;
+ bool dataLoaderStartRequested = false;
TimePoint connectionLostTime = TimePoint();
const IncrementalService& incrementalService;
@@ -208,6 +208,8 @@
bool prepareDataLoader(IncFsMount& ifs, DataLoaderParamsParcel* params = nullptr,
const DataLoaderStatusListener* externalListener = nullptr);
+ bool startDataLoader(MountId mountId) const;
+
BindPathMap::const_iterator findStorageLocked(std::string_view path) const;
StorageId findStorageId(std::string_view path) const;
diff --git a/services/people/java/com/android/server/people/data/ConversationStore.java b/services/people/java/com/android/server/people/data/ConversationStore.java
index 8481e5b..28e3d4b 100644
--- a/services/people/java/com/android/server/people/data/ConversationStore.java
+++ b/services/people/java/com/android/server/people/data/ConversationStore.java
@@ -89,25 +89,21 @@
* Loads conversations from disk to memory in a background thread. This should be called
* after the device powers on and the user has been unlocked.
*/
- @MainThread
- void loadConversationsFromDisk() {
- mScheduledExecutorService.execute(() -> {
- synchronized (this) {
- ConversationInfosProtoDiskReadWriter conversationInfosProtoDiskReadWriter =
- getConversationInfosProtoDiskReadWriter();
- if (conversationInfosProtoDiskReadWriter == null) {
- return;
- }
- List<ConversationInfo> conversationsOnDisk =
- conversationInfosProtoDiskReadWriter.read(CONVERSATIONS_FILE_NAME);
- if (conversationsOnDisk == null) {
- return;
- }
- for (ConversationInfo conversationInfo : conversationsOnDisk) {
- updateConversationsInMemory(conversationInfo);
- }
- }
- });
+ @WorkerThread
+ synchronized void loadConversationsFromDisk() {
+ ConversationInfosProtoDiskReadWriter conversationInfosProtoDiskReadWriter =
+ getConversationInfosProtoDiskReadWriter();
+ if (conversationInfosProtoDiskReadWriter == null) {
+ return;
+ }
+ List<ConversationInfo> conversationsOnDisk =
+ conversationInfosProtoDiskReadWriter.read(CONVERSATIONS_FILE_NAME);
+ if (conversationsOnDisk == null) {
+ return;
+ }
+ for (ConversationInfo conversationInfo : conversationsOnDisk) {
+ updateConversationsInMemory(conversationInfo);
+ }
}
/**
diff --git a/services/people/java/com/android/server/people/data/DataManager.java b/services/people/java/com/android/server/people/data/DataManager.java
index 4e0afc5..7085f96 100644
--- a/services/people/java/com/android/server/people/data/DataManager.java
+++ b/services/people/java/com/android/server/people/data/DataManager.java
@@ -28,6 +28,7 @@
import android.app.prediction.AppTargetEvent;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -87,13 +88,13 @@
private static final String TAG = "DataManager";
- private static final long QUERY_EVENTS_MAX_AGE_MS = DateUtils.DAY_IN_MILLIS;
+ private static final long QUERY_EVENTS_MAX_AGE_MS = 5L * DateUtils.MINUTE_IN_MILLIS;
private static final long USAGE_STATS_QUERY_INTERVAL_SEC = 120L;
private final Context mContext;
private final Injector mInjector;
- private final ScheduledExecutorService mUsageStatsQueryExecutor;
- private final ScheduledExecutorService mDiskReadWriterExecutor;
+ private final ScheduledExecutorService mScheduledExecutor;
+ private final Object mLock = new Object();
private final SparseArray<UserData> mUserDataArray = new SparseArray<>();
private final SparseArray<BroadcastReceiver> mBroadcastReceivers = new SparseArray<>();
@@ -118,8 +119,7 @@
DataManager(Context context, Injector injector) {
mContext = context;
mInjector = injector;
- mUsageStatsQueryExecutor = mInjector.createScheduledExecutor();
- mDiskReadWriterExecutor = mInjector.createScheduledExecutor();
+ mScheduledExecutor = mInjector.createScheduledExecutor();
}
/** Initialization. Called when the system services are up running. */
@@ -138,103 +138,56 @@
/** This method is called when a user is unlocked. */
public void onUserUnlocked(int userId) {
- UserData userData = mUserDataArray.get(userId);
- if (userData == null) {
- userData = new UserData(userId, mDiskReadWriterExecutor);
- mUserDataArray.put(userId, userData);
+ synchronized (mLock) {
+ UserData userData = mUserDataArray.get(userId);
+ if (userData == null) {
+ userData = new UserData(userId, mScheduledExecutor);
+ mUserDataArray.put(userId, userData);
+ }
+ userData.setUserUnlocked();
}
- userData.setUserUnlocked();
- updateDefaultDialer(userData);
- updateDefaultSmsApp(userData);
-
- ScheduledFuture<?> scheduledFuture = mUsageStatsQueryExecutor.scheduleAtFixedRate(
- new UsageStatsQueryRunnable(userId), 1L, USAGE_STATS_QUERY_INTERVAL_SEC,
- TimeUnit.SECONDS);
- mUsageStatsQueryFutures.put(userId, scheduledFuture);
-
- IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(TelecomManager.ACTION_DEFAULT_DIALER_CHANGED);
- intentFilter.addAction(SmsApplication.ACTION_DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL);
- BroadcastReceiver broadcastReceiver = new PerUserBroadcastReceiver(userId);
- mBroadcastReceivers.put(userId, broadcastReceiver);
- mContext.registerReceiverAsUser(
- broadcastReceiver, UserHandle.of(userId), intentFilter, null, null);
-
- ContentObserver contactsContentObserver = new ContactsContentObserver(
- BackgroundThread.getHandler());
- mContactsContentObservers.put(userId, contactsContentObserver);
- mContext.getContentResolver().registerContentObserver(
- Contacts.CONTENT_URI, /* notifyForDescendants= */ true,
- contactsContentObserver, userId);
-
- NotificationListener notificationListener = new NotificationListener();
- mNotificationListeners.put(userId, notificationListener);
- try {
- notificationListener.registerAsSystemService(mContext,
- new ComponentName(mContext, getClass()), userId);
- } catch (RemoteException e) {
- // Should never occur for local calls.
- }
-
- PackageMonitor packageMonitor = new PerUserPackageMonitor();
- packageMonitor.register(mContext, null, UserHandle.of(userId), true);
- mPackageMonitors.put(userId, packageMonitor);
-
- if (userId == UserHandle.USER_SYSTEM) {
- // The call log and MMS/SMS messages are shared across user profiles. So only need to
- // register the content observers once for the primary user.
- // TODO: Register observers after the conversations and events being loaded from disk.
- mCallLogContentObserver = new CallLogContentObserver(BackgroundThread.getHandler());
- mContext.getContentResolver().registerContentObserver(
- CallLog.CONTENT_URI, /* notifyForDescendants= */ true,
- mCallLogContentObserver, UserHandle.USER_SYSTEM);
-
- mMmsSmsContentObserver = new MmsSmsContentObserver(BackgroundThread.getHandler());
- mContext.getContentResolver().registerContentObserver(
- MmsSms.CONTENT_URI, /* notifyForDescendants= */ false,
- mMmsSmsContentObserver, UserHandle.USER_SYSTEM);
- }
-
- DataMaintenanceService.scheduleJob(mContext, userId);
+ mScheduledExecutor.execute(() -> setupUser(userId));
}
/** This method is called when a user is stopping. */
public void onUserStopping(int userId) {
- if (mUserDataArray.indexOfKey(userId) >= 0) {
- mUserDataArray.get(userId).setUserStopped();
- }
- if (mUsageStatsQueryFutures.indexOfKey(userId) >= 0) {
- mUsageStatsQueryFutures.get(userId).cancel(true);
- }
- if (mBroadcastReceivers.indexOfKey(userId) >= 0) {
- mContext.unregisterReceiver(mBroadcastReceivers.get(userId));
- }
- if (mContactsContentObservers.indexOfKey(userId) >= 0) {
- mContext.getContentResolver().unregisterContentObserver(
- mContactsContentObservers.get(userId));
- }
- if (mNotificationListeners.indexOfKey(userId) >= 0) {
- try {
- mNotificationListeners.get(userId).unregisterAsSystemService();
- } catch (RemoteException e) {
- // Should never occur for local calls.
+ synchronized (mLock) {
+ ContentResolver contentResolver = mContext.getContentResolver();
+ if (mUserDataArray.indexOfKey(userId) >= 0) {
+ mUserDataArray.get(userId).setUserStopped();
}
- }
- if (mPackageMonitors.indexOfKey(userId) >= 0) {
- mPackageMonitors.get(userId).unregister();
- }
- if (userId == UserHandle.USER_SYSTEM) {
- if (mCallLogContentObserver != null) {
- mContext.getContentResolver().unregisterContentObserver(mCallLogContentObserver);
- mCallLogContentObserver = null;
+ if (mUsageStatsQueryFutures.indexOfKey(userId) >= 0) {
+ mUsageStatsQueryFutures.get(userId).cancel(true);
}
- if (mMmsSmsContentObserver != null) {
- mContext.getContentResolver().unregisterContentObserver(mMmsSmsContentObserver);
- mCallLogContentObserver = null;
+ if (mBroadcastReceivers.indexOfKey(userId) >= 0) {
+ mContext.unregisterReceiver(mBroadcastReceivers.get(userId));
}
- }
+ if (mContactsContentObservers.indexOfKey(userId) >= 0) {
+ contentResolver.unregisterContentObserver(mContactsContentObservers.get(userId));
+ }
+ if (mNotificationListeners.indexOfKey(userId) >= 0) {
+ try {
+ mNotificationListeners.get(userId).unregisterAsSystemService();
+ } catch (RemoteException e) {
+ // Should never occur for local calls.
+ }
+ }
+ if (mPackageMonitors.indexOfKey(userId) >= 0) {
+ mPackageMonitors.get(userId).unregister();
+ }
+ if (userId == UserHandle.USER_SYSTEM) {
+ if (mCallLogContentObserver != null) {
+ contentResolver.unregisterContentObserver(mCallLogContentObserver);
+ mCallLogContentObserver = null;
+ }
+ if (mMmsSmsContentObserver != null) {
+ contentResolver.unregisterContentObserver(mMmsSmsContentObserver);
+ mCallLogContentObserver = null;
+ }
+ }
- DataMaintenanceService.cancelJob(mContext, userId);
+ DataMaintenanceService.cancelJob(mContext, userId);
+ }
}
/**
@@ -288,6 +241,9 @@
return;
}
UserData userData = getUnlockedUserData(appTarget.getUser().getIdentifier());
+ if (userData == null) {
+ return;
+ }
PackageData packageData = userData.getOrCreatePackageData(appTarget.getPackageName());
String mimeType = intentFilter != null ? intentFilter.getDataType(0) : null;
@Event.EventType int eventType = mimeTypeToShareEventType(mimeType);
@@ -353,6 +309,68 @@
userData.restore(payload);
}
+ private void setupUser(@UserIdInt int userId) {
+ synchronized (mLock) {
+ UserData userData = getUnlockedUserData(userId);
+ if (userData == null) {
+ return;
+ }
+ userData.loadUserData();
+
+ updateDefaultDialer(userData);
+ updateDefaultSmsApp(userData);
+
+ ScheduledFuture<?> scheduledFuture = mScheduledExecutor.scheduleAtFixedRate(
+ new UsageStatsQueryRunnable(userId), 1L, USAGE_STATS_QUERY_INTERVAL_SEC,
+ TimeUnit.SECONDS);
+ mUsageStatsQueryFutures.put(userId, scheduledFuture);
+
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(TelecomManager.ACTION_DEFAULT_DIALER_CHANGED);
+ intentFilter.addAction(SmsApplication.ACTION_DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL);
+ BroadcastReceiver broadcastReceiver = new PerUserBroadcastReceiver(userId);
+ mBroadcastReceivers.put(userId, broadcastReceiver);
+ mContext.registerReceiverAsUser(
+ broadcastReceiver, UserHandle.of(userId), intentFilter, null, null);
+
+ ContentObserver contactsContentObserver = new ContactsContentObserver(
+ BackgroundThread.getHandler());
+ mContactsContentObservers.put(userId, contactsContentObserver);
+ mContext.getContentResolver().registerContentObserver(
+ Contacts.CONTENT_URI, /* notifyForDescendants= */ true,
+ contactsContentObserver, userId);
+
+ NotificationListener notificationListener = new NotificationListener();
+ mNotificationListeners.put(userId, notificationListener);
+ try {
+ notificationListener.registerAsSystemService(mContext,
+ new ComponentName(mContext, getClass()), userId);
+ } catch (RemoteException e) {
+ // Should never occur for local calls.
+ }
+
+ PackageMonitor packageMonitor = new PerUserPackageMonitor();
+ packageMonitor.register(mContext, null, UserHandle.of(userId), true);
+ mPackageMonitors.put(userId, packageMonitor);
+
+ if (userId == UserHandle.USER_SYSTEM) {
+ // The call log and MMS/SMS messages are shared across user profiles. So only need
+ // to register the content observers once for the primary user.
+ mCallLogContentObserver = new CallLogContentObserver(BackgroundThread.getHandler());
+ mContext.getContentResolver().registerContentObserver(
+ CallLog.CONTENT_URI, /* notifyForDescendants= */ true,
+ mCallLogContentObserver, UserHandle.USER_SYSTEM);
+
+ mMmsSmsContentObserver = new MmsSmsContentObserver(BackgroundThread.getHandler());
+ mContext.getContentResolver().registerContentObserver(
+ MmsSms.CONTENT_URI, /* notifyForDescendants= */ false,
+ mMmsSmsContentObserver, UserHandle.USER_SYSTEM);
+ }
+
+ DataMaintenanceService.scheduleJob(mContext, userId);
+ }
+ }
+
private int mimeTypeToShareEventType(String mimeType) {
if (mimeType.startsWith("text/")) {
return Event.TYPE_SHARE_TEXT;
diff --git a/services/people/java/com/android/server/people/data/EventStore.java b/services/people/java/com/android/server/people/data/EventStore.java
index 00d4241..9cf84c9 100644
--- a/services/people/java/com/android/server/people/data/EventStore.java
+++ b/services/people/java/com/android/server/people/data/EventStore.java
@@ -17,9 +17,9 @@
package com.android.server.people.data;
import android.annotation.IntDef;
-import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.WorkerThread;
import android.net.Uri;
import android.util.ArrayMap;
@@ -90,20 +90,16 @@
* Loads existing {@link EventHistoryImpl}s from disk. This should be called when device powers
* on and user is unlocked.
*/
- @MainThread
- void loadFromDisk() {
- mScheduledExecutorService.execute(() -> {
- synchronized (this) {
- for (@EventCategory int category = 0; category < mEventsCategoryDirs.size();
- category++) {
- File categoryDir = mEventsCategoryDirs.get(category);
- Map<String, EventHistoryImpl> existingEventHistoriesImpl =
- EventHistoryImpl.eventHistoriesImplFromDisk(categoryDir,
- mScheduledExecutorService);
- mEventHistoryMaps.get(category).putAll(existingEventHistoriesImpl);
- }
- }
- });
+ @WorkerThread
+ synchronized void loadFromDisk() {
+ for (@EventCategory int category = 0; category < mEventsCategoryDirs.size();
+ category++) {
+ File categoryDir = mEventsCategoryDirs.get(category);
+ Map<String, EventHistoryImpl> existingEventHistoriesImpl =
+ EventHistoryImpl.eventHistoriesImplFromDisk(categoryDir,
+ mScheduledExecutorService);
+ mEventHistoryMaps.get(category).putAll(existingEventHistoriesImpl);
+ }
}
/**
diff --git a/services/people/java/com/android/server/people/data/PackageData.java b/services/people/java/com/android/server/people/data/PackageData.java
index 3e4c992..28837d5 100644
--- a/services/people/java/com/android/server/people/data/PackageData.java
+++ b/services/people/java/com/android/server/people/data/PackageData.java
@@ -25,6 +25,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.annotation.WorkerThread;
import android.content.LocusId;
import android.os.FileUtils;
import android.text.TextUtils;
@@ -77,6 +78,7 @@
* Returns a map of package directory names as keys and their associated {@link PackageData}.
* This should be called when device is powered on and unlocked.
*/
+ @WorkerThread
@NonNull
static Map<String, PackageData> packagesDataFromDisk(@UserIdInt int userId,
@NonNull Predicate<String> isDefaultDialerPredicate,
diff --git a/services/people/java/com/android/server/people/data/UserData.java b/services/people/java/com/android/server/people/data/UserData.java
index ed8c595..429d5b7 100644
--- a/services/people/java/com/android/server/people/data/UserData.java
+++ b/services/people/java/com/android/server/people/data/UserData.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.annotation.WorkerThread;
import android.os.Environment;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -75,12 +76,6 @@
void setUserUnlocked() {
mIsUnlocked = true;
-
- // Ensures per user root directory for people data is present, and attempt to load
- // data from disk.
- mPerUserPeopleDataDir.mkdirs();
- mPackageDataMap.putAll(PackageData.packagesDataFromDisk(mUserId, this::isDefaultDialer,
- this::isDefaultSmsApp, mScheduledExecutorService, mPerUserPeopleDataDir));
}
void setUserStopped() {
@@ -91,6 +86,15 @@
return mIsUnlocked;
}
+ @WorkerThread
+ void loadUserData() {
+ mPerUserPeopleDataDir.mkdir();
+ Map<String, PackageData> packageDataMap = PackageData.packagesDataFromDisk(
+ mUserId, this::isDefaultDialer, this::isDefaultSmsApp, mScheduledExecutorService,
+ mPerUserPeopleDataDir);
+ mPackageDataMap.putAll(packageDataMap);
+ }
+
/**
* Gets the {@link PackageData} for the specified {@code packageName} if exists; otherwise
* creates a new instance and returns it.
diff --git a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
index c94bb87..5c82200 100644
--- a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
@@ -79,6 +79,7 @@
private static final String CALLING_PACKAGE2 = "com.package.name2";
private static final String NAMESPACE1 = "namespace1";
private static final String NAMESPACE2 = "namespace2";
+ private static final String DISABLE_RESCUE_PARTY_FLAG = "disable_rescue_party";
private MockitoSession mSession;
private HashMap<String, String> mSystemSettingsMap;
@@ -316,6 +317,13 @@
@Test
public void testExplicitlyEnablingAndDisablingRescue() {
+ // mock the DeviceConfig get call to avoid hitting
+ // android.permission.READ_DEVICE_CONFIG when calling real DeviceConfig.
+ doReturn(true)
+ .when(() -> DeviceConfig.getBoolean(
+ eq(DeviceConfig.NAMESPACE_CONFIGURATION),
+ eq(DISABLE_RESCUE_PARTY_FLAG),
+ eq(false)));
SystemProperties.set(RescueParty.PROP_ENABLE_RESCUE, Boolean.toString(false));
SystemProperties.set(PROP_DISABLE_RESCUE, Boolean.toString(true));
assertEquals(RescuePartyObserver.getInstance(mMockContext).execute(sFailingPackage,
@@ -327,6 +335,22 @@
}
@Test
+ public void testDisablingRescueByDeviceConfigFlag() {
+ doReturn(true)
+ .when(() -> DeviceConfig.getBoolean(
+ eq(DeviceConfig.NAMESPACE_CONFIGURATION),
+ eq(DISABLE_RESCUE_PARTY_FLAG),
+ eq(false)));
+ SystemProperties.set(RescueParty.PROP_ENABLE_RESCUE, Boolean.toString(false));
+
+ assertEquals(RescuePartyObserver.getInstance(mMockContext).execute(sFailingPackage,
+ PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING), false);
+
+ // Restore the property value initalized in SetUp()
+ SystemProperties.set(RescueParty.PROP_ENABLE_RESCUE, Boolean.toString(true));
+ }
+
+ @Test
public void testHealthCheckLevels() {
RescuePartyObserver observer = RescuePartyObserver.getInstance(mMockContext);
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
index 95f4e83..c45ee7b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ApplicationExitInfoTest.java
@@ -55,6 +55,7 @@
import android.text.TextUtils;
import android.util.Pair;
+import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.appop.AppOpsService;
import com.android.server.wm.ActivityTaskManagerService;
@@ -125,6 +126,8 @@
mAms.mActivityTaskManager.initialize(null, null, mContext.getMainLooper());
mAms.mAtmInternal = spy(mAms.mActivityTaskManager.getAtmInternal());
mAms.mPackageManagerInt = mPackageManagerInt;
+ doReturn(new ComponentName("", "")).when(mPackageManagerInt).getSystemUiServiceComponent();
+ LocalServices.addService(PackageManagerInternal.class, mPackageManagerInt);
}
@After
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index fc2ae40..053a798 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -75,8 +75,10 @@
import android.app.IApplicationThread;
import android.app.IServiceConnection;
+import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManagerInternal;
import android.content.pm.ServiceInfo;
import android.os.Build;
import android.os.IBinder;
@@ -87,6 +89,7 @@
import android.util.ArraySet;
import android.util.SparseArray;
+import com.android.server.LocalServices;
import com.android.server.wm.ActivityServiceConnectionsHolder;
import com.android.server.wm.ActivityTaskManagerService;
import com.android.server.wm.WindowProcessController;
@@ -127,6 +130,7 @@
private static final String MOCKAPP5_PROCESSNAME = "test #5";
private static final String MOCKAPP5_PACKAGENAME = "com.android.test.test5";
private static Context sContext;
+ private static PackageManagerInternal sPackageManagerInternal;
private static ActivityManagerService sService;
@BeforeClass
@@ -134,13 +138,21 @@
sContext = getInstrumentation().getTargetContext();
System.setProperty("dexmaker.share_classloader", "true");
+ sPackageManagerInternal = mock(PackageManagerInternal.class);
+ doReturn(new ComponentName("", "")).when(sPackageManagerInternal)
+ .getSystemUiServiceComponent();
+ LocalServices.addService(PackageManagerInternal.class, sPackageManagerInternal);
+
sService = mock(ActivityManagerService.class);
sService.mActivityTaskManager = new ActivityTaskManagerService(sContext);
sService.mActivityTaskManager.initialize(null, null, sContext.getMainLooper());
+ sService.mPackageManagerInt = sPackageManagerInternal;
sService.mAtmInternal = spy(sService.mActivityTaskManager.getAtmInternal());
sService.mConstants = new ActivityManagerConstants(sContext, sService,
sContext.getMainThreadHandler());
+ setFieldValue(ActivityManagerService.class, sService, "mContext",
+ sContext);
ProcessList pr = new ProcessList();
pr.init(sService, new ActiveUids(sService, false), null);
setFieldValue(ActivityManagerService.class, sService, "mProcessList",
@@ -972,7 +984,7 @@
sService.mOomAdjuster.updateOomAdjLocked(app, false, OomAdjuster.OOM_ADJ_REASON_NONE);
doReturn(null).when(sService).getTopAppLocked();
- assertProcStates(app, PROCESS_STATE_FOREGROUND_SERVICE, VISIBLE_APP_ADJ,
+ assertProcStates(app, PROCESS_STATE_BOUND_TOP, VISIBLE_APP_ADJ,
SCHED_GROUP_DEFAULT);
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
index 959dc05..de6f55b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
@@ -147,7 +147,7 @@
AndroidPackage mockMyPkg = mock(AndroidPackage.class);
when(mockMyPkg.isPrivileged()).thenReturn(false);
when(mockMyPkg.getUid()).thenReturn(mMyUid);
- when(mockMyPkg.getFeatures()).thenReturn(Collections.emptyList());
+ when(mockMyPkg.getAttributions()).thenReturn(Collections.emptyList());
when(mockPackageManagerInternal.getPackage(sMyPackageName)).thenReturn(mockMyPkg);
doReturn(mockPackageManagerInternal).when(
diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
index eb2dd64..8be9213 100644
--- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
@@ -251,6 +251,28 @@
}
@Test
+ public void testAllowRemoveOverrideNoOverride() throws Exception {
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addDisabledChangeWithId(1234L)
+ .addLoggingOnlyChangeWithId(2L)
+ .build();
+ ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
+ .withPackageName("com.some.package")
+ .build();
+ when(mPackageManager.getApplicationInfo(eq("com.some.package"), anyInt()))
+ .thenReturn(applicationInfo);
+
+ // Reject all override attempts.
+ // Force the validator to prevent overriding the change by using a user build.
+ when(mBuildClassifier.isDebuggableBuild()).thenReturn(false);
+ when(mBuildClassifier.isFinalBuild()).thenReturn(true);
+ // Try to remove a non existing override, and it doesn't fail.
+ assertThat(compatConfig.removeOverride(1234L, "com.some.package")).isFalse();
+ assertThat(compatConfig.removeOverride(2L, "com.some.package")).isFalse();
+ compatConfig.removePackageOverrides("com.some.package");
+ }
+
+ @Test
public void testRemovePackageOverride() throws Exception {
CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
.addEnabledChangeWithId(1234L)
@@ -267,6 +289,49 @@
}
@Test
+ public void testEnableTargetSdkChangesForPackage() throws Exception {
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addEnabledChangeWithId(1L)
+ .addDisabledChangeWithId(2L)
+ .addTargetSdkChangeWithId(3, 3L)
+ .addTargetSdkChangeWithId(4, 4L)
+ .build();
+ ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
+ .withPackageName("foo.bar")
+ .withTargetSdk(2)
+ .build();
+
+ assertThat(compatConfig.isChangeEnabled(3, applicationInfo)).isFalse();
+ assertThat(compatConfig.isChangeEnabled(4, applicationInfo)).isFalse();
+
+ assertThat(compatConfig.enableTargetSdkChangesForPackage("foo.bar", 3)).isEqualTo(1);
+ assertThat(compatConfig.isChangeEnabled(3, applicationInfo)).isTrue();
+ assertThat(compatConfig.isChangeEnabled(4, applicationInfo)).isFalse();
+ }
+
+ @Test
+ public void testDisableTargetSdkChangesForPackage() throws Exception {
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addEnabledChangeWithId(1L)
+ .addDisabledChangeWithId(2L)
+ .addTargetSdkChangeWithId(3, 3L)
+ .addTargetSdkChangeWithId(4, 4L)
+ .build();
+ ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
+ .withPackageName("foo.bar")
+ .withTargetSdk(2)
+ .build();
+
+ assertThat(compatConfig.enableTargetSdkChangesForPackage("foo.bar", 3)).isEqualTo(1);
+ assertThat(compatConfig.isChangeEnabled(3, applicationInfo)).isTrue();
+ assertThat(compatConfig.isChangeEnabled(4, applicationInfo)).isFalse();
+
+ assertThat(compatConfig.disableTargetSdkChangesForPackage("foo.bar", 3)).isEqualTo(1);
+ assertThat(compatConfig.isChangeEnabled(3, applicationInfo)).isFalse();
+ assertThat(compatConfig.isChangeEnabled(4, applicationInfo)).isFalse();
+ }
+
+ @Test
public void testLookupChangeId() throws Exception {
CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
.addEnabledChangeWithIdAndName(1234L, "MY_CHANGE")
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 2a6a24e..7571f09 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -3872,79 +3872,80 @@
Settings.System.SCREEN_BRIGHTNESS, "0", DpmMockContext.CALLER_USER_HANDLE);
}
- public void testSetAutoTimeModifiesSetting() throws Exception {
+ public void testSetAutoTimeEnabledModifiesSetting() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
- dpm.setAutoTime(admin1, true);
+ dpm.setAutoTimeEnabled(admin1, true);
verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME, 1);
- dpm.setAutoTime(admin1, false);
+ dpm.setAutoTimeEnabled(admin1, false);
verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME, 0);
}
- public void testSetAutoTimeWithPOOnUser0() throws Exception {
+ public void testSetAutoTimeEnabledWithPOOnUser0() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupProfileOwnerOnUser0();
- dpm.setAutoTime(admin1, true);
+ dpm.setAutoTimeEnabled(admin1, true);
verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME, 1);
- dpm.setAutoTime(admin1, false);
+ dpm.setAutoTimeEnabled(admin1, false);
verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME, 0);
}
- public void testSetAutoTimeFailWithPONotOnUser0() throws Exception {
+ public void testSetAutoTimeEnabledFailWithPONotOnUser0() throws Exception {
setupProfileOwner();
- assertExpectException(SecurityException.class, null, () -> dpm.setAutoTime(admin1, false));
+ assertExpectException(SecurityException.class, null,
+ () -> dpm.setAutoTimeEnabled(admin1, false));
verify(getServices().settings, never()).settingsGlobalPutInt(Settings.Global.AUTO_TIME, 0);
}
- public void testSetAutoTimeWithPOOfOrganizationOwnedDevice() throws Exception {
+ public void testSetAutoTimeEnabledWithPOOfOrganizationOwnedDevice() throws Exception {
setupProfileOwner();
configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE);
- dpm.setAutoTime(admin1, true);
+ dpm.setAutoTimeEnabled(admin1, true);
verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME, 1);
- dpm.setAutoTime(admin1, false);
+ dpm.setAutoTimeEnabled(admin1, false);
verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME, 0);
}
- public void testSetAutoTimeZoneModifiesSetting() throws Exception {
+ public void testSetAutoTimeZoneEnabledModifiesSetting() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
- dpm.setAutoTimeZone(admin1, true);
+ dpm.setAutoTimeZoneEnabled(admin1, true);
verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME_ZONE, 1);
- dpm.setAutoTimeZone(admin1, false);
+ dpm.setAutoTimeZoneEnabled(admin1, false);
verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME_ZONE, 0);
}
- public void testSetAutoTimeZoneWithPOOnUser0() throws Exception {
+ public void testSetAutoTimeZoneEnabledWithPOOnUser0() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupProfileOwnerOnUser0();
- dpm.setAutoTimeZone(admin1, true);
+ dpm.setAutoTimeZoneEnabled(admin1, true);
verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME_ZONE, 1);
- dpm.setAutoTimeZone(admin1, false);
+ dpm.setAutoTimeZoneEnabled(admin1, false);
verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME_ZONE, 0);
}
- public void testSetAutoTimeZoneFailWithPONotOnUser0() throws Exception {
+ public void testSetAutoTimeZoneEnabledFailWithPONotOnUser0() throws Exception {
setupProfileOwner();
assertExpectException(SecurityException.class, null,
- () -> dpm.setAutoTimeZone(admin1, false));
+ () -> dpm.setAutoTimeZoneEnabled(admin1, false));
verify(getServices().settings, never()).settingsGlobalPutInt(Settings.Global.AUTO_TIME_ZONE,
0);
}
- public void testSetAutoTimeZoneWithPOOfOrganizationOwnedDevice() throws Exception {
+ public void testSetAutoTimeZoneEnabledWithPOOfOrganizationOwnedDevice() throws Exception {
setupProfileOwner();
configureProfileOwnerOfOrgOwnedDevice(admin1, DpmMockContext.CALLER_USER_HANDLE);
- dpm.setAutoTimeZone(admin1, true);
+ dpm.setAutoTimeZoneEnabled(admin1, true);
verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME_ZONE, 1);
- dpm.setAutoTimeZone(admin1, false);
+ dpm.setAutoTimeZoneEnabled(admin1, false);
verify(getServices().settings).settingsGlobalPutInt(Settings.Global.AUTO_TIME_ZONE, 0);
}
diff --git a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
index 3dd1504..81545d4 100644
--- a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java
@@ -28,6 +28,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -321,6 +322,11 @@
// we cannot check installer cert because it seems to be device specific.
assertEquals(VERSION_CODE, appInstallMetadata.getVersionCode());
assertFalse(appInstallMetadata.isPreInstalled());
+ // Asserting source stamp not present.
+ assertFalse(appInstallMetadata.isStampPresent());
+ assertFalse(appInstallMetadata.isStampVerified());
+ assertFalse(appInstallMetadata.isStampTrusted());
+ assertNull(appInstallMetadata.getStampCertificateHash());
// These are hardcoded in the test apk android manifest
Map<String, String> allowedInstallers =
appInstallMetadata.getAllowedInstallersAndCertificates();
diff --git a/services/tests/servicestests/src/com/android/server/lights/LightsServiceTest.java b/services/tests/servicestests/src/com/android/server/lights/LightsServiceTest.java
index b0def60..ccbaee4 100644
--- a/services/tests/servicestests/src/com/android/server/lights/LightsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/lights/LightsServiceTest.java
@@ -18,6 +18,11 @@
import static android.hardware.lights.LightsRequest.Builder;
+import static android.graphics.Color.BLACK;
+import static android.graphics.Color.BLUE;
+import static android.graphics.Color.GREEN;
+import static android.graphics.Color.WHITE;
+
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
@@ -92,7 +97,7 @@
// When the session requests to turn 3/4 lights on:
LightsManager.LightsSession session = manager.openSession();
- session.setLights(new Builder()
+ session.requestLights(new Builder()
.setLight(manager.getLights().get(0), new LightState(0xf1))
.setLight(manager.getLights().get(1), new LightState(0xf2))
.setLight(manager.getLights().get(2), new LightState(0xf3))
@@ -114,18 +119,18 @@
Light micLight = manager.getLights().get(0);
// The light should begin by being off.
- assertThat(manager.getLightState(micLight).getColor()).isEqualTo(0x00000000);
+ assertThat(manager.getLightState(micLight).getColor()).isEqualTo(BLACK);
// When a session commits changes:
LightsManager.LightsSession session = manager.openSession();
- session.setLights(new Builder().setLight(micLight, new LightState(0xff00ff00)).build());
+ session.requestLights(new Builder().setLight(micLight, new LightState(GREEN)).build());
// Then the light should turn on.
- assertThat(manager.getLightState(micLight).getColor()).isEqualTo(0xff00ff00);
+ assertThat(manager.getLightState(micLight).getColor()).isEqualTo(GREEN);
// When the session goes away:
session.close();
// Then the light should turn off.
- assertThat(manager.getLightState(micLight).getColor()).isEqualTo(0x00000000);
+ assertThat(manager.getLightState(micLight).getColor()).isEqualTo(BLACK);
}
@Test
@@ -138,15 +143,15 @@
LightsManager.LightsSession session2 = manager.openSession();
// When session1 and session2 both request the same light:
- session1.setLights(new Builder().setLight(micLight, new LightState(0xff0000ff)).build());
- session2.setLights(new Builder().setLight(micLight, new LightState(0xffffffff)).build());
+ session1.requestLights(new Builder().setLight(micLight, new LightState(BLUE)).build());
+ session2.requestLights(new Builder().setLight(micLight, new LightState(WHITE)).build());
// Then session1 should win because it was created first.
- assertThat(manager.getLightState(micLight).getColor()).isEqualTo(0xff0000ff);
+ assertThat(manager.getLightState(micLight).getColor()).isEqualTo(BLUE);
// When session1 goes away:
session1.close();
// Then session2 should have its request go into effect.
- assertThat(manager.getLightState(micLight).getColor()).isEqualTo(0xffffffff);
+ assertThat(manager.getLightState(micLight).getColor()).isEqualTo(WHITE);
// When session2 goes away:
session2.close();
@@ -162,10 +167,10 @@
// When the session turns a light on:
LightsManager.LightsSession session = manager.openSession();
- session.setLights(new Builder().setLight(micLight, new LightState(0xffffffff)).build());
+ session.requestLights(new Builder().setLight(micLight, new LightState(WHITE)).build());
// And then the session clears it again:
- session.setLights(new Builder().clearLight(micLight).build());
+ session.requestLights(new Builder().clearLight(micLight).build());
// Then the light should turn back off.
assertThat(manager.getLightState(micLight).getColor()).isEqualTo(0);
diff --git a/services/tests/servicestests/src/com/android/server/people/data/ConversationStoreTest.java b/services/tests/servicestests/src/com/android/server/people/data/ConversationStoreTest.java
index 4e63237..e10cbbf 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/ConversationStoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/ConversationStoreTest.java
@@ -273,9 +273,8 @@
// Ensure that futures were cancelled and the immediate flush occurred.
assertEquals(0, mMockScheduledExecutorService.getFutures().size());
- // Expect to see 2 executes: loadConversationFromDisk and saveConversationsToDisk.
- // loadConversationFromDisk gets called each time we call #resetConversationStore().
- assertEquals(2, mMockScheduledExecutorService.getExecutes().size());
+ // Expect to see 1 execute: saveConversationsToDisk.
+ assertEquals(1, mMockScheduledExecutorService.getExecutes().size());
resetConversationStore();
ConversationInfo out1 = mConversationStore.getConversation(SHORTCUT_ID);
diff --git a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
index a4d63ac..5199604 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
@@ -183,6 +183,11 @@
when(mExecutorService.scheduleAtFixedRate(any(Runnable.class), anyLong(), anyLong(), any(
TimeUnit.class))).thenReturn(mScheduledFuture);
+ doAnswer(ans -> {
+ Runnable runnable = (Runnable) ans.getArguments()[0];
+ runnable.run();
+ return null;
+ }).when(mExecutorService).execute(any(Runnable.class));
when(mUserManager.getEnabledProfiles(USER_ID_PRIMARY))
.thenReturn(Arrays.asList(
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 9f3bf02..6eec649 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -18,6 +18,7 @@
import static android.app.ActivityManager.PROCESS_STATE_TOP;
import static android.app.ActivityManager.START_ABORTED;
+import static android.app.ActivityManager.START_CANCELED;
import static android.app.ActivityManager.START_CLASS_NOT_FOUND;
import static android.app.ActivityManager.START_DELIVERED_TO_TOP;
import static android.app.ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
@@ -202,10 +203,11 @@
final IApplicationThread caller = mock(IApplicationThread.class);
final WindowProcessListener listener = mock(WindowProcessListener.class);
+ final ApplicationInfo ai = new ApplicationInfo();
+ ai.packageName = "com.android.test.package";
final WindowProcessController wpc =
containsConditions(preconditions, PRECONDITION_NO_CALLER_APP)
- ? null : new WindowProcessController(
- service, mock(ApplicationInfo.class), null, 0, -1, null, listener);
+ ? null : new WindowProcessController(service, ai, null, 0, -1, null, listener);
doReturn(wpc).when(service).getProcessController(anyObject());
final Intent intent = new Intent();
@@ -344,6 +346,7 @@
doReturn(false).when(mMockPackageManager).isInstantAppInstallerComponent(any());
doReturn(null).when(mMockPackageManager).resolveIntent(any(), any(), anyInt(), anyInt(),
anyInt(), anyBoolean(), anyInt());
+ doReturn(new ComponentName("", "")).when(mMockPackageManager).getSystemUiServiceComponent();
// Never review permissions
doReturn(false).when(mMockPackageManager).isPermissionsReviewRequired(any(), anyInt());
@@ -655,6 +658,7 @@
final WindowProcessListener listener = mock(WindowProcessListener.class);
final ApplicationInfo ai = new ApplicationInfo();
ai.uid = callingUid;
+ ai.packageName = "com.android.test.package";
final WindowProcessController callerApp =
new WindowProcessController(mService, ai, null, callingUid, -1, null, listener);
callerApp.setHasForegroundActivities(hasForegroundActivities);
@@ -892,7 +896,7 @@
.execute();
// Simulate a failed start
- starter.postStartActivityProcessing(null, START_ABORTED, null);
+ starter.postStartActivityProcessing(null, START_CANCELED, null);
verify(recentTasks, times(1)).setFreezeTaskListReordering();
verify(recentTasks, times(1)).resetFreezeTaskListReorderingOnTimeout();
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 5cf1fbb..a380ece 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
@@ -16,6 +16,8 @@
package com.android.server.wm;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
@@ -69,7 +71,7 @@
final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null);
statusBar.setControllableInsetProvider(getController().getSourceProvider(ITYPE_STATUS_BAR));
- assertNotNull(getController().getInsetsForDispatch(app).getSource(ITYPE_STATUS_BAR));
+ assertNotNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_STATUS_BAR));
}
@Test
@@ -101,6 +103,34 @@
}
@Test
+ public void testStripForDispatch_pip() {
+ final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
+ final WindowState navBar = createWindow(null, TYPE_APPLICATION, "navBar");
+ final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
+
+ getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null);
+ getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindow(navBar, null, null);
+ app.setWindowingMode(WINDOWING_MODE_PINNED);
+
+ assertNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_STATUS_BAR));
+ assertNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_NAVIGATION_BAR));
+ }
+
+ @Test
+ public void testStripForDispatch_freeform() {
+ final WindowState statusBar = createWindow(null, TYPE_APPLICATION, "statusBar");
+ final WindowState navBar = createWindow(null, TYPE_APPLICATION, "navBar");
+ final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
+
+ getController().getSourceProvider(ITYPE_STATUS_BAR).setWindow(statusBar, null, null);
+ getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindow(navBar, null, null);
+ app.setWindowingMode(WINDOWING_MODE_FREEFORM);
+
+ assertNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_STATUS_BAR));
+ assertNull(getController().getInsetsForDispatch(app).peekSource(ITYPE_NAVIGATION_BAR));
+ }
+
+ @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/LaunchParamsPersisterTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
index ac4c228f..8f3ff52 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
@@ -37,8 +37,8 @@
import android.os.UserHandle;
import android.platform.test.annotations.Presubmit;
-import androidx.test.InstrumentationRegistry;
import androidx.test.filters.MediumTest;
+import androidx.test.platform.app.InstrumentationRegistry;
import com.android.server.LocalServices;
import com.android.server.pm.PackageList;
@@ -72,6 +72,10 @@
ComponentName.createRelative("com.android.foo", ".BarActivity");
private static final ComponentName ALTERNATIVE_COMPONENT =
ComponentName.createRelative("com.android.foo", ".AlternativeBarActivity");
+ private static final String TEST_WINDOW_LAYOUT_AFFINITY = "135:.Affinity";
+ private static final String TEST_ALTERNATIVE_WINDOW_LAYOUT_AFFINITY =
+ "246:.AlternativeAffinity";
+ private static final String TEST_DIFFERENT_AFFINITY_WITH_SAME_UID = "135:.DifferentAffinity";
private static final int TEST_WINDOWING_MODE = WINDOWING_MODE_FREEFORM;
private static final Rect TEST_BOUNDS = new Rect(100, 200, 300, 400);
@@ -99,11 +103,12 @@
public void setUp() throws Exception {
mPersisterQueue = new TestPersisterQueue();
- final File cacheFolder = InstrumentationRegistry.getContext().getCacheDir();
+ final File cacheFolder =
+ InstrumentationRegistry.getInstrumentation().getContext().getCacheDir();
mFolder = new File(cacheFolder, "launch_params_tests");
deleteRecursively(mFolder);
- mDisplayUniqueId = "test:" + Integer.toString(sNextUniqueId++);
+ mDisplayUniqueId = "test:" + sNextUniqueId++;
mTestDisplay = new TestDisplayContent.Builder(mService, 1000, 1500)
.setUniqueId(mDisplayUniqueId).build();
when(mRootWindowContainer.getDisplayContent(eq(mDisplayUniqueId)))
@@ -131,6 +136,7 @@
LocalServices.addService(PackageManagerInternal.class, mMockPmi);
when(mMockPmi.getPackageList(any())).thenReturn(new PackageList(
Collections.singletonList(TEST_COMPONENT.getPackageName()), /* observer */ null));
+ when(mMockPmi.getSystemUiServiceComponent()).thenReturn(new ComponentName("", ""));
mTarget.onSystemReady();
final ArgumentCaptor<PackageManagerInternal.PackageListObserver> observerCaptor =
@@ -210,6 +216,61 @@
}
@Test
+ public void testUsesRecordWithSameWindowLayoutAffinityInSameInstance_NoPreviousRecord() {
+ mTestTask.mWindowLayoutAffinity = TEST_WINDOW_LAYOUT_AFFINITY;
+ mTarget.saveTask(mTestTask);
+
+ mTaskWithDifferentComponent.mWindowLayoutAffinity = TEST_WINDOW_LAYOUT_AFFINITY;
+ mTarget.getLaunchParams(mTaskWithDifferentComponent, null, mResult);
+
+ assertEquals(mTestDisplay.mDisplayId, mResult.mPreferredDisplayId);
+ assertEquals(TEST_WINDOWING_MODE, mResult.mWindowingMode);
+ assertEquals(TEST_BOUNDS, mResult.mBounds);
+ }
+
+ @Test
+ public void testUsesRecordWithSameWindowLayoutAffinityInSameInstance_HasOldPreviousRecord()
+ throws Exception {
+ mTaskWithDifferentComponent.mWindowLayoutAffinity = TEST_WINDOW_LAYOUT_AFFINITY;
+ mTarget.saveTask(mTaskWithDifferentComponent);
+
+ Thread.sleep(1); // Sleep 1ms so that the timestamp can for sure increase.
+
+ mTestTask.mWindowLayoutAffinity = TEST_WINDOW_LAYOUT_AFFINITY;
+ mTarget.saveTask(mTestTask);
+
+ mTarget.getLaunchParams(mTaskWithDifferentComponent, null, mResult);
+
+ assertEquals(mTestDisplay.mDisplayId, mResult.mPreferredDisplayId);
+ assertEquals(TEST_WINDOWING_MODE, mResult.mWindowingMode);
+ assertEquals(TEST_BOUNDS, mResult.mBounds);
+ }
+
+ @Test
+ public void testReturnsEmptyLaunchParamsUidInLaunchAffinityMismatch() {
+ mTestTask.mWindowLayoutAffinity = TEST_WINDOW_LAYOUT_AFFINITY;
+ mTarget.saveTask(mTestTask);
+
+ mTaskWithDifferentComponent.mWindowLayoutAffinity = TEST_DIFFERENT_AFFINITY_WITH_SAME_UID;
+ mResult.mWindowingMode = WINDOWING_MODE_FULLSCREEN;
+ mTarget.getLaunchParams(mTaskWithDifferentComponent, null, mResult);
+
+ assertTrue("Result must be empty.", mResult.isEmpty());
+ }
+
+ @Test
+ public void testReturnsEmptyLaunchParamsWindowLayoutAffinityMismatch() {
+ mTestTask.affinity = TEST_WINDOW_LAYOUT_AFFINITY;
+ mTarget.saveTask(mTestTask);
+
+ mTaskWithDifferentComponent.mWindowLayoutAffinity = TEST_ALTERNATIVE_WINDOW_LAYOUT_AFFINITY;
+ mResult.mWindowingMode = WINDOWING_MODE_FULLSCREEN;
+ mTarget.getLaunchParams(mTaskWithDifferentComponent, null, mResult);
+
+ assertTrue("Result must be empty.", mResult.isEmpty());
+ }
+
+ @Test
public void testSavesAndRestoresLaunchParamsAcrossInstances() {
mTarget.saveTask(mTestTask);
mPersisterQueue.flush();
@@ -227,6 +288,52 @@
}
@Test
+ public void testUsesRecordWithSameWindowLayoutAffinityAcrossInstances_NoPreviousRecord() {
+ mTestTask.mWindowLayoutAffinity = TEST_WINDOW_LAYOUT_AFFINITY;
+ mTarget.saveTask(mTestTask);
+ mPersisterQueue.flush();
+
+ final LaunchParamsPersister target = new LaunchParamsPersister(mPersisterQueue, mSupervisor,
+ mUserFolderGetter);
+ target.onSystemReady();
+ target.onUnlockUser(TEST_USER_ID);
+
+ mTaskWithDifferentComponent.mWindowLayoutAffinity = TEST_WINDOW_LAYOUT_AFFINITY;
+ target.getLaunchParams(mTaskWithDifferentComponent, null, mResult);
+
+ assertEquals(mTestDisplay.mDisplayId, mResult.mPreferredDisplayId);
+ assertEquals(TEST_WINDOWING_MODE, mResult.mWindowingMode);
+ assertEquals(TEST_BOUNDS, mResult.mBounds);
+ }
+
+ @Test
+ public void testUsesRecordWithSameWindowLayoutAffinityAcrossInstances_HasOldPreviousRecord()
+ throws Exception {
+ mTaskWithDifferentComponent.mWindowLayoutAffinity = TEST_WINDOW_LAYOUT_AFFINITY;
+ mTarget.saveTask(mTaskWithDifferentComponent);
+ mPersisterQueue.flush();
+
+ // Sleep 1s because many file systems only save last modified time as precise as 1s so we
+ // can for sure know the last modified time is different.
+ Thread.sleep(1000);
+
+ mTestTask.mWindowLayoutAffinity = TEST_WINDOW_LAYOUT_AFFINITY;
+ mTarget.saveTask(mTestTask);
+ mPersisterQueue.flush();
+
+ final LaunchParamsPersister target = new LaunchParamsPersister(mPersisterQueue, mSupervisor,
+ mUserFolderGetter);
+ target.onSystemReady();
+ target.onUnlockUser(TEST_USER_ID);
+
+ target.getLaunchParams(mTaskWithDifferentComponent, null, mResult);
+
+ assertEquals(mTestDisplay.mDisplayId, mResult.mPreferredDisplayId);
+ assertEquals(TEST_WINDOWING_MODE, mResult.mWindowingMode);
+ assertEquals(TEST_BOUNDS, mResult.mBounds);
+ }
+
+ @Test
public void testClearsRecordsOfTheUserOnUserCleanUp() {
mTarget.saveTask(mTestTask);
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index 55d12db..560d03f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -40,6 +40,7 @@
import android.app.AppOpsManager;
import android.app.usage.UsageStatsManagerInternal;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.IntentFilter;
@@ -213,6 +214,9 @@
anyString(), anyInt());
doReturn(null).when(packageManagerInternal).getDefaultHomeActivity(anyInt());
+ ComponentName systemServiceComponent = new ComponentName("android.test.system.service", "");
+ doReturn(systemServiceComponent).when(packageManagerInternal).getSystemUiServiceComponent();
+
// PowerManagerInternal
final PowerManagerInternal pmi = mock(PowerManagerInternal.class);
final PowerSaveState state = new PowerSaveState.Builder().build();
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
index 53a3682..19ed7a9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
@@ -213,6 +213,16 @@
}
@Test
+ public void testRegisterTaskOrganizerWithExistingTasks() throws RemoteException {
+ final ActivityStack stack = createTaskStackOnDisplay(mDisplayContent);
+ final Task task = createTaskInStack(stack, 0 /* userId */);
+ stack.setWindowingMode(WINDOWING_MODE_PINNED);
+
+ final ITaskOrganizer organizer = registerMockOrganizer(WINDOWING_MODE_PINNED);
+ verify(organizer, times(1)).taskAppeared(any());
+ }
+
+ @Test
public void testTaskTransaction() {
removeGlobalMinSizeRestriction();
final ActivityStack stack = new ActivityTestsBase.StackBuilder(mWm.mRoot)
@@ -241,6 +251,32 @@
}
@Test
+ public void testSetWindowingMode() {
+ final ActivityStack stack = new ActivityTestsBase.StackBuilder(mWm.mRoot)
+ .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
+ final WindowContainerTransaction t = new WindowContainerTransaction();
+
+ t.setWindowingMode(stack.mRemoteToken, WINDOWING_MODE_FULLSCREEN);
+ mWm.mAtmService.mTaskOrganizerController.applyContainerTransaction(t, null);
+
+ assertEquals(WINDOWING_MODE_FULLSCREEN, stack.getWindowingMode());
+ }
+
+ @Test
+ public void testSetActivityWindowingMode() {
+ final ActivityRecord record = makePipableActivity();
+ final ActivityStack stack = record.getStack();
+ final WindowContainerTransaction t = new WindowContainerTransaction();
+
+ t.setWindowingMode(stack.mRemoteToken, WINDOWING_MODE_PINNED);
+ t.setActivityWindowingMode(stack.mRemoteToken, WINDOWING_MODE_FULLSCREEN);
+ mWm.mAtmService.mTaskOrganizerController.applyContainerTransaction(t, null);
+
+ assertEquals(WINDOWING_MODE_FULLSCREEN, record.getWindowingMode());
+ assertEquals(WINDOWING_MODE_PINNED, stack.getWindowingMode());
+ }
+
+ @Test
public void testContainerChanges() {
removeGlobalMinSizeRestriction();
final ActivityStack stack = new ActivityTestsBase.StackBuilder(mWm.mRoot)
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
index e1475a4..91c3c27 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestIWindow.java
@@ -77,7 +77,8 @@
}
@Override
- public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep, boolean sync)
+ public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep, float zoom,
+ boolean sync)
throws RemoteException {
}
@@ -85,7 +86,6 @@
public void dispatchWallpaperCommand(String action, int x, int y, int z, Bundle extras,
boolean sync) throws RemoteException {
}
-
@Override
public void dispatchDragEvent(DragEvent event) throws RemoteException {
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
index aa66524..900f014 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
@@ -17,19 +17,29 @@
package com.android.server.wm;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
+import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.IBinder;
+import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import android.view.DisplayInfo;
import android.view.Gravity;
@@ -139,4 +149,124 @@
assertEquals(Configuration.ORIENTATION_LANDSCAPE, dc.getConfiguration().orientation);
assertEquals(portraitFrame, wallpaperWindow.getFrameLw());
}
+
+ @Test
+ public void testWallpaperZoom() throws RemoteException {
+ final DisplayContent dc = mWm.mRoot.getDefaultDisplay();
+ final WallpaperWindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm,
+ mock(IBinder.class), true, dc, true /* ownerCanManageAppTokens */);
+ final WindowState wallpaperWindow = createWindow(null, TYPE_WALLPAPER, wallpaperWindowToken,
+ "wallpaperWindow");
+ wallpaperWindow.getAttrs().privateFlags |=
+ WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS;
+
+ final WindowState homeWindow = createWallpaperTargetWindow(dc);
+
+ spyOn(dc.mWallpaperController);
+ doReturn(true).when(dc.mWallpaperController).isWallpaperVisible();
+
+ dc.mWallpaperController.adjustWallpaperWindows();
+
+ spyOn(wallpaperWindow.mClient);
+
+ float zoom = .5f;
+ dc.mWallpaperController.setWallpaperZoomOut(homeWindow, zoom);
+ assertEquals(zoom, wallpaperWindow.mWallpaperZoomOut, .01f);
+ verify(wallpaperWindow.mClient).dispatchWallpaperOffsets(anyFloat(), anyFloat(), anyFloat(),
+ anyFloat(), eq(zoom), anyBoolean());
+ }
+
+ @Test
+ public void testWallpaperZoom_shouldNotScaleWallpaper() throws RemoteException {
+ final DisplayContent dc = mWm.mRoot.getDefaultDisplay();
+ final WallpaperWindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm,
+ mock(IBinder.class), true, dc, true /* ownerCanManageAppTokens */);
+ final WindowState wallpaperWindow = createWindow(null, TYPE_WALLPAPER, wallpaperWindowToken,
+ "wallpaperWindow");
+ wallpaperWindow.getAttrs().privateFlags |=
+ WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS;
+
+ final WindowState homeWindow = createWallpaperTargetWindow(dc);
+
+ spyOn(dc.mWallpaperController);
+ doReturn(true).when(dc.mWallpaperController).isWallpaperVisible();
+
+ dc.mWallpaperController.adjustWallpaperWindows();
+
+ spyOn(wallpaperWindow.mClient);
+
+ float newZoom = .5f;
+ wallpaperWindow.mShouldScaleWallpaper = false;
+ // Set zoom, and make sure the window animator scale didn't actually change, but the zoom
+ // value did, and we do dispatch the zoom to the wallpaper service
+ dc.mWallpaperController.setWallpaperZoomOut(homeWindow, newZoom);
+ assertEquals(newZoom, wallpaperWindow.mWallpaperZoomOut, .01f);
+ assertEquals(1f, wallpaperWindow.mWinAnimator.mWallpaperScale, .01f);
+ verify(wallpaperWindow.mClient).dispatchWallpaperOffsets(anyFloat(), anyFloat(), anyFloat(),
+ anyFloat(), eq(newZoom), anyBoolean());
+ }
+
+ @Test
+ public void testWallpaperZoom_multipleCallers() {
+ final DisplayContent dc = mWm.mRoot.getDefaultDisplay();
+ final WallpaperWindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm,
+ mock(IBinder.class), true, dc,
+ true /* ownerCanManageAppTokens */);
+ final WindowState wallpaperWindow = createWindow(null, TYPE_WALLPAPER, wallpaperWindowToken,
+ "wallpaperWindow");
+ wallpaperWindow.getAttrs().privateFlags |=
+ WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS;
+
+
+ spyOn(dc.mWallpaperController);
+ doReturn(true).when(dc.mWallpaperController).isWallpaperVisible();
+
+ final WindowState homeWindow = createWallpaperTargetWindow(dc);
+
+ WindowState otherWindow = createWindow(null /* parent */, TYPE_APPLICATION, dc,
+ "otherWindow");
+
+ dc.mWallpaperController.adjustWallpaperWindows();
+
+ spyOn(wallpaperWindow.mClient);
+
+ // Set zoom from 2 windows
+ float homeWindowInitialZoom = .5f;
+ float otherWindowInitialZoom = .7f;
+ dc.mWallpaperController.setWallpaperZoomOut(homeWindow, homeWindowInitialZoom);
+ dc.mWallpaperController.setWallpaperZoomOut(otherWindow, otherWindowInitialZoom);
+ // Make sure the largest one wins
+ assertEquals(otherWindowInitialZoom, wallpaperWindow.mWallpaperZoomOut, .01f);
+
+ // Change zoom to a larger zoom from homeWindow
+ float homeWindowZoom2 = .8f;
+ dc.mWallpaperController.setWallpaperZoomOut(homeWindow, homeWindowZoom2);
+ // New zoom should be current
+ assertEquals(homeWindowZoom2, wallpaperWindow.mWallpaperZoomOut, .01f);
+
+ // Set homeWindow zoom to a lower zoom, but keep the one from otherWindow
+ dc.mWallpaperController.setWallpaperZoomOut(homeWindow, homeWindowInitialZoom);
+
+ // Zoom from otherWindow should be the current.
+ assertEquals(otherWindowInitialZoom, wallpaperWindow.mWallpaperZoomOut, .01f);
+ }
+
+
+ private WindowState createWallpaperTargetWindow(DisplayContent dc) {
+ final ActivityRecord homeActivity = new ActivityTestsBase.ActivityBuilder(mWm.mAtmService)
+ .setStack(dc.getRootHomeTask())
+ .setCreateTask(true)
+ .build();
+ homeActivity.setVisibility(true);
+
+ WindowState appWindow = createWindow(null /* parent */, TYPE_BASE_APPLICATION,
+ homeActivity, "wallpaperTargetWindow");
+ appWindow.getAttrs().flags |= FLAG_SHOW_WALLPAPER;
+ appWindow.mHasSurface = true;
+ spyOn(appWindow);
+ doReturn(true).when(appWindow).isDrawFinishedLw();
+
+ homeActivity.addWindow(appWindow);
+ return appWindow;
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
index 34e487b..07a6179 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowProcessControllerTests.java
@@ -29,6 +29,7 @@
import static org.mockito.Mockito.when;
import android.app.IApplicationThread;
+import android.content.ComponentName;
import android.content.pm.ApplicationInfo;
import android.content.res.Configuration;
import android.platform.test.annotations.Presubmit;
@@ -55,8 +56,11 @@
@Before
public void setUp() {
mMockListener = mock(WindowProcessListener.class);
+
+ ApplicationInfo info = mock(ApplicationInfo.class);
+ info.packageName = "test.package.name";
mWpc = new WindowProcessController(
- mService, mock(ApplicationInfo.class), null, 0, -1, null, mMockListener);
+ mService, info, null, 0, -1, null, mMockListener);
mWpc.setThread(mock(IApplicationThread.class));
}
@@ -176,6 +180,26 @@
assertEquals(mWpc.getLastReportedConfiguration(), newConfig);
}
+ @Test
+ public void testActivityNotOverridingSystemUiProcessConfig() {
+ final ComponentName systemUiServiceComponent = mService.getSysUiServiceComponentLocked();
+ ApplicationInfo applicationInfo = mock(ApplicationInfo.class);
+ applicationInfo.packageName = systemUiServiceComponent.getPackageName();
+
+ WindowProcessController wpc = new WindowProcessController(
+ mService, applicationInfo, null, 0, -1, null, mMockListener);
+ wpc.setThread(mock(IApplicationThread.class));
+
+ final ActivityRecord activity = new ActivityBuilder(mService)
+ .setCreateTask(true)
+ .setUseProcess(wpc)
+ .build();
+
+ wpc.addActivityIfNeeded(activity);
+ // System UI owned processes should not be registered for activity config changes.
+ assertFalse(wpc.registeredForActivityConfigChanges());
+ }
+
private TestDisplayContent createTestDisplayContentInContainer() {
return new TestDisplayContent.Builder(mService, 1000, 1500).build();
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java
index af81ab6..be0987d 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java
@@ -257,6 +257,9 @@
int userHandle) {
SQLiteDatabase db = getReadableDatabase();
Cursor c = db.rawQuery(selectQuery, null);
+ if (DBG) {
+ Slog.w(TAG, "querying database: " + selectQuery);
+ }
try {
if (c.moveToFirst()) {
@@ -334,7 +337,10 @@
return model;
} while (c.moveToNext());
}
- Slog.w(TAG, "No SoundModel available for the given keyphrase");
+
+ if (DBG) {
+ Slog.w(TAG, "No SoundModel available for the given keyphrase");
+ }
} finally {
c.close();
db.close();
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 0b24dd2..0eba07b 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -41,6 +41,7 @@
import android.content.res.Resources;
import android.database.ContentObserver;
import android.hardware.soundtrigger.IRecognitionStatusCallback;
+import android.hardware.soundtrigger.KeyphraseEnrollmentInfo;
import android.hardware.soundtrigger.KeyphraseMetadata;
import android.hardware.soundtrigger.ModelParams;
import android.hardware.soundtrigger.SoundTrigger;
@@ -223,6 +224,7 @@
class VoiceInteractionManagerServiceStub extends IVoiceInteractionManagerService.Stub {
VoiceInteractionManagerServiceImpl mImpl;
+ KeyphraseEnrollmentInfo mEnrollmentApplicationInfo;
private boolean mSafeMode;
private int mCurUser;
@@ -447,6 +449,15 @@
}
}
+ private void getOrCreateEnrollmentApplicationInfo() {
+ synchronized (this) {
+ if (mEnrollmentApplicationInfo == null) {
+ mEnrollmentApplicationInfo = new KeyphraseEnrollmentInfo(
+ mContext.getPackageManager());
+ }
+ }
+ }
+
private void setCurrentUserLocked(@UserIdInt int userHandle) {
mCurUser = userHandle;
final UserInfo userInfo = mUserManagerInternal.getUserInfo(mCurUser);
@@ -1380,12 +1391,17 @@
pw.println(" mCurUserUnlocked: " + mCurUserUnlocked);
pw.println(" mCurUserSupported: " + mCurUserSupported);
dumpSupportedUsers(pw, " ");
+ if (mEnrollmentApplicationInfo == null) {
+ pw.println(" (No enrollment application info)");
+ } else {
+ pw.println(" " + mEnrollmentApplicationInfo.toString());
+ }
mDbHelper.dump(pw);
if (mImpl == null) {
pw.println(" (No active implementation)");
- return;
+ } else {
+ mImpl.dumpLocked(fd, pw, args);
}
- mImpl.dumpLocked(fd, pw, args);
}
mSoundTriggerInternal.dump(fd, pw, args);
}
@@ -1438,8 +1454,9 @@
}
private boolean isCallerTrustedEnrollmentApplication() {
- return mImpl.mEnrollmentApplicationInfo.isUidSupportedEnrollmentApplication(
- Binder.getCallingUid());
+ getOrCreateEnrollmentApplicationInfo();
+ return mEnrollmentApplicationInfo.isUidSupportedEnrollmentApplication(
+ Binder.getCallingUid());
}
private void setImplLocked(VoiceInteractionManagerServiceImpl impl) {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index b813f87..a62b03c 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -36,7 +36,6 @@
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
-import android.hardware.soundtrigger.KeyphraseEnrollmentInfo;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -79,7 +78,6 @@
final IActivityManager mAm;
final IActivityTaskManager mAtm;
final VoiceInteractionServiceInfo mInfo;
- final KeyphraseEnrollmentInfo mEnrollmentApplicationInfo;
final ComponentName mSessionComponentName;
final IWindowManager mIWindowManager;
boolean mBound = false;
@@ -135,7 +133,6 @@
mComponent = service;
mAm = ActivityManager.getService();
mAtm = ActivityTaskManager.getService();
- mEnrollmentApplicationInfo = new KeyphraseEnrollmentInfo(context.getPackageManager());
VoiceInteractionServiceInfo info;
try {
info = new VoiceInteractionServiceInfo(context.getPackageManager(), service, mUser);
@@ -406,7 +403,6 @@
pw.println(" Active session:");
mActiveSession.dump(" ", pw);
}
- pw.println(" " + mEnrollmentApplicationInfo.toString());
}
void startLocked() {
diff --git a/telecomm/java/android/telecom/CallRedirectionService.java b/telecomm/java/android/telecom/CallRedirectionService.java
index 36c6377..c832f53 100644
--- a/telecomm/java/android/telecom/CallRedirectionService.java
+++ b/telecomm/java/android/telecom/CallRedirectionService.java
@@ -38,16 +38,14 @@
*
* <p>
* Below is an example manifest registration for a {@code CallRedirectionService}.
- * <pre>
* {@code
* <service android:name="your.package.YourCallRedirectionServiceImplementation"
- * android:permission="android.permission.BIND_REDIRECTION_SERVICE">
+ * android:permission="android.permission.BIND_CALL_REDIRECTION_SERVICE">
* <intent-filter>
* <action android:name="android.telecom.CallRedirectionService"/>
* </intent-filter>
* </service>
* }
- * </pre>
*/
public abstract class CallRedirectionService extends Service {
/**
diff --git a/telecomm/java/android/telecom/DisconnectCause.java b/telecomm/java/android/telecom/DisconnectCause.java
index 0093843..bebbbd0 100644
--- a/telecomm/java/android/telecom/DisconnectCause.java
+++ b/telecomm/java/android/telecom/DisconnectCause.java
@@ -80,17 +80,20 @@
* Reason code (returned via {@link #getReason()}) which indicates that a call could not be
* completed because the cellular radio is off or out of service, the device is connected to
* a wifi network, but the user has not enabled wifi calling.
+ * @hide
*/
public static final String REASON_WIFI_ON_BUT_WFC_OFF = "REASON_WIFI_ON_BUT_WFC_OFF";
/**
* Reason code (returned via {@link #getReason()}), which indicates that the video telephony
* call was disconnected because IMS access is blocked.
+ * @hide
*/
public static final String REASON_IMS_ACCESS_BLOCKED = "REASON_IMS_ACCESS_BLOCKED";
/**
* Reason code, which indicates that the conference call is simulating single party conference.
+ * @hide
*/
public static final String REASON_EMULATING_SINGLE_CALL = "EMULATING_SINGLE_CALL";
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index 4e6e1a5..768c8ee 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -53,7 +53,6 @@
* {@link android.telecom.ConnectionService}.
* @hide
*/
- @SystemApi
public static final String EXTRA_SORT_ORDER =
"android.telecom.extra.SORT_ORDER";
@@ -89,7 +88,6 @@
* rather than cellular calls.
* @hide
*/
- @SystemApi
public static final String EXTRA_ALWAYS_USE_VOIP_AUDIO_MODE =
"android.telecom.extra.ALWAYS_USE_VOIP_AUDIO_MODE";
@@ -114,7 +112,6 @@
*
* @hide
*/
- @SystemApi
public static final String EXTRA_SUPPORTS_VIDEO_CALLING_FALLBACK =
"android.telecom.extra.SUPPORTS_VIDEO_CALLING_FALLBACK";
@@ -163,7 +160,6 @@
* in progress.
* @hide
*/
- @SystemApi
public static final String EXTRA_PLAY_CALL_RECORDING_TONE =
"android.telecom.extra.PLAY_CALL_RECORDING_TONE";
@@ -258,7 +254,6 @@
* See {@link #getCapabilities}
* @hide
*/
- @SystemApi
public static final int CAPABILITY_EMERGENCY_CALLS_ONLY = 0x80;
/**
@@ -282,7 +277,6 @@
* convert all outgoing video calls to emergency numbers to audio-only.
* @hide
*/
- @SystemApi
public static final int CAPABILITY_EMERGENCY_VIDEO_CALLING = 0x200;
/**
@@ -340,7 +334,6 @@
*
* @hide
*/
- @SystemApi
public static final int CAPABILITY_EMERGENCY_PREFERRED = 0x2000;
/**
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 7f4fcc0..1792256 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -318,13 +318,13 @@
* the remote handle of the new call.
* @hide
*/
- @SystemApi
public static final String EXTRA_UNKNOWN_CALL_HANDLE =
"android.telecom.extra.UNKNOWN_CALL_HANDLE";
/**
* Optional extra for incoming and outgoing calls containing a long which specifies the time the
* call was created. This value is in milliseconds since boot.
+ * @hide
*/
public static final String EXTRA_CALL_CREATED_TIME_MILLIS =
"android.telecom.extra.CALL_CREATED_TIME_MILLIS";
@@ -388,7 +388,6 @@
* </ul>
* @hide
*/
- @SystemApi
public static final String EXTRA_CALL_TECHNOLOGY_TYPE =
"android.telecom.extra.CALL_TECHNOLOGY_TYPE";
@@ -731,7 +730,6 @@
* @see #EXTRA_CURRENT_TTY_MODE
* @hide
*/
- @SystemApi
public static final String ACTION_CURRENT_TTY_MODE_CHANGED =
"android.telecom.action.CURRENT_TTY_MODE_CHANGED";
@@ -746,7 +744,6 @@
* </ul>
* @hide
*/
- @SystemApi
public static final String EXTRA_CURRENT_TTY_MODE =
"android.telecom.extra.CURRENT_TTY_MODE";
@@ -757,7 +754,6 @@
* @see #EXTRA_TTY_PREFERRED_MODE
* @hide
*/
- @SystemApi
public static final String ACTION_TTY_PREFERRED_MODE_CHANGED =
"android.telecom.action.TTY_PREFERRED_MODE_CHANGED";
@@ -768,7 +764,6 @@
*
* @hide
*/
- @SystemApi
public static final String EXTRA_TTY_PREFERRED_MODE =
"android.telecom.extra.TTY_PREFERRED_MODE";
@@ -846,7 +841,6 @@
*
* @hide
*/
- @SystemApi
public static final String EXTRA_CALL_SOURCE = "android.telecom.extra.CALL_SOURCE";
/**
@@ -943,8 +937,8 @@
*/
public TelecomManager(Context context, ITelecomService telecomServiceImpl) {
Context appContext = context.getApplicationContext();
- if (appContext != null && Objects.equals(context.getFeatureId(),
- appContext.getFeatureId())) {
+ if (appContext != null && Objects.equals(context.getAttributionTag(),
+ appContext.getAttributionTag())) {
mContext = appContext;
} else {
mContext = context;
@@ -978,7 +972,7 @@
try {
if (isServiceConnected()) {
return getTelecomService().getDefaultOutgoingPhoneAccount(uriScheme,
- mContext.getOpPackageName(), mContext.getFeatureId());
+ mContext.getOpPackageName(), mContext.getAttributionTag());
}
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelecomService#getDefaultOutgoingPhoneAccount", e);
@@ -1176,7 +1170,7 @@
try {
if (isServiceConnected()) {
return getTelecomService().getSelfManagedPhoneAccounts(mContext.getOpPackageName(),
- mContext.getFeatureId());
+ mContext.getAttributionTag());
}
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelecomService#getSelfManagedPhoneAccounts()", e);
@@ -1202,7 +1196,7 @@
try {
if (isServiceConnected()) {
return getTelecomService().getCallCapablePhoneAccounts(includeDisabledAccounts,
- mContext.getOpPackageName(), mContext.getFeatureId());
+ mContext.getOpPackageName(), mContext.getAttributionTag());
}
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelecomService#getCallCapablePhoneAccounts(" +
@@ -1506,7 +1500,7 @@
try {
if (isServiceConnected()) {
return getTelecomService().isVoiceMailNumber(accountHandle, number,
- mContext.getOpPackageName(), mContext.getFeatureId());
+ mContext.getOpPackageName(), mContext.getAttributionTag());
}
} catch (RemoteException e) {
Log.e(TAG, "RemoteException calling ITelecomService#isVoiceMailNumber.", e);
@@ -1528,7 +1522,7 @@
try {
if (isServiceConnected()) {
return getTelecomService().getVoiceMailNumber(accountHandle,
- mContext.getOpPackageName(), mContext.getFeatureId());
+ mContext.getOpPackageName(), mContext.getAttributionTag());
}
} catch (RemoteException e) {
Log.e(TAG, "RemoteException calling ITelecomService#hasVoiceMailNumber.", e);
@@ -1549,7 +1543,7 @@
try {
if (isServiceConnected()) {
return getTelecomService().getLine1Number(accountHandle,
- mContext.getOpPackageName(), mContext.getFeatureId());
+ mContext.getOpPackageName(), mContext.getAttributionTag());
}
} catch (RemoteException e) {
Log.e(TAG, "RemoteException calling ITelecomService#getLine1Number.", e);
@@ -1571,7 +1565,7 @@
try {
if (isServiceConnected()) {
return getTelecomService().isInCall(mContext.getOpPackageName(),
- mContext.getFeatureId());
+ mContext.getAttributionTag());
}
} catch (RemoteException e) {
Log.e(TAG, "RemoteException calling isInCall().", e);
@@ -1597,7 +1591,7 @@
try {
if (isServiceConnected()) {
return getTelecomService().isInManagedCall(mContext.getOpPackageName(),
- mContext.getFeatureId());
+ mContext.getAttributionTag());
}
} catch (RemoteException e) {
Log.e(TAG, "RemoteException calling isInManagedCall().", e);
@@ -1778,7 +1772,7 @@
try {
if (isServiceConnected()) {
return getTelecomService().isTtySupported(mContext.getOpPackageName(),
- mContext.getFeatureId());
+ mContext.getAttributionTag());
}
} catch (RemoteException e) {
Log.e(TAG, "RemoteException attempting to get TTY supported state.", e);
@@ -1803,7 +1797,7 @@
try {
if (isServiceConnected()) {
return getTelecomService().getCurrentTtyMode(mContext.getOpPackageName(),
- mContext.getFeatureId());
+ mContext.getAttributionTag());
}
} catch (RemoteException e) {
Log.e(TAG, "RemoteException attempting to get the current TTY mode.", e);
@@ -2033,7 +2027,7 @@
if (service != null) {
try {
service.showInCallScreen(showDialpad, mContext.getOpPackageName(),
- mContext.getFeatureId());
+ mContext.getAttributionTag());
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelecomService#showCallScreen", e);
}
@@ -2096,7 +2090,7 @@
}
try {
service.placeCall(address, extras == null ? new Bundle() : extras,
- mContext.getOpPackageName(), mContext.getFeatureId());
+ mContext.getOpPackageName(), mContext.getAttributionTag());
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelecomService#placeCall", e);
}
diff --git a/telephony/java/android/telephony/Annotation.java b/telephony/java/android/telephony/Annotation.java
index 9ae86c8..dcd4eb5 100644
--- a/telephony/java/android/telephony/Annotation.java
+++ b/telephony/java/android/telephony/Annotation.java
@@ -1,7 +1,6 @@
package android.telephony;
import android.annotation.IntDef;
-import android.provider.Telephony;
import android.telecom.Connection;
import android.telephony.data.ApnSetting;
@@ -653,15 +652,6 @@
@Retention(RetentionPolicy.SOURCE)
public @interface UiccAppType{}
- /** @hide */
- @IntDef({
- Telephony.Carriers.SKIP_464XLAT_DEFAULT,
- Telephony.Carriers.SKIP_464XLAT_DISABLE,
- Telephony.Carriers.SKIP_464XLAT_ENABLE,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface Skip464XlatStatus {}
-
/**
* Override network type
*/
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 4415508..e2112a59 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2382,17 +2382,16 @@
* <p> If a measure is not set, signal criteria reporting from modem will not be triggered and
* not be used for calculating signal level. If multiple measures are set bit, the parameter
* whose value is smallest is used to indicate the signal level.
+ * <UL>
+ * <LI>RSRP = 1 << 0</LI>
+ * <LI>RSRQ = 1 << 1</LI>
+ * <LI>RSSNR = 1 << 2</LI>
+ * </UL>
+ * <p> The value of this key must be bitwise OR of {@link CellSignalStrengthLte#USE_RSRP},
+ * {@link CellSignalStrengthLte#USE_RSRQ}, {@link CellSignalStrengthLte#USE_RSSNR}.
*
- * RSRP = 1 << 0,
- * RSRQ = 1 << 1,
- * RSSNR = 1 << 2,
- *
- * The value of this key must be bitwise OR of {@link CellSignalStrengthLte#USE_RSRP},
- * {@link CellSignalStrengthLte#USE_RSRQ}, {@link CellSignalStrengthLte#USE_RSSNR}.
- *
- * For example, if both RSRP and RSRQ are used, the value of key is 3 (1 << 0 | 1 << 1).
- * If the key is invalid or not configured, a default value (RSRP = 1 << 0)
- * will apply.
+ * <p> For example, if both RSRP and RSRQ are used, the value of key is 3 (1 << 0 | 1 << 1).
+ * If the key is invalid or not configured, a default value (RSRP = 1 << 0) will apply.
*
* @hide
*/
@@ -2401,16 +2400,18 @@
/**
* List of 4 customized 5G SS reference signal received power (SSRSRP) thresholds.
- *
+ * <p>
* Reference: 3GPP TS 38.215
- *
+ * <p>
* 4 threshold integers must be within the boundaries [-140 dB, -44 dB], and the levels are:
- * "NONE: [-140, threshold1]"
- * "POOR: (threshold1, threshold2]"
- * "MODERATE: (threshold2, threshold3]"
- * "GOOD: (threshold3, threshold4]"
- * "EXCELLENT: (threshold4, -44]"
- *
+ * <UL>
+ * <LI>"NONE: [-140, threshold1]"</LI>
+ * <LI>"POOR: (threshold1, threshold2]"</LI>
+ * <LI>"MODERATE: (threshold2, threshold3]"</LI>
+ * <LI>"GOOD: (threshold3, threshold4]"</LI>
+ * <LI>"EXCELLENT: (threshold4, -44]"</LI>
+ * </UL>
+ * <p>
* This key is considered invalid if the format is violated. If the key is invalid or
* not configured, a default value set will apply.
*/
@@ -2419,16 +2420,18 @@
/**
* List of 4 customized 5G SS reference signal received quality (SSRSRQ) thresholds.
- *
+ * <p>
* Reference: 3GPP TS 38.215
- *
+ * <p>
* 4 threshold integers must be within the boundaries [-20 dB, -3 dB], and the levels are:
- * "NONE: [-20, threshold1]"
- * "POOR: (threshold1, threshold2]"
- * "MODERATE: (threshold2, threshold3]"
- * "GOOD: (threshold3, threshold4]"
- * "EXCELLENT: (threshold4, -3]"
- *
+ * <UL>
+ * <LI>"NONE: [-20, threshold1]"</LI>
+ * <LI>"POOR: (threshold1, threshold2]"</LI>
+ * <LI>"MODERATE: (threshold2, threshold3]"</LI>
+ * <LI>"GOOD: (threshold3, threshold4]"</LI>
+ * <LI>"EXCELLENT: (threshold4, -3]"</LI>
+ * </UL>
+ * <p>
* This key is considered invalid if the format is violated. If the key is invalid or
* not configured, a default value set will apply.
*/
@@ -2437,17 +2440,19 @@
/**
* List of 4 customized 5G SS signal-to-noise and interference ratio (SSSINR) thresholds.
- *
+ * <p>
* Reference: 3GPP TS 38.215,
* 3GPP TS 38.133 10.1.16.1
- *
+ * <p>
* 4 threshold integers must be within the boundaries [-23 dB, 40 dB], and the levels are:
- * "NONE: [-23, threshold1]"
- * "POOR: (threshold1, threshold2]"
- * "MODERATE: (threshold2, threshold3]"
- * "GOOD: (threshold3, threshold4]"
- * "EXCELLENT: (threshold4, 40]"
- *
+ * <UL>
+ * <LI>"NONE: [-23, threshold1]"</LI>
+ * <LI>"POOR: (threshold1, threshold2]"</LI>
+ * <LI>"MODERATE: (threshold2, threshold3]"</LI>
+ * <LI>"GOOD: (threshold3, threshold4]"</LI>
+ * <LI>"EXCELLENT: (threshold4, 40]"</LI>
+ * </UL>
+ * <p>
* This key is considered invalid if the format is violated. If the key is invalid or
* not configured, a default value set will apply.
*/
@@ -2462,19 +2467,19 @@
* <p> If a measure is not set, signal criteria reporting from modem will not be triggered and
* not be used for calculating signal level. If multiple measures are set bit, the parameter
* whose value is smallest is used to indicate the signal level.
- *
- * SSRSRP = 1 << 0,
- * SSRSRQ = 1 << 1,
- * SSSINR = 1 << 2,
- *
+ * <UL>
+ * <LI>SSRSRP = 1 << 0</LI>
+ * <LI>SSRSRQ = 1 << 1</LI>
+ * <LI>SSSINR = 1 << 2</LI>
+ * </UL>
* The value of this key must be bitwise OR of {@link CellSignalStrengthNr#USE_SSRSRP},
* {@link CellSignalStrengthNr#USE_SSRSRQ}, {@link CellSignalStrengthNr#USE_SSSINR}.
*
- * For example, if both SSRSRP and SSSINR are used, the value of key is 5 (1 << 0 | 1 << 2).
+ * <p> For example, if both SSRSRP and SSSINR are used, the value of key is 5 (1 << 0 | 1 << 2).
* If the key is invalid or not configured, a default value (SSRSRP = 1 << 0) will apply.
*
- * Reference: 3GPP TS 38.215,
- * 3GPP TS 38.133 10.1.16.1
+ * <p> Reference: 3GPP TS 38.215,
+ * 3GPP TS 38.133 10.1.16.1
*
* @hide
*/
@@ -3530,6 +3535,15 @@
"support_wps_over_ims_bool";
/**
+ * The two digital number pattern of MMI code which is defined by carrier.
+ * If the dial number matches this pattern, it will be dialed out normally not USSD.
+ *
+ * @hide
+ */
+ public static final String KEY_MMI_TWO_DIGIT_NUMBER_PATTERN_STRING_ARRAY =
+ "mmi_two_digit_number_pattern_string_array";
+
+ /**
* Holds the list of carrier certificate hashes.
* Note that each carrier has its own certificates.
*/
@@ -4086,6 +4100,7 @@
new int[] {4 /* BUSY */});
sDefaults.putBoolean(KEY_PREVENT_CLIR_ACTIVATION_AND_DEACTIVATION_CODE_BOOL, false);
sDefaults.putLong(KEY_DATA_SWITCH_VALIDATION_TIMEOUT_LONG, 2000);
+ sDefaults.putStringArray(KEY_MMI_TWO_DIGIT_NUMBER_PATTERN_STRING_ARRAY, new String[0]);
sDefaults.putInt(KEY_PARAMETERS_USED_FOR_LTE_SIGNAL_BAR_INT,
CellSignalStrengthLte.USE_RSRP);
// Default wifi configurations.
@@ -4147,7 +4162,7 @@
return null;
}
return loader.getConfigForSubIdWithFeature(subId, mContext.getOpPackageName(),
- mContext.getFeatureId());
+ mContext.getAttributionTag());
} catch (RemoteException ex) {
Rlog.e(TAG, "Error getting config for subId " + subId + ": "
+ ex.toString());
diff --git a/telephony/java/android/telephony/PinResult.java b/telephony/java/android/telephony/PinResult.java
index c14bd91..98d6448 100644
--- a/telephony/java/android/telephony/PinResult.java
+++ b/telephony/java/android/telephony/PinResult.java
@@ -19,7 +19,6 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -32,7 +31,6 @@
*
* @hide
*/
-@SystemApi
public final class PinResult implements Parcelable {
/** @hide */
@IntDef({
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 45cba51..dd20d06 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -580,7 +580,6 @@
*
* @hide
*/
- @SystemApi
public @RegState int getDataRegistrationState() {
return getDataRegState();
}
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 8ac9023b..01a40f5 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -1144,7 +1144,7 @@
ISub iSub = TelephonyManager.getSubscriptionService();
if (iSub != null) {
subInfo = iSub.getActiveSubscriptionInfo(subId, mContext.getOpPackageName(),
- mContext.getFeatureId());
+ mContext.getAttributionTag());
}
} catch (RemoteException ex) {
// ignore it
@@ -1178,7 +1178,7 @@
ISub iSub = TelephonyManager.getSubscriptionService();
if (iSub != null) {
result = iSub.getActiveSubscriptionInfoForIccId(iccId, mContext.getOpPackageName(),
- mContext.getFeatureId());
+ mContext.getAttributionTag());
}
} catch (RemoteException ex) {
// ignore it
@@ -1212,7 +1212,7 @@
ISub iSub = TelephonyManager.getSubscriptionService();
if (iSub != null) {
result = iSub.getActiveSubscriptionInfoForSimSlotIndex(slotIndex,
- mContext.getOpPackageName(), mContext.getFeatureId());
+ mContext.getOpPackageName(), mContext.getAttributionTag());
}
} catch (RemoteException ex) {
// ignore it
@@ -1236,7 +1236,7 @@
ISub iSub = TelephonyManager.getSubscriptionService();
if (iSub != null) {
result = iSub.getAllSubInfoList(mContext.getOpPackageName(),
- mContext.getFeatureId());
+ mContext.getAttributionTag());
}
} catch (RemoteException ex) {
// ignore it
@@ -1300,8 +1300,13 @@
* both active and hidden SubscriptionInfos.
*
*/
- public @Nullable List<SubscriptionInfo> getActiveAndHiddenSubscriptionInfoList() {
- return getActiveSubscriptionInfoList(/* userVisibleonly */false);
+ public @NonNull List<SubscriptionInfo> getCompleteActiveSubscriptionInfoList() {
+ List<SubscriptionInfo> completeList = getActiveSubscriptionInfoList(
+ /* userVisibleonly */false);
+ if (completeList == null) {
+ completeList = new ArrayList<>();
+ }
+ return completeList;
}
/**
@@ -1317,7 +1322,7 @@
ISub iSub = TelephonyManager.getSubscriptionService();
if (iSub != null) {
activeList = iSub.getActiveSubscriptionInfoList(mContext.getOpPackageName(),
- mContext.getFeatureId());
+ mContext.getAttributionTag());
}
} catch (RemoteException ex) {
// ignore it
@@ -1368,7 +1373,7 @@
ISub iSub = TelephonyManager.getSubscriptionService();
if (iSub != null) {
result = iSub.getAvailableSubscriptionInfoList(mContext.getOpPackageName(),
- mContext.getFeatureId());
+ mContext.getAttributionTag());
}
} catch (RemoteException ex) {
// ignore it
@@ -1486,7 +1491,7 @@
ISub iSub = TelephonyManager.getSubscriptionService();
if (iSub != null) {
result = iSub.getAllSubInfoCount(mContext.getOpPackageName(),
- mContext.getFeatureId());
+ mContext.getAttributionTag());
}
} catch (RemoteException ex) {
// ignore it
@@ -1515,7 +1520,7 @@
ISub iSub = TelephonyManager.getSubscriptionService();
if (iSub != null) {
result = iSub.getActiveSubInfoCount(mContext.getOpPackageName(),
- mContext.getFeatureId());
+ mContext.getAttributionTag());
}
} catch (RemoteException ex) {
// ignore it
@@ -2270,7 +2275,7 @@
ISub iSub = TelephonyManager.getSubscriptionService();
if (iSub != null) {
resultValue = iSub.getSubscriptionProperty(subId, propKey,
- context.getOpPackageName(), context.getFeatureId());
+ context.getOpPackageName(), context.getAttributionTag());
}
} catch (RemoteException ex) {
// ignore it
@@ -2434,7 +2439,7 @@
ISub iSub = TelephonyManager.getSubscriptionService();
if (iSub != null) {
return iSub.isActiveSubId(subId, mContext.getOpPackageName(),
- mContext.getFeatureId());
+ mContext.getAttributionTag());
}
} catch (RemoteException ex) {
}
@@ -2697,13 +2702,14 @@
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public @NonNull List<SubscriptionInfo> getOpportunisticSubscriptions() {
String contextPkg = mContext != null ? mContext.getOpPackageName() : "<unknown>";
- String contextFeature = mContext != null ? mContext.getFeatureId() : null;
+ String contextAttributionTag = mContext != null ? mContext.getAttributionTag() : null;
List<SubscriptionInfo> subInfoList = null;
try {
ISub iSub = TelephonyManager.getSubscriptionService();
if (iSub != null) {
- subInfoList = iSub.getOpportunisticSubscriptions(contextPkg, contextFeature);
+ subInfoList = iSub.getOpportunisticSubscriptions(contextPkg,
+ contextAttributionTag);
}
} catch (RemoteException ex) {
// ignore it
@@ -2942,7 +2948,7 @@
public @NonNull List<SubscriptionInfo> getSubscriptionsInGroup(@NonNull ParcelUuid groupUuid) {
Preconditions.checkNotNull(groupUuid, "groupUuid can't be null");
String contextPkg = mContext != null ? mContext.getOpPackageName() : "<unknown>";
- String contextFeature = mContext != null ? mContext.getFeatureId() : null;
+ String contextAttributionTag = mContext != null ? mContext.getAttributionTag() : null;
if (VDBG) {
logd("[getSubscriptionsInGroup]+ groupUuid:" + groupUuid);
}
@@ -2951,7 +2957,8 @@
try {
ISub iSub = TelephonyManager.getSubscriptionService();
if (iSub != null) {
- result = iSub.getSubscriptionsInGroup(groupUuid, contextPkg, contextFeature);
+ result = iSub.getSubscriptionsInGroup(groupUuid, contextPkg,
+ contextAttributionTag);
} else {
if (!isSystemProcess()) {
throw new IllegalStateException("telephony service is null.");
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 23a2b9c..610ec5e 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -345,10 +345,10 @@
mSubId = subId;
Context appContext = context.getApplicationContext();
if (appContext != null) {
- if (Objects.equals(context.getFeatureId(), appContext.getFeatureId())) {
+ if (Objects.equals(context.getAttributionTag(), appContext.getAttributionTag())) {
mContext = appContext;
} else {
- mContext = appContext.createFeatureContext(context.getFeatureId());
+ mContext = appContext.createAttributionContext(context.getAttributionTag());
}
} else {
mContext = context;
@@ -393,12 +393,12 @@
}
}
- private String getFeatureId() {
+ private String getAttributionTag() {
// For legacy reasons the TelephonyManager has API for getting
// a static instance with no context set preventing us from
- // getting the feature Id.
+ // getting the attribution tag.
if (mContext != null) {
- return mContext.getFeatureId();
+ return mContext.getAttributionTag();
}
return null;
}
@@ -1896,7 +1896,7 @@
try {
return telephony.getDeviceSoftwareVersionForSlot(slotIndex, getOpPackageName(),
- getFeatureId());
+ getAttributionTag());
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
@@ -1938,7 +1938,7 @@
if (telephony == null)
return null;
return telephony.getDeviceIdWithFeature(mContext.getOpPackageName(),
- mContext.getFeatureId());
+ mContext.getAttributionTag());
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
@@ -1983,7 +1983,7 @@
if (info == null)
return null;
return info.getDeviceIdForPhone(slotIndex, mContext.getOpPackageName(),
- mContext.getFeatureId());
+ mContext.getAttributionTag());
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
@@ -2041,7 +2041,7 @@
if (telephony == null) return null;
try {
- return telephony.getImeiForSlot(slotIndex, getOpPackageName(), getFeatureId());
+ return telephony.getImeiForSlot(slotIndex, getOpPackageName(), getAttributionTag());
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
@@ -2135,7 +2135,8 @@
if (telephony == null) return null;
try {
- String meid = telephony.getMeidForSlot(slotIndex, getOpPackageName(), getFeatureId());
+ String meid = telephony.getMeidForSlot(slotIndex, getOpPackageName(),
+ getAttributionTag());
if (TextUtils.isEmpty(meid)) {
Log.d(TAG, "getMeid: return null because MEID is not available");
return null;
@@ -2237,7 +2238,7 @@
if (info == null)
return null;
String nai = info.getNaiForSubscriber(subId, mContext.getOpPackageName(),
- mContext.getFeatureId());
+ mContext.getAttributionTag());
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Rlog.v(TAG, "Nai = " + nai);
}
@@ -2271,7 +2272,7 @@
}
CellIdentity cellIdentity = telephony.getCellLocation(mContext.getOpPackageName(),
- mContext.getFeatureId());
+ mContext.getAttributionTag());
CellLocation cl = cellIdentity.asCellLocation();
if (cl == null || cl.isEmpty()) {
Rlog.d(TAG, "getCellLocation returning null because CellLocation is empty or"
@@ -2355,7 +2356,7 @@
if (telephony == null)
return null;
return telephony.getNeighboringCellInfo(mContext.getOpPackageName(),
- mContext.getFeatureId());
+ mContext.getAttributionTag());
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
@@ -2371,7 +2372,12 @@
public static final int PHONE_TYPE_CDMA = PhoneConstants.PHONE_TYPE_CDMA;
/** Phone is via SIP. */
public static final int PHONE_TYPE_SIP = PhoneConstants.PHONE_TYPE_SIP;
- /** Phone is via IMS. */
+
+ /**
+ * Phone is via IMS.
+ *
+ * @hide
+ */
public static final int PHONE_TYPE_IMS = PhoneConstants.PHONE_TYPE_IMS;
/**
@@ -2379,7 +2385,6 @@
*
* @hide
*/
- @SystemApi
public static final int PHONE_TYPE_THIRD_PARTY = PhoneConstants.PHONE_TYPE_THIRD_PARTY;
/**
@@ -2957,7 +2962,7 @@
ITelephony telephony = getITelephony();
if (telephony != null) {
return telephony.getNetworkTypeForSubscriber(subId, getOpPackageName(),
- getFeatureId());
+ getAttributionTag());
} else {
// This can happen when the ITelephony interface is not up yet.
return NETWORK_TYPE_UNKNOWN;
@@ -3022,7 +3027,7 @@
ITelephony telephony = getITelephony();
if (telephony != null) {
return telephony.getDataNetworkTypeForSubscriber(subId, getOpPackageName(),
- getFeatureId());
+ getAttributionTag());
} else {
// This can happen when the ITelephony interface is not up yet.
return NETWORK_TYPE_UNKNOWN;
@@ -3059,7 +3064,7 @@
ITelephony telephony = getITelephony();
if (telephony != null) {
return telephony.getVoiceNetworkTypeForSubscriber(subId, getOpPackageName(),
- getFeatureId());
+ getAttributionTag());
} else {
// This can happen when the ITelephony interface is not up yet.
return NETWORK_TYPE_UNKNOWN;
@@ -3763,29 +3768,6 @@
}
/**
- * Returns the ISO-3166 country code equivalent for the SIM provider's country code
- * of the default subscription
- * <p>
- * The ISO-3166 country code is provided in lowercase 2 character format.
- * @return the lowercase 2 character ISO-3166 country code, or empty string is not available.
- * <p>
- * Note: This API is introduced to unblock mainlining work as the following APIs in
- * Linkify.java invokes getSimCountryIso() without a context. TODO(Bug 144576376): remove
- * this API once the following APIs are redesigned to access telephonymanager with a context.
- *
- * {@link Linkify#addLinks(@NonNull Spannable text, @LinkifyMask int mask)}
- * {@link Linkify#addLinks(@NonNull Spannable text, @LinkifyMask int mask,
- @Nullable Function<String, URLSpan> urlSpanFactory)}
- *
- * @hide
- */
- @SystemApi
- @NonNull
- public static String getDefaultSimCountryIso() {
- return getSimCountryIso(SubscriptionManager.getDefaultSubscriptionId());
- }
-
- /**
* Returns the ISO country code equivalent for the SIM provider's country code.
*
* @param subId for which SimCountryIso is returned
@@ -3868,7 +3850,7 @@
if (info == null)
return null;
return info.getIccSerialNumberForSubscriber(subId, mContext.getOpPackageName(),
- mContext.getFeatureId());
+ mContext.getAttributionTag());
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
@@ -3912,7 +3894,7 @@
if (telephony == null)
return PhoneConstants.LTE_ON_CDMA_UNKNOWN;
return telephony.getLteOnCdmaModeForSubscriber(subId, getOpPackageName(),
- getFeatureId());
+ getAttributionTag());
} catch (RemoteException ex) {
// Assume no ICC card if remote exception which shouldn't happen
return PhoneConstants.LTE_ON_CDMA_UNKNOWN;
@@ -4141,7 +4123,7 @@
if (info == null)
return null;
return info.getSubscriberIdForSubscriber(subId, mContext.getOpPackageName(),
- mContext.getFeatureId());
+ mContext.getAttributionTag());
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
@@ -4309,7 +4291,7 @@
if (info == null)
return null;
return info.getGroupIdLevel1ForSubscriber(getSubId(), mContext.getOpPackageName(),
- mContext.getFeatureId());
+ mContext.getAttributionTag());
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
@@ -4333,7 +4315,7 @@
if (info == null)
return null;
return info.getGroupIdLevel1ForSubscriber(subId, mContext.getOpPackageName(),
- mContext.getFeatureId());
+ mContext.getAttributionTag());
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
@@ -4384,7 +4366,7 @@
ITelephony telephony = getITelephony();
if (telephony != null)
number = telephony.getLine1NumberForDisplay(subId, mContext.getOpPackageName(),
- mContext.getFeatureId());
+ mContext.getAttributionTag());
} catch (RemoteException ex) {
} catch (NullPointerException ex) {
}
@@ -4396,7 +4378,7 @@
if (info == null)
return null;
return info.getLine1NumberForSubscriber(subId, mContext.getOpPackageName(),
- mContext.getFeatureId());
+ mContext.getAttributionTag());
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
@@ -4475,7 +4457,7 @@
ITelephony telephony = getITelephony();
if (telephony != null)
alphaTag = telephony.getLine1AlphaTagForDisplay(subId,
- getOpPackageName(), getFeatureId());
+ getOpPackageName(), getAttributionTag());
} catch (RemoteException ex) {
} catch (NullPointerException ex) {
}
@@ -4487,7 +4469,7 @@
if (info == null)
return null;
return info.getLine1AlphaTagForSubscriber(subId, getOpPackageName(),
- getFeatureId());
+ getAttributionTag());
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
@@ -4517,7 +4499,7 @@
ITelephony telephony = getITelephony();
if (telephony != null)
return telephony.getMergedSubscriberIds(getSubId(), getOpPackageName(),
- getFeatureId());
+ getAttributionTag());
} catch (RemoteException ex) {
} catch (NullPointerException ex) {
}
@@ -4574,7 +4556,7 @@
IPhoneSubInfo info = getSubscriberInfoService();
if (info == null)
return null;
- return info.getMsisdnForSubscriber(subId, getOpPackageName(), getFeatureId());
+ return info.getMsisdnForSubscriber(subId, getOpPackageName(), getAttributionTag());
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
@@ -4609,7 +4591,7 @@
if (info == null)
return null;
return info.getVoiceMailNumberForSubscriber(subId, getOpPackageName(),
- getFeatureId());
+ getAttributionTag());
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
@@ -4734,7 +4716,7 @@
ITelephony telephony = getITelephony();
if (telephony != null) {
return telephony.getVisualVoicemailPackageName(mContext.getOpPackageName(),
- getFeatureId(), getSubId());
+ getAttributionTag(), getSubId());
}
} catch (RemoteException ex) {
} catch (NullPointerException ex) {
@@ -5171,7 +5153,7 @@
if (telephony == null)
return 0;
return telephony.getVoiceMessageCountForSubscriber(subId, getOpPackageName(),
- getFeatureId());
+ getAttributionTag());
} catch (RemoteException ex) {
return 0;
} catch (NullPointerException ex) {
@@ -5208,7 +5190,7 @@
if (info == null)
return null;
return info.getVoiceMailAlphaTagForSubscriber(subId, getOpPackageName(),
- getFeatureId());
+ getAttributionTag());
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
@@ -5591,7 +5573,7 @@
(TelephonyRegistryManager)
mContext.getSystemService(Context.TELEPHONY_REGISTRY_SERVICE);
if (telephonyRegistry != null) {
- telephonyRegistry.listenForSubscriber(mSubId, getOpPackageName(), getFeatureId(),
+ telephonyRegistry.listenForSubscriber(mSubId, getOpPackageName(), getAttributionTag(),
listener, events, notifyNow);
} else {
Rlog.w(TAG, "telephony registry not ready.");
@@ -5624,7 +5606,7 @@
if (telephony == null)
return -1;
return telephony.getCdmaEriIconIndexForSubscriber(subId, getOpPackageName(),
- getFeatureId());
+ getAttributionTag());
} catch (RemoteException ex) {
// the phone process is restarting.
return -1;
@@ -5648,7 +5630,7 @@
if (telephony == null)
return -1;
return telephony.getCdmaEriIconModeForSubscriber(subId, getOpPackageName(),
- getFeatureId());
+ getAttributionTag());
} catch (RemoteException ex) {
// the phone process is restarting.
return -1;
@@ -5680,7 +5662,7 @@
if (telephony == null)
return null;
return telephony.getCdmaEriTextForSubscriber(subId, getOpPackageName(),
- getFeatureId());
+ getAttributionTag());
} catch (RemoteException ex) {
// the phone process is restarting.
return null;
@@ -5772,7 +5754,7 @@
ITelephony telephony = getITelephony();
if (telephony == null)
return null;
- return telephony.getAllCellInfo(getOpPackageName(), getFeatureId());
+ return telephony.getAllCellInfo(getOpPackageName(), getAttributionTag());
} catch (RemoteException ex) {
} catch (NullPointerException ex) {
}
@@ -5872,7 +5854,7 @@
Binder.restoreCallingIdentity(identity);
}
}
- }, getOpPackageName(), getFeatureId());
+ }, getOpPackageName(), getAttributionTag());
} catch (RemoteException ex) {
}
}
@@ -5923,7 +5905,7 @@
Binder.restoreCallingIdentity(identity);
}
}
- }, getOpPackageName(), getFeatureId(), workSource);
+ }, getOpPackageName(), getAttributionTag(), workSource);
} catch (RemoteException ex) {
}
}
@@ -7209,7 +7191,7 @@
if (telephony == null)
return null;
return telephony.getForbiddenPlmns(subId, appType, mContext.getOpPackageName(),
- getFeatureId());
+ getAttributionTag());
} catch (RemoteException ex) {
return null;
} catch (NullPointerException ex) {
@@ -7243,7 +7225,7 @@
ITelephony telephony = getITelephony();
if (telephony == null) return -1;
return telephony.setForbiddenPlmns(
- getSubId(), APPTYPE_USIM, fplmns, getOpPackageName(), getFeatureId());
+ getSubId(), APPTYPE_USIM, fplmns, getOpPackageName(), getAttributionTag());
} catch (RemoteException ex) {
Rlog.e(TAG, "setForbiddenPlmns RemoteException: " + ex.getMessage());
} catch (NullPointerException ex) {
@@ -7264,7 +7246,7 @@
ITelephony telephony = getITelephony();
if (telephony == null)
return new String[0];
- return telephony.getPcscfAddress(apnType, getOpPackageName(), getFeatureId());
+ return telephony.getPcscfAddress(apnType, getOpPackageName(), getAttributionTag());
} catch (RemoteException e) {
return new String[0];
}
@@ -7837,7 +7819,7 @@
ITelephony telephony = getITelephony();
if (telephony != null) {
return telephony.getCellNetworkScanResults(getSubId(), getOpPackageName(),
- getFeatureId());
+ getAttributionTag());
}
} catch (RemoteException ex) {
Rlog.e(TAG, "getAvailableNetworks RemoteException", ex);
@@ -7892,7 +7874,7 @@
}
}
return mTelephonyScanManager.requestNetworkScan(getSubId(), request, executor, callback,
- getOpPackageName(), getFeatureId());
+ getOpPackageName(), getAttributionTag());
}
/**
@@ -8646,7 +8628,7 @@
try {
ITelephony telephony = getITelephony();
if (telephony != null)
- return telephony.isRadioOnWithFeature(getOpPackageName(), getFeatureId());
+ return telephony.isRadioOnWithFeature(getOpPackageName(), getAttributionTag());
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelephony#isRadioOn", e);
}
@@ -8725,7 +8707,6 @@
*
* @hide
*/
- @SystemApi
@Nullable
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public PinResult supplyPinReportPinResult(@NonNull String pin) {
@@ -8750,7 +8731,6 @@
*
* @hide
*/
- @SystemApi
@Nullable
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public PinResult supplyPukReportPinResult(@NonNull String puk, @NonNull String pin) {
@@ -8942,7 +8922,10 @@
}
/**
- * Shut down all the live radios over all the slot index.
+ * Shut down all the live radios over all the slot indexes.
+ *
+ * <p>To know when the radio has completed powering off, use
+ * {@link PhoneStateListener#LISTEN_SERVICE_STATE LISTEN_SERVICE_STATE}.
*
* @hide
*/
@@ -8955,7 +8938,8 @@
telephony.shutdownMobileRadios();
}
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#shutdownMobileRadios", e);
+ Log.e(TAG, "Error calling ITelephony#shutdownAllRadios", e);
+ e.rethrowAsRuntimeException();
}
}
@@ -8974,7 +8958,8 @@
return telephony.needMobileRadioShutdown();
}
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelephony#needMobileRadioShutdown", e);
+ Log.e(TAG, "Error calling ITelephony#isAnyRadioPoweredOn", e);
+ e.rethrowAsRuntimeException();
}
return false;
}
@@ -9017,7 +9002,7 @@
ITelephony telephony = getITelephony();
if (telephony != null) {
return telephony.getRadioPowerState(getSlotIndex(), mContext.getOpPackageName(),
- mContext.getFeatureId());
+ mContext.getAttributionTag());
}
} catch (RemoteException ex) {
// This could happen if binder process crashes.
@@ -9408,7 +9393,7 @@
try {
ITelephony telephony = getITelephony();
if (telephony != null)
- return telephony.isVideoCallingEnabled(getOpPackageName(), getFeatureId());
+ return telephony.isVideoCallingEnabled(getOpPackageName(), getAttributionTag());
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelephony#isVideoCallingEnabled", e);
}
@@ -9425,7 +9410,7 @@
ITelephony telephony = getITelephony();
if (telephony != null) {
return telephony.canChangeDtmfToneLength(mSubId, getOpPackageName(),
- getFeatureId());
+ getAttributionTag());
}
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelephony#canChangeDtmfToneLength", e);
@@ -9444,7 +9429,7 @@
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
- return telephony.isWorldPhone(mSubId, getOpPackageName(), getFeatureId());
+ return telephony.isWorldPhone(mSubId, getOpPackageName(), getAttributionTag());
}
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelephony#isWorldPhone", e);
@@ -10172,7 +10157,8 @@
ITelephony service = getITelephony();
if (service != null) {
retval = service.getSubIdForPhoneAccountHandle(
- phoneAccountHandle, mContext.getOpPackageName(), mContext.getFeatureId());
+ phoneAccountHandle, mContext.getOpPackageName(),
+ mContext.getAttributionTag());
}
} catch (RemoteException ex) {
Log.e(TAG, "getSubscriptionId RemoteException", ex);
@@ -10313,7 +10299,7 @@
ITelephony service = getITelephony();
if (service != null) {
return service.getServiceStateForSubscriber(subId, getOpPackageName(),
- getFeatureId());
+ getAttributionTag());
}
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelephony#getServiceStateForSubscriber", e);
@@ -11034,7 +11020,8 @@
try {
ITelephony service = getITelephony();
if (service != null) {
- return service.getClientRequestStats(getOpPackageName(), getFeatureId(), subId);
+ return service.getClientRequestStats(getOpPackageName(), getAttributionTag(),
+ subId);
}
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelephony#getClientRequestStats", e);
@@ -11145,21 +11132,21 @@
}
/**
- * Checks whether cellular data connection is enabled in the device.
+ * Checks whether cellular data connection is allowed in the device.
*
- * Whether cellular data connection is enabled, meaning upon request whether will try to setup
- * metered data connection considering all factors below:
- * 1) User turned on data setting {@link #isDataEnabled}.
- * 2) Carrier allows data to be on.
- * 3) Network policy.
- * And possibly others.
- *
- * @return {@code true} if the overall data connection is capable; {@code false} if not.
+ * <p>Whether cellular data connection is allowed considers all factors below:
+ * <UL>
+ * <LI>User turned on data setting {@link #isDataEnabled}.</LI>
+ * <LI>Carrier allows data to be on.</LI>
+ * <LI>Network policy.</LI>
+ * <LI>And possibly others.</LI>
+ * </UL>
+ * @return {@code true} if the overall data connection is allowed; {@code false} if not.
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
- public boolean isDataConnectionEnabled() {
+ public boolean isDataConnectionAllowed() {
boolean retVal = false;
try {
int subId = getSubId(SubscriptionManager.getDefaultDataSubscriptionId());
@@ -11167,8 +11154,9 @@
if (telephony != null)
retVal = telephony.isDataEnabled(subId);
} catch (RemoteException e) {
- Log.e(TAG, "Error isDataConnectionEnabled", e);
+ Log.e(TAG, "Error isDataConnectionAllowed", e);
} catch (NullPointerException e) {
+ return false;
}
return retVal;
}
@@ -11319,7 +11307,7 @@
ITelephony telephony = getITelephony();
if (telephony != null) {
return telephony.getNumberOfModemsWithSimultaneousDataConnections(
- getSubId(), getOpPackageName(), getFeatureId());
+ getSubId(), getOpPackageName(), getAttributionTag());
}
} catch (RemoteException ex) {
// This could happen if binder process crashes.
@@ -11749,7 +11737,7 @@
ITelephony telephony = getITelephony();
if (telephony != null) {
return telephony.getEmergencyNumberList(mContext.getOpPackageName(),
- mContext.getFeatureId());
+ mContext.getAttributionTag());
} else {
throw new IllegalStateException("telephony service is null.");
}
@@ -11804,7 +11792,7 @@
ITelephony telephony = getITelephony();
if (telephony != null) {
emergencyNumberList = telephony.getEmergencyNumberList(
- mContext.getOpPackageName(), mContext.getFeatureId());
+ mContext.getOpPackageName(), mContext.getAttributionTag());
if (emergencyNumberList != null) {
for (Integer subscriptionId : emergencyNumberList.keySet()) {
List<EmergencyNumber> numberList = emergencyNumberList.get(subscriptionId);
@@ -11897,7 +11885,7 @@
}
/**
- * A test API to return the emergency number db version.
+ * Returns the emergency number database version.
*
* <p>Requires Permission:
* {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE READ_PRIVILEGED_PHONE_STATE}
@@ -11906,6 +11894,7 @@
*/
@TestApi
@SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public int getEmergencyNumberDbVersion() {
try {
ITelephony telephony = getITelephony();
@@ -12112,13 +12101,13 @@
})
public int getPreferredOpportunisticDataSubscription() {
String packageName = mContext != null ? mContext.getOpPackageName() : "<unknown>";
- String featureId = mContext != null ? mContext.getFeatureId() : null;
+ String attributionTag = mContext != null ? mContext.getAttributionTag() : null;
int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
try {
IOns iOpportunisticNetworkService = getIOns();
if (iOpportunisticNetworkService != null) {
subId = iOpportunisticNetworkService.getPreferredDataSubscriptionId(
- packageName, featureId);
+ packageName, attributionTag);
}
} catch (RemoteException ex) {
Rlog.e(TAG, "getPreferredDataSubscriptionId RemoteException", ex);
@@ -12235,18 +12224,20 @@
/**
* It indicates whether modem is enabled or not per slot.
- * It's the corresponding status of {@link #enableModemForSlot}.
+ * It's the corresponding status of TelephonyManager.enableModemForSlot.
*
+ * <p>Requires Permission:
+ * READ_PRIVILEGED_PHONE_STATE or
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
* @param slotIndex which slot it's checking.
- * @hide
*/
- @SystemApi
+ @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public boolean isModemEnabledForSlot(int slotIndex) {
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
return telephony.isModemEnabledForSlot(slotIndex, mContext.getOpPackageName(),
- mContext.getFeatureId());
+ mContext.getAttributionTag());
}
} catch (RemoteException ex) {
Log.e(TAG, "enableModem RemoteException", ex);
@@ -12351,7 +12342,7 @@
try {
ITelephony service = getITelephony();
if (service != null) {
- return service.isMultiSimSupported(getOpPackageName(), getFeatureId());
+ return service.isMultiSimSupported(getOpPackageName(), getAttributionTag());
}
} catch (RemoteException e) {
Log.e(TAG, "isMultiSimSupported RemoteException", e);
@@ -12403,7 +12394,7 @@
ITelephony service = getITelephony();
if (service != null) {
return service.doesSwitchMultiSimConfigTriggerReboot(getSubId(),
- getOpPackageName(), getFeatureId());
+ getOpPackageName(), getAttributionTag());
}
} catch (RemoteException e) {
Log.e(TAG, "doesSwitchMultiSimConfigTriggerReboot RemoteException", e);
@@ -12472,7 +12463,6 @@
* @throws {@link SecurityException} if the caller is not the system or phone process.
* @hide
*/
- @SystemApi
@TestApi
// TODO: add new permission tag indicating that this is system-only.
public @NonNull List<ApnSetting> getDevicePolicyOverrideApns(@NonNull Context context) {
@@ -12503,7 +12493,6 @@
* @throws {@link SecurityException} if the caller is not the system or phone process.
* @hide
*/
- @SystemApi
@TestApi
// TODO: add new permission tag indicating that this is system-only.
public int addDevicePolicyOverrideApn(@NonNull Context context,
@@ -12534,7 +12523,6 @@
* @throws {@link SecurityException} if the caller is not the system or phone process.
* @hide
*/
- @SystemApi
@TestApi
// TODO: add new permission tag indicating that this is system-only.
public boolean modifyDevicePolicyOverrideApn(@NonNull Context context, int apnId,
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index f5dfacc6..bfb54b0 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -18,7 +18,6 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.annotation.SystemApi;
import android.content.ContentValues;
import android.database.Cursor;
import android.hardware.radio.V1_5.ApnTypes;
@@ -27,7 +26,6 @@
import android.os.Parcelable;
import android.provider.Telephony;
import android.provider.Telephony.Carriers;
-import android.telephony.Annotation;
import android.telephony.Annotation.ApnType;
import android.telephony.Annotation.NetworkType;
import android.telephony.ServiceState;
@@ -126,6 +124,15 @@
/** Authentication type for PAP or CHAP. */
public static final int AUTH_TYPE_PAP_OR_CHAP = 3;
+ /** @hide */
+ @IntDef({
+ Telephony.Carriers.SKIP_464XLAT_DEFAULT,
+ Telephony.Carriers.SKIP_464XLAT_DISABLE,
+ Telephony.Carriers.SKIP_464XLAT_ENABLE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Skip464XlatStatus {}
+
/**
* APN types for data connections. These are usage categories for an APN
* entry. One APN entry may support multiple APN types, eg, a single APN
@@ -139,7 +146,6 @@
*
* @hide
*/
- @SystemApi
public static final String TYPE_ALL_STRING = "*";
/**
@@ -147,7 +153,6 @@
*
* @hide
*/
- @SystemApi
public static final String TYPE_DEFAULT_STRING = "default";
@@ -156,7 +161,6 @@
*
* @hide
*/
- @SystemApi
public static final String TYPE_MMS_STRING = "mms";
@@ -165,7 +169,6 @@
*
* @hide
*/
- @SystemApi
public static final String TYPE_SUPL_STRING = "supl";
/**
@@ -173,7 +176,6 @@
*
* @hide
*/
- @SystemApi
public static final String TYPE_DUN_STRING = "dun";
/**
@@ -181,7 +183,6 @@
*
* @hide
*/
- @SystemApi
public static final String TYPE_HIPRI_STRING = "hipri";
/**
@@ -189,7 +190,6 @@
*
* @hide
*/
- @SystemApi
public static final String TYPE_FOTA_STRING = "fota";
/**
@@ -197,7 +197,6 @@
*
* @hide
*/
- @SystemApi
public static final String TYPE_IMS_STRING = "ims";
/**
@@ -205,7 +204,6 @@
*
* @hide
*/
- @SystemApi
public static final String TYPE_CBS_STRING = "cbs";
/**
@@ -213,7 +211,6 @@
*
* @hide
*/
- @SystemApi
public static final String TYPE_IA_STRING = "ia";
/**
@@ -222,7 +219,6 @@
*
* @hide
*/
- @SystemApi
public static final String TYPE_EMERGENCY_STRING = "emergency";
/**
@@ -230,7 +226,6 @@
*
* @hide
*/
- @SystemApi
public static final String TYPE_MCX_STRING = "mcx";
/**
@@ -238,7 +233,6 @@
*
* @hide
*/
- @SystemApi
public static final String TYPE_XCAP_STRING = "xcap";
@@ -745,7 +739,7 @@
* @return SKIP_464XLAT_DEFAULT, SKIP_464XLAT_DISABLE or SKIP_464XLAT_ENABLE
* @hide
*/
- @Annotation.Skip464XlatStatus
+ @Skip464XlatStatus
public int getSkip464Xlat() {
return mSkip464Xlat;
}
@@ -1416,7 +1410,6 @@
* @return comma delimited list of APN types.
* @hide
*/
- @SystemApi
@NonNull
public static String getApnTypesStringFromBitmask(int apnTypeBitmask) {
List<String> types = new ArrayList<>();
@@ -2065,7 +2058,7 @@
* @param skip464xlat skip464xlat for this APN.
* @hide
*/
- public Builder setSkip464Xlat(@Annotation.Skip464XlatStatus int skip464xlat) {
+ public Builder setSkip464Xlat(@Skip464XlatStatus int skip464xlat) {
this.mSkip464Xlat = skip464xlat;
return this;
}
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index 3341fa7..4b5303f 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -294,8 +294,15 @@
throw new IllegalArgumentException("Must include a non-null Executor.");
}
c.setExecutor(executor);
+
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new ImsException("Could not find Telephony Service.",
+ ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
+
try {
- getITelephony().registerImsRegistrationCallback(mSubId, c.getBinder());
+ iTelephony.registerImsRegistrationCallback(mSubId, c.getBinder());
} catch (ServiceSpecificException e) {
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
// Rethrow as runtime error to keep API compatible.
@@ -331,8 +338,15 @@
throw new IllegalArgumentException("Must include a non-null Executor.");
}
c.setExecutor(executor);
+
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new ImsException("Could not find Telephony Service.",
+ ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
+
try {
- getITelephony().registerImsRegistrationCallback(mSubId, c.getBinder());
+ iTelephony.registerImsRegistrationCallback(mSubId, c.getBinder());
} catch (ServiceSpecificException e) {
throw new ImsException(e.getMessage(), e.errorCode);
} catch (RemoteException | IllegalStateException e) {
@@ -361,8 +375,14 @@
if (c == null) {
throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
}
+
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new RuntimeException("Could not find Telephony Service.");
+ }
+
try {
- getITelephony().unregisterImsRegistrationCallback(mSubId, c.getBinder());
+ iTelephony.unregisterImsRegistrationCallback(mSubId, c.getBinder());
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -387,8 +407,14 @@
if (c == null) {
throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
}
+
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new RuntimeException("Could not find Telephony Service.");
+ }
+
try {
- getITelephony().unregisterImsRegistrationCallback(mSubId, c.getBinder());
+ iTelephony.unregisterImsRegistrationCallback(mSubId, c.getBinder());
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -409,8 +435,14 @@
if (executor == null) {
throw new IllegalArgumentException("Must include a non-null Executor.");
}
+
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new RuntimeException("Could not find Telephony Service.");
+ }
+
try {
- getITelephony().getImsMmTelRegistrationState(mSubId, new IIntegerConsumer.Stub() {
+ iTelephony.getImsMmTelRegistrationState(mSubId, new IIntegerConsumer.Stub() {
@Override
public void accept(int result) {
executor.execute(() -> stateCallback.accept(result));
@@ -443,8 +475,14 @@
if (executor == null) {
throw new IllegalArgumentException("Must include a non-null Executor.");
}
+
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new RuntimeException("Could not find Telephony Service.");
+ }
+
try {
- getITelephony().getImsMmTelRegistrationTransportType(mSubId,
+ iTelephony.getImsMmTelRegistrationTransportType(mSubId,
new IIntegerConsumer.Stub() {
@Override
public void accept(int result) {
@@ -506,8 +544,15 @@
throw new IllegalArgumentException("Must include a non-null Executor.");
}
c.setExecutor(executor);
+
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new ImsException("Could not find Telephony Service.",
+ ImsException.CODE_ERROR_INVALID_SUBSCRIPTION);
+ }
+
try {
- getITelephony().registerMmTelCapabilityCallback(mSubId, c.getBinder());
+ iTelephony.registerMmTelCapabilityCallback(mSubId, c.getBinder());
} catch (ServiceSpecificException e) {
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
// Rethrow as runtime error to keep API compatible.
@@ -553,8 +598,14 @@
if (c == null) {
throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
}
+
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new RuntimeException("Could not find Telephony Service.");
+ }
+
try {
- getITelephony().unregisterMmTelCapabilityCallback(mSubId, c.getBinder());
+ iTelephony.unregisterMmTelCapabilityCallback(mSubId, c.getBinder());
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -599,8 +650,13 @@
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
android.Manifest.permission.READ_PRECISE_PHONE_STATE})
public boolean isAdvancedCallingSettingEnabled() {
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new RuntimeException("Could not find Telephony Service.");
+ }
+
try {
- return getITelephony().isAdvancedCallingSettingEnabled(mSubId);
+ return iTelephony.isAdvancedCallingSettingEnabled(mSubId);
} catch (ServiceSpecificException e) {
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
// Rethrow as runtime error to keep API compatible.
@@ -640,8 +696,13 @@
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
@SystemApi @TestApi
public void setAdvancedCallingSettingEnabled(boolean isEnabled) {
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new RuntimeException("Could not find Telephony Service.");
+ }
+
try {
- getITelephony().setAdvancedCallingSettingEnabled(mSubId, isEnabled);
+ iTelephony.setAdvancedCallingSettingEnabled(mSubId, isEnabled);
} catch (ServiceSpecificException e) {
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
// Rethrow as runtime error to keep API compatible.
@@ -680,8 +741,13 @@
@SystemApi @TestApi
public boolean isCapable(@MmTelFeature.MmTelCapabilities.MmTelCapability int capability,
@ImsRegistrationImplBase.ImsRegistrationTech int imsRegTech) {
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new RuntimeException("Could not find Telephony Service.");
+ }
+
try {
- return getITelephony().isCapable(mSubId, capability, imsRegTech);
+ return iTelephony.isCapable(mSubId, capability, imsRegTech);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -709,8 +775,13 @@
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public boolean isAvailable(@MmTelFeature.MmTelCapabilities.MmTelCapability int capability,
@ImsRegistrationImplBase.ImsRegistrationTech int imsRegTech) {
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new RuntimeException("Could not find Telephony Service.");
+ }
+
try {
- return getITelephony().isAvailable(mSubId, capability, imsRegTech);
+ return iTelephony.isAvailable(mSubId, capability, imsRegTech);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
@@ -744,6 +815,13 @@
if (executor == null) {
throw new IllegalArgumentException("Must include a non-null Executor.");
}
+
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new ImsException("Could not find Telephony Service.",
+ ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
+
try {
getITelephony().isMmTelCapabilitySupported(mSubId, new IIntegerConsumer.Stub() {
@Override
@@ -788,8 +866,13 @@
android.Manifest.permission.READ_PRECISE_PHONE_STATE})
@SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236).
public boolean isVtSettingEnabled() {
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new RuntimeException("Could not find Telephony Service.");
+ }
+
try {
- return getITelephony().isVtSettingEnabled(mSubId);
+ return iTelephony.isVtSettingEnabled(mSubId);
} catch (ServiceSpecificException e) {
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
// Rethrow as runtime error to keep API compatible.
@@ -813,8 +896,13 @@
@SystemApi @TestApi
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setVtSettingEnabled(boolean isEnabled) {
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new RuntimeException("Could not find Telephony Service.");
+ }
+
try {
- getITelephony().setVtSettingEnabled(mSubId, isEnabled);
+ iTelephony.setVtSettingEnabled(mSubId, isEnabled);
} catch (ServiceSpecificException e) {
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
// Rethrow as runtime error to keep API compatible.
@@ -853,8 +941,13 @@
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
android.Manifest.permission.READ_PRECISE_PHONE_STATE})
public boolean isVoWiFiSettingEnabled() {
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new RuntimeException("Could not find Telephony Service.");
+ }
+
try {
- return getITelephony().isVoWiFiSettingEnabled(mSubId);
+ return iTelephony.isVoWiFiSettingEnabled(mSubId);
} catch (ServiceSpecificException e) {
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
// Rethrow as runtime error to keep API compatible.
@@ -879,8 +972,13 @@
@SystemApi @TestApi
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setVoWiFiSettingEnabled(boolean isEnabled) {
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new RuntimeException("Could not find Telephony Service.");
+ }
+
try {
- getITelephony().setVoWiFiSettingEnabled(mSubId, isEnabled);
+ iTelephony.setVoWiFiSettingEnabled(mSubId, isEnabled);
} catch (ServiceSpecificException e) {
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
// Rethrow as runtime error to keep API compatible.
@@ -921,8 +1019,13 @@
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
android.Manifest.permission.READ_PRECISE_PHONE_STATE})
public boolean isVoWiFiRoamingSettingEnabled() {
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new RuntimeException("Could not find Telephony Service.");
+ }
+
try {
- return getITelephony().isVoWiFiRoamingSettingEnabled(mSubId);
+ return iTelephony.isVoWiFiRoamingSettingEnabled(mSubId);
} catch (ServiceSpecificException e) {
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
// Rethrow as runtime error to keep API compatible.
@@ -948,8 +1051,13 @@
@SystemApi @TestApi
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setVoWiFiRoamingSettingEnabled(boolean isEnabled) {
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new RuntimeException("Could not find Telephony Service.");
+ }
+
try {
- getITelephony().setVoWiFiRoamingSettingEnabled(mSubId, isEnabled);
+ iTelephony.setVoWiFiRoamingSettingEnabled(mSubId, isEnabled);
} catch (ServiceSpecificException e) {
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
// Rethrow as runtime error to keep API compatible.
@@ -980,8 +1088,13 @@
@SystemApi @TestApi
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setVoWiFiNonPersistent(boolean isCapable, int mode) {
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new RuntimeException("Could not find Telephony Service.");
+ }
+
try {
- getITelephony().setVoWiFiNonPersistent(mSubId, isCapable, mode);
+ iTelephony.setVoWiFiNonPersistent(mSubId, isCapable, mode);
} catch (ServiceSpecificException e) {
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
// Rethrow as runtime error to keep API compatible.
@@ -1025,8 +1138,13 @@
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
android.Manifest.permission.READ_PRECISE_PHONE_STATE})
public @WiFiCallingMode int getVoWiFiModeSetting() {
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new RuntimeException("Could not find Telephony Service.");
+ }
+
try {
- return getITelephony().getVoWiFiModeSetting(mSubId);
+ return iTelephony.getVoWiFiModeSetting(mSubId);
} catch (ServiceSpecificException e) {
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
// Rethrow as runtime error to keep API compatible.
@@ -1054,8 +1172,13 @@
@SystemApi @TestApi
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setVoWiFiModeSetting(@WiFiCallingMode int mode) {
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new RuntimeException("Could not find Telephony Service.");
+ }
+
try {
- getITelephony().setVoWiFiModeSetting(mSubId, mode);
+ iTelephony.setVoWiFiModeSetting(mSubId, mode);
} catch (ServiceSpecificException e) {
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
// Rethrow as runtime error to keep API compatible.
@@ -1085,8 +1208,13 @@
@SystemApi @TestApi
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public @WiFiCallingMode int getVoWiFiRoamingModeSetting() {
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new RuntimeException("Could not find Telephony Service.");
+ }
+
try {
- return getITelephony().getVoWiFiRoamingModeSetting(mSubId);
+ return iTelephony.getVoWiFiRoamingModeSetting(mSubId);
} catch (ServiceSpecificException e) {
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
// Rethrow as runtime error to keep API compatible.
@@ -1116,8 +1244,13 @@
@SystemApi @TestApi
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setVoWiFiRoamingModeSetting(@WiFiCallingMode int mode) {
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new RuntimeException("Could not find Telephony Service.");
+ }
+
try {
- getITelephony().setVoWiFiRoamingModeSetting(mSubId, mode);
+ iTelephony.setVoWiFiRoamingModeSetting(mSubId, mode);
} catch (ServiceSpecificException e) {
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
// Rethrow as runtime error to keep API compatible.
@@ -1145,8 +1278,13 @@
@SystemApi @TestApi
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setRttCapabilitySetting(boolean isEnabled) {
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new RuntimeException("Could not find Telephony Service.");
+ }
+
try {
- getITelephony().setRttCapabilitySetting(mSubId, isEnabled);
+ iTelephony.setRttCapabilitySetting(mSubId, isEnabled);
} catch (ServiceSpecificException e) {
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
// Rethrow as runtime error to keep API compatible.
@@ -1186,8 +1324,13 @@
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
android.Manifest.permission.READ_PRECISE_PHONE_STATE})
public boolean isTtyOverVolteEnabled() {
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new RuntimeException("Could not find Telephony Service.");
+ }
+
try {
- return getITelephony().isTtyOverVolteEnabled(mSubId);
+ return iTelephony.isTtyOverVolteEnabled(mSubId);
} catch (ServiceSpecificException e) {
if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) {
// Rethrow as runtime error to keep API compatible.
@@ -1223,8 +1366,15 @@
if (callback == null) {
throw new IllegalArgumentException("Must include a non-null Consumer.");
}
+
+ ITelephony iTelephony = getITelephony();
+ if (iTelephony == null) {
+ throw new ImsException("Could not find Telephony Service.",
+ ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
+
try {
- getITelephony().getImsMmTelFeatureState(mSubId, new IIntegerConsumer.Stub() {
+ iTelephony.getImsMmTelFeatureState(mSubId, new IIntegerConsumer.Stub() {
@Override
public void accept(int result) {
executor.execute(() -> callback.accept(result));
@@ -1243,9 +1393,6 @@
.getTelephonyServiceManager()
.getTelephonyServiceRegisterer()
.get());
- if (binder == null) {
- throw new RuntimeException("Could not find Telephony Service.");
- }
return binder;
}
}
diff --git a/telephony/java/android/telephony/ims/RcsUceAdapter.java b/telephony/java/android/telephony/ims/RcsUceAdapter.java
index 30306c7..05ab6bd 100644
--- a/telephony/java/android/telephony/ims/RcsUceAdapter.java
+++ b/telephony/java/android/telephony/ims/RcsUceAdapter.java
@@ -291,7 +291,7 @@
try {
imsRcsController.requestCapabilities(mSubId, mContext.getOpPackageName(),
- mContext.getFeatureId(), contactNumbers, internalCallback);
+ mContext.getAttributionTag(), contactNumbers, internalCallback);
} catch (RemoteException e) {
Log.e(TAG, "Error calling IImsRcsController#requestCapabilities", e);
throw new ImsException("Remote IMS Service is not available",
@@ -352,7 +352,7 @@
try {
// Telephony.SimInfo#IMS_RCS_UCE_ENABLED can also be used to listen to changes to this.
return imsRcsController.isUceSettingEnabled(mSubId, mContext.getOpPackageName(),
- mContext.getFeatureId());
+ mContext.getAttributionTag());
} catch (RemoteException e) {
Log.e(TAG, "Error calling IImsRcsController#isUceSettingEnabled", e);
throw new ImsException("Remote IMS Service is not available",
diff --git a/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java b/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java
index 5904916..c7e5a5e 100644
--- a/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java
+++ b/tests/MemoryUsage/src/com/android/tests/memoryusage/MemoryUsageTest.java
@@ -322,7 +322,7 @@
mAtm.startActivityAndWait(null,
getInstrumentation().getContext().getBasePackageName(),
- getInstrumentation().getContext().getFeatureId(), mLaunchIntent,
+ getInstrumentation().getContext().getAttributionTag(), mLaunchIntent,
mimeType, null, null, 0, mLaunchIntent.getFlags(), null, null,
UserHandle.USER_CURRENT_OR_SELF);
} catch (RemoteException e) {
diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
index 819fc02..8cc8cf4 100644
--- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
+++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
@@ -1063,52 +1063,6 @@
assertThat(bootObserver2.mitigatedBootLoop()).isFalse();
}
- /**
- * Test to verify that Package Watchdog syncs health check requests with the controller
- * correctly, and that the requests are only synced when the set of observed packages
- * changes.
- */
- @Test
- public void testSyncHealthCheckRequests() {
- TestController testController = spy(TestController.class);
- testController.setSupportedPackages(List.of(APP_A, APP_B, APP_C));
- PackageWatchdog watchdog = createWatchdog(testController, true);
-
- TestObserver testObserver1 = new TestObserver(OBSERVER_NAME_1);
- watchdog.registerHealthObserver(testObserver1);
- watchdog.startObservingHealth(testObserver1, List.of(APP_A), LONG_DURATION);
- mTestLooper.dispatchAll();
-
- TestObserver testObserver2 = new TestObserver(OBSERVER_NAME_2);
- watchdog.registerHealthObserver(testObserver2);
- watchdog.startObservingHealth(testObserver2, List.of(APP_B), LONG_DURATION);
- mTestLooper.dispatchAll();
-
- TestObserver testObserver3 = new TestObserver(OBSERVER_NAME_3);
- watchdog.registerHealthObserver(testObserver3);
- watchdog.startObservingHealth(testObserver3, List.of(APP_C), LONG_DURATION);
- mTestLooper.dispatchAll();
-
- watchdog.unregisterHealthObserver(testObserver1);
- mTestLooper.dispatchAll();
-
- watchdog.unregisterHealthObserver(testObserver2);
- mTestLooper.dispatchAll();
-
- watchdog.unregisterHealthObserver(testObserver3);
- mTestLooper.dispatchAll();
-
- List<Set> expectedSyncRequests = List.of(
- Set.of(APP_A),
- Set.of(APP_A, APP_B),
- Set.of(APP_A, APP_B, APP_C),
- Set.of(APP_B, APP_C),
- Set.of(APP_C),
- Set.of()
- );
- assertThat(testController.getSyncRequests()).isEqualTo(expectedSyncRequests);
- }
-
private void adoptShellPermissions(String... permissions) {
InstrumentationRegistry
.getInstrumentation()
@@ -1265,7 +1219,6 @@
private Consumer<String> mPassedConsumer;
private Consumer<List<PackageConfig>> mSupportedConsumer;
private Runnable mNotifySyncRunnable;
- private List<Set> mSyncRequests = new ArrayList<>();
@Override
public void setEnabled(boolean enabled) {
@@ -1285,7 +1238,6 @@
@Override
public void syncRequests(Set<String> packages) {
- mSyncRequests.add(packages);
mRequestedPackages.clear();
if (mIsEnabled) {
packages.retainAll(mSupportedPackages);
@@ -1316,10 +1268,6 @@
return Collections.emptyList();
}
}
-
- public List<Set> getSyncRequests() {
- return mSyncRequests;
- }
}
private static class TestClock implements PackageWatchdog.SystemClock {
diff --git a/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java
index 8e6f198..e415170 100644
--- a/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java
+++ b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/WindowInsetsActivity.java
@@ -16,11 +16,15 @@
package com.google.android.test.windowinsetstests;
+import static android.view.WindowInsets.Type.ime;
import static android.view.WindowInsetsAnimation.Callback.DISPATCH_MODE_STOP;
import static java.lang.Math.max;
import static java.lang.Math.min;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
@@ -37,6 +41,8 @@
import android.view.WindowInsetsAnimation.Callback;
import android.view.WindowInsetsAnimationControlListener;
import android.view.WindowInsetsAnimationController;
+import android.view.WindowInsetsController;
+import android.view.WindowInsetsController.OnControllableInsetsChangedListener;
import android.view.animation.LinearInterpolator;
import android.widget.LinearLayout;
@@ -82,8 +88,8 @@
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mDown = event.getY();
- mDownInsets = v.getRootWindowInsets().getInsets(Type.ime());
- mShownAtDown = v.getRootWindowInsets().isVisible(Type.ime());
+ mDownInsets = v.getRootWindowInsets().getInsets(ime());
+ mShownAtDown = v.getRootWindowInsets().isVisible(ime());
mRequestedController = false;
mCurrentRequest = null;
break;
@@ -94,7 +100,7 @@
> mViewConfiguration.getScaledTouchSlop()
&& !mRequestedController) {
mRequestedController = true;
- v.getWindowInsetsController().controlWindowInsetsAnimation(Type.ime(),
+ v.getWindowInsetsController().controlWindowInsetsAnimation(ime(),
1000, new LinearInterpolator(),
mCurrentRequest = new WindowInsetsAnimationControlListener() {
@Override
@@ -189,6 +195,51 @@
getWindow().getDecorView().post(() -> getWindow().setDecorFitsSystemWindows(false));
}
+ @Override
+ public void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ getWindow().getInsetsController().addOnControllableInsetsChangedListener(
+ new OnControllableInsetsChangedListener() {
+
+ boolean hasControl = false;
+ @Override
+ public void onControllableInsetsChanged(WindowInsetsController controller,
+ int types) {
+ if ((types & ime()) != 0 && !hasControl) {
+ hasControl = true;
+ controller.controlWindowInsetsAnimation(ime(), -1,
+ new LinearInterpolator(),
+ new WindowInsetsAnimationControlListener() {
+ @Override
+ public void onReady(
+ WindowInsetsAnimationController controller,
+ int types) {
+ ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
+ anim.setDuration(1500);
+ anim.addUpdateListener(animation
+ -> controller.setInsetsAndAlpha(
+ controller.getShownStateInsets(),
+ (float) animation.getAnimatedValue(),
+ anim.getAnimatedFraction()));
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ controller.finish(true);
+ }
+ });
+ anim.start();
+ }
+
+ @Override
+ public void onCancelled() {
+ }
+ });
+ }
+ }
+ });
+ }
+
static class Transition {
private int mEndBottom;
private int mStartBottom;
@@ -200,7 +251,7 @@
}
void onPrepare(WindowInsetsAnimation animation) {
- if ((animation.getTypeMask() & Type.ime()) != 0) {
+ if ((animation.getTypeMask() & ime()) != 0) {
mInsetsAnimation = animation;
}
mStartBottom = mView.getBottom();
diff --git a/tests/net/common/java/android/net/RouteInfoTest.java b/tests/net/common/java/android/net/RouteInfoTest.java
index fe51b3a..1658262 100644
--- a/tests/net/common/java/android/net/RouteInfoTest.java
+++ b/tests/net/common/java/android/net/RouteInfoTest.java
@@ -19,19 +19,40 @@
import static android.net.RouteInfo.RTN_UNREACHABLE;
import static com.android.testutils.MiscAssertsKt.assertEqualBothWays;
+import static com.android.testutils.MiscAssertsKt.assertFieldCountEquals;
import static com.android.testutils.MiscAssertsKt.assertNotEqualEitherWay;
-import static com.android.testutils.ParcelUtilsKt.assertParcelSane;
import static com.android.testutils.ParcelUtilsKt.assertParcelingIsLossless;
-import android.test.suitebuilder.annotation.SmallTest;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
-import junit.framework.TestCase;
+import android.os.Build;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
-public class RouteInfoTest extends TestCase {
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class RouteInfoTest {
+ @Rule
+ public final DevSdkIgnoreRule ignoreRule = new DevSdkIgnoreRule();
+
+ private static final int INVALID_ROUTE_TYPE = -1;
private InetAddress Address(String addr) {
return InetAddress.parseNumericAddress(addr);
@@ -41,15 +62,32 @@
return new IpPrefix(prefix);
}
- @SmallTest
+ @Test
public void testConstructor() {
RouteInfo r;
-
// Invalid input.
try {
r = new RouteInfo((IpPrefix) null, null, "rmnet0");
fail("Expected RuntimeException: destination and gateway null");
- } catch(RuntimeException e) {}
+ } catch (RuntimeException e) { }
+
+ try {
+ r = new RouteInfo(Prefix("2001:db8:ace::/49"), Address("2001:db8::1"), "rmnet0",
+ INVALID_ROUTE_TYPE);
+ fail("Invalid route type should cause exception");
+ } catch (IllegalArgumentException e) { }
+
+ try {
+ r = new RouteInfo(Prefix("2001:db8:ace::/49"), Address("192.0.2.1"), "rmnet0",
+ RTN_UNREACHABLE);
+ fail("Address family mismatch should cause exception");
+ } catch (IllegalArgumentException e) { }
+
+ try {
+ r = new RouteInfo(Prefix("0.0.0.0/0"), Address("2001:db8::1"), "rmnet0",
+ RTN_UNREACHABLE);
+ fail("Address family mismatch should cause exception");
+ } catch (IllegalArgumentException e) { }
// Null destination is default route.
r = new RouteInfo((IpPrefix) null, Address("2001:db8::1"), null);
@@ -74,6 +112,7 @@
assertNull(r.getInterface());
}
+ @Test
public void testMatches() {
class PatchedRouteInfo {
private final RouteInfo mRouteInfo;
@@ -113,6 +152,7 @@
assertFalse(ipv4Default.matches(Address("2001:db8::f00")));
}
+ @Test
public void testEquals() {
// IPv4
RouteInfo r1 = new RouteInfo(Prefix("2001:db8:ace::/48"), Address("2001:db8::1"), "wlan0");
@@ -146,6 +186,7 @@
assertNotEqualEitherWay(r1, r3);
}
+ @Test
public void testHostAndDefaultRoutes() {
RouteInfo r;
@@ -228,6 +269,7 @@
assertFalse(r.isIPv6Default());
}
+ @Test
public void testTruncation() {
LinkAddress l;
RouteInfo r;
@@ -244,6 +286,7 @@
// Make sure that creating routes to multicast addresses doesn't throw an exception. Even though
// there's nothing we can do with them, we don't want to crash if, e.g., someone calls
// requestRouteToHostAddress("230.0.0.0", MOBILE_HIPRI);
+ @Test
public void testMulticastRoute() {
RouteInfo r;
r = new RouteInfo(Prefix("230.0.0.0/32"), Address("192.0.2.1"), "wlan0");
@@ -251,16 +294,36 @@
// No exceptions? Good.
}
+ @Test
public void testParceling() {
RouteInfo r;
-
- r = new RouteInfo(Prefix("::/0"), Address("2001:db8::"), null);
+ r = new RouteInfo(Prefix("192.0.2.0/24"), Address("192.0.2.1"), null);
assertParcelingIsLossless(r);
-
r = new RouteInfo(Prefix("192.0.2.0/24"), null, "wlan0");
- assertParcelSane(r, 7);
+ assertParcelingIsLossless(r);
+ r = new RouteInfo(Prefix("192.0.2.0/24"), Address("192.0.2.1"), "wlan0", RTN_UNREACHABLE);
+ assertParcelingIsLossless(r);
}
+ @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
+ public void testMtuParceling() {
+ final RouteInfo r = new RouteInfo(Prefix("ff02::1/128"), Address("2001:db8::"), "testiface",
+ RTN_UNREACHABLE, 1450 /* mtu */);
+ assertParcelingIsLossless(r);
+ }
+
+ @Test @IgnoreAfter(Build.VERSION_CODES.Q)
+ public void testFieldCount_Q() {
+ assertFieldCountEquals(6, RouteInfo.class);
+ }
+
+ @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
+ public void testFieldCount() {
+ // Make sure any new field is covered by the above parceling tests when changing this number
+ assertFieldCountEquals(7, RouteInfo.class);
+ }
+
+ @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
public void testMtu() {
RouteInfo r;
r = new RouteInfo(Prefix("0.0.0.0/0"), Address("0.0.0.0"), "wlan0",
diff --git a/tests/net/common/java/android/net/util/SocketUtilsTest.kt b/tests/net/common/java/android/net/util/SocketUtilsTest.kt
index 9c7cfb0..aaf97f3 100644
--- a/tests/net/common/java/android/net/util/SocketUtilsTest.kt
+++ b/tests/net/common/java/android/net/util/SocketUtilsTest.kt
@@ -14,8 +14,9 @@
* limitations under the License.
*/
-package android.net.util;
+package android.net.util
+import android.os.Build
import android.system.NetlinkSocketAddress
import android.system.Os
import android.system.OsConstants.AF_INET
@@ -26,18 +27,26 @@
import android.system.PacketSocketAddress
import androidx.test.filters.SmallTest
import androidx.test.runner.AndroidJUnit4
+import com.android.testutils.DevSdkIgnoreRule
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Assert.fail
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
private const val TEST_INDEX = 123
private const val TEST_PORT = 555
+private const val FF_BYTE = 0xff.toByte()
+
@RunWith(AndroidJUnit4::class)
@SmallTest
class SocketUtilsTest {
+ @Rule @JvmField
+ val ignoreRule = DevSdkIgnoreRule()
+
@Test
fun testMakeNetlinkSocketAddress() {
val nlAddress = SocketUtils.makeNetlinkSocketAddress(TEST_PORT, RTMGRP_NEIGH)
@@ -50,16 +59,21 @@
}
@Test
- fun testMakePacketSocketAddress() {
+ fun testMakePacketSocketAddress_Q() {
val pkAddress = SocketUtils.makePacketSocketAddress(ETH_P_ALL, TEST_INDEX)
assertTrue("Not PacketSocketAddress object", pkAddress is PacketSocketAddress)
- val ff = 0xff.toByte()
- val pkAddress2 = SocketUtils.makePacketSocketAddress(TEST_INDEX,
- byteArrayOf(ff, ff, ff, ff, ff, ff))
+ val pkAddress2 = SocketUtils.makePacketSocketAddress(TEST_INDEX, ByteArray(6) { FF_BYTE })
assertTrue("Not PacketSocketAddress object", pkAddress2 is PacketSocketAddress)
}
+ @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
+ fun testMakePacketSocketAddress() {
+ val pkAddress = SocketUtils.makePacketSocketAddress(
+ ETH_P_ALL, TEST_INDEX, ByteArray(6) { FF_BYTE })
+ assertTrue("Not PacketSocketAddress object", pkAddress is PacketSocketAddress)
+ }
+
@Test
fun testCloseSocket() {
// Expect no exception happening with null object.
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 8c0c36b..6985415 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -23,8 +23,6 @@
import static android.content.pm.PackageManager.MATCH_ANY_USER;
import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport;
-import static android.net.ConnectivityDiagnosticsManager.DataStallReport;
import static android.net.ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_SUPL;
@@ -100,6 +98,7 @@
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.startsWith;
import static org.mockito.Matchers.anyInt;
@@ -6870,8 +6869,13 @@
HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
// Verify onConnectivityReport fired
- verify(mConnectivityDiagnosticsCallback)
- .onConnectivityReport(any(ConnectivityReport.class));
+ verify(mConnectivityDiagnosticsCallback).onConnectivityReport(
+ argThat(report -> {
+ final NetworkCapabilities nc = report.getNetworkCapabilities();
+ return nc.getUids() == null
+ && nc.getAdministratorUids().isEmpty()
+ && nc.getOwnerUid() == Process.INVALID_UID;
+ }));
}
@Test
@@ -6886,7 +6890,13 @@
HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
// Verify onDataStallSuspected fired
- verify(mConnectivityDiagnosticsCallback).onDataStallSuspected(any(DataStallReport.class));
+ verify(mConnectivityDiagnosticsCallback).onDataStallSuspected(
+ argThat(report -> {
+ final NetworkCapabilities nc = report.getNetworkCapabilities();
+ return nc.getUids() == null
+ && nc.getAdministratorUids().isEmpty()
+ && nc.getOwnerUid() == Process.INVALID_UID;
+ }));
}
@Test
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index a9e0b9a..36deca3 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -64,6 +64,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.annotation.NonNull;
import android.app.AlarmManager;
import android.app.usage.NetworkStatsManager;
import android.content.Context;
@@ -163,7 +164,6 @@
private @Mock IBinder mBinder;
private @Mock AlarmManager mAlarmManager;
private HandlerThread mHandlerThread;
- private Handler mHandler;
private NetworkStatsService mService;
private INetworkStatsSession mSession;
@@ -192,15 +192,11 @@
PowerManager.WakeLock wakeLock =
powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
- mService = new NetworkStatsService(
- mServiceContext, mNetManager, mAlarmManager, wakeLock, mClock,
- mServiceContext.getSystemService(TelephonyManager.class), mSettings,
- mStatsFactory, new NetworkStatsObservers(), mStatsDir, getBaseDir(mStatsDir));
mHandlerThread = new HandlerThread("HandlerThread");
- mHandlerThread.start();
- Handler.Callback callback = new NetworkStatsService.HandlerCallback(mService);
- mHandler = new Handler(mHandlerThread.getLooper(), callback);
- mService.setHandler(mHandler, callback);
+ final NetworkStatsService.Dependencies deps = makeDependencies();
+ mService = new NetworkStatsService(mServiceContext, mNetManager, mAlarmManager, wakeLock,
+ mClock, mServiceContext.getSystemService(TelephonyManager.class), mSettings,
+ mStatsFactory, new NetworkStatsObservers(), mStatsDir, getBaseDir(mStatsDir), deps);
mElapsedRealtime = 0L;
@@ -217,11 +213,21 @@
// catch INetworkManagementEventObserver during systemReady()
ArgumentCaptor<INetworkManagementEventObserver> networkObserver =
- ArgumentCaptor.forClass(INetworkManagementEventObserver.class);
+ ArgumentCaptor.forClass(INetworkManagementEventObserver.class);
verify(mNetManager).registerObserver(networkObserver.capture());
mNetworkObserver = networkObserver.getValue();
}
+ @NonNull
+ private NetworkStatsService.Dependencies makeDependencies() {
+ return new NetworkStatsService.Dependencies() {
+ @Override
+ public HandlerThread makeHandlerThread() {
+ return mHandlerThread;
+ }
+ };
+ }
+
@After
public void tearDown() throws Exception {
IoUtils.deleteContents(mStatsDir);
@@ -234,6 +240,8 @@
mSession.close();
mService = null;
+
+ mHandlerThread.quitSafely();
}
@Test
@@ -939,9 +947,7 @@
long minThresholdInBytes = 2 * 1024 * 1024; // 2 MB
assertEquals(minThresholdInBytes, request.thresholdInBytes);
- // Send dummy message to make sure that any previous message has been handled
- mHandler.sendMessage(mHandler.obtainMessage(-1));
- HandlerUtilsKt.waitForIdle(mHandler, WAIT_TIMEOUT);
+ HandlerUtilsKt.waitForIdle(mHandlerThread, WAIT_TIMEOUT);
// Make sure that the caller binder gets connected
verify(mBinder).linkToDeath(any(IBinder.DeathRecipient.class), anyInt());
@@ -1077,7 +1083,7 @@
// Simulates alert quota of the provider has been reached.
cb.onAlertReached();
- HandlerUtilsKt.waitForIdle(mHandler, WAIT_TIMEOUT);
+ HandlerUtilsKt.waitForIdle(mHandlerThread, WAIT_TIMEOUT);
// Verifies that polling is triggered by alert reached.
provider.expectStatsUpdate(0 /* unused */);
@@ -1294,9 +1300,7 @@
private void forcePollAndWaitForIdle() {
mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL));
- // Send dummy message to make sure that any previous message has been handled
- mHandler.sendMessage(mHandler.obtainMessage(-1));
- HandlerUtilsKt.waitForIdle(mHandler, WAIT_TIMEOUT);
+ HandlerUtilsKt.waitForIdle(mHandlerThread, WAIT_TIMEOUT);
}
static class LatchedHandler extends Handler {
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index 5aa32f8..bcfce66 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -366,8 +366,12 @@
});
manifest_action["instrumentation"]["meta-data"] = meta_data_action;
+ // TODO moltmann: Remove
manifest_action["feature"];
manifest_action["feature"]["inherit-from"];
+
+ manifest_action["attribution"];
+ manifest_action["attribution"]["inherit-from"];
manifest_action["original-package"];
manifest_action["overlay"];
manifest_action["protected-broadcast"];
diff --git a/tools/stats_log_api_gen/Android.bp b/tools/stats_log_api_gen/Android.bp
index cbf6fe8..b1e2487 100644
--- a/tools/stats_log_api_gen/Android.bp
+++ b/tools/stats_log_api_gen/Android.bp
@@ -120,12 +120,6 @@
"liblog",
"libcutils",
],
- apex_available: [
- "//apex_available:platform",
- //TODO(b/149781190): Remove this once statsd no longer depends on libstatslog
- "com.android.os.statsd",
- "test_com.android.os.statsd",
- ],
target: {
android: {
shared_libs: ["libstatssocket"],
diff --git a/wifi/Android.bp b/wifi/Android.bp
index 91174d3..f4d2881 100644
--- a/wifi/Android.bp
+++ b/wifi/Android.bp
@@ -177,14 +177,14 @@
java_library {
name: "framework-wifi-stubs-publicapi",
srcs: [":framework-wifi-stubs-srcs-publicapi"],
- sdk_version: "module_current",
+ sdk_version: "current",
installable: false,
}
java_library {
name: "framework-wifi-stubs-systemapi",
srcs: [":framework-wifi-stubs-srcs-systemapi"],
- sdk_version: "module_current",
+ sdk_version: "system_current",
libs: ["framework-annotations-lib"],
installable: false,
}
diff --git a/wifi/java/android/net/wifi/SoftApConfiguration.java b/wifi/java/android/net/wifi/SoftApConfiguration.java
index 2b47623..a269e17 100644
--- a/wifi/java/android/net/wifi/SoftApConfiguration.java
+++ b/wifi/java/android/net/wifi/SoftApConfiguration.java
@@ -35,7 +35,6 @@
import java.nio.charset.CharsetEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
-import java.util.Iterator;
import java.util.List;
import java.util.Objects;
@@ -211,7 +210,7 @@
* Delay in milliseconds before shutting down soft AP when
* there are no connected devices.
*/
- private final int mShutdownTimeoutMillis;
+ private final long mShutdownTimeoutMillis;
/**
* THe definition of security type OPEN.
@@ -247,7 +246,7 @@
private SoftApConfiguration(@Nullable String ssid, @Nullable MacAddress bssid,
@Nullable String passphrase, boolean hiddenSsid, @BandType int band, int channel,
@SecurityType int securityType, int maxNumberOfClients, boolean shutdownTimeoutEnabled,
- int shutdownTimeoutMillis, boolean clientControlByUser,
+ long shutdownTimeoutMillis, boolean clientControlByUser,
@NonNull List<MacAddress> blockedList, @NonNull List<MacAddress> allowedList) {
mSsid = ssid;
mBssid = bssid;
@@ -327,7 +326,7 @@
dest.writeInt(mSecurityType);
dest.writeInt(mMaxNumberOfClients);
dest.writeBoolean(mAutoShutdownEnabled);
- dest.writeInt(mShutdownTimeoutMillis);
+ dest.writeLong(mShutdownTimeoutMillis);
dest.writeBoolean(mClientControlByUser);
dest.writeTypedList(mBlockedClientList);
dest.writeTypedList(mAllowedClientList);
@@ -346,7 +345,7 @@
in.readString(),
in.readParcelable(MacAddress.class.getClassLoader()),
in.readString(), in.readBoolean(), in.readInt(), in.readInt(), in.readInt(),
- in.readInt(), in.readBoolean(), in.readInt(), in.readBoolean(),
+ in.readInt(), in.readBoolean(), in.readLong(), in.readBoolean(),
in.createTypedArrayList(MacAddress.CREATOR),
in.createTypedArrayList(MacAddress.CREATOR));
}
@@ -454,19 +453,19 @@
/**
* Returns the shutdown timeout in milliseconds.
* The Soft AP will shutdown when there are no devices associated to it for
- * the timeout duration. See {@link Builder#setShutdownTimeoutMillis(int)}.
+ * the timeout duration. See {@link Builder#setShutdownTimeoutMillis(long)}.
*
* @hide
*/
@SystemApi
- public int getShutdownTimeoutMillis() {
+ public long getShutdownTimeoutMillis() {
return mShutdownTimeoutMillis;
}
/**
* Returns a flag indicating whether clients need to be pre-approved by the user.
* (true: authorization required) or not (false: not required).
- * {@link Builder#enableClientControlByUser(Boolean)}.
+ * {@link Builder#setClientControlByUserEnabled(Boolean)}.
*
* @hide
*/
@@ -478,7 +477,7 @@
/**
* Returns List of clients which aren't allowed to associate to the AP.
*
- * Clients are configured using {@link Builder#setClientList(List, List)}
+ * Clients are configured using {@link Builder#setBlockedClientList(List)}
*
* @hide
*/
@@ -490,7 +489,7 @@
/**
* List of clients which are allowed to associate to the AP.
- * Clients are configured using {@link Builder#setClientList(List, List)}
+ * Clients are configured using {@link Builder#setAllowedClientList(List)}
*
* @hide
*/
@@ -575,7 +574,7 @@
private int mMaxNumberOfClients;
private int mSecurityType;
private boolean mAutoShutdownEnabled;
- private int mShutdownTimeoutMillis;
+ private long mShutdownTimeoutMillis;
private boolean mClientControlByUser;
private List<MacAddress> mBlockedClientList;
private List<MacAddress> mAllowedClientList;
@@ -627,6 +626,11 @@
*/
@NonNull
public SoftApConfiguration build() {
+ for (MacAddress client : mAllowedClientList) {
+ if (mBlockedClientList.contains(client)) {
+ throw new IllegalArgumentException("A MacAddress exist in both client list");
+ }
+ }
return new SoftApConfiguration(mSsid, mBssid, mPassphrase,
mHiddenSsid, mBand, mChannel, mSecurityType, mMaxNumberOfClients,
mAutoShutdownEnabled, mShutdownTimeoutMillis, mClientControlByUser,
@@ -835,7 +839,7 @@
* @param enable true to enable, false to disable.
* @return Builder for chaining.
*
- * @see #setShutdownTimeoutMillis(int)
+ * @see #setShutdownTimeoutMillis(long)
*/
@NonNull
public Builder setAutoShutdownEnabled(boolean enable) {
@@ -862,7 +866,7 @@
* @see #setAutoShutdownEnabled(boolean)
*/
@NonNull
- public Builder setShutdownTimeoutMillis(@IntRange(from = 0) int timeoutMillis) {
+ public Builder setShutdownTimeoutMillis(@IntRange(from = 0) long timeoutMillis) {
if (timeoutMillis < 0) {
throw new IllegalArgumentException("Invalid timeout value");
}
@@ -878,7 +882,7 @@
*
* If manual user control is enabled then clients will be accepted, rejected, or require
* a user approval based on the configuration provided by
- * {@link #setClientList(List, List)}.
+ * {@link #setBlockedClientList(List)} and {@link #setAllowedClientList(List)}.
*
* <p>
* This method requires hardware support. Hardware support can be determined using
@@ -898,26 +902,48 @@
* @return Builder for chaining.
*/
@NonNull
- public Builder enableClientControlByUser(boolean enabled) {
+ public Builder setClientControlByUserEnabled(boolean enabled) {
mClientControlByUser = enabled;
return this;
}
/**
- * This method together with {@link enableClientControlByUser(boolean)} control client
- * connections to the AP. If {@link enableClientControlByUser(false)} is configured than
+ * This method together with {@link setClientControlByUserEnabled(boolean)} control client
+ * connections to the AP. If client control by user is disabled using the above method then
* this API has no effect and clients are allowed to associate to the AP (within limit of
* max number of clients).
*
- * If {@link enableClientControlByUser(true)} is configured then this API configures
- * 2 lists:
+ * If client control by user is enabled then this API configures the list of clients
+ * which are explicitly allowed. These are auto-accepted.
+ *
+ * All other clients which attempt to associate, whose MAC addresses are on neither list,
+ * are:
* <ul>
- * <li>List of clients which are blocked. These are rejected.</li>
- * <li>List of clients which are explicitly allowed. These are auto-accepted.</li>
+ * <li>Rejected</li>
+ * <li>A callback {@link WifiManager.SoftApCallback#onBlockedClientConnecting(WifiClient)}
+ * is issued (which allows the user to add them to the allowed client list if desired).<li>
* </ul>
*
- * <p>
+ * @param allowedClientList list of clients which are allowed to associate to the AP
+ * without user pre-approval.
+ * @return Builder for chaining.
+ */
+ @NonNull
+ public Builder setAllowedClientList(@NonNull List<MacAddress> allowedClientList) {
+ mAllowedClientList = new ArrayList<>(allowedClientList);
+ return this;
+ }
+
+ /**
+ * This method together with {@link setClientControlByUserEnabled(boolean)} control client
+ * connections to the AP. If client control by user is disabled using the above method then
+ * this API has no effect and clients are allowed to associate to the AP (within limit of
+ * max number of clients).
+ *
+ * If client control by user is enabled then this API this API configures the list of
+ * clients which are blocked. These are rejected.
+ *
* All other clients which attempt to associate, whose MAC addresses are on neither list,
* are:
* <ul>
@@ -927,23 +953,11 @@
* </ul>
*
* @param blockedClientList list of clients which are not allowed to associate to the AP.
- * @param allowedClientList list of clients which are allowed to associate to the AP
- * without user pre-approval.
* @return Builder for chaining.
*/
@NonNull
- public Builder setClientList(@NonNull List<MacAddress> blockedClientList,
- @NonNull List<MacAddress> allowedClientList) {
+ public Builder setBlockedClientList(@NonNull List<MacAddress> blockedClientList) {
mBlockedClientList = new ArrayList<>(blockedClientList);
- mAllowedClientList = new ArrayList<>(allowedClientList);
- Iterator<MacAddress> iterator = mAllowedClientList.iterator();
- while (iterator.hasNext()) {
- MacAddress client = iterator.next();
- int index = mBlockedClientList.indexOf(client);
- if (index != -1) {
- throw new IllegalArgumentException("A MacAddress exist in both list");
- }
- }
return this;
}
}
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index e0b433d..ba68d17 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -635,13 +635,6 @@
public String preSharedKey;
/**
- * Optional SAE Password Id for use with WPA3-SAE. It is an ASCII string.
- * @hide
- */
- @SystemApi
- public @Nullable String saePasswordId;
-
- /**
* Four WEP keys. For each of the four values, provide either an ASCII
* string enclosed in double quotation marks (e.g., {@code "abcdef"}),
* a string of hex digits (e.g., {@code 0102030405}), or an empty string
@@ -2334,9 +2327,6 @@
sbuf.append('*');
}
- sbuf.append('\n').append(" SAE Password Id: ");
- sbuf.append(this.saePasswordId);
-
sbuf.append("\nEnterprise config:\n");
sbuf.append(enterpriseConfig);
@@ -2731,7 +2721,6 @@
providerFriendlyName = source.providerFriendlyName;
isHomeProviderNetwork = source.isHomeProviderNetwork;
preSharedKey = source.preSharedKey;
- saePasswordId = source.saePasswordId;
mNetworkSelectionStatus.copy(source.getNetworkSelectionStatus());
apBand = source.apBand;
@@ -2819,7 +2808,6 @@
dest.writeLong(roamingConsortiumId);
}
dest.writeString(preSharedKey);
- dest.writeString(saePasswordId);
for (String wepKey : wepKeys) {
dest.writeString(wepKey);
}
@@ -2895,7 +2883,6 @@
config.roamingConsortiumIds[i] = in.readLong();
}
config.preSharedKey = in.readString();
- config.saePasswordId = in.readString();
for (int i = 0; i < config.wepKeys.length; i++) {
config.wepKeys[i] = in.readString();
}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 9e29a7a..e1acaf8 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -727,8 +727,9 @@
/**
* If Soft Ap client is blocked, this reason code means that client doesn't exist in the
- * specified configuration {@link SoftApConfiguration.Builder#setClientList(List, List)}
- * and the {@link SoftApConfiguration.Builder#enableClientControlByUser(true)}
+ * specified configuration {@link SoftApConfiguration.Builder#setBlockedClientList(List)}
+ * and {@link SoftApConfiguration.Builder#setAllowedClientList(List)}
+ * and the {@link SoftApConfiguration.Builder#setClientControlByUserEnabled(boolean)}
* is configured as well.
* @hide
*/
@@ -1352,7 +1353,7 @@
try {
ParceledListSlice<WifiConfiguration> parceledList =
mService.getConfiguredNetworks(mContext.getOpPackageName(),
- mContext.getFeatureId());
+ mContext.getAttributionTag());
if (parceledList == null) {
return Collections.emptyList();
}
@@ -1369,7 +1370,7 @@
try {
ParceledListSlice<WifiConfiguration> parceledList =
mService.getPrivilegedConfiguredNetworks(mContext.getOpPackageName(),
- mContext.getFeatureId());
+ mContext.getAttributionTag());
if (parceledList == null) {
return Collections.emptyList();
}
@@ -1898,7 +1899,7 @@
@NonNull List<WifiNetworkSuggestion> networkSuggestions) {
try {
return mService.addNetworkSuggestions(
- networkSuggestions, mContext.getOpPackageName(), mContext.getFeatureId());
+ networkSuggestions, mContext.getOpPackageName(), mContext.getAttributionTag());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2680,8 +2681,8 @@
public boolean startScan(WorkSource workSource) {
try {
String packageName = mContext.getOpPackageName();
- String featureId = mContext.getFeatureId();
- return mService.startScan(packageName, featureId);
+ String attributionTag = mContext.getAttributionTag();
+ return mService.startScan(packageName, attributionTag);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2713,7 +2714,7 @@
public WifiInfo getConnectionInfo() {
try {
return mService.getConnectionInfo(mContext.getOpPackageName(),
- mContext.getFeatureId());
+ mContext.getAttributionTag());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2728,35 +2729,38 @@
public List<ScanResult> getScanResults() {
try {
return mService.getScanResults(mContext.getOpPackageName(),
- mContext.getFeatureId());
+ mContext.getAttributionTag());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
- * Return the filtered ScanResults which may be authenticated by the suggested network
- * configurations.
- * @param networkSuggestions The list of {@link WifiNetworkSuggestion}
- * @param scanResults The scan results to be filtered, this is optional, if it is null or
- * empty, wifi system would use the recent scan results in the system.
- * @return The map of {@link WifiNetworkSuggestion} and the list of {@link ScanResult} which
- * may be authenticated by the corresponding network configuration.
+ * Get the filtered ScanResults which match the network configurations specified by the
+ * {@code networkSuggestionsToMatch}. Suggestions which use {@link WifiConfiguration} use
+ * SSID and the security type to match. Suggestions which use {@link PasspointConfigration}
+ * use the matching rules of Hotspot 2.0.
+ * @param networkSuggestionsToMatch The list of {@link WifiNetworkSuggestion} to match against.
+ * These may or may not be suggestions which are installed on the device.
+ * @param scanResults The scan results to be filtered. Optional - if not provided(empty list),
+ * the Wi-Fi service will use the most recent scan results which the system has.
+ * @return The map of {@link WifiNetworkSuggestion} to the list of {@link ScanResult}
+ * corresponding to networks which match them.
* @hide
*/
@SystemApi
@RequiresPermission(allOf = {ACCESS_FINE_LOCATION, ACCESS_WIFI_STATE})
@NonNull
public Map<WifiNetworkSuggestion, List<ScanResult>> getMatchingScanResults(
- @NonNull List<WifiNetworkSuggestion> networkSuggestions,
+ @NonNull List<WifiNetworkSuggestion> networkSuggestionsToMatch,
@Nullable List<ScanResult> scanResults) {
- if (networkSuggestions == null) {
+ if (networkSuggestionsToMatch == null) {
throw new IllegalArgumentException("networkSuggestions must not be null.");
}
try {
return mService.getMatchingScanResults(
- networkSuggestions, scanResults,
- mContext.getOpPackageName(), mContext.getFeatureId());
+ networkSuggestionsToMatch, scanResults,
+ mContext.getOpPackageName(), mContext.getAttributionTag());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -3195,7 +3199,7 @@
new LocalOnlyHotspotCallbackProxy(this, executor, callback);
try {
String packageName = mContext.getOpPackageName();
- String featureId = mContext.getFeatureId();
+ String featureId = mContext.getAttributionTag();
int returnCode = mService.startLocalOnlyHotspot(proxy, packageName, featureId,
config);
if (returnCode != LocalOnlyHotspotCallback.REQUEST_REGISTERED) {
@@ -3372,7 +3376,7 @@
*/
@NonNull
@SystemApi
- @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
public SoftApConfiguration getSoftApConfiguration() {
try {
return mService.getSoftApConfiguration();
@@ -3406,9 +3410,10 @@
* If the API is called while the tethered soft AP is enabled, the configuration will apply to
* the current soft AP if the new configuration only includes
* {@link SoftApConfiguration.Builder#setMaxNumberOfClients(int)}
- * or {@link SoftApConfiguration.Builder#setShutdownTimeoutMillis(int)}
- * or {@link SoftApConfiguration.Builder#enableClientControlByUser(boolean)}
- * or {@link SoftApConfiguration.Builder#setClientList(List, List)}.
+ * or {@link SoftApConfiguration.Builder#setShutdownTimeoutMillis(long)}
+ * or {@link SoftApConfiguration.Builder#setClientControlByUserEnabled(boolean)}
+ * or {@link SoftApConfiguration.Builder#setBlockedClientList(List)}
+ * or {@link SoftApConfiguration.Builder#setAllowedClientList(List)}
*
* Otherwise, the configuration changes will be applied when the Soft AP is next started
* (the framework will not stop/start the AP).
@@ -5886,7 +5891,7 @@
try {
mService.registerSuggestionConnectionStatusListener(new Binder(),
new SuggestionConnectionStatusListenerProxy(executor, listener),
- listener.hashCode(), mContext.getOpPackageName(), mContext.getFeatureId());
+ listener.hashCode(), mContext.getOpPackageName(), mContext.getAttributionTag());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index 5e48919..d299cdc 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -182,7 +182,7 @@
public List<Integer> getAvailableChannels(int band) {
try {
Bundle bundle = mService.getAvailableChannels(band, mContext.getOpPackageName(),
- mContext.getFeatureId());
+ mContext.getAttributionTag());
List<Integer> channels = bundle.getIntegerArrayList(GET_AVAILABLE_CHANNELS_EXTRA);
return channels == null ? new ArrayList<>() : channels;
} catch (RemoteException e) {
@@ -963,7 +963,7 @@
scanParams.putParcelable(SCAN_PARAMS_SCAN_SETTINGS_KEY, settings);
scanParams.putParcelable(SCAN_PARAMS_WORK_SOURCE_KEY, workSource);
scanParams.putString(REQUEST_PACKAGE_NAME_KEY, mContext.getOpPackageName());
- scanParams.putString(REQUEST_FEATURE_ID_KEY, mContext.getFeatureId());
+ scanParams.putString(REQUEST_FEATURE_ID_KEY, mContext.getAttributionTag());
mAsyncChannel.sendMessage(CMD_START_BACKGROUND_SCAN, 0, key, scanParams);
}
@@ -984,7 +984,7 @@
validateChannel();
Bundle scanParams = new Bundle();
scanParams.putString(REQUEST_PACKAGE_NAME_KEY, mContext.getOpPackageName());
- scanParams.putString(REQUEST_FEATURE_ID_KEY, mContext.getFeatureId());
+ scanParams.putString(REQUEST_FEATURE_ID_KEY, mContext.getAttributionTag());
mAsyncChannel.sendMessage(CMD_STOP_BACKGROUND_SCAN, 0, key, scanParams);
}
@@ -1001,7 +1001,7 @@
validateChannel();
Bundle scanParams = new Bundle();
scanParams.putString(REQUEST_PACKAGE_NAME_KEY, mContext.getOpPackageName());
- scanParams.putString(REQUEST_FEATURE_ID_KEY, mContext.getFeatureId());
+ scanParams.putString(REQUEST_FEATURE_ID_KEY, mContext.getAttributionTag());
Message reply =
mAsyncChannel.sendMessageSynchronously(CMD_GET_SCAN_RESULTS, 0, 0, scanParams);
return reply.what == CMD_OP_SUCCEEDED;
@@ -1056,7 +1056,7 @@
scanParams.putParcelable(SCAN_PARAMS_SCAN_SETTINGS_KEY, settings);
scanParams.putParcelable(SCAN_PARAMS_WORK_SOURCE_KEY, workSource);
scanParams.putString(REQUEST_PACKAGE_NAME_KEY, mContext.getOpPackageName());
- scanParams.putString(REQUEST_FEATURE_ID_KEY, mContext.getFeatureId());
+ scanParams.putString(REQUEST_FEATURE_ID_KEY, mContext.getAttributionTag());
mAsyncChannel.sendMessage(CMD_START_SINGLE_SCAN, 0, key, scanParams);
}
@@ -1073,7 +1073,7 @@
validateChannel();
Bundle scanParams = new Bundle();
scanParams.putString(REQUEST_PACKAGE_NAME_KEY, mContext.getOpPackageName());
- scanParams.putString(REQUEST_FEATURE_ID_KEY, mContext.getFeatureId());
+ scanParams.putString(REQUEST_FEATURE_ID_KEY, mContext.getAttributionTag());
mAsyncChannel.sendMessage(CMD_STOP_SINGLE_SCAN, 0, key, scanParams);
}
@@ -1086,7 +1086,7 @@
validateChannel();
Bundle scanParams = new Bundle();
scanParams.putString(REQUEST_PACKAGE_NAME_KEY, mContext.getOpPackageName());
- scanParams.putString(REQUEST_FEATURE_ID_KEY, mContext.getFeatureId());
+ scanParams.putString(REQUEST_FEATURE_ID_KEY, mContext.getAttributionTag());
Message reply = mAsyncChannel.sendMessageSynchronously(CMD_GET_SINGLE_SCAN_RESULTS, 0, 0,
scanParams);
if (reply.what == WifiScanner.CMD_OP_SUCCEEDED) {
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareManager.java b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
index 2ebaa18..c2ae17c 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareManager.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
@@ -267,7 +267,7 @@
try {
Binder binder = new Binder();
- mService.connect(binder, mContext.getOpPackageName(), mContext.getFeatureId(),
+ mService.connect(binder, mContext.getOpPackageName(), mContext.getAttributionTag(),
new WifiAwareEventCallbackProxy(this, looper, binder, attachCallback,
identityChangedListener), configRequest,
identityChangedListener != null);
@@ -298,7 +298,7 @@
}
try {
- mService.publish(mContext.getOpPackageName(), mContext.getFeatureId(), clientId,
+ mService.publish(mContext.getOpPackageName(), mContext.getAttributionTag(), clientId,
publishConfig,
new WifiAwareDiscoverySessionCallbackProxy(this, looper, true, callback,
clientId));
@@ -336,7 +336,7 @@
}
try {
- mService.subscribe(mContext.getOpPackageName(), mContext.getFeatureId(), clientId,
+ mService.subscribe(mContext.getOpPackageName(), mContext.getAttributionTag(), clientId,
subscribeConfig,
new WifiAwareDiscoverySessionCallbackProxy(this, looper, false, callback,
clientId));
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index a310ff6..724ccf0 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -1180,7 +1180,7 @@
== AsyncChannel.STATUS_SUCCESSFUL) {
Bundle bundle = new Bundle();
bundle.putString(CALLING_PACKAGE, c.mContext.getOpPackageName());
- bundle.putString(CALLING_FEATURE_ID, c.mContext.getFeatureId());
+ bundle.putString(CALLING_FEATURE_ID, c.mContext.getAttributionTag());
bundle.putBinder(CALLING_BINDER, binder);
c.mAsyncChannel.sendMessage(UPDATE_CHANNEL_INFO, 0,
c.putListener(null), bundle);
diff --git a/wifi/java/android/net/wifi/rtt/WifiRttManager.java b/wifi/java/android/net/wifi/rtt/WifiRttManager.java
index cb0c5d4..865702a 100644
--- a/wifi/java/android/net/wifi/rtt/WifiRttManager.java
+++ b/wifi/java/android/net/wifi/rtt/WifiRttManager.java
@@ -146,8 +146,8 @@
Binder binder = new Binder();
try {
- mService.startRanging(binder, mContext.getOpPackageName(), mContext.getFeatureId(),
- workSource, request, new IRttCallback.Stub() {
+ mService.startRanging(binder, mContext.getOpPackageName(),
+ mContext.getAttributionTag(), workSource, request, new IRttCallback.Stub() {
@Override
public void onRangingFailure(int status) throws RemoteException {
clearCallingIdentity();
diff --git a/wifi/tests/AndroidTest.xml b/wifi/tests/AndroidTest.xml
index 987fee7..34e2e3a 100644
--- a/wifi/tests/AndroidTest.xml
+++ b/wifi/tests/AndroidTest.xml
@@ -25,4 +25,10 @@
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
<option name="hidden-api-checks" value="false"/>
</test>
+
+ <!-- Only run FrameworksWifiApiTests in MTS if the Wifi Mainline module is installed. -->
+ <object type="module_controller"
+ class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
+ <option name="mainline-module-package-name" value="com.google.android.wifi" />
+ </object>
</configuration>
diff --git a/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java b/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java
index 060ddf0..1a44270 100644
--- a/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/SoftApConfigurationTest.java
@@ -127,8 +127,9 @@
.setMaxNumberOfClients(10)
.setAutoShutdownEnabled(true)
.setShutdownTimeoutMillis(500000)
- .enableClientControlByUser(true)
- .setClientList(testBlockedClientList, testAllowedClientList)
+ .setClientControlByUserEnabled(true)
+ .setBlockedClientList(testBlockedClientList)
+ .setAllowedClientList(testAllowedClientList)
.build();
assertThat(original.getPassphrase()).isEqualTo("secretsecret");
assertThat(original.getSecurityType()).isEqualTo(
@@ -264,7 +265,9 @@
ArrayList<MacAddress> testBlockedClientList = new ArrayList<>();
testBlockedClientList.add(testMacAddress_1);
SoftApConfiguration.Builder configBuilder = new SoftApConfiguration.Builder();
- configBuilder.setClientList(testBlockedClientList, testAllowedClientList);
+ configBuilder.setBlockedClientList(testBlockedClientList)
+ .setAllowedClientList(testAllowedClientList)
+ .build();
}
@Test
diff --git a/wifi/tests/src/android/net/wifi/WifiScannerTest.java b/wifi/tests/src/android/net/wifi/WifiScannerTest.java
index 0cc76b6..4881200 100644
--- a/wifi/tests/src/android/net/wifi/WifiScannerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiScannerTest.java
@@ -267,7 +267,7 @@
assertNull(messageBundle.getParcelable(WifiScanner.SCAN_PARAMS_WORK_SOURCE_KEY));
assertEquals(mContext.getOpPackageName(),
messageBundle.getParcelable(WifiScanner.REQUEST_PACKAGE_NAME_KEY));
- assertEquals(mContext.getFeatureId(),
+ assertEquals(mContext.getAttributionTag(),
messageBundle.getParcelable(WifiScanner.REQUEST_FEATURE_ID_KEY));
}
@@ -297,7 +297,7 @@
Bundle messageBundle = (Bundle) message.obj;
assertEquals(mContext.getOpPackageName(),
messageBundle.getParcelable(WifiScanner.REQUEST_PACKAGE_NAME_KEY));
- assertEquals(mContext.getFeatureId(),
+ assertEquals(mContext.getAttributionTag(),
messageBundle.getParcelable(WifiScanner.REQUEST_FEATURE_ID_KEY));
}
diff --git a/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java b/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java
index a9dcde0..e6eae416 100644
--- a/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/rtt/WifiRttManagerTest.java
@@ -71,7 +71,7 @@
mMockLooperExecutor = mMockLooper.getNewExecutor();
when(mockContext.getOpPackageName()).thenReturn(packageName);
- when(mockContext.getFeatureId()).thenReturn(featureId);
+ when(mockContext.getAttributionTag()).thenReturn(featureId);
}
/**