Merge "Allow to exempt apps from restrictions to RECORD_AUDIO" into rvc-dev
diff --git a/Android.bp b/Android.bp
index 78d38c5..71513b7 100644
--- a/Android.bp
+++ b/Android.bp
@@ -470,7 +470,7 @@
"framework-statsd-stubs-module_libs_api",
"framework-permission-stubs-systemapi",
"framework-wifi-stubs-systemapi",
- "framework-tethering-stubs",
+ "framework-tethering-stubs-module_libs_api",
],
installable: true,
javac_shard_size: 150,
@@ -518,7 +518,7 @@
"framework-sdkextensions-stubs-systemapi",
"framework-statsd-stubs-module_libs_api",
"framework-wifi-stubs-systemapi",
- "framework-tethering-stubs",
+ "framework-tethering-stubs-module_libs_api",
// TODO (b/147688669) should be framework-telephony-stubs
"framework-telephony",
// TODO(jiyong): add stubs for APEXes here
@@ -540,7 +540,6 @@
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/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/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/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
index dc61f2ae..c84627d 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
@@ -54,6 +54,7 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -102,9 +103,6 @@
private final OnAlarmListener mAnomalyAlarmListener = new AnomalyAlarmListener();
private final OnAlarmListener mPullingAlarmListener = new PullingAlarmListener();
private final OnAlarmListener mPeriodicAlarmListener = new PeriodicAlarmListener();
- private final BroadcastReceiver mAppUpdateReceiver;
- private final BroadcastReceiver mUserUpdateReceiver;
- private final ShutdownEventReceiver mShutdownEventReceiver;
private StatsManagerService mStatsManagerService;
@@ -118,27 +116,6 @@
super();
mContext = context;
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
- mAppUpdateReceiver = new AppUpdateReceiver();
- mUserUpdateReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- synchronized (sStatsdLock) {
- if (sStatsd == null) {
- Log.w(TAG, "Could not access statsd for UserUpdateReceiver");
- return;
- }
- try {
- // Pull the latest state of UID->app name, version mapping.
- // Needed since the new user basically has a version of every app.
- informAllUidsLocked(context);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to inform statsd latest update of all apps", e);
- forgetEverythingLocked();
- }
- }
- }
- };
- mShutdownEventReceiver = new ShutdownEventReceiver();
if (DEBUG) Log.d(TAG, "Registered receiver for ACTION_PACKAGE_REPLACED and ADDED.");
HandlerThread handlerThread = new HandlerThread(TAG);
handlerThread.start();
@@ -162,9 +139,18 @@
return ret;
}
- // Assumes that sStatsdLock is held.
- @GuardedBy("sStatsdLock")
- private void informAllUidsLocked(Context context) throws RemoteException {
+ /**
+ * Non-blocking call to retrieve a reference to statsd
+ *
+ * @return IStatsd object if statsd is ready, null otherwise.
+ */
+ private static IStatsd getStatsdNonblocking() {
+ synchronized (sStatsdLock) {
+ return sStatsd;
+ }
+ }
+
+ private static void informAllUidsLocked(Context context) throws RemoteException {
UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
PackageManager pm = context.getPackageManager();
final List<UserHandle> users = um.getUserHandles(true);
@@ -273,7 +259,6 @@
if (!replacing) {
// Don't bother sending an update if we're right about to get another
// intent for the new version that's added.
- PackageManager pm = context.getPackageManager();
String app = intent.getData().getSchemeSpecificPart();
sStatsd.informOnePackageRemoved(app, uid);
}
@@ -303,23 +288,43 @@
}
}
- public final static class AnomalyAlarmListener implements OnAlarmListener {
+ private static final class UserUpdateReceiver extends BroadcastReceiver {
@Override
- public void onAlarm() {
- Log.i(TAG, "StatsCompanionService believes an anomaly has occurred at time "
- + System.currentTimeMillis() + "ms.");
+ public void onReceive(Context context, Intent intent) {
synchronized (sStatsdLock) {
if (sStatsd == null) {
- Log.w(TAG, "Could not access statsd to inform it of anomaly alarm firing");
+ Log.w(TAG, "Could not access statsd for UserUpdateReceiver");
return;
}
try {
- // Two-way call to statsd to retain AlarmManager wakelock
- sStatsd.informAnomalyAlarmFired();
+ // Pull the latest state of UID->app name, version mapping.
+ // Needed since the new user basically has a version of every app.
+ informAllUidsLocked(context);
} catch (RemoteException e) {
- Log.w(TAG, "Failed to inform statsd of anomaly alarm firing", e);
+ Log.e(TAG, "Failed to inform statsd latest update of all apps", e);
}
}
+ }
+ }
+
+ public static final class AnomalyAlarmListener implements OnAlarmListener {
+ @Override
+ public void onAlarm() {
+ if (DEBUG) {
+ Log.i(TAG, "StatsCompanionService believes an anomaly has occurred at time "
+ + System.currentTimeMillis() + "ms.");
+ }
+ IStatsd statsd = getStatsdNonblocking();
+ if (statsd == null) {
+ Log.w(TAG, "Could not access statsd to inform it of anomaly alarm firing");
+ return;
+ }
+ try {
+ // Two-way call to statsd to retain AlarmManager wakelock
+ statsd.informAnomalyAlarmFired();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to inform statsd of anomaly alarm firing", e);
+ }
// AlarmManager releases its own wakelock here.
}
}
@@ -330,17 +335,16 @@
if (DEBUG) {
Log.d(TAG, "Time to poll something.");
}
- synchronized (sStatsdLock) {
- if (sStatsd == null) {
- Log.w(TAG, "Could not access statsd to inform it of pulling alarm firing.");
- return;
- }
- try {
- // Two-way call to statsd to retain AlarmManager wakelock
- sStatsd.informPollAlarmFired();
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to inform statsd of pulling alarm firing.", e);
- }
+ IStatsd statsd = getStatsdNonblocking();
+ if (statsd == null) {
+ Log.w(TAG, "Could not access statsd to inform it of pulling alarm firing.");
+ return;
+ }
+ try {
+ // Two-way call to statsd to retain AlarmManager wakelock
+ statsd.informPollAlarmFired();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to inform statsd of pulling alarm firing.", e);
}
}
}
@@ -351,17 +355,16 @@
if (DEBUG) {
Log.d(TAG, "Time to trigger periodic alarm.");
}
- synchronized (sStatsdLock) {
- if (sStatsd == null) {
- Log.w(TAG, "Could not access statsd to inform it of periodic alarm firing.");
- return;
- }
- try {
- // Two-way call to statsd to retain AlarmManager wakelock
- sStatsd.informAlarmForSubscriberTriggeringFired();
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to inform statsd of periodic alarm firing.", e);
- }
+ IStatsd statsd = getStatsdNonblocking();
+ if (statsd == null) {
+ Log.w(TAG, "Could not access statsd to inform it of periodic alarm firing.");
+ return;
+ }
+ try {
+ // Two-way call to statsd to retain AlarmManager wakelock
+ statsd.informAlarmForSubscriberTriggeringFired();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to inform statsd of periodic alarm firing.", e);
}
// AlarmManager releases its own wakelock here.
}
@@ -379,17 +382,19 @@
return;
}
- Log.i(TAG, "StatsCompanionService noticed a shutdown.");
- synchronized (sStatsdLock) {
- if (sStatsd == null) {
- Log.w(TAG, "Could not access statsd to inform it of a shutdown event.");
- return;
- }
- try {
- sStatsd.informDeviceShutdown();
- } catch (Exception e) {
- Log.w(TAG, "Failed to inform statsd of a shutdown event.", e);
- }
+ if (DEBUG) {
+ Log.i(TAG, "StatsCompanionService noticed a shutdown.");
+ }
+ IStatsd statsd = getStatsdNonblocking();
+ if (statsd == null) {
+ Log.w(TAG, "Could not access statsd to inform it of a shutdown event.");
+ return;
+ }
+ try {
+ // two way binder call
+ statsd.informDeviceShutdown();
+ } catch (Exception e) {
+ Log.w(TAG, "Failed to inform statsd of a shutdown event.", e);
}
}
}
@@ -515,7 +520,7 @@
}
}
- @Override
+ @Override // Binder call
public void triggerUidSnapshot() {
StatsCompanion.enforceStatsdCallingUid();
synchronized (sStatsdLock) {
@@ -525,7 +530,7 @@
} catch (RemoteException e) {
Log.e(TAG, "Failed to trigger uid snapshot.", e);
} finally {
- restoreCallingIdentity(token);
+ Binder.restoreCallingIdentity(token);
}
}
}
@@ -539,15 +544,28 @@
// Statsd related code
/**
- * Fetches the statsd IBinder service.
- * Note: This should only be called from sayHiToStatsd. All other clients should use the cached
- * sStatsd with a null check.
+ * Fetches the statsd IBinder service. This is a blocking call.
+ * Note: This should only be called from {@link #sayHiToStatsd()}. All other clients should use
+ * the cached sStatsd via {@link #getStatsdNonblocking()}.
*/
- private static IStatsd fetchStatsdService() {
- return IStatsd.Stub.asInterface(StatsFrameworkInitializer
- .getStatsServiceManager()
- .getStatsdServiceRegisterer()
- .get());
+ private IStatsd fetchStatsdService(StatsdDeathRecipient deathRecipient) {
+ synchronized (sStatsdLock) {
+ if (sStatsd == null) {
+ sStatsd = IStatsd.Stub.asInterface(StatsFrameworkInitializer
+ .getStatsServiceManager()
+ .getStatsdServiceRegisterer()
+ .get());
+ if (sStatsd != null) {
+ try {
+ sStatsd.asBinder().linkToDeath(deathRecipient, /* flags */ 0);
+ } catch (RemoteException e) {
+ Log.e(TAG, "linkToDeath(StatsdDeathRecipient) failed");
+ statsdNotReadyLocked();
+ }
+ }
+ }
+ return sStatsd;
+ }
}
/**
@@ -567,67 +585,84 @@
* statsd.
*/
private void sayHiToStatsd() {
- synchronized (sStatsdLock) {
- if (sStatsd != null) {
- Log.e(TAG, "Trying to fetch statsd, but it was already fetched",
- new IllegalStateException(
- "sStatsd is not null when being fetched"));
- return;
- }
- sStatsd = fetchStatsdService();
- if (sStatsd == null) {
- Log.i(TAG,
- "Could not yet find statsd to tell it that StatsCompanion is "
- + "alive.");
- return;
- }
- mStatsManagerService.statsdReady(sStatsd);
- if (DEBUG) Log.d(TAG, "Saying hi to statsd");
+ if (getStatsdNonblocking() != null) {
+ Log.e(TAG, "Trying to fetch statsd, but it was already fetched",
+ new IllegalStateException(
+ "sStatsd is not null when being fetched"));
+ return;
+ }
+ StatsdDeathRecipient deathRecipient = new StatsdDeathRecipient();
+ IStatsd statsd = fetchStatsdService(deathRecipient);
+ if (statsd == null) {
+ Log.i(TAG,
+ "Could not yet find statsd to tell it that StatsCompanion is "
+ + "alive.");
+ return;
+ }
+ mStatsManagerService.statsdReady(statsd);
+ if (DEBUG) Log.d(TAG, "Saying hi to statsd");
+ try {
+ statsd.statsCompanionReady();
+
+ cancelAnomalyAlarm();
+ cancelPullingAlarm();
+
+ BroadcastReceiver appUpdateReceiver = new AppUpdateReceiver();
+ BroadcastReceiver userUpdateReceiver = new UserUpdateReceiver();
+ BroadcastReceiver shutdownEventReceiver = new ShutdownEventReceiver();
+
+ // Setup broadcast receiver for updates.
+ IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_REPLACED);
+ filter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ filter.addDataScheme("package");
+ mContext.registerReceiverForAllUsers(appUpdateReceiver, filter, null, null);
+
+ // Setup receiver for user initialize (which happens once for a new user)
+ // and
+ // if a user is removed.
+ filter = new IntentFilter(Intent.ACTION_USER_INITIALIZE);
+ filter.addAction(Intent.ACTION_USER_REMOVED);
+ mContext.registerReceiverForAllUsers(userUpdateReceiver, filter, null, null);
+
+ // Setup receiver for device reboots or shutdowns.
+ filter = new IntentFilter(Intent.ACTION_REBOOT);
+ filter.addAction(Intent.ACTION_SHUTDOWN);
+ mContext.registerReceiverForAllUsers(
+ shutdownEventReceiver, filter, null, null);
+
+ // Only add the receivers if the registration is successful.
+ deathRecipient.addRegisteredBroadcastReceivers(
+ List.of(appUpdateReceiver, userUpdateReceiver, shutdownEventReceiver));
+
+ final long token = Binder.clearCallingIdentity();
try {
- sStatsd.statsCompanionReady();
- // If the statsCompanionReady two-way binder call returns, link to statsd.
- try {
- sStatsd.asBinder().linkToDeath(new StatsdDeathRecipient(), 0);
- } catch (RemoteException e) {
- Log.e(TAG, "linkToDeath(StatsdDeathRecipient) failed", e);
- forgetEverythingLocked();
- }
- // Setup broadcast receiver for updates.
- IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_REPLACED);
- filter.addAction(Intent.ACTION_PACKAGE_ADDED);
- filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- filter.addDataScheme("package");
- mContext.registerReceiverForAllUsers(mAppUpdateReceiver, filter, null, null);
-
- // Setup receiver for user initialize (which happens once for a new user)
- // and
- // if a user is removed.
- filter = new IntentFilter(Intent.ACTION_USER_INITIALIZE);
- filter.addAction(Intent.ACTION_USER_REMOVED);
- mContext.registerReceiverForAllUsers(mUserUpdateReceiver, filter, null, null);
-
- // Setup receiver for device reboots or shutdowns.
- filter = new IntentFilter(Intent.ACTION_REBOOT);
- filter.addAction(Intent.ACTION_SHUTDOWN);
- mContext.registerReceiverForAllUsers(
- mShutdownEventReceiver, filter, null, null);
- final long token = Binder.clearCallingIdentity();
- try {
- // Pull the latest state of UID->app name, version mapping when
- // statsd starts.
- informAllUidsLocked(mContext);
- } finally {
- restoreCallingIdentity(token);
- }
- Log.i(TAG, "Told statsd that StatsCompanionService is alive.");
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to inform statsd that statscompanion is ready", e);
- forgetEverythingLocked();
+ // Pull the latest state of UID->app name, version mapping when
+ // statsd starts.
+ informAllUidsLocked(mContext);
+ } finally {
+ Binder.restoreCallingIdentity(token);
}
+ Log.i(TAG, "Told statsd that StatsCompanionService is alive.");
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to inform statsd that statscompanion is ready", e);
}
}
private class StatsdDeathRecipient implements IBinder.DeathRecipient {
+
+ private List<BroadcastReceiver> mReceiversToUnregister;
+
+ StatsdDeathRecipient() {
+ mReceiversToUnregister = new ArrayList<>();
+ }
+
+ public void addRegisteredBroadcastReceivers(List<BroadcastReceiver> receivers) {
+ synchronized (sStatsdLock) {
+ mReceiversToUnregister.addAll(receivers);
+ }
+ }
+
@Override
public void binderDied() {
Log.i(TAG, "Statsd is dead - erase all my knowledge, except pullers");
@@ -656,20 +691,18 @@
}
}
}
- forgetEverythingLocked();
+ // We only unregister in binder death becaseu receivers can only be unregistered
+ // once, or an IllegalArgumentException is thrown.
+ for (BroadcastReceiver receiver: mReceiversToUnregister) {
+ mContext.unregisterReceiver(receiver);
+ }
+ statsdNotReadyLocked();
}
}
}
- @GuardedBy("StatsCompanionService.sStatsdLock")
- private void forgetEverythingLocked() {
+ private void statsdNotReadyLocked() {
sStatsd = null;
- mContext.unregisterReceiver(mAppUpdateReceiver);
- mContext.unregisterReceiver(mUserUpdateReceiver);
- mContext.unregisterReceiver(mShutdownEventReceiver);
- cancelAnomalyAlarm();
- cancelPullingAlarm();
-
mStatsManagerService.statsdNotReady();
}
diff --git a/api/current.txt b/api/current.txt
index 15f10fa..d944d24 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4368,7 +4368,7 @@
method @Deprecated public int noteProxyOpNoThrow(@NonNull String, @Nullable String, int);
method public int noteProxyOpNoThrow(@NonNull String, @Nullable String, int, @Nullable String, @Nullable String);
method @Nullable public static String permissionToOp(@NonNull String);
- method public void setNotedAppOpsCollector(@Nullable android.app.AppOpsManager.AppOpsCollector);
+ method public void setOnOpNotedCallback(@Nullable java.util.concurrent.Executor, @Nullable android.app.AppOpsManager.OnOpNotedCallback);
method @Deprecated public int startOp(@NonNull String, int, @NonNull String);
method public int startOp(@NonNull String, int, @Nullable String, @Nullable String, @Nullable String);
method @Deprecated public int startOpNoThrow(@NonNull String, int, @NonNull String);
@@ -4424,14 +4424,6 @@
field public static final int WATCH_FOREGROUND_CHANGES = 1; // 0x1
}
- public abstract static class AppOpsManager.AppOpsCollector {
- ctor public AppOpsManager.AppOpsCollector();
- method @NonNull public java.util.concurrent.Executor getAsyncNotedExecutor();
- method public abstract void onAsyncNoted(@NonNull android.app.AsyncNotedAppOp);
- method public abstract void onNoted(@NonNull android.app.SyncNotedAppOp);
- method public abstract void onSelfNoted(@NonNull android.app.SyncNotedAppOp);
- }
-
public static interface AppOpsManager.OnOpActiveChangedListener {
method public void onOpActiveChanged(@NonNull String, int, @NonNull String, boolean);
}
@@ -4440,6 +4432,13 @@
method public void onOpChanged(String, String);
}
+ public abstract static class AppOpsManager.OnOpNotedCallback {
+ ctor public AppOpsManager.OnOpNotedCallback();
+ method public abstract void onAsyncNoted(@NonNull android.app.AsyncNotedAppOp);
+ method public abstract void onNoted(@NonNull android.app.SyncNotedAppOp);
+ method public abstract void onSelfNoted(@NonNull android.app.SyncNotedAppOp);
+ }
+
public class Application extends android.content.ContextWrapper implements android.content.ComponentCallbacks2 {
ctor public Application();
method public static String getProcessName();
@@ -4591,7 +4590,7 @@
method @NonNull public String getMessage();
method @IntRange(from=0) public int getNotingUid();
method @NonNull public String getOp();
- method @IntRange(from=0) public long getTime();
+ method public long getTime();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.AsyncNotedAppOp> CREATOR;
}
@@ -9467,7 +9466,7 @@
public static final class WifiDeviceFilter.Builder {
ctor public WifiDeviceFilter.Builder();
method @NonNull public android.companion.WifiDeviceFilter build();
- method @NonNull public android.companion.WifiDeviceFilter.Builder setBssid(@Nullable android.net.MacAddress);
+ method @NonNull public android.companion.WifiDeviceFilter.Builder setBssid(@NonNull android.net.MacAddress);
method @NonNull public android.companion.WifiDeviceFilter.Builder setBssidMask(@NonNull android.net.MacAddress);
method @NonNull public android.companion.WifiDeviceFilter.Builder setNamePattern(@Nullable java.util.regex.Pattern);
}
@@ -9882,7 +9881,7 @@
method public void notifyChange(@NonNull android.net.Uri, @Nullable android.database.ContentObserver);
method @Deprecated public void notifyChange(@NonNull android.net.Uri, @Nullable android.database.ContentObserver, boolean);
method public void notifyChange(@NonNull android.net.Uri, @Nullable android.database.ContentObserver, int);
- method public void notifyChange(@NonNull Iterable<android.net.Uri>, @Nullable android.database.ContentObserver, int);
+ method public void notifyChange(@NonNull java.util.Collection<android.net.Uri>, @Nullable android.database.ContentObserver, int);
method @Nullable public final android.content.res.AssetFileDescriptor openAssetFile(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException;
method @Nullable public final android.content.res.AssetFileDescriptor openAssetFileDescriptor(@NonNull android.net.Uri, @NonNull String) throws java.io.FileNotFoundException;
method @Nullable public final android.content.res.AssetFileDescriptor openAssetFileDescriptor(@NonNull android.net.Uri, @NonNull String, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException;
@@ -10566,6 +10565,7 @@
field public static final String ACTION_APP_ERROR = "android.intent.action.APP_ERROR";
field public static final String ACTION_ASSIST = "android.intent.action.ASSIST";
field public static final String ACTION_ATTACH_DATA = "android.intent.action.ATTACH_DATA";
+ field public static final String ACTION_AUTO_REVOKE_PERMISSIONS = "android.intent.action.AUTO_REVOKE_PERMISSIONS";
field public static final String ACTION_BATTERY_CHANGED = "android.intent.action.BATTERY_CHANGED";
field public static final String ACTION_BATTERY_LOW = "android.intent.action.BATTERY_LOW";
field public static final String ACTION_BATTERY_OKAY = "android.intent.action.BATTERY_OKAY";
@@ -12972,11 +12972,11 @@
method @Deprecated public final void dispatchChange(boolean);
method public final void dispatchChange(boolean, @Nullable android.net.Uri);
method public final void dispatchChange(boolean, @Nullable android.net.Uri, int);
- method public final void dispatchChange(boolean, @NonNull Iterable<android.net.Uri>, int);
+ method public final void dispatchChange(boolean, @NonNull java.util.Collection<android.net.Uri>, int);
method public void onChange(boolean);
method public void onChange(boolean, @Nullable android.net.Uri);
method public void onChange(boolean, @Nullable android.net.Uri, int);
- method public void onChange(boolean, @NonNull Iterable<android.net.Uri>, int);
+ method public void onChange(boolean, @NonNull java.util.Collection<android.net.Uri>, int);
}
public interface CrossProcessCursor extends android.database.Cursor {
@@ -36154,6 +36154,8 @@
method public static boolean isExternalStorageEmulated(@NonNull java.io.File);
method public static boolean isExternalStorageLegacy();
method public static boolean isExternalStorageLegacy(@NonNull java.io.File);
+ method public static boolean isExternalStorageManager();
+ method public static boolean isExternalStorageManager(@NonNull java.io.File);
method public static boolean isExternalStorageRemovable();
method public static boolean isExternalStorageRemovable(@NonNull java.io.File);
field public static String DIRECTORY_ALARMS;
@@ -46594,12 +46596,9 @@
field public static final String EXTRA_SLOT_INDEX = "android.telephony.extra.SLOT_INDEX";
field public static final String EXTRA_SUBSCRIPTION_INDEX = "android.telephony.extra.SUBSCRIPTION_INDEX";
field public static final String IMSI_KEY_AVAILABILITY_INT = "imsi_key_availability_int";
- field public static final String KEY_5G_ICON_CONFIGURATION_STRING = "5g_icon_configuration_string";
- field public static final String KEY_5G_ICON_DISPLAY_GRACE_PERIOD_SEC_INT = "5g_icon_display_grace_period_sec_int";
field public static final String KEY_5G_NR_SSRSRP_THRESHOLDS_INT_ARRAY = "5g_nr_ssrsrp_thresholds_int_array";
field public static final String KEY_5G_NR_SSRSRQ_THRESHOLDS_INT_ARRAY = "5g_nr_ssrsrq_thresholds_int_array";
field public static final String KEY_5G_NR_SSSINR_THRESHOLDS_INT_ARRAY = "5g_nr_sssinr_thresholds_int_array";
- field public static final String KEY_5G_WATCHDOG_TIME_MS_LONG = "5g_watchdog_time_long";
field public static final String KEY_ADDITIONAL_CALL_SETTING_BOOL = "additional_call_setting_bool";
field public static final String KEY_ALLOW_ADDING_APNS_BOOL = "allow_adding_apns_bool";
field public static final String KEY_ALLOW_ADD_CALL_DURING_VIDEO_CALL_BOOL = "allow_add_call_during_video_call";
@@ -46792,7 +46791,6 @@
field public static final String KEY_SHOW_APN_SETTING_CDMA_BOOL = "show_apn_setting_cdma_bool";
field public static final String KEY_SHOW_BLOCKING_PAY_PHONE_OPTION_BOOL = "show_blocking_pay_phone_option_bool";
field public static final String KEY_SHOW_CALL_BLOCKING_DISABLED_NOTIFICATION_ALWAYS_BOOL = "show_call_blocking_disabled_notification_always_bool";
- field public static final String KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING = "show_carrier_data_icon_pattern_string";
field public static final String KEY_SHOW_CDMA_CHOICES_BOOL = "show_cdma_choices_bool";
field public static final String KEY_SHOW_FORWARDED_NUMBER_BOOL = "show_forwarded_number_bool";
field public static final String KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL = "show_iccid_in_sim_status_bool";
@@ -47572,7 +47570,6 @@
method @NonNull public java.util.List<java.lang.Integer> getAvailableServices();
method @Nullable public android.telephony.CellIdentity getCellIdentity();
method public int getDomain();
- method public int getNrState();
method @Nullable public String getRegisteredPlmn();
method public int getTransportType();
method public boolean isRegistered();
@@ -47775,9 +47772,7 @@
method public boolean getIsManualSelection();
method @NonNull public java.util.List<android.telephony.NetworkRegistrationInfo> getNetworkRegistrationInfoList();
method public String getOperatorAlphaLong();
- method @Nullable public String getOperatorAlphaLongRaw();
method public String getOperatorAlphaShort();
- method @Nullable public String getOperatorAlphaShortRaw();
method public String getOperatorNumeric();
method public boolean getRoaming();
method public int getState();
@@ -55587,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);
@@ -55601,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();
@@ -58000,7 +58001,7 @@
method @Deprecated public abstract void removeSessionCookie();
method public abstract void removeSessionCookies(@Nullable android.webkit.ValueCallback<java.lang.Boolean>);
method public abstract void setAcceptCookie(boolean);
- method public static void setAcceptFileSchemeCookies(boolean);
+ method @Deprecated public static void setAcceptFileSchemeCookies(boolean);
method public abstract void setAcceptThirdPartyCookies(android.webkit.WebView, boolean);
method public abstract void setCookie(String, String);
method public abstract void setCookie(String, String, @Nullable android.webkit.ValueCallback<java.lang.Boolean>);
@@ -58365,8 +58366,8 @@
method public abstract String getUserAgentString();
method public abstract void setAllowContentAccess(boolean);
method public abstract void setAllowFileAccess(boolean);
- method public abstract void setAllowFileAccessFromFileURLs(boolean);
- method public abstract void setAllowUniversalAccessFromFileURLs(boolean);
+ method @Deprecated public abstract void setAllowFileAccessFromFileURLs(boolean);
+ method @Deprecated public abstract void setAllowUniversalAccessFromFileURLs(boolean);
method public abstract void setAppCacheEnabled(boolean);
method @Deprecated public abstract void setAppCacheMaxSize(long);
method public abstract void setAppCachePath(String);
@@ -82232,4 +82233,3 @@
}
}
-
diff --git a/api/removed.txt b/api/removed.txt
index fb6d576..8537b21 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -69,6 +69,10 @@
package android.content {
+ public abstract class ContentResolver {
+ method @Deprecated public void notifyChange(@NonNull Iterable<android.net.Uri>, @Nullable android.database.ContentObserver, int);
+ }
+
public abstract class Context {
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 9510a3f..65251d7 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -232,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";
@@ -2939,7 +2940,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 {
@@ -4986,7 +4987,7 @@
package android.media.tv.tuner.filter {
- public class AlpFilterConfiguration extends android.media.tv.tuner.filter.FilterConfiguration {
+ public final class AlpFilterConfiguration extends android.media.tv.tuner.filter.FilterConfiguration {
method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public static android.media.tv.tuner.filter.AlpFilterConfiguration.Builder builder(@NonNull android.content.Context);
method public int getLengthType();
method public int getPacketType();
@@ -5001,10 +5002,11 @@
field public static final int PACKET_TYPE_SIGNALING = 4; // 0x4
}
- public static class AlpFilterConfiguration.Builder extends android.media.tv.tuner.filter.FilterConfiguration.Builder<android.media.tv.tuner.filter.AlpFilterConfiguration.Builder> {
+ public static final class AlpFilterConfiguration.Builder {
method @NonNull public android.media.tv.tuner.filter.AlpFilterConfiguration build();
method @NonNull public android.media.tv.tuner.filter.AlpFilterConfiguration.Builder setLengthType(int);
method @NonNull public android.media.tv.tuner.filter.AlpFilterConfiguration.Builder setPacketType(int);
+ method @NonNull public android.media.tv.tuner.filter.AlpFilterConfiguration.Builder setSettings(@Nullable android.media.tv.tuner.filter.Settings);
}
public class AudioDescriptor {
@@ -5092,15 +5094,11 @@
method public abstract int getType();
}
- public abstract static class FilterConfiguration.Builder<T extends android.media.tv.tuner.filter.FilterConfiguration.Builder<T>> {
- method @NonNull public T setSettings(@Nullable android.media.tv.tuner.filter.Settings);
- }
-
public abstract class FilterEvent {
ctor public FilterEvent();
}
- public class IpFilterConfiguration extends android.media.tv.tuner.filter.FilterConfiguration {
+ public final class IpFilterConfiguration extends android.media.tv.tuner.filter.FilterConfiguration {
method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public static android.media.tv.tuner.filter.IpFilterConfiguration.Builder builder(@NonNull android.content.Context);
method @NonNull @Size(min=4, max=16) public byte[] getDstIpAddress();
method public int getDstPort();
@@ -5110,11 +5108,12 @@
method public boolean isPassthrough();
}
- public static class IpFilterConfiguration.Builder extends android.media.tv.tuner.filter.FilterConfiguration.Builder<android.media.tv.tuner.filter.IpFilterConfiguration.Builder> {
+ public static final class IpFilterConfiguration.Builder {
method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration build();
method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setDstIpAddress(@NonNull byte[]);
method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setDstPort(int);
method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setPassthrough(boolean);
+ method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setSettings(@Nullable android.media.tv.tuner.filter.Settings);
method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setSrcIpAddress(@NonNull byte[]);
method @NonNull public android.media.tv.tuner.filter.IpFilterConfiguration.Builder setSrcPort(int);
}
@@ -5138,15 +5137,16 @@
method public boolean isSecureMemory();
}
- public class MmtpFilterConfiguration extends android.media.tv.tuner.filter.FilterConfiguration {
+ public final class MmtpFilterConfiguration extends android.media.tv.tuner.filter.FilterConfiguration {
method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public static android.media.tv.tuner.filter.MmtpFilterConfiguration.Builder builder(@NonNull android.content.Context);
method public int getMmtpPacketId();
method public int getType();
}
- public static class MmtpFilterConfiguration.Builder extends android.media.tv.tuner.filter.FilterConfiguration.Builder<android.media.tv.tuner.filter.MmtpFilterConfiguration.Builder> {
+ public static final class MmtpFilterConfiguration.Builder {
method @NonNull public android.media.tv.tuner.filter.MmtpFilterConfiguration build();
method @NonNull public android.media.tv.tuner.filter.MmtpFilterConfiguration.Builder setMmtpPacketId(int);
+ method @NonNull public android.media.tv.tuner.filter.MmtpFilterConfiguration.Builder setSettings(@Nullable android.media.tv.tuner.filter.Settings);
}
public class MmtpRecordEvent extends android.media.tv.tuner.filter.FilterEvent {
@@ -5281,7 +5281,7 @@
field public static final long TIMESTAMP_UNAVAILABLE = -1L; // 0xffffffffffffffffL
}
- public class TlvFilterConfiguration extends android.media.tv.tuner.filter.FilterConfiguration {
+ public final class TlvFilterConfiguration extends android.media.tv.tuner.filter.FilterConfiguration {
method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public static android.media.tv.tuner.filter.TlvFilterConfiguration.Builder builder(@NonNull android.content.Context);
method public int getPacketType();
method public int getType();
@@ -5294,21 +5294,23 @@
field public static final int PACKET_TYPE_SIGNALING = 254; // 0xfe
}
- public static class TlvFilterConfiguration.Builder extends android.media.tv.tuner.filter.FilterConfiguration.Builder<android.media.tv.tuner.filter.TlvFilterConfiguration.Builder> {
+ public static final class TlvFilterConfiguration.Builder {
method @NonNull public android.media.tv.tuner.filter.TlvFilterConfiguration build();
method @NonNull public android.media.tv.tuner.filter.TlvFilterConfiguration.Builder setCompressedIpPacket(boolean);
method @NonNull public android.media.tv.tuner.filter.TlvFilterConfiguration.Builder setPacketType(int);
method @NonNull public android.media.tv.tuner.filter.TlvFilterConfiguration.Builder setPassthrough(boolean);
+ method @NonNull public android.media.tv.tuner.filter.TlvFilterConfiguration.Builder setSettings(@Nullable android.media.tv.tuner.filter.Settings);
}
- public class TsFilterConfiguration extends android.media.tv.tuner.filter.FilterConfiguration {
+ public final class TsFilterConfiguration extends android.media.tv.tuner.filter.FilterConfiguration {
method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public static android.media.tv.tuner.filter.TsFilterConfiguration.Builder builder(@NonNull android.content.Context);
method public int getTpid();
method public int getType();
}
- public static class TsFilterConfiguration.Builder extends android.media.tv.tuner.filter.FilterConfiguration.Builder<android.media.tv.tuner.filter.TsFilterConfiguration.Builder> {
+ public static final class TsFilterConfiguration.Builder {
method @NonNull public android.media.tv.tuner.filter.TsFilterConfiguration build();
+ method @NonNull public android.media.tv.tuner.filter.TsFilterConfiguration.Builder setSettings(@Nullable android.media.tv.tuner.filter.Settings);
method @NonNull public android.media.tv.tuner.filter.TsFilterConfiguration.Builder setTpid(int);
}
@@ -7328,17 +7330,17 @@
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void connect(int, @Nullable android.net.wifi.WifiManager.ActionListener);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void disable(int, @Nullable android.net.wifi.WifiManager.ActionListener);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK}) public void disableEphemeralNetwork(@NonNull String);
- method @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL) public void factoryReset();
+ method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void factoryReset();
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void forget(int, @Nullable android.net.wifi.WifiManager.ActionListener);
method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.List<android.util.Pair<android.net.wifi.WifiConfiguration,java.util.Map<java.lang.Integer,java.util.List<android.net.wifi.ScanResult>>>> getAllMatchingWifiConfigs(@NonNull java.util.List<android.net.wifi.ScanResult>);
- method @Nullable @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL) public String getCountryCode();
+ method @Nullable @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public String getCountryCode();
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public android.net.Network getCurrentNetwork();
method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public String[] getFactoryMacAddresses();
method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD}) public java.util.Map<android.net.wifi.hotspot2.OsuProvider,java.util.List<android.net.wifi.ScanResult>> getMatchingOsuProviders(@Nullable java.util.List<android.net.wifi.ScanResult>);
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();
@@ -7459,9 +7461,9 @@
method public void onWifiUsabilityStats(int, boolean, @NonNull android.net.wifi.WifiUsabilityStatsEntry);
}
- public static interface WifiManager.ScoreChangeCallback {
- method public void onScoreChange(int, int);
- method public void onTriggerUpdateOfWifiUsabilityStats(int);
+ public static interface WifiManager.ScoreUpdateObserver {
+ method public void notifyScoreUpdate(int, int);
+ method public void triggerUpdateOfWifiUsabilityStats(int);
}
public static interface WifiManager.SoftApCallback {
@@ -7481,9 +7483,9 @@
}
public static interface WifiManager.WifiConnectedNetworkScorer {
- method public void setScoreChangeCallback(@NonNull android.net.wifi.WifiManager.ScoreChangeCallback);
- method public void start(int);
- method public void stop(int);
+ method public void onSetScoreUpdateObserver(@NonNull android.net.wifi.WifiManager.ScoreUpdateObserver);
+ method public void onStart(int);
+ method public void onStop(int);
}
public final class WifiMigration {
@@ -7985,7 +7987,7 @@
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void factoryReset(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.READ_WIFI_CREDENTIAL}) public void requestPersistentGroupInfo(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @Nullable android.net.wifi.p2p.WifiP2pManager.PersistentGroupInfoListener);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.OVERRIDE_WIFI_CONFIG}) public void setDeviceName(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @NonNull String, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener);
- method @RequiresPermission(allOf={android.Manifest.permission.CONNECTIVITY_INTERNAL, android.Manifest.permission.CONFIGURE_WIFI_DISPLAY}) public void setMiracastMode(int);
+ method @RequiresPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY) public void setMiracastMode(int);
method @RequiresPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY) public void setWfdInfo(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @NonNull android.net.wifi.p2p.WifiP2pWfdInfo, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.OVERRIDE_WIFI_CONFIG}) public void setWifiP2pChannels(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, int, int, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener);
method @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void startListening(@NonNull android.net.wifi.p2p.WifiP2pManager.Channel, @Nullable android.net.wifi.p2p.WifiP2pManager.ActionListener);
@@ -8944,7 +8946,7 @@
}
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 +8954,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);
}
@@ -9435,7 +9437,6 @@
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";
@@ -9444,11 +9445,6 @@
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
@@ -10912,19 +10908,6 @@
method @NonNull public java.util.List<android.telephony.CbGeoUtils.LatLng> getVertices();
}
- public final class CdmaEriInformation implements android.os.Parcelable {
- method public int describeContents();
- method public int getEriIconIndex();
- method public int getEriIconMode();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CdmaEriInformation> CREATOR;
- field public static final int ERI_FLASH = 2; // 0x2
- field public static final int ERI_ICON_MODE_FLASH = 1; // 0x1
- field public static final int ERI_ICON_MODE_NORMAL = 0; // 0x0
- field public static final int ERI_OFF = 1; // 0x1
- field public static final int ERI_ON = 0; // 0x0
- }
-
public class CellBroadcastIntents {
method public static void sendSmsCbReceivedBroadcast(@NonNull android.content.Context, @Nullable android.os.UserHandle, @NonNull android.telephony.SmsCbMessage, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, int);
field public static final String ACTION_AREA_INFO_UPDATED = "android.telephony.action.AREA_INFO_UPDATED";
@@ -10982,7 +10965,6 @@
public final class DataSpecificRegistrationInfo implements android.os.Parcelable {
method public int describeContents();
method @NonNull public android.telephony.LteVopsSupportInfo getLteVopsSupportInfo();
- method public boolean isUsingCarrierAggregation();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.DataSpecificRegistrationInfo> CREATOR;
}
@@ -11220,19 +11202,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();
@@ -11364,11 +11333,9 @@
method public void fillInNotifierBundle(@NonNull android.os.Bundle);
method public int getDataNetworkType();
method public int getDataRegistrationState();
- method public boolean getDataRoamingFromRegistration();
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);
- method public int getNrFrequencyRange();
method @NonNull public static android.telephony.ServiceState newFromBundle(@NonNull android.os.Bundle);
field public static final int ROAMING_TYPE_DOMESTIC = 2; // 0x2
field public static final int ROAMING_TYPE_INTERNATIONAL = 3; // 0x3
@@ -11620,7 +11587,6 @@
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCarrierPrivilegeStatus(int);
method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<java.lang.String> getCarrierPrivilegedPackagesForAllActiveSubscriptions();
method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.CarrierRestrictionRules getCarrierRestrictionRules();
- method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.CdmaEriInformation getCdmaEriInformation();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMdn();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMdn(int);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMin();
@@ -11728,10 +11694,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();
@@ -11904,23 +11868,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/system-removed.txt b/api/system-removed.txt
index 07b8969..23e2499 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -11,6 +11,12 @@
public class AppOpsManager {
method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.GET_APP_OPS_STATS) public java.util.List<android.app.AppOpsManager.PackageOps> getOpsForPackage(int, @NonNull String, @Nullable int[]);
+ method @Deprecated public void setNotedAppOpsCollector(@Nullable android.app.AppOpsManager.AppOpsCollector);
+ }
+
+ @Deprecated public abstract static class AppOpsManager.AppOpsCollector extends android.app.AppOpsManager.OnOpNotedCallback {
+ ctor public AppOpsManager.AppOpsCollector();
+ method @NonNull public java.util.concurrent.Executor getAsyncNotedExecutor();
}
public class Notification implements android.os.Parcelable {
diff --git a/api/test-current.txt b/api/test-current.txt
index 9d284b5..218b934 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";
@@ -1278,7 +1279,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 +2812,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 {
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..32a5243 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"];
@@ -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;
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 974e203..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 3940aa8..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..49163273 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 isolatedUid,
+ int hostUid, 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/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 4bc1fa0..6564dc9 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -162,7 +162,7 @@
* might also make sense inside of a single app if the access is forwarded between two features of
* the app.
*
- * <p>An app can register an {@link AppOpsCollector} to get informed about what accesses the
+ * <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
* particularly useful for an app that want to find unexpected private data accesses.
*/
@@ -206,16 +206,16 @@
private static final Object sLock = new Object();
- /** Current {@link AppOpsCollector}. Change via {@link #setNotedAppOpsCollector} */
+ /** Current {@link OnOpNotedCallback}. Change via {@link #setOnOpNotedCallback} */
@GuardedBy("sLock")
- private static @Nullable AppOpsCollector sNotedAppOpsCollector;
+ private static @Nullable OnOpNotedCallback sOnOpNotedCallback;
/**
* Additional collector that collect accesses and forwards a few of them them via
* {@link IAppOpsService#reportRuntimeAppOpAccessMessageAndGetConfig}.
*/
- private static AppOpsCollector sMessageCollector =
- new AppOpsCollector() {
+ private static OnOpNotedCallback sMessageCollector =
+ new OnOpNotedCallback() {
@Override
public void onNoted(@NonNull SyncNotedAppOp op) {
reportStackTraceIfNeeded(op);
@@ -7823,8 +7823,8 @@
*/
private void collectNotedOpForSelf(int op, @Nullable String featureId) {
synchronized (sLock) {
- if (sNotedAppOpsCollector != null) {
- sNotedAppOpsCollector.onSelfNoted(new SyncNotedAppOp(op, featureId));
+ if (sOnOpNotedCallback != null) {
+ sOnOpNotedCallback.onSelfNoted(new SyncNotedAppOp(op, featureId));
}
}
sMessageCollector.onSelfNoted(new SyncNotedAppOp(op, featureId));
@@ -7973,8 +7973,8 @@
synchronized (sLock) {
for (int code = notedAppOps.nextSetBit(0); code != -1;
code = notedAppOps.nextSetBit(code + 1)) {
- if (sNotedAppOpsCollector != null) {
- sNotedAppOpsCollector.onNoted(new SyncNotedAppOp(code, featureId));
+ if (sOnOpNotedCallback != null) {
+ sOnOpNotedCallback.onNoted(new SyncNotedAppOp(code, featureId));
}
}
}
@@ -7987,33 +7987,45 @@
}
/**
- * Register a new {@link AppOpsCollector}.
+ * Set a new {@link OnOpNotedCallback}.
*
- * <p>There can only ever be one collector per process. If there currently is a collector
- * registered, it will be unregistered.
+ * <p>There can only ever be one collector per process. If there currently is another callback
+ * set, this will fail.
*
- * <p><b>Only appops related to dangerous permissions are collected.</b>
+ * @param asyncExecutor executor to execute {@link OnOpNotedCallback#onAsyncNoted} on, {@code
+ * null} to unset
+ * @param callback listener to set, {@code null} to unset
*
- * @param collector The collector to set or {@code null} to unregister.
+ * @throws IllegalStateException If another callback is already registered
*/
- public void setNotedAppOpsCollector(@Nullable AppOpsCollector collector) {
+ public void setOnOpNotedCallback(@Nullable @CallbackExecutor Executor asyncExecutor,
+ @Nullable OnOpNotedCallback callback) {
+ Preconditions.checkState((callback == null) == (asyncExecutor == null));
+
synchronized (sLock) {
- if (sNotedAppOpsCollector != null) {
+ if (callback == null) {
+ Preconditions.checkState(sOnOpNotedCallback != null,
+ "No callback is currently registered");
+
try {
mService.stopWatchingAsyncNoted(mContext.getPackageName(),
- sNotedAppOpsCollector.mAsyncCb);
+ sOnOpNotedCallback.mAsyncCb);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
- }
- sNotedAppOpsCollector = collector;
+ sOnOpNotedCallback = null;
+ } else {
+ Preconditions.checkState(sOnOpNotedCallback == null,
+ "Another callback is already registered");
- if (sNotedAppOpsCollector != null) {
+ callback.mAsyncExecutor = asyncExecutor;
+ sOnOpNotedCallback = callback;
+
List<AsyncNotedAppOp> missedAsyncOps = null;
try {
mService.startWatchingAsyncNoted(mContext.getPackageName(),
- sNotedAppOpsCollector.mAsyncCb);
+ sOnOpNotedCallback.mAsyncCb);
missedAsyncOps = mService.extractAsyncOps(mContext.getPackageName());
} catch (RemoteException e) {
e.rethrowFromSystemServer();
@@ -8023,10 +8035,9 @@
int numMissedAsyncOps = missedAsyncOps.size();
for (int i = 0; i < numMissedAsyncOps; i++) {
final AsyncNotedAppOp asyncNotedAppOp = missedAsyncOps.get(i);
- if (sNotedAppOpsCollector != null) {
- sNotedAppOpsCollector.getAsyncNotedExecutor().execute(
- () -> sNotedAppOpsCollector.onAsyncNoted(
- asyncNotedAppOp));
+ if (sOnOpNotedCallback != null) {
+ sOnOpNotedCallback.getAsyncNotedExecutor().execute(
+ () -> sOnOpNotedCallback.onAsyncNoted(asyncNotedAppOp));
}
}
}
@@ -8034,27 +8045,50 @@
}
}
+ // TODO moltmann: Remove
/**
- * @return {@code true} iff the process currently is currently collecting noted appops.
+ * Will be removed before R ships, leave it just to not break apps immediately.
*
- * @see #setNotedAppOpsCollector(AppOpsCollector)
+ * @removed
*
* @hide
*/
- public static boolean isCollectingNotedAppOps() {
- return sNotedAppOpsCollector != null;
+ @SystemApi
+ @Deprecated
+ public void setNotedAppOpsCollector(@Nullable AppOpsCollector collector) {
+ synchronized (sLock) {
+ if (collector != null) {
+ if (isListeningForOpNoted()) {
+ setOnOpNotedCallback(null, null);
+ }
+ setOnOpNotedCallback(new HandlerExecutor(Handler.getMain()), collector);
+ } else if (sOnOpNotedCallback != null) {
+ setOnOpNotedCallback(null, null);
+ }
+ }
}
/**
- * Callback an app can {@link #setNotedAppOpsCollector register} to monitor the app-ops the
- * system has tracked for it. I.e. each time any app calls {@link #noteOp} or {@link #startOp}
- * one of the callback methods of this object is called.
+ * @return {@code true} iff the process currently is currently collecting noted appops.
*
- * <p><b>There will be a callback for all app-ops related to runtime permissions, but not
+ * @see #setOnOpNotedCallback
+ *
+ * @hide
+ */
+ public static boolean isListeningForOpNoted() {
+ return sOnOpNotedCallback != null;
+ }
+
+ /**
+ * Callback an app can {@link #setOnOpNotedCallback set} to monitor the app-ops the
+ * system has tracked for it. I.e. each time any app calls {@link #noteOp} or {@link #startOp}
+ * one of a method of this object is called.
+ *
+ * <p><b>There will be a call for all app-ops related to runtime permissions, but not
* necessarily for all other app-ops.
*
* <pre>
- * setNotedAppOpsCollector(new AppOpsCollector() {
+ * setOnOpNotedCallback(getMainExecutor(), new OnOpNotedCallback() {
* ArraySet<Pair<String, String>> opsNotedForThisProcess = new ArraySet<>();
*
* private synchronized void addAccess(String op, String accessLocation) {
@@ -8079,24 +8113,36 @@
* });
* </pre>
*
- * @see #setNotedAppOpsCollector
+ * @see #setOnOpNotedCallback
*/
- public abstract static class AppOpsCollector {
+ public abstract static class OnOpNotedCallback {
+ private @NonNull Executor mAsyncExecutor;
+
/** Callback registered with the system. This will receive the async notes ops */
private final IAppOpsAsyncNotedCallback mAsyncCb = new IAppOpsAsyncNotedCallback.Stub() {
@Override
public void opNoted(AsyncNotedAppOp op) {
Objects.requireNonNull(op);
- getAsyncNotedExecutor().execute(() -> onAsyncNoted(op));
+ long token = Binder.clearCallingIdentity();
+ try {
+ getAsyncNotedExecutor().execute(() -> onAsyncNoted(op));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
};
+ // TODO moltmann: Remove
/**
+ * Will be removed before R ships.
+ *
* @return The executor for the system to use when calling {@link #onAsyncNoted}.
+ *
+ * @hide
*/
- public @NonNull Executor getAsyncNotedExecutor() {
- return new HandlerExecutor(Handler.getMain());
+ protected @NonNull Executor getAsyncNotedExecutor() {
+ return mAsyncExecutor;
}
/**
@@ -8106,7 +8152,7 @@
* <p>Called on the calling thread before the API returns. This allows the app to e.g.
* collect stack traces to figure out where the access came from.
*
- * @param op The op noted
+ * @param op op noted
*/
public abstract void onNoted(@NonNull SyncNotedAppOp op);
@@ -8116,7 +8162,7 @@
* <p>This is very similar to {@link #onNoted} only that the tracking was not caused by the
* API provider in a separate process, but by one in the app's own process.
*
- * @param op The op noted
+ * @param op op noted
*/
public abstract void onSelfNoted(@NonNull SyncNotedAppOp op);
@@ -8128,14 +8174,30 @@
* guaranteed. Due to how async calls work in Android this might even be delivered slightly
* before the private data is delivered to the app.
*
- * <p>If the app is not running or no {@link AppOpsCollector} is registered a small amount
- * of noted app-ops are buffered and then delivered as soon as a collector is registered.
+ * <p>If the app is not running or no {@link OnOpNotedCallback} is registered a small amount
+ * of noted app-ops are buffered and then delivered as soon as a listener is registered.
*
- * @param asyncOp The op noted
+ * @param asyncOp op noted
*/
public abstract void onAsyncNoted(@NonNull AsyncNotedAppOp asyncOp);
}
+ // TODO moltmann: Remove
+ /**
+ * Will be removed before R ships, leave it just to not break apps immediately.
+ *
+ * @removed
+ *
+ * @hide
+ */
+ @SystemApi
+ @Deprecated
+ public abstract static class AppOpsCollector extends OnOpNotedCallback {
+ public @NonNull Executor getAsyncNotedExecutor() {
+ return new HandlerExecutor(Handler.getMain());
+ }
+ };
+
/**
* Generate a stack trace used for noted app-ops logging.
*
diff --git a/core/java/android/app/AsyncNotedAppOp.java b/core/java/android/app/AsyncNotedAppOp.java
index c2b2063..4d955db 100644
--- a/core/java/android/app/AsyncNotedAppOp.java
+++ b/core/java/android/app/AsyncNotedAppOp.java
@@ -16,6 +16,7 @@
package android.app;
+import android.annotation.CurrentTimeMillisLong;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -27,10 +28,11 @@
/**
* When an {@link AppOpsManager#noteOp(String, int, String, String, String) app-op is noted} and the
- * app the app-op is noted for has a {@link AppOpsManager.AppOpsCollector} registered the note-event
- * needs to be delivered to the collector. Usually this is done via an {@link SyncNotedAppOp}, but
- * in some cases this is not possible. In this case an {@link AsyncNotedAppOp} is send to the system
- * server and then forwarded to the {@link AppOpsManager.AppOpsCollector} in the app.
+ * app the app-op is noted for has a {@link AppOpsManager.OnOpNotedCallback} registered the
+ * note-event needs to be delivered to the callback. Usually this is done via an
+ * {@link SyncNotedAppOp}, but in some cases this is not possible. In this case an
+ * {@link AsyncNotedAppOp} is send to the system server and then forwarded to the
+ * {@link AppOpsManager.OnOpNotedCallback} in the app.
*/
@Immutable
@DataClass(genEqualsHashCode = true,
@@ -53,7 +55,7 @@
private final @NonNull String mMessage;
/** Milliseconds since epoch when the op was noted */
- private final @IntRange(from = 0) long mTime;
+ private final @CurrentTimeMillisLong long mTime;
/**
* @return Op that was noted.
@@ -70,7 +72,7 @@
- // Code below generated by codegen v1.0.14.
+ // Code below generated by codegen v1.0.15.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -104,7 +106,7 @@
@IntRange(from = 0) int notingUid,
@Nullable String featureId,
@NonNull String message,
- @IntRange(from = 0) long time) {
+ @CurrentTimeMillisLong long time) {
this.mOpCode = opCode;
com.android.internal.util.AnnotationValidations.validate(
IntRange.class, null, mOpCode,
@@ -119,8 +121,7 @@
NonNull.class, null, mMessage);
this.mTime = time;
com.android.internal.util.AnnotationValidations.validate(
- IntRange.class, null, mTime,
- "from", 0);
+ CurrentTimeMillisLong.class, null, mTime);
onConstructed();
}
@@ -153,7 +154,7 @@
* Milliseconds since epoch when the op was noted
*/
@DataClass.Generated.Member
- public @IntRange(from = 0) long getTime() {
+ public @CurrentTimeMillisLong long getTime() {
return mTime;
}
@@ -240,8 +241,7 @@
NonNull.class, null, mMessage);
this.mTime = time;
com.android.internal.util.AnnotationValidations.validate(
- IntRange.class, null, mTime,
- "from", 0);
+ CurrentTimeMillisLong.class, null, mTime);
onConstructed();
}
@@ -261,10 +261,10 @@
};
@DataClass.Generated(
- time = 1583375913345L,
- codegenVersion = "1.0.14",
+ time = 1583866178330L,
+ 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.IntRange(from=0L) 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 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)")
@Deprecated
private void __metadata() {}
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/SyncNotedAppOp.java b/core/java/android/app/SyncNotedAppOp.java
index aa11b95..13b90ca 100644
--- a/core/java/android/app/SyncNotedAppOp.java
+++ b/core/java/android/app/SyncNotedAppOp.java
@@ -28,9 +28,9 @@
* Description of an app-op that was noted for the current process.
*
* <p>This is either delivered after a
- * {@link AppOpsManager.AppOpsCollector#onNoted(SyncNotedAppOp) two way binder call} or
+ * {@link AppOpsManager.OnOpNotedCallback#onNoted(SyncNotedAppOp) two way binder call} or
* when the app
- * {@link AppOpsManager.AppOpsCollector#onSelfNoted(SyncNotedAppOp) notes an app-op for
+ * {@link AppOpsManager.OnOpNotedCallback#onSelfNoted(SyncNotedAppOp) notes an app-op for
* itself}.
*/
@Immutable
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/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/companion/WifiDeviceFilter.java b/core/java/android/companion/WifiDeviceFilter.java
index 58bf874..8b48f4c 100644
--- a/core/java/android/companion/WifiDeviceFilter.java
+++ b/core/java/android/companion/WifiDeviceFilter.java
@@ -51,6 +51,7 @@
* expression will be shown
*/
@DataClass.ParcelWith(Parcelling.BuiltIn.ForPattern.class)
+ @DataClass.MaySetToNull
private @Nullable Pattern mNamePattern = null;
/**
@@ -86,7 +87,7 @@
- // Code below generated by codegen v1.0.11.
+ // Code below generated by codegen v1.0.15.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -273,7 +274,7 @@
* If set, only devices with BSSID matching the given one will be shown
*/
@DataClass.Generated.Member
- public @NonNull Builder setBssid(@Nullable MacAddress value) {
+ public @NonNull Builder setBssid(@NonNull MacAddress value) {
checkNotUsed();
mBuilderFieldsSet |= 0x2;
mBssid = value;
@@ -322,11 +323,15 @@
}
@DataClass.Generated(
- time = 1571960300742L,
- codegenVersion = "1.0.11",
+ time = 1582688421965L,
+ codegenVersion = "1.0.15",
sourceFile = "frameworks/base/core/java/android/companion/WifiDeviceFilter.java",
- inputSignatures = "private @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForPattern.class) @android.annotation.Nullable java.util.regex.Pattern mNamePattern\nprivate @android.annotation.Nullable android.net.MacAddress mBssid\nprivate @android.annotation.NonNull android.net.MacAddress mBssidMask\npublic @java.lang.Override boolean matches(android.net.wifi.ScanResult)\npublic @java.lang.Override java.lang.String getDeviceDisplayName(android.net.wifi.ScanResult)\npublic @java.lang.Override int getMediumType()\nclass WifiDeviceFilter extends java.lang.Object implements [android.companion.DeviceFilter<android.net.wifi.ScanResult>]\n@com.android.internal.util.DataClass(genParcelable=true, genAidl=false, genBuilder=true, genEqualsHashCode=true, genHiddenGetters=true)")
+ inputSignatures = "private @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForPattern.class) @com.android.internal.util.DataClass.MaySetToNull @android.annotation.Nullable java.util.regex.Pattern mNamePattern\nprivate @android.annotation.Nullable android.net.MacAddress mBssid\nprivate @android.annotation.NonNull android.net.MacAddress mBssidMask\npublic @java.lang.Override boolean matches(android.net.wifi.ScanResult)\npublic @java.lang.Override java.lang.String getDeviceDisplayName(android.net.wifi.ScanResult)\npublic @java.lang.Override int getMediumType()\nclass WifiDeviceFilter extends java.lang.Object implements [android.companion.DeviceFilter<android.net.wifi.ScanResult>]\n@com.android.internal.util.DataClass(genParcelable=true, genAidl=false, genBuilder=true, genEqualsHashCode=true, genHiddenGetters=true)")
@Deprecated
private void __metadata() {}
+
+ //@formatter:on
+ // End of generated code
+
}
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 911ffa0..31e1fc8 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -83,6 +83,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Random;
@@ -2670,6 +2671,15 @@
ContentProvider.getUserIdFromUri(uri, mContext.getUserId()));
}
+ /** @removed */
+ @Deprecated
+ public void notifyChange(@NonNull Iterable<Uri> uris, @Nullable ContentObserver observer,
+ @NotifyFlags int flags) {
+ final Collection<Uri> asCollection = new ArrayList<>();
+ uris.forEach(asCollection::add);
+ notifyChange(asCollection, observer, flags);
+ }
+
/**
* Notify registered observers that several rows have been updated.
* <p>
@@ -2694,7 +2704,7 @@
* @param flags Flags such as {@link #NOTIFY_SYNC_TO_NETWORK} or
* {@link #NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS}.
*/
- public void notifyChange(@NonNull Iterable<Uri> uris, @Nullable ContentObserver observer,
+ public void notifyChange(@NonNull Collection<Uri> uris, @Nullable ContentObserver observer,
@NotifyFlags int flags) {
Objects.requireNonNull(uris, "uris");
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index c6f6972..4bb7346 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1881,6 +1881,20 @@
"android.intent.action.MANAGE_PERMISSIONS";
/**
+ * Activity action: Launch UI to manage auto-revoke state.
+ * <p>
+ * Input: {@link #EXTRA_PACKAGE_NAME} specifies the package whose
+ * auto-revoke state will be reviewed (mandatory).
+ * </p>
+ * <p>
+ * Output: Nothing.
+ * </p>
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_AUTO_REVOKE_PERMISSIONS =
+ "android.intent.action.AUTO_REVOKE_PERMISSIONS";
+
+ /**
* Activity action: Launch UI to review permissions for an app.
* The system uses this intent if permission review for apps not
* supporting the new runtime permissions model is enabled. In
diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java
index 61128f2..f19ab01 100644
--- a/core/java/android/content/IntentFilter.java
+++ b/core/java/android/content/IntentFilter.java
@@ -274,6 +274,9 @@
*/
public static final String SCHEME_HTTPS = "https";
+ /** The value to indicate a wildcard for incoming match arguments. */
+ private static final String WILDCARD = "*";
+
private int mPriority;
@UnsupportedAppUsage
private int mOrder;
@@ -758,6 +761,17 @@
* @return True if the action is listed in the filter.
*/
public final boolean matchAction(String action) {
+ return matchAction(action, false);
+ }
+
+ /**
+ * Variant of {@link #matchAction(String)} that allows a wildcard for the provided action.
+ * @param wildcardSupported if true, will allow action to use wildcards
+ */
+ private boolean matchAction(String action, boolean wildcardSupported) {
+ if (wildcardSupported && !mActions.isEmpty() && WILDCARD.equals(action)) {
+ return true;
+ }
return hasAction(action);
}
@@ -1120,20 +1134,33 @@
* {@link IntentFilter#MATCH_CATEGORY_HOST}.
*/
public int match(Uri data) {
+ return match(data, false);
+ }
+
+ /**
+ * Variant of {@link #match(Uri)} that supports wildcards on the scheme, host and
+ * path of the provided {@link Uri}
+ *
+ * @param wildcardSupported if true, will allow parameters to use wildcards
+ * @hide
+ */
+ public int match(Uri data, boolean wildcardSupported) {
String host = data.getHost();
if (host == null) {
return NO_MATCH_DATA;
}
if (false) Log.v("IntentFilter",
"Match host " + host + ": " + mHost);
- if (mWild) {
- if (host.length() < mHost.length()) {
+ if (!wildcardSupported || !WILDCARD.equals(host)) {
+ if (mWild) {
+ if (host.length() < mHost.length()) {
+ return NO_MATCH_DATA;
+ }
+ host = host.substring(host.length() - mHost.length());
+ }
+ if (host.compareToIgnoreCase(mHost) != 0) {
return NO_MATCH_DATA;
}
- host = host.substring(host.length()-mHost.length());
- }
- if (host.compareToIgnoreCase(mHost) != 0) {
- return NO_MATCH_DATA;
}
if (mPort >= 0) {
if (mPort != data.getPort()) {
@@ -1207,9 +1234,21 @@
* filter.
*/
public final boolean hasDataSchemeSpecificPart(String data) {
+ return hasDataSchemeSpecificPart(data, false);
+ }
+
+ /**
+ * Variant of {@link #hasDataSchemeSpecificPart(String)} that supports wildcards on the provided
+ * ssp.
+ * @param supportWildcards if true, will allow parameters to use wildcards
+ */
+ private boolean hasDataSchemeSpecificPart(String data, boolean supportWildcards) {
if (mDataSchemeSpecificParts == null) {
return false;
}
+ if (supportWildcards && WILDCARD.equals(data) && mDataSchemeSpecificParts.size() > 0) {
+ return true;
+ }
final int numDataSchemeSpecificParts = mDataSchemeSpecificParts.size();
for (int i = 0; i < numDataSchemeSpecificParts; i++) {
final PatternMatcher pe = mDataSchemeSpecificParts.get(i);
@@ -1388,9 +1427,21 @@
* filter.
*/
public final boolean hasDataPath(String data) {
+ return hasDataPath(data, false);
+ }
+
+ /**
+ * Variant of {@link #hasDataPath(String)} that supports wildcards on the provided scheme, host,
+ * and path.
+ * @param wildcardSupported if true, will allow parameters to use wildcards
+ */
+ private boolean hasDataPath(String data, boolean wildcardSupported) {
if (mDataPaths == null) {
return false;
}
+ if (wildcardSupported && WILDCARD.equals(data)) {
+ return true;
+ }
final int numDataPaths = mDataPaths.size();
for (int i = 0; i < numDataPaths; i++) {
final PatternMatcher pe = mDataPaths.get(i);
@@ -1435,13 +1486,24 @@
* {@link #MATCH_CATEGORY_PORT}, {@link #NO_MATCH_DATA}.
*/
public final int matchDataAuthority(Uri data) {
- if (mDataAuthorities == null || data == null) {
+ return matchDataAuthority(data, false);
+ }
+
+ /**
+ * Variant of {@link #matchDataAuthority(Uri)} that allows wildcard matching of the provided
+ * authority.
+ *
+ * @param wildcardSupported if true, will allow parameters to use wildcards
+ * @hide
+ */
+ public final int matchDataAuthority(Uri data, boolean wildcardSupported) {
+ if (data == null || mDataAuthorities == null) {
return NO_MATCH_DATA;
}
final int numDataAuthorities = mDataAuthorities.size();
for (int i = 0; i < numDataAuthorities; i++) {
final AuthorityEntry ae = mDataAuthorities.get(i);
- int match = ae.match(data);
+ int match = ae.match(data, wildcardSupported);
if (match >= 0) {
return match;
}
@@ -1488,6 +1550,15 @@
* @see #match
*/
public final int matchData(String type, String scheme, Uri data) {
+ return matchData(type, scheme, data, false);
+ }
+
+ /**
+ * Variant of {@link #matchData(String, String, Uri)} that allows wildcard matching
+ * of the provided type, scheme, host and path parameters.
+ * @param wildcardSupported if true, will allow parameters to use wildcards
+ */
+ private int matchData(String type, String scheme, Uri data, boolean wildcardSupported) {
final ArrayList<String> types = mDataTypes;
final ArrayList<String> schemes = mDataSchemes;
@@ -1499,7 +1570,8 @@
}
if (schemes != null) {
- if (schemes.contains(scheme != null ? scheme : "")) {
+ if (schemes.contains(scheme != null ? scheme : "")
+ || wildcardSupported && WILDCARD.equals(scheme)) {
match = MATCH_CATEGORY_SCHEME;
} else {
return NO_MATCH_DATA;
@@ -1507,19 +1579,19 @@
final ArrayList<PatternMatcher> schemeSpecificParts = mDataSchemeSpecificParts;
if (schemeSpecificParts != null && data != null) {
- match = hasDataSchemeSpecificPart(data.getSchemeSpecificPart())
+ match = hasDataSchemeSpecificPart(data.getSchemeSpecificPart(), wildcardSupported)
? MATCH_CATEGORY_SCHEME_SPECIFIC_PART : NO_MATCH_DATA;
}
if (match != MATCH_CATEGORY_SCHEME_SPECIFIC_PART) {
// If there isn't any matching ssp, we need to match an authority.
final ArrayList<AuthorityEntry> authorities = mDataAuthorities;
if (authorities != null) {
- int authMatch = matchDataAuthority(data);
+ int authMatch = matchDataAuthority(data, wildcardSupported);
if (authMatch >= 0) {
final ArrayList<PatternMatcher> paths = mDataPaths;
if (paths == null) {
match = authMatch;
- } else if (hasDataPath(data.getPath())) {
+ } else if (hasDataPath(data.getPath(), wildcardSupported)) {
match = MATCH_CATEGORY_PATH;
} else {
return NO_MATCH_DATA;
@@ -1541,7 +1613,8 @@
// to force everyone to say they handle content: or file: URIs.
if (scheme != null && !"".equals(scheme)
&& !"content".equals(scheme)
- && !"file".equals(scheme)) {
+ && !"file".equals(scheme)
+ && !(wildcardSupported && WILDCARD.equals(scheme))) {
return NO_MATCH_DATA;
}
}
@@ -1701,13 +1774,23 @@
*/
public final int match(String action, String type, String scheme,
Uri data, Set<String> categories, String logTag) {
- if (action != null && !matchAction(action)) {
+ return match(action, type, scheme, data, categories, logTag, false /*supportWildcards*/);
+ }
+
+ /**
+ * Variant of {@link #match(ContentResolver, Intent, boolean, String)} that supports wildcards
+ * in the action, type, scheme, host and path.
+ * @hide if true, will allow supported parameters to use wildcards to match this filter
+ */
+ public final int match(String action, String type, String scheme,
+ Uri data, Set<String> categories, String logTag, boolean supportWildcards) {
+ if (action != null && !matchAction(action, supportWildcards)) {
if (false) Log.v(
logTag, "No matching action " + action + " for " + this);
return NO_MATCH_ACTION;
}
- int dataMatch = matchData(type, scheme, data);
+ int dataMatch = matchData(type, scheme, data, supportWildcards);
if (dataMatch < 0) {
if (false) {
if (dataMatch == NO_MATCH_TYPE) {
diff --git a/core/java/android/database/ContentObserver.java b/core/java/android/database/ContentObserver.java
index ede264d..578d53b 100644
--- a/core/java/android/database/ContentObserver.java
+++ b/core/java/android/database/ContentObserver.java
@@ -19,6 +19,9 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.app.compat.CompatChanges;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ContentResolver.NotifyFlags;
import android.net.Uri;
@@ -26,12 +29,26 @@
import android.os.UserHandle;
import java.util.Arrays;
+import java.util.Collection;
/**
* Receives call backs for changes to content.
* Must be implemented by objects which are added to a {@link ContentObservable}.
*/
public abstract class ContentObserver {
+ /**
+ * Starting in {@link android.os.Build.VERSION_CODES#R}, there is a new
+ * public API overload {@link #onChange(boolean, Uri, int)} that delivers a
+ * {@code int flags} argument.
+ * <p>
+ * Some apps may be relying on a previous hidden API that delivered a
+ * {@code int userId} argument, and this change is used to control delivery
+ * of the new {@code int flags} argument in its place.
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion=android.os.Build.VERSION_CODES.Q)
+ private static final long ADD_CONTENT_OBSERVER_FLAGS = 150939131L;
+
private final Object mLock = new Object();
private Transport mTransport; // guarded by mLock
@@ -164,16 +181,26 @@
* @param uris The Uris of the changed content.
* @param flags Flags indicating details about this change.
*/
- public void onChange(boolean selfChange, @NonNull Iterable<Uri> uris, @NotifyFlags int flags) {
+ public void onChange(boolean selfChange, @NonNull Collection<Uri> uris,
+ @NotifyFlags int flags) {
for (Uri uri : uris) {
onChange(selfChange, uri, flags);
}
}
/** @hide */
- public void onChange(boolean selfChange, @NonNull Iterable<Uri> uris, @NotifyFlags int flags,
- @UserIdInt int userId) {
- onChange(selfChange, uris, flags);
+ public void onChange(boolean selfChange, @NonNull Collection<Uri> uris,
+ @NotifyFlags int flags, @UserIdInt int userId) {
+ // There are dozens of people relying on the hidden API inside the
+ // system UID, so hard-code the old behavior for all of them; for
+ // everyone else we gate based on a specific change
+ if (!CompatChanges.isChangeEnabled(ADD_CONTENT_OBSERVER_FLAGS)
+ || android.os.Process.myUid() == android.os.Process.SYSTEM_UID) {
+ // Deliver userId through argument to preserve hidden API behavior
+ onChange(selfChange, uris, userId);
+ } else {
+ onChange(selfChange, uris, flags);
+ }
}
/**
@@ -186,7 +213,7 @@
*
* @deprecated Callers should migrate towards using a richer overload that
* provides more details about the change, such as
- * {@link #dispatchChange(boolean, Iterable, int)}.
+ * {@link #dispatchChange(boolean, Collection, int)}.
*/
@Deprecated
public final void dispatchChange(boolean selfChange) {
@@ -206,7 +233,7 @@
* @param uri The Uri of the changed content.
*/
public final void dispatchChange(boolean selfChange, @Nullable Uri uri) {
- dispatchChange(selfChange, Arrays.asList(uri), 0, UserHandle.getCallingUserId());
+ dispatchChange(selfChange, uri, 0);
}
/**
@@ -224,7 +251,7 @@
*/
public final void dispatchChange(boolean selfChange, @Nullable Uri uri,
@NotifyFlags int flags) {
- dispatchChange(selfChange, Arrays.asList(uri), flags, UserHandle.getCallingUserId());
+ dispatchChange(selfChange, Arrays.asList(uri), flags);
}
/**
@@ -240,13 +267,13 @@
* @param uris The Uri of the changed content.
* @param flags Flags indicating details about this change.
*/
- public final void dispatchChange(boolean selfChange, @NonNull Iterable<Uri> uris,
+ public final void dispatchChange(boolean selfChange, @NonNull Collection<Uri> uris,
@NotifyFlags int flags) {
dispatchChange(selfChange, uris, flags, UserHandle.getCallingUserId());
}
/** @hide */
- public final void dispatchChange(boolean selfChange, @NonNull Iterable<Uri> uris,
+ public final void dispatchChange(boolean selfChange, @NonNull Collection<Uri> uris,
@NotifyFlags int flags, @UserIdInt int userId) {
if (mHandler == null) {
onChange(selfChange, uris, flags, userId);
diff --git a/core/java/android/database/CursorToBulkCursorAdaptor.java b/core/java/android/database/CursorToBulkCursorAdaptor.java
index 1855dd2..ce86807 100644
--- a/core/java/android/database/CursorToBulkCursorAdaptor.java
+++ b/core/java/android/database/CursorToBulkCursorAdaptor.java
@@ -20,10 +20,12 @@
import android.annotation.UserIdInt;
import android.content.ContentResolver.NotifyFlags;
import android.net.Uri;
-import android.os.*;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
import java.util.ArrayList;
-
+import java.util.Collection;
/**
* Wraps a BulkCursor around an existing Cursor making it remotable.
@@ -81,7 +83,7 @@
}
@Override
- public void onChange(boolean selfChange, @NonNull Iterable<Uri> uris,
+ public void onChange(boolean selfChange, @NonNull Collection<Uri> uris,
@NotifyFlags int flags, @UserIdInt int userId) {
// Since we deliver changes from the most-specific to least-specific
// overloads, we only need to redirect from the most-specific local
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 85ef4a3..a091f84 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -846,6 +846,33 @@
@NonNull String physicalCameraId) {
// default empty implementation
}
+
+ /**
+ * A camera device has been opened by an application.
+ *
+ * <p>The default implementation of this method does nothing.</p>
+ *
+ * @param cameraId The unique identifier of the new camera.
+ * @param packageId The package Id of the application opening the camera.
+ *
+ * @see #onCameraClosed
+ */
+ /** @hide */
+ public void onCameraOpened(@NonNull String cameraId, @NonNull String packageId) {
+ // default empty implementation
+ }
+
+ /**
+ * A previously-opened camera has been closed.
+ *
+ * <p>The default implementation of this method does nothing.</p>
+ *
+ * @param cameraId The unique identifier of the closed camera.
+ */
+ /** @hide */
+ public void onCameraClosed(@NonNull String cameraId) {
+ // default empty implementation
+ }
}
/**
@@ -1276,6 +1303,12 @@
}
@Override
public void onCameraAccessPrioritiesChanged() {
+ }
+ @Override
+ public void onCameraOpened(String id, String clientPackageId) {
+ }
+ @Override
+ public void onCameraClosed(String id) {
}};
String[] cameraIds = null;
@@ -1503,6 +1536,38 @@
}
}
+ private void postSingleCameraOpenedUpdate(final AvailabilityCallback callback,
+ final Executor executor, final String id, final String packageId) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ executor.execute(
+ new Runnable() {
+ @Override
+ public void run() {
+ callback.onCameraOpened(id, packageId);
+ }
+ });
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ private void postSingleCameraClosedUpdate(final AvailabilityCallback callback,
+ final Executor executor, final String id) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ executor.execute(
+ new Runnable() {
+ @Override
+ public void run() {
+ callback.onCameraClosed(id);
+ }
+ });
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
private void postSingleUpdate(final AvailabilityCallback callback, final Executor executor,
final String id, final String physicalId, final int status) {
if (isAvailable(status)) {
@@ -1846,6 +1911,32 @@
}
}
+ @Override
+ public void onCameraOpened(String cameraId, String clientPackageId) {
+ synchronized (mLock) {
+ final int callbackCount = mCallbackMap.size();
+ for (int i = 0; i < callbackCount; i++) {
+ Executor executor = mCallbackMap.valueAt(i);
+ final AvailabilityCallback callback = mCallbackMap.keyAt(i);
+
+ postSingleCameraOpenedUpdate(callback, executor, cameraId, clientPackageId);
+ }
+ }
+ }
+
+ @Override
+ public void onCameraClosed(String cameraId) {
+ synchronized (mLock) {
+ final int callbackCount = mCallbackMap.size();
+ for (int i = 0; i < callbackCount; i++) {
+ Executor executor = mCallbackMap.valueAt(i);
+ final AvailabilityCallback callback = mCallbackMap.keyAt(i);
+
+ postSingleCameraClosedUpdate(callback, executor, cameraId);
+ }
+ }
+ }
+
/**
* Try to connect to camera service after some delay if any client registered camera
* availability callback or torch status callback.
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/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/BinderProxy.java b/core/java/android/os/BinderProxy.java
index dd3f9fd..20e5f24 100644
--- a/core/java/android/os/BinderProxy.java
+++ b/core/java/android/os/BinderProxy.java
@@ -526,7 +526,7 @@
final AppOpsManager.PausedNotedAppOpsCollection prevCollection =
AppOpsManager.pauseNotedAppOpsCollection();
- if ((flags & FLAG_ONEWAY) == 0 && AppOpsManager.isCollectingNotedAppOps()) {
+ if ((flags & FLAG_ONEWAY) == 0 && AppOpsManager.isListeningForOpNoted()) {
flags |= FLAG_COLLECT_NOTED_APP_OPS;
}
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 21a1e0f..f2fb5b2 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -39,6 +39,7 @@
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
+import java.util.Objects;
/**
* Provides access to environment variables.
@@ -1253,6 +1254,50 @@
uid, context.getOpPackageName()) == AppOpsManager.MODE_ALLOWED;
}
+ /**
+ * Returns whether the calling app has All Files Access on the primary shared/external storage
+ * media.
+ * <p>Declaring the permission {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE} isn't
+ * enough to gain the access.
+ * <p>To request access, use
+ * {@link android.provider.Settings#ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION}.
+ */
+ public static boolean isExternalStorageManager() {
+ final File externalDir = sCurrentUser.getExternalDirs()[0];
+ return isExternalStorageManager(externalDir);
+ }
+
+ /**
+ * Returns whether the calling app has All Files Access at the given {@code path}
+ * <p>Declaring the permission {@link android.Manifest.permission#MANAGE_EXTERNAL_STORAGE} isn't
+ * enough to gain the access.
+ * <p>To request access, use
+ * {@link android.provider.Settings#ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION}.
+ */
+ public static boolean isExternalStorageManager(@NonNull File path) {
+ final Context context = Objects.requireNonNull(AppGlobals.getInitialApplication());
+ String packageName = Objects.requireNonNull(context.getPackageName());
+ int uid = context.getApplicationInfo().uid;
+
+ final AppOpsManager appOps = context.getSystemService(AppOpsManager.class);
+ final int opMode =
+ appOps.checkOpNoThrow(AppOpsManager.OP_MANAGE_EXTERNAL_STORAGE, uid, packageName);
+
+ switch (opMode) {
+ case AppOpsManager.MODE_DEFAULT:
+ return PackageManager.PERMISSION_GRANTED
+ == context.checkPermission(
+ Manifest.permission.MANAGE_EXTERNAL_STORAGE, Process.myPid(), uid);
+ case AppOpsManager.MODE_ALLOWED:
+ return true;
+ case AppOpsManager.MODE_ERRORED:
+ case AppOpsManager.MODE_IGNORED:
+ return false;
+ default:
+ throw new IllegalStateException("Unknown AppOpsManager mode " + opMode);
+ }
+ }
+
static File getDirectory(String variableName, String defaultPath) {
String path = System.getenv(variableName);
return path == null ? new File(defaultPath) : new File(path);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 641de4a..084f37f 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
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 629dc8b..03b38ab 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -3735,7 +3735,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 +3784,6 @@
* <p>Type: INTEGER</p>
*@hide
*/
- @SystemApi
public static final String PROFILE_ID = "profile_id";
/**
@@ -3986,7 +3984,6 @@
*
* @hide
*/
- @SystemApi
public static final String SKIP_464XLAT = "skip_464xlat";
/**
@@ -3995,7 +3992,6 @@
*
* @hide
*/
- @SystemApi
public static final int SKIP_464XLAT_DEFAULT = -1;
/**
@@ -4004,7 +4000,6 @@
*
* @hide
*/
- @SystemApi
public static final int SKIP_464XLAT_DISABLE = 0;
/**
@@ -4013,7 +4008,6 @@
*
* @hide
*/
- @SystemApi
public static final int SKIP_464XLAT_ENABLE = 1;
@@ -4392,6 +4386,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/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/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java
index 74b9136..1beeb65 100644
--- a/core/java/android/service/notification/StatusBarNotification.java
+++ b/core/java/android/service/notification/StatusBarNotification.java
@@ -237,16 +237,24 @@
public StatusBarNotification cloneLight() {
final Notification no = new Notification();
this.notification.cloneInto(no, false); // light copy
- return new StatusBarNotification(this.pkg, this.opPkg,
- this.id, this.tag, this.uid, this.initialPid,
- no, this.user, this.overrideGroupKey, this.postTime);
+ return cloneShallow(no);
}
@Override
public StatusBarNotification clone() {
- return new StatusBarNotification(this.pkg, this.opPkg,
+ return cloneShallow(this.notification.clone());
+ }
+
+ /**
+ * @param notification Some kind of clone of this.notification.
+ * @return A shallow copy of self, with notification in place of this.notification.
+ */
+ StatusBarNotification cloneShallow(Notification notification) {
+ StatusBarNotification result = new StatusBarNotification(this.pkg, this.opPkg,
this.id, this.tag, this.uid, this.initialPid,
- this.notification.clone(), this.user, this.overrideGroupKey, this.postTime);
+ notification, this.user, this.overrideGroupKey, this.postTime);
+ result.setInstanceId(this.mInstanceId);
+ return result;
}
@Override
diff --git a/core/java/android/view/ITaskOrganizer.aidl b/core/java/android/view/ITaskOrganizer.aidl
index 5ccdd30..565f694 100644
--- a/core/java/android/view/ITaskOrganizer.aidl
+++ b/core/java/android/view/ITaskOrganizer.aidl
@@ -27,7 +27,7 @@
*/
oneway interface ITaskOrganizer {
void taskAppeared(in ActivityManager.RunningTaskInfo taskInfo);
- void taskVanished(in IWindowContainer container);
+ void taskVanished(in ActivityManager.RunningTaskInfo taskInfo);
/**
* Called upon completion of
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 302d4f3..607886f 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -52,6 +52,7 @@
import android.view.animation.PathInterpolator;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -59,6 +60,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Objects;
import java.util.function.BiFunction;
/**
@@ -306,6 +308,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) -> {
@@ -459,6 +466,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 */);
}
@@ -542,9 +556,7 @@
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();
@@ -554,6 +566,13 @@
false /* fade */, animationType, getLayoutInsetsDuringAnimationMode(types));
}
+ 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,
@@ -567,6 +586,7 @@
return cancellationSignal;
}
cancelExistingControllers(types);
+ mLastStartedAnimTypes |= types;
final ArraySet<Integer> internalTypes = InsetsState.toInternalType(types);
final SparseArray<InsetsSourceControl> controls = new SparseArray<>();
@@ -994,6 +1014,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/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/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 9228fbd..9e5298b 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);
}
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/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java
index ff80ef7..f62a28e 100644
--- a/core/java/android/webkit/CookieManager.java
+++ b/core/java/android/webkit/CookieManager.java
@@ -268,17 +268,28 @@
protected abstract boolean allowFileSchemeCookiesImpl();
/**
- * Sets whether the application's {@link WebView} instances should send and
- * accept cookies for file scheme URLs.
- * Use of cookies with file scheme URLs is potentially insecure and turned
- * off by default.
- * Do not use this feature unless you can be sure that no unintentional
- * sharing of cookie data can take place.
+ * Sets whether the application's {@link WebView} instances should send and accept cookies for
+ * file scheme URLs.
* <p>
- * Note that calls to this method will have no effect if made after a
- * {@link WebView} or CookieManager instance has been created.
+ * Use of cookies with file scheme URLs is potentially insecure and turned off by default. All
+ * {@code file://} URLs share all their cookies, which may lead to leaking private app cookies
+ * (ex. any malicious file can access cookies previously set by other (trusted) files).
+ * <p class="note">
+ * Loading content via {@code file://} URLs is generally discouraged. See the note in
+ * {@link WebSettings#setAllowFileAccess}.
+ * Using <a href="{@docRoot}reference/androidx/webkit/WebViewAssetLoader.html">
+ * androidx.webkit.WebViewAssetLoader</a> to load files over {@code http(s)://} URLs allows
+ * the standard web security model to be used for setting and sharing cookies for local files.
+ * <p>
+ * Note that calls to this method will have no effect if made after calling other
+ * {@link CookieManager} APIs.
+ *
+ * @deprecated This setting is not secure, please use
+ * <a href="{@docRoot}reference/androidx/webkit/WebViewAssetLoader.html">
+ * androidx.webkit.WebViewAssetLoader</a> instead.
*/
// Static for backward compatibility.
+ @Deprecated
public static void setAcceptFileSchemeCookies(boolean accept) {
getInstance().setAcceptFileSchemeCookiesImpl(accept);
}
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 53541f7..35dd576 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -983,48 +983,63 @@
public abstract void setJavaScriptEnabled(boolean flag);
/**
- * Sets whether JavaScript running in the context of a file scheme URL
- * should be allowed to access content from any origin. This includes
- * access to content from other file scheme URLs. See
- * {@link #setAllowFileAccessFromFileURLs}. To enable the most restrictive,
- * and therefore secure policy, this setting should be disabled.
- * Note that this setting affects only JavaScript access to file scheme
- * resources. Other access to such resources, for example, from image HTML
- * elements, is unaffected. To prevent possible violation of same domain policy
- * when targeting {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH_MR1} and earlier,
- * you should explicitly set this value to {@code false}.
+ * Sets whether cross-origin requests in the context of a file scheme URL should be allowed to
+ * access content from <i>any</i> origin. This includes access to content from other file
+ * scheme URLs or web contexts. Note that some access such as image HTML elements doesn't
+ * follow same-origin rules and isn't affected by this setting.
+ * <p>
+ * <b>Don't</b> enable this setting if you open files that may be created or altered by
+ * external sources. Enabling this setting allows malicious scripts loaded in a {@code file://}
+ * context to launch cross-site scripting attacks, either accessing arbitrary local files
+ * including WebView cookies, app private data or even credentials used on arbitrary web sites.
+ * <p class="note">
+ * Loading content via {@code file://} URLs is generally discouraged. See the note in
+ * {@link #setAllowFileAccess}.
* <p>
* The default value is {@code true} for apps targeting
- * {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH_MR1} and below,
- * and {@code false} when targeting {@link android.os.Build.VERSION_CODES#JELLY_BEAN}
- * and above.
+ * {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH_MR1} and below, and {@code false}
+ * when targeting {@link android.os.Build.VERSION_CODES#JELLY_BEAN} and above. To prevent
+ * possible violation of same domain policy when targeting
+ * {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH_MR1} and earlier, you should
+ * explicitly set this value to {@code false}.
*
- * @param flag whether JavaScript running in the context of a file scheme
- * URL should be allowed to access content from any origin
+ * @param flag whether JavaScript running in the context of a file scheme URL should be allowed
+ * to access content from any origin
+ * @deprecated This setting is not secure, please use
+ * <a href="{@docRoot}reference/androidx/webkit/WebViewAssetLoader.html">
+ * androidx.webkit.WebViewAssetLoader</a> to load file content securely.
*/
+ @Deprecated
public abstract void setAllowUniversalAccessFromFileURLs(boolean flag);
/**
- * Sets whether JavaScript running in the context of a file scheme URL
- * should be allowed to access content from other file scheme URLs. To
- * enable the most restrictive, and therefore secure, policy this setting
- * should be disabled. Note that the value of this setting is ignored if
- * the value of {@link #getAllowUniversalAccessFromFileURLs} is {@code true}.
- * Note too, that this setting affects only JavaScript access to file scheme
- * resources. Other access to such resources, for example, from image HTML
- * elements, is unaffected. To prevent possible violation of same domain policy
- * when targeting {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH_MR1} and earlier,
- * you should explicitly set this value to {@code false}.
+ * Sets whether cross-origin requests in the context of a file scheme URL should be allowed to
+ * access content from other file scheme URLs. Note that some accesses such as image HTML
+ * elements don't follow same-origin rules and aren't affected by this setting.
* <p>
- * The default value is {@code true} for apps targeting
- * {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH_MR1} and below,
- * and {@code false} when targeting {@link android.os.Build.VERSION_CODES#JELLY_BEAN}
- * and above.
+ * <b>Don't</b> enable this setting if you open files that may be created or altered by
+ * external sources. Enabling this setting allows malicious scripts loaded in a {@code file://}
+ * context to access arbitrary local files including WebView cookies and app private data.
+ * <p class="note">
+ * Loading content via {@code file://} URLs is generally discouraged. See the note in
+ * {@link #setAllowFileAccess}.
+ * <p>
+ * Note that the value of this setting is ignored if the value of
+ * {@link #getAllowUniversalAccessFromFileURLs} is {@code true}. The default value is
+ * {@code true} for apps targeting {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH_MR1}
+ * and below, and {@code false} when targeting {@link android.os.Build.VERSION_CODES#JELLY_BEAN}
+ * and above. To prevent possible violation of same domain policy when targeting
+ * {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH_MR1} and earlier, you should
+ * explicitly set this value to {@code false}.
*
* @param flag whether JavaScript running in the context of a file scheme
* URL should be allowed to access content from other file
* scheme URLs
+ * @deprecated This setting is not secure, please use
+ * <a href="{@docRoot}reference/androidx/webkit/WebViewAssetLoader.html">
+ * androidx.webkit.WebViewAssetLoader</a> to load file content securely.
*/
+ @Deprecated
public abstract void setAllowFileAccessFromFileURLs(boolean flag);
/**
diff --git a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
index 5cdcab0..54ea57a 100644
--- a/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
+++ b/core/java/com/android/internal/accessibility/AccessibilityShortcutController.java
@@ -56,6 +56,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
@@ -133,7 +134,7 @@
// Keep track of state of shortcut settings
final ContentObserver co = new ContentObserver(handler) {
@Override
- public void onChange(boolean selfChange, Uri uri, int userId) {
+ public void onChange(boolean selfChange, Collection<Uri> uris, int flags, int userId) {
if (userId == mUserId) {
onSettingsChanged();
}
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index c487e96..c099301 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -2398,17 +2398,20 @@
}
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;
+ }
getMainThreadHandler().post(() -> {
if (mResolverDrawerLayout == null || gridAdapter == null) {
diff --git a/core/java/com/android/internal/logging/InstanceId.java b/core/java/com/android/internal/logging/InstanceId.java
index 85643fc..c90d8512 100644
--- a/core/java/com/android/internal/logging/InstanceId.java
+++ b/core/java/com/android/internal/logging/InstanceId.java
@@ -48,6 +48,17 @@
return mId;
}
+ /**
+ * Create a fake instance ID for testing purposes. Not for production use. See also
+ * InstanceIdSequenceFake, which is a testing replacement for InstanceIdSequence.
+ * @param id The ID you want to assign.
+ * @return new InstanceId.
+ */
+ @VisibleForTesting
+ public static InstanceId fakeInstanceId(int id) {
+ return new InstanceId(id);
+ }
+
@Override
public int hashCode() {
return mId;
diff --git a/core/java/com/android/internal/os/KernelCpuThreadReaderSettingsObserver.java b/core/java/com/android/internal/os/KernelCpuThreadReaderSettingsObserver.java
index f8c0d9e..fdcc8a8 100644
--- a/core/java/com/android/internal/os/KernelCpuThreadReaderSettingsObserver.java
+++ b/core/java/com/android/internal/os/KernelCpuThreadReaderSettingsObserver.java
@@ -29,6 +29,7 @@
import com.android.internal.annotations.VisibleForTesting;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import java.util.function.Predicate;
import java.util.regex.Matcher;
@@ -99,7 +100,7 @@
}
@Override
- public void onChange(boolean selfChange, Uri uri, int userId) {
+ public void onChange(boolean selfChange, Collection<Uri> uris, int flags, int userId) {
updateReader();
}
diff --git a/core/java/com/android/internal/util/NotificationMessagingUtil.java b/core/java/com/android/internal/util/NotificationMessagingUtil.java
index bf796cd..28994fd 100644
--- a/core/java/com/android/internal/util/NotificationMessagingUtil.java
+++ b/core/java/com/android/internal/util/NotificationMessagingUtil.java
@@ -28,6 +28,7 @@
import android.service.notification.StatusBarNotification;
import android.util.ArrayMap;
+import java.util.Collection;
import java.util.Objects;
/**
@@ -77,8 +78,8 @@
private final ContentObserver mSmsContentObserver = new ContentObserver(
new Handler(Looper.getMainLooper())) {
@Override
- public void onChange(boolean selfChange, Uri uri, int userId) {
- if (Settings.Secure.getUriFor(DEFAULT_SMS_APP_SETTING).equals(uri)) {
+ public void onChange(boolean selfChange, Collection<Uri> uris, int flags, int userId) {
+ if (uris.contains(Settings.Secure.getUriFor(DEFAULT_SMS_APP_SETTING))) {
cacheDefaultSmsApp(userId);
}
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index ed3fb07..0dd3ad6 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1315,7 +1315,7 @@
android:description="@string/permdesc_camera"
android:protectionLevel="dangerous|instant" />
- <!-- @SystemApi Required in addition to android.permission.CAMERA to be able to access
+ <!-- @SystemApi Required in addition to android.permission.CAMERA to be able to access
system only camera devices.
<p>Protection level: system|signature
@hide -->
@@ -1325,6 +1325,15 @@
android:description="@string/permdesc_systemCamera"
android:protectionLevel="system|signature" />
+ <!-- Allows receiving the camera service notifications when a camera is opened
+ (by a certain application package) or closed.
+ @hide -->
+ <permission android:name="android.permission.CAMERA_OPEN_CLOSE_LISTENER"
+ android:permissionGroup="android.permission-group.UNDEFINED"
+ android:label="@string/permlab_cameraOpenCloseListener"
+ android:description="@string/permdesc_cameraOpenCloseListener"
+ android:protectionLevel="signature" />
+
<!-- ====================================================================== -->
<!-- Permissions for accessing the device sensors -->
<!-- ====================================================================== -->
@@ -3736,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" />
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/config.xml b/core/res/res/values/config.xml
index 0b6e65fe..617949d 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>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index f7206b9..789628d 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1166,6 +1166,11 @@
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=NONE] -->
<string name="permdesc_systemCamera">This privileged | system app can take pictures and record videos using a system camera at any time. Requires the android.permission.CAMERA permission to be held by the app as well</string>
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=NONE] -->
+ <string name="permlab_cameraOpenCloseListener">Allow an application or service to receive callbacks about camera devices being opened or closed.</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=NONE] -->
+ <string name="permdesc_cameraOpenCloseListener">This signature app can receive callbacks when any camera device is being opened (by what application package) or closed.</string>
+
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_vibrate">control vibration</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
diff --git a/core/tests/coretests/src/android/content/AbstractCrossUserContentResolverTest.java b/core/tests/coretests/src/android/content/AbstractCrossUserContentResolverTest.java
index c307e64..328429c 100644
--- a/core/tests/coretests/src/android/content/AbstractCrossUserContentResolverTest.java
+++ b/core/tests/coretests/src/android/content/AbstractCrossUserContentResolverTest.java
@@ -39,6 +39,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Collection;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -194,8 +195,8 @@
}
@Override
- public void onChange(boolean selfChange, Uri uri, int userId) {
- if (mExpectedUri.equals(uri) && mExpectedUserId == userId) {
+ public void onChange(boolean selfChange, Collection<Uri> uris, int flags, int userId) {
+ if (uris.contains(mExpectedUri) && mExpectedUserId == userId) {
mLatch.countDown();
}
}
diff --git a/core/tests/coretests/src/android/os/EnvironmentTest.java b/core/tests/coretests/src/android/os/EnvironmentTest.java
index d98ceaf..c0325ca 100644
--- a/core/tests/coretests/src/android/os/EnvironmentTest.java
+++ b/core/tests/coretests/src/android/os/EnvironmentTest.java
@@ -23,7 +23,10 @@
import static android.os.Environment.classifyExternalStorageDirectory;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import android.app.AppOpsManager;
import android.content.Context;
import androidx.test.InstrumentationRegistry;
@@ -40,10 +43,33 @@
public class EnvironmentTest {
private File dir;
- private Context getContext() {
+ private static Context getContext() {
return InstrumentationRegistry.getContext();
}
+ /**
+ * Sets {@code mode} for the given {@code ops} and the given {@code uid}.
+ *
+ * <p>This method drops shell permission identity.
+ */
+ private static void setAppOpsModeForUid(int uid, int mode, String... ops) {
+ if (ops == null) {
+ return;
+ }
+ InstrumentationRegistry.getInstrumentation()
+ .getUiAutomation()
+ .adoptShellPermissionIdentity();
+ try {
+ for (String op : ops) {
+ getContext().getSystemService(AppOpsManager.class).setUidMode(op, uid, mode);
+ }
+ } finally {
+ InstrumentationRegistry.getInstrumentation()
+ .getUiAutomation()
+ .dropShellPermissionIdentity();
+ }
+ }
+
@Before
public void setUp() throws Exception {
dir = getContext().getDir("testing", Context.MODE_PRIVATE);
@@ -101,4 +127,17 @@
Environment.buildPath(dir, "Taxes.pdf").createNewFile();
assertEquals(HAS_OTHER, classifyExternalStorageDirectory(dir));
}
+
+ @Test
+ public void testIsExternalStorageManager() throws Exception {
+ assertFalse(Environment.isExternalStorageManager());
+ try {
+ setAppOpsModeForUid(Process.myUid(), AppOpsManager.MODE_ALLOWED,
+ AppOpsManager.OPSTR_MANAGE_EXTERNAL_STORAGE);
+ assertTrue(Environment.isExternalStorageManager());
+ } finally {
+ setAppOpsModeForUid(Process.myUid(), AppOpsManager.MODE_DEFAULT,
+ AppOpsManager.OPSTR_MANAGE_EXTERNAL_STORAGE);
+ }
+ }
}
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index 7737b1a..023fc17 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -49,6 +49,7 @@
import android.platform.test.annotations.Presubmit;
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 +68,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;
@@ -171,15 +174,24 @@
mController.onControlsChanged(new InsetsSourceControl[] { control });
assertEquals(mLeash,
mController.getSourceConsumer(ITYPE_STATUS_BAR).getControl().getLeash());
+ mController.addOnControllableInsetsChangedListener(
+ ((controller, typeMask) -> assertEquals(statusBars(), typeMask)));
}
@Test
public void testControlsRevoked() {
+ OnControllableInsetsChangedListener listener
+ = mock(OnControllableInsetsChangedListener.class);
+ mController.addOnControllableInsetsChangedListener(listener);
InsetsSourceControl control =
new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point());
mController.onControlsChanged(new InsetsSourceControl[] { control });
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
@@ -206,10 +218,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());
}
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/data/etc/com.android.documentsui.xml b/data/etc/com.android.documentsui.xml
index b6671db..1e570ba 100644
--- a/data/etc/com.android.documentsui.xml
+++ b/data/etc/com.android.documentsui.xml
@@ -20,6 +20,7 @@
<permission name="android.permission.INTERACT_ACROSS_USERS"/>
<!-- Permissions required for reading and logging compat changes -->
<permission name="android.permission.LOG_COMPAT_CHANGE"/>
+ <permission name="android.permission.MODIFY_QUIET_MODE"/>
<permission name="android.permission.READ_COMPAT_CHANGE_CONFIG"/>
</privapp-permissions>
</permissions>
diff --git a/data/etc/com.android.systemui.xml b/data/etc/com.android.systemui.xml
index 38e18a9..72827a9 100644
--- a/data/etc/com.android.systemui.xml
+++ b/data/etc/com.android.systemui.xml
@@ -63,5 +63,6 @@
<permission name="android.permission.WRITE_SECURE_SETTINGS"/>
<permission name="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS"/>
<permission name="android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS" />
+ <permission name="android.permission.CAMERA_OPEN_CLOSE_LISTENER" />
</privapp-permissions>
</permissions>
diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp
index 84c07d7..39900e6 100644
--- a/libs/hwui/Readback.cpp
+++ b/libs/hwui/Readback.cpp
@@ -146,12 +146,11 @@
}
Layer layer(mRenderThread.renderState(), nullptr, 255, SkBlendMode::kSrc);
- bool disableFilter = MathUtils::areEqual(skiaSrcRect.width(), skiaDestRect.width()) &&
- MathUtils::areEqual(skiaSrcRect.height(), skiaDestRect.height());
- layer.setForceFilter(!disableFilter);
layer.setSize(displayedWidth, displayedHeight);
texTransform.copyTo(layer.getTexTransform());
layer.setImage(image);
+ // Scaling filter is not explicitly set here, because it is done inside copyLayerInfo
+ // after checking the necessity based on the src/dest rect size and the transformation.
if (copyLayerInto(&layer, &skiaSrcRect, &skiaDestRect, bitmap)) {
copyResult = CopyResult::Success;
}
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/filter/AlpFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java
index 7b29494..8a29442 100644
--- a/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java
@@ -18,6 +18,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.content.Context;
@@ -33,7 +34,7 @@
* @hide
*/
@SystemApi
-public class AlpFilterConfiguration extends FilterConfiguration {
+public final class AlpFilterConfiguration extends FilterConfiguration {
/**
* IPv4 packet type.
*/
@@ -123,9 +124,10 @@
/**
* Builder for {@link AlpFilterConfiguration}.
*/
- public static class Builder extends FilterConfiguration.Builder<Builder> {
+ public static final class Builder {
private int mPacketType;
private int mLengthType;
+ private Settings mSettings;
private Builder() {
}
@@ -150,16 +152,20 @@
}
/**
+ * Sets filter settings.
+ */
+ @NonNull
+ public Builder setSettings(@Nullable Settings settings) {
+ mSettings = settings;
+ return this;
+ }
+
+ /**
* Builds a {@link AlpFilterConfiguration} object.
*/
@NonNull
public AlpFilterConfiguration build() {
return new AlpFilterConfiguration(mSettings, mPacketType, mLengthType);
}
-
- @Override
- Builder self() {
- return this;
- }
}
}
diff --git a/media/java/android/media/tv/tuner/filter/Filter.java b/media/java/android/media/tv/tuner/filter/Filter.java
index 52bdb59..4777fe8 100644
--- a/media/java/android/media/tv/tuner/filter/Filter.java
+++ b/media/java/android/media/tv/tuner/filter/Filter.java
@@ -225,6 +225,7 @@
mCallback = cb;
mExecutor = executor;
}
+
/** @hide */
public FilterCallback getCallback() {
return mCallback;
diff --git a/media/java/android/media/tv/tuner/filter/FilterConfiguration.java b/media/java/android/media/tv/tuner/filter/FilterConfiguration.java
index a8c9356..dd7e5fc 100644
--- a/media/java/android/media/tv/tuner/filter/FilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/FilterConfiguration.java
@@ -16,7 +16,6 @@
package android.media.tv.tuner.filter;
-import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
@@ -48,26 +47,4 @@
public Settings getSettings() {
return mSettings;
}
-
- /**
- * Builder for {@link FilterConfiguration}.
- *
- * @param <T> The subclass to be built.
- */
- public abstract static class Builder<T extends Builder<T>> {
- /* package */ Settings mSettings;
-
- /* package */ Builder() {
- }
-
- /**
- * Sets filter settings.
- */
- @NonNull
- public T setSettings(@Nullable Settings settings) {
- mSettings = settings;
- return self();
- }
- /* package */ abstract T self();
- }
}
diff --git a/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java
index a8dbfa5..04f3410 100644
--- a/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java
@@ -17,6 +17,7 @@
package android.media.tv.tuner.filter;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.Size;
import android.annotation.SystemApi;
@@ -29,7 +30,7 @@
* @hide
*/
@SystemApi
-public class IpFilterConfiguration extends FilterConfiguration {
+public final class IpFilterConfiguration extends FilterConfiguration {
private final byte[] mSrcIpAddress;
private final byte[] mDstIpAddress;
private final int mSrcPort;
@@ -104,12 +105,13 @@
/**
* Builder for {@link IpFilterConfiguration}.
*/
- public static class Builder extends FilterConfiguration.Builder<Builder> {
+ public static final class Builder {
private byte[] mSrcIpAddress;
private byte[] mDstIpAddress;
private int mSrcPort;
private int mDstPort;
private boolean mPassthrough;
+ private Settings mSettings;
private Builder() {
}
@@ -156,6 +158,15 @@
}
/**
+ * Sets filter settings.
+ */
+ @NonNull
+ public Builder setSettings(@Nullable Settings settings) {
+ mSettings = settings;
+ return this;
+ }
+
+ /**
* Builds a {@link IpFilterConfiguration} object.
*/
@NonNull
@@ -169,10 +180,5 @@
return new IpFilterConfiguration(
mSettings, mSrcIpAddress, mDstIpAddress, mSrcPort, mDstPort, mPassthrough);
}
-
- @Override
- Builder self() {
- return this;
- }
}
}
diff --git a/media/java/android/media/tv/tuner/filter/MmtpFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/MmtpFilterConfiguration.java
index 0601829..c0453b4 100644
--- a/media/java/android/media/tv/tuner/filter/MmtpFilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/MmtpFilterConfiguration.java
@@ -17,6 +17,7 @@
package android.media.tv.tuner.filter;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.content.Context;
@@ -28,7 +29,7 @@
* @hide
*/
@SystemApi
-public class MmtpFilterConfiguration extends FilterConfiguration {
+public final class MmtpFilterConfiguration extends FilterConfiguration {
private final int mMmtpPid;
private MmtpFilterConfiguration(Settings settings, int mmtpPid) {
@@ -65,8 +66,9 @@
/**
* Builder for {@link IpFilterConfiguration}.
*/
- public static class Builder extends FilterConfiguration.Builder<Builder> {
+ public static final class Builder {
private int mMmtpPid;
+ private Settings mSettings;
private Builder() {
}
@@ -81,16 +83,20 @@
}
/**
+ * Sets filter settings.
+ */
+ @NonNull
+ public Builder setSettings(@Nullable Settings settings) {
+ mSettings = settings;
+ return this;
+ }
+
+ /**
* Builds a {@link IpFilterConfiguration} object.
*/
@NonNull
public MmtpFilterConfiguration build() {
return new MmtpFilterConfiguration(mSettings, mMmtpPid);
}
-
- @Override
- Builder self() {
- return this;
- }
}
}
diff --git a/media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java
index ac4fc83..c5191bf 100644
--- a/media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java
@@ -17,6 +17,7 @@
package android.media.tv.tuner.filter;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.content.Context;
@@ -28,7 +29,7 @@
* @hide
*/
@SystemApi
-public class TlvFilterConfiguration extends FilterConfiguration {
+public final class TlvFilterConfiguration extends FilterConfiguration {
/**
* IPv4 packet type.
*/
@@ -108,10 +109,11 @@
/**
* Builder for {@link TlvFilterConfiguration}.
*/
- public static class Builder extends FilterConfiguration.Builder<Builder> {
+ public static final class Builder {
private int mPacketType;
private boolean mIsCompressedIpPacket;
private boolean mPassthrough;
+ private Settings mSettings;
private Builder() {
}
@@ -144,6 +146,15 @@
}
/**
+ * Sets filter settings.
+ */
+ @NonNull
+ public Builder setSettings(@Nullable Settings settings) {
+ mSettings = settings;
+ return this;
+ }
+
+ /**
* Builds a {@link TlvFilterConfiguration} object.
*/
@NonNull
@@ -151,10 +162,5 @@
return new TlvFilterConfiguration(
mSettings, mPacketType, mIsCompressedIpPacket, mPassthrough);
}
-
- @Override
- Builder self() {
- return this;
- }
}
}
diff --git a/media/java/android/media/tv/tuner/filter/TsFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/TsFilterConfiguration.java
index 6a8b6da..a7140eb 100644
--- a/media/java/android/media/tv/tuner/filter/TsFilterConfiguration.java
+++ b/media/java/android/media/tv/tuner/filter/TsFilterConfiguration.java
@@ -17,6 +17,7 @@
package android.media.tv.tuner.filter;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.content.Context;
@@ -28,7 +29,7 @@
* @hide
*/
@SystemApi
-public class TsFilterConfiguration extends FilterConfiguration {
+public final class TsFilterConfiguration extends FilterConfiguration {
private final int mTpid;
private TsFilterConfiguration(Settings settings, int tpid) {
@@ -63,8 +64,9 @@
/**
* Builder for {@link TsFilterConfiguration}.
*/
- public static class Builder extends FilterConfiguration.Builder<Builder> {
+ public static final class Builder {
private int mTpid;
+ private Settings mSettings;
private Builder() {
}
@@ -81,16 +83,20 @@
}
/**
+ * Sets filter settings.
+ */
+ @NonNull
+ public Builder setSettings(@Nullable Settings settings) {
+ mSettings = settings;
+ return this;
+ }
+
+ /**
* Builds a {@link TsFilterConfiguration} object.
*/
@NonNull
public TsFilterConfiguration build() {
return new TsFilterConfiguration(mSettings, mTpid);
}
-
- @Override
- Builder self() {
- return this;
- }
}
}
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 737c95d..893e516 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -242,13 +242,6 @@
});
}
-void JMediaCodec::releaseAsync() {
- if (mCodec != NULL) {
- mCodec->releaseAsync();
- }
- mInitStatus = NO_INIT;
-}
-
JMediaCodec::~JMediaCodec() {
if (mLooper != NULL) {
/* MediaCodec and looper should have been released explicitly already
@@ -1131,10 +1124,7 @@
}
static void android_media_MediaCodec_release(JNIEnv *env, jobject thiz) {
- sp<JMediaCodec> codec = getMediaCodec(env, thiz);
- if (codec != NULL) {
- codec->releaseAsync();
- }
+ setMediaCodec(env, thiz, NULL);
}
static void throwCodecException(JNIEnv *env, status_t err, int32_t actionCode, const char *msg) {
@@ -2807,7 +2797,7 @@
static void android_media_MediaCodec_native_finalize(
JNIEnv *env, jobject thiz) {
- setMediaCodec(env, thiz, NULL);
+ android_media_MediaCodec_release(env, thiz);
}
// MediaCodec.LinearBlock
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index 400ce1b..8899fee 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -61,7 +61,6 @@
void registerSelf();
void release();
- void releaseAsync();
status_t enableOnFrameRenderedListener(jboolean enable);
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 273c776..679f18a 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -34,19 +34,28 @@
using ::android::hardware::Void;
using ::android::hardware::hidl_bitfield;
using ::android::hardware::hidl_vec;
+using ::android::hardware::tv::tuner::V1_0::AudioExtraMetaData;
+using ::android::hardware::tv::tuner::V1_0::Constant;
using ::android::hardware::tv::tuner::V1_0::DataFormat;
using ::android::hardware::tv::tuner::V1_0::DemuxAlpFilterSettings;
using ::android::hardware::tv::tuner::V1_0::DemuxAlpFilterType;
using ::android::hardware::tv::tuner::V1_0::DemuxAlpLengthType;
using ::android::hardware::tv::tuner::V1_0::DemuxFilterAvSettings;
+using ::android::hardware::tv::tuner::V1_0::DemuxFilterDownloadEvent;
using ::android::hardware::tv::tuner::V1_0::DemuxFilterDownloadSettings;
+using ::android::hardware::tv::tuner::V1_0::DemuxFilterIpPayloadEvent;
using ::android::hardware::tv::tuner::V1_0::DemuxFilterMainType;
using ::android::hardware::tv::tuner::V1_0::DemuxFilterMediaEvent;
+using ::android::hardware::tv::tuner::V1_0::DemuxFilterMmtpRecordEvent;
using ::android::hardware::tv::tuner::V1_0::DemuxFilterPesDataSettings;
+using ::android::hardware::tv::tuner::V1_0::DemuxFilterPesEvent;
using ::android::hardware::tv::tuner::V1_0::DemuxFilterRecordSettings;
using ::android::hardware::tv::tuner::V1_0::DemuxFilterSectionBits;
+using ::android::hardware::tv::tuner::V1_0::DemuxFilterSectionEvent;
using ::android::hardware::tv::tuner::V1_0::DemuxFilterSectionSettings;
using ::android::hardware::tv::tuner::V1_0::DemuxFilterSettings;
+using ::android::hardware::tv::tuner::V1_0::DemuxFilterTemiEvent;
+using ::android::hardware::tv::tuner::V1_0::DemuxFilterTsRecordEvent;
using ::android::hardware::tv::tuner::V1_0::DemuxIpAddress;
using ::android::hardware::tv::tuner::V1_0::DemuxIpFilterSettings;
using ::android::hardware::tv::tuner::V1_0::DemuxIpFilterType;
@@ -136,6 +145,7 @@
jmethodID dvrInitID;
jmethodID onFrontendEventID;
jmethodID onFilterStatusID;
+ jmethodID onFilterEventID;
jmethodID lnbInitID;
jmethodID onLnbEventID;
jmethodID descramblerInitID;
@@ -248,48 +258,287 @@
return linearBlock;
}
-jobject FilterCallback::getMediaEvent(const DemuxFilterEvent::Event& event) {
+jobjectArray FilterCallback::getSectionEvent(
+ jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events) {
JNIEnv *env = AndroidRuntime::getJNIEnv();
- jclass clazz = env->FindClass("android/media/tv/tuner/filter/MediaEvent");
- jmethodID eventInit = env->GetMethodID(clazz,
+ jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/SectionEvent");
+ jmethodID eventInit = env->GetMethodID(eventClazz, "<init>", "(IIII)V");
+
+ for (int i = 0; i < events.size(); i++) {
+ auto event = events[i];
+ DemuxFilterSectionEvent sectionEvent = event.section();
+
+ jint tableId = static_cast<jint>(sectionEvent.tableId);
+ jint version = static_cast<jint>(sectionEvent.version);
+ jint sectionNum = static_cast<jint>(sectionEvent.sectionNum);
+ jint dataLength = static_cast<jint>(sectionEvent.dataLength);
+
+ jobject obj =
+ env->NewObject(eventClazz, eventInit, tableId, version, sectionNum, dataLength);
+ env->SetObjectArrayElement(arr, i, obj);
+ }
+ return arr;
+}
+
+jobjectArray FilterCallback::getMediaEvent(
+ jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events) {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/MediaEvent");
+ jmethodID eventInit = env->GetMethodID(eventClazz,
"<init>",
"(IZJJJLandroid/media/MediaCodec$LinearBlock;"
"ZJIZLandroid/media/tv/tuner/filter/AudioDescriptor;)V");
- DemuxFilterMediaEvent mediaEvent = event.media();
- uint32_t dataLength = mediaEvent.dataLength;
- const native_handle_t* h = mediaEvent.avMemory.getNativeHandle();
- jobject block = handleToLinearBlock(h, dataLength);
- // TODO: handle other fields
+ for (int i = 0; i < events.size(); i++) {
+ auto event = events[i];
+ DemuxFilterMediaEvent mediaEvent = event.media();
- return env->NewObject(clazz, eventInit, (jint) 0, (jboolean) 0, (jlong) 0, (jlong) 0, (jlong) 0,
- block, (jboolean) 0, (jlong) 0, (jint) 0, (jboolean) 0, NULL);
+ jobject audioDescriptor = NULL;
+ if (mediaEvent.extraMetaData.getDiscriminator()
+ == DemuxFilterMediaEvent::ExtraMetaData::hidl_discriminator::audio) {
+ jclass adClazz = env->FindClass("android/media/tv/tuner/filter/AudioDescriptor");
+ jmethodID adInit = env->GetMethodID(adClazz, "<init>", "(BBCBBB)V");
+
+ AudioExtraMetaData ad = mediaEvent.extraMetaData.audio();
+ jbyte adFade = static_cast<jbyte>(ad.adFade);
+ jbyte adPan = static_cast<jbyte>(ad.adPan);
+ jchar versionTextTag = static_cast<jchar>(ad.versionTextTag);
+ jbyte adGainCenter = static_cast<jbyte>(ad.adGainCenter);
+ jbyte adGainFront = static_cast<jbyte>(ad.adGainFront);
+ jbyte adGainSurround = static_cast<jbyte>(ad.adGainSurround);
+
+ audioDescriptor =
+ env->NewObject(adClazz, adInit, adFade, adPan, versionTextTag, adGainCenter,
+ adGainFront, adGainSurround);
+ }
+
+ jlong dataLength = static_cast<jlong>(mediaEvent.dataLength);
+ const native_handle_t* h = NULL;
+ jobject block = NULL;
+ if (mediaEvent.avMemory != NULL) {
+ h = mediaEvent.avMemory.getNativeHandle();
+ block = handleToLinearBlock(h, dataLength);
+ }
+
+ jint streamId = static_cast<jint>(mediaEvent.streamId);
+ jboolean isPtsPresent = static_cast<jboolean>(mediaEvent.isPtsPresent);
+ jlong pts = static_cast<jlong>(mediaEvent.pts);
+ jlong offset = static_cast<jlong>(mediaEvent.offset);
+ jboolean isSecureMemory = static_cast<jboolean>(mediaEvent.isSecureMemory);
+ jlong avDataId = static_cast<jlong>(mediaEvent.avDataId);
+ jint mpuSequenceNumber = static_cast<jint>(mediaEvent.mpuSequenceNumber);
+ jboolean isPesPrivateData = static_cast<jboolean>(mediaEvent.isPesPrivateData);
+
+ jobject obj =
+ env->NewObject(eventClazz, eventInit, streamId, isPtsPresent, pts, dataLength,
+ offset, block, isSecureMemory, avDataId, mpuSequenceNumber, isPesPrivateData,
+ audioDescriptor);
+ env->SetObjectArrayElement(arr, i, obj);
+ }
+ return arr;
+}
+
+jobjectArray FilterCallback::getPesEvent(
+ jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events) {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/PesEvent");
+ jmethodID eventInit = env->GetMethodID(eventClazz, "<init>", "(III)V");
+
+ for (int i = 0; i < events.size(); i++) {
+ auto event = events[i];
+ DemuxFilterPesEvent pesEvent = event.pes();
+
+ jint streamId = static_cast<jint>(pesEvent.streamId);
+ jint dataLength = static_cast<jint>(pesEvent.dataLength);
+ jint mpuSequenceNumber = static_cast<jint>(pesEvent.mpuSequenceNumber);
+
+ jobject obj =
+ env->NewObject(eventClazz, eventInit, streamId, dataLength, mpuSequenceNumber);
+ env->SetObjectArrayElement(arr, i, obj);
+ }
+ return arr;
+}
+
+jobjectArray FilterCallback::getTsRecordEvent(
+ jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events) {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/TsRecordEvent");
+ jmethodID eventInit = env->GetMethodID(eventClazz, "<init>", "(IIIJ)V");
+
+ for (int i = 0; i < events.size(); i++) {
+ auto event = events[i];
+ DemuxFilterTsRecordEvent tsRecordEvent = event.tsRecord();
+ DemuxPid pid = tsRecordEvent.pid;
+
+ jint jpid = static_cast<jint>(Constant::INVALID_TS_PID);
+
+ if (pid.getDiscriminator() == DemuxPid::hidl_discriminator::tPid) {
+ jpid = static_cast<jint>(pid.tPid());
+ } else if (pid.getDiscriminator() == DemuxPid::hidl_discriminator::mmtpPid) {
+ jpid = static_cast<jint>(pid.mmtpPid());
+ }
+
+ jint sc = 0;
+
+ if (tsRecordEvent.scIndexMask.getDiscriminator()
+ == DemuxFilterTsRecordEvent::ScIndexMask::hidl_discriminator::sc) {
+ sc = static_cast<jint>(tsRecordEvent.scIndexMask.sc());
+ } else if (tsRecordEvent.scIndexMask.getDiscriminator()
+ == DemuxFilterTsRecordEvent::ScIndexMask::hidl_discriminator::scHevc) {
+ sc = static_cast<jint>(tsRecordEvent.scIndexMask.scHevc());
+ }
+
+ jint ts = static_cast<jint>(tsRecordEvent.tsIndexMask);
+
+ jlong byteNumber = static_cast<jlong>(tsRecordEvent.byteNumber);
+
+ jobject obj =
+ env->NewObject(eventClazz, eventInit, jpid, ts, sc, byteNumber);
+ env->SetObjectArrayElement(arr, i, obj);
+ }
+ return arr;
+}
+
+jobjectArray FilterCallback::getMmtpRecordEvent(
+ jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events) {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/MmtpRecordEvent");
+ jmethodID eventInit = env->GetMethodID(eventClazz, "<init>", "(IJ)V");
+
+ for (int i = 0; i < events.size(); i++) {
+ auto event = events[i];
+ DemuxFilterMmtpRecordEvent mmtpRecordEvent = event.mmtpRecord();
+
+ jint scHevcIndexMask = static_cast<jint>(mmtpRecordEvent.scHevcIndexMask);
+ jlong byteNumber = static_cast<jlong>(mmtpRecordEvent.byteNumber);
+
+ jobject obj =
+ env->NewObject(eventClazz, eventInit, scHevcIndexMask, byteNumber);
+ env->SetObjectArrayElement(arr, i, obj);
+ }
+ return arr;
+}
+
+jobjectArray FilterCallback::getDownloadEvent(
+ jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events) {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/DownloadEvent");
+ jmethodID eventInit = env->GetMethodID(eventClazz, "<init>", "(IIIII)V");
+
+ for (int i = 0; i < events.size(); i++) {
+ auto event = events[i];
+ DemuxFilterDownloadEvent downloadEvent = event.download();
+
+ jint itemId = static_cast<jint>(downloadEvent.itemId);
+ jint mpuSequenceNumber = static_cast<jint>(downloadEvent.mpuSequenceNumber);
+ jint itemFragmentIndex = static_cast<jint>(downloadEvent.itemFragmentIndex);
+ jint lastItemFragmentIndex = static_cast<jint>(downloadEvent.lastItemFragmentIndex);
+ jint dataLength = static_cast<jint>(downloadEvent.dataLength);
+
+ jobject obj =
+ env->NewObject(eventClazz, eventInit, itemId, mpuSequenceNumber, itemFragmentIndex,
+ lastItemFragmentIndex, dataLength);
+ env->SetObjectArrayElement(arr, i, obj);
+ }
+ return arr;
+}
+
+jobjectArray FilterCallback::getIpPayloadEvent(
+ jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events) {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/IpPayloadEvent");
+ jmethodID eventInit = env->GetMethodID(eventClazz, "<init>", "(I)V");
+
+ for (int i = 0; i < events.size(); i++) {
+ auto event = events[i];
+ DemuxFilterIpPayloadEvent ipPayloadEvent = event.ipPayload();
+ jint dataLength = static_cast<jint>(ipPayloadEvent.dataLength);
+ jobject obj = env->NewObject(eventClazz, eventInit, dataLength);
+ env->SetObjectArrayElement(arr, i, obj);
+ }
+ return arr;
+}
+
+jobjectArray FilterCallback::getTemiEvent(
+ jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events) {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/TemiEvent");
+ jmethodID eventInit = env->GetMethodID(eventClazz, "<init>", "(JB[B)V");
+
+ for (int i = 0; i < events.size(); i++) {
+ auto event = events[i];
+ DemuxFilterTemiEvent temiEvent = event.temi();
+ jlong pts = static_cast<jlong>(temiEvent.pts);
+ jbyte descrTag = static_cast<jbyte>(temiEvent.descrTag);
+ std::vector<uint8_t> descrData = temiEvent.descrData;
+
+ jbyteArray array = env->NewByteArray(descrData.size());
+ env->SetByteArrayRegion(
+ array, 0, descrData.size(), reinterpret_cast<jbyte*>(&descrData[0]));
+
+ jobject obj = env->NewObject(eventClazz, eventInit, pts, descrTag, array);
+ env->SetObjectArrayElement(arr, i, obj);
+ }
+ return arr;
}
Return<void> FilterCallback::onFilterEvent(const DemuxFilterEvent& filterEvent) {
ALOGD("FilterCallback::onFilterEvent");
JNIEnv *env = AndroidRuntime::getJNIEnv();
- jclass clazz = env->FindClass("android/media/tv/tuner/filter/Filter");
std::vector<DemuxFilterEvent::Event> events = filterEvent.events;
jclass eventClazz = env->FindClass("android/media/tv/tuner/filter/FilterEvent");
jobjectArray array = env->NewObjectArray(events.size(), eventClazz, NULL);
- for (int i = 0; i < events.size(); i++) {
- auto event = events[i];
- if (event.getDiscriminator() == DemuxFilterEvent::Event::hidl_discriminator::media) {
- env->SetObjectArrayElement(array, i, getMediaEvent(event));
+ if (!events.empty()) {
+ auto event = events[0];
+ switch (event.getDiscriminator()) {
+ case DemuxFilterEvent::Event::hidl_discriminator::media: {
+ array = getMediaEvent(array, events);
+ break;
+ }
+ case DemuxFilterEvent::Event::hidl_discriminator::section: {
+ array = getSectionEvent(array, events);
+ break;
+ }
+ case DemuxFilterEvent::Event::hidl_discriminator::pes: {
+ array = getPesEvent(array, events);
+ break;
+ }
+ case DemuxFilterEvent::Event::hidl_discriminator::tsRecord: {
+ array = getTsRecordEvent(array, events);
+ break;
+ }
+ case DemuxFilterEvent::Event::hidl_discriminator::mmtpRecord: {
+ array = getMmtpRecordEvent(array, events);
+ break;
+ }
+ case DemuxFilterEvent::Event::hidl_discriminator::download: {
+ array = getDownloadEvent(array, events);
+ break;
+ }
+ case DemuxFilterEvent::Event::hidl_discriminator::ipPayload: {
+ array = getIpPayloadEvent(array, events);
+ break;
+ }
+ case DemuxFilterEvent::Event::hidl_discriminator::temi: {
+ array = getTemiEvent(array, events);
+ break;
+ }
+ default: {
+ break;
+ }
}
}
env->CallVoidMethod(
mFilter,
- env->GetMethodID(clazz, "onFilterEvent",
- "([Landroid/media/tv/tuner/filter/FilterEvent;)V"),
+ gFields.onFilterEventID,
array);
return Void();
}
+
Return<void> FilterCallback::onFilterStatus(const DemuxFilterStatus status) {
ALOGD("FilterCallback::onFilterStatus");
JNIEnv *env = AndroidRuntime::getJNIEnv();
@@ -308,9 +557,16 @@
/////////////// Filter ///////////////////////
-Filter::Filter(sp<IFilter> sp, jweak obj) : mFilterSp(sp), mFilterObj(obj) {}
+Filter::Filter(sp<IFilter> sp, jobject obj) : mFilterSp(sp) {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+ mFilterObj = env->NewWeakGlobalRef(obj);
+}
Filter::~Filter() {
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+ env->DeleteWeakGlobalRef(mFilterObj);
+ mFilterObj = NULL;
EventFlag::deleteEventFlag(&mFilterMQEventFlag);
}
@@ -816,6 +1072,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");
@@ -1616,8 +1903,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");
@@ -1625,6 +1911,9 @@
env->GetMethodID(filterClazz, "<init>", "(I)V");
gFields.onFilterStatusID =
env->GetMethodID(filterClazz, "onFilterStatus", "(I)V");
+ gFields.onFilterEventID =
+ env->GetMethodID(filterClazz, "onFilterEvent",
+ "([Landroid/media/tv/tuner/filter/FilterEvent;)V");
jclass timeFilterClazz = env->FindClass("android/media/tv/tuner/filter/TimeFilter");
gFields.timeFilterContext = env->GetFieldID(timeFilterClazz, "mNativeContext", "J");
@@ -1737,6 +2026,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);
@@ -2629,6 +2924,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;",
diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h
index fec4cd8..3b8682f 100644
--- a/media/jni/android_media_tv_Tuner.h
+++ b/media/jni/android_media_tv_Tuner.h
@@ -114,7 +114,22 @@
jobject handleToLinearBlock(const native_handle_t* handle, uint32_t size);
private:
jweak mFilter;
- jobject getMediaEvent(const DemuxFilterEvent::Event& event);
+ jobjectArray getSectionEvent(
+ jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events);
+ jobjectArray getMediaEvent(
+ jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events);
+ jobjectArray getPesEvent(
+ jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events);
+ jobjectArray getTsRecordEvent(
+ jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events);
+ jobjectArray getMmtpRecordEvent(
+ jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events);
+ jobjectArray getDownloadEvent(
+ jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events);
+ jobjectArray getIpPayloadEvent(
+ jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events);
+ jobjectArray getTemiEvent(
+ jobjectArray& arr, const std::vector<DemuxFilterEvent::Event>& events);
};
struct FrontendCallback : public IFrontendCallback {
@@ -129,7 +144,7 @@
};
struct Filter : public RefBase {
- Filter(sp<IFilter> sp, jweak obj);
+ Filter(sp<IFilter> sp, jobject obj);
~Filter();
int close();
sp<IFilter> getIFilter();
@@ -165,6 +180,7 @@
int setLna(bool enable);
jobject getLnbIds();
jobject openLnbById(int id);
+ jobject openLnbByName(jstring name);
jobject openFilter(DemuxFilterType type, int bufferSize);
jobject openTimeFilter();
jobject openDescrambler();
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 c529952..6354ccd 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
@@ -320,6 +320,15 @@
public void onCameraAccessPrioritiesChanged() {
Log.v(TAG, "Camera access permission change");
}
+ @Override
+ public void onCameraOpened(String cameraId, String clientPackageName) {
+ Log.v(TAG, String.format("Camera %s is opened by client package %s",
+ cameraId, clientPackageName));
+ }
+ @Override
+ public void onCameraClosed(String cameraId) {
+ Log.v(TAG, String.format("Camera %s is closed", cameraId));
+ }
}
/**
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
index 6f985a4..140c075 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
@@ -49,6 +49,8 @@
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.BatteryControllerImpl;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -106,6 +108,11 @@
NotificationLockscreenUserManagerImpl notificationLockscreenUserManager);
@Binds
+ @Singleton
+ public abstract BatteryController provideBatteryController(
+ BatteryControllerImpl controllerImpl);
+
+ @Binds
abstract DockManager bindDockManager(DockManagerImpl dockManager);
@Binds
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/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/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index cd62420..2d351c7 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -1259,7 +1259,8 @@
public boolean reset() {
// overrideableByRestore = true as resetting to default value isn't considered a
// modification.
- return update(this.defaultValue, false, packageName, null, true, true);
+ return update(this.defaultValue, false, packageName, null, true, true,
+ /* resetToDefault */ true);
}
public boolean isTransient() {
@@ -1272,6 +1273,13 @@
public boolean update(String value, boolean setDefault, String packageName, String tag,
boolean forceNonSystemPackage, boolean overrideableByRestore) {
+ return update(value, setDefault, packageName, tag, forceNonSystemPackage,
+ overrideableByRestore, /* resetToDefault */ false);
+ }
+
+ private boolean update(String value, boolean setDefault, String packageName, String tag,
+ boolean forceNonSystemPackage, boolean overrideableByRestore,
+ boolean resetToDefault) {
if (NULL_VALUE.equals(value)) {
value = null;
}
@@ -1305,7 +1313,7 @@
}
// isValuePreservedInRestore shouldn't change back to false if it has been set to true.
- boolean isPreserved = this.isValuePreservedInRestore || !overrideableByRestore;
+ boolean isPreserved = shouldPreserveSetting(overrideableByRestore, resetToDefault);
// Is something gonna change?
if (Objects.equals(value, this.value)
@@ -1329,6 +1337,17 @@
+ " packageName=" + packageName + " tag=" + tag
+ " defaultFromSystem=" + defaultFromSystem + "}";
}
+
+ private boolean shouldPreserveSetting(boolean overrideableByRestore,
+ boolean resetToDefault) {
+ if (resetToDefault) {
+ // By default settings are not marked as preserved.
+ return false;
+ }
+
+ // isValuePreservedInRestore shouldn't change back to false if it has been set to true.
+ return this.isValuePreservedInRestore || !overrideableByRestore;
+ }
}
/**
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
index b855d87..6a3c661 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsStateTest.java
@@ -241,6 +241,18 @@
assertTrue(settingsReader.getSettingLocked(SETTING_NAME).isValuePreservedInRestore());
}
+ public void testResetSetting_preservedFlagIsReset() {
+ SettingsState settingsState = getSettingStateObject();
+ // Initialize the setting.
+ settingsState.insertSettingLocked(SETTING_NAME, "1", null, false, TEST_PACKAGE);
+ // Update the setting so that preserved flag is set.
+ settingsState.insertSettingLocked(SETTING_NAME, "2", null, false, TEST_PACKAGE);
+
+ settingsState.resetSettingLocked(SETTING_NAME);
+ assertFalse(settingsState.getSettingLocked(SETTING_NAME).isValuePreservedInRestore());
+
+ }
+
private SettingsState getSettingStateObject() {
SettingsState settingsState = new SettingsState(getContext(), mLock, mSettingsFile, 1,
SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED, Looper.getMainLooper());
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index e13e49f..8f859b2 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -204,7 +204,6 @@
<!-- Permission needed to run network tests in CTS -->
<uses-permission android:name="android.permission.MANAGE_TEST_NETWORKS" />
- <uses-permission android:name="android.permission.NETWORK_STACK" />
<!-- Permission needed to test tcp keepalive offload. -->
<uses-permission android:name="android.permission.PACKET_KEEPALIVE_OFFLOAD" />
@@ -276,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/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 30b461d..da93db7 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -147,6 +147,7 @@
<uses-permission android:name="android.permission.CONFIGURE_WIFI_DISPLAY" />
<uses-permission android:name="android.permission.CAMERA" />
+ <uses-permission android:name="android.permission.CAMERA_OPEN_CLOSE_LISTENER" />
<!-- Screen Capturing -->
<uses-permission android:name="android.permission.MANAGE_MEDIA_PROJECTION" />
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/config.xml b/packages/SystemUI/res/values/config.xml
index d160829..20cafd0 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 -->
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index caf22fe..18fec29 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2653,4 +2653,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..4770910 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">
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/src/com/android/keyguard/clock/ClockManager.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
index 0367464..2200b22 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
@@ -43,6 +43,7 @@
import com.android.systemui.util.InjectionInflationController;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -74,8 +75,8 @@
private final ContentObserver mContentObserver =
new ContentObserver(mMainHandler) {
@Override
- public void onChange(boolean selfChange, Uri uri, int userId) {
- super.onChange(selfChange, uri, userId);
+ public void onChange(boolean selfChange, Collection<Uri> uris,
+ int flags, int userId) {
if (Objects.equals(userId,
mCurrentUserObservable.getCurrentUser().getValue())) {
reload();
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/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 22c2c7e..ae1438e 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -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 e8acbab..aedd2db 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -1386,13 +1386,14 @@
if (DEBUG_BUBBLE_STACK_VIEW) {
Log.d(TAG, "onBubbleDragStart: bubble=" + bubble);
}
- maybeShowManageEducation(false);
mExpandedAnimationController.prepareForBubbleDrag(bubble, mMagneticTarget);
// We're dragging an individual bubble, so set the magnetized object to the magnetized
// bubble.
mMagnetizedObject = mExpandedAnimationController.getMagnetizedBubbleDraggingOut();
mMagnetizedObject.setMagnetListener(mIndividualBubbleMagnetListener);
+
+ maybeShowManageEducation(false);
}
/** Called with the coordinates to which an individual bubble has been dragged. */
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/ControlsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
index 989b7cf..e5d36f9 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
@@ -127,7 +127,7 @@
internal val settingObserver = object : ContentObserver(null) {
override fun onChange(
selfChange: Boolean,
- uris: MutableIterable<Uri>,
+ uris: Collection<Uri>,
flags: Int,
userId: Int
) {
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..502354a 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,8 @@
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 var listOfStructures = emptyList<StructureContainer>()
private lateinit var comparator: Comparator<StructureContainer>
@@ -172,9 +180,48 @@
layoutResource = R.layout.controls_management_favorites
inflate()
}
-
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 +231,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()
}
@@ -207,11 +260,25 @@
}
}
+ 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)
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/ControlsListingControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
index 9b108cf..94487e5 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
@@ -88,6 +88,8 @@
init {
serviceListing.addCallback(serviceListingCallback)
+ serviceListing.setListening(true)
+ serviceListing.reload()
}
override fun changeUser(newUser: UserHandle) {
@@ -95,11 +97,12 @@
callbacks.clear()
availableServices = emptyList()
serviceListing.setListening(false)
- serviceListing.removeCallback(serviceListingCallback)
currentUserId = newUser.identifier
val contextForUser = context.createContextAsUser(newUser, 0)
serviceListing = serviceListingBuilder(contextForUser)
serviceListing.addCallback(serviceListingCallback)
+ serviceListing.setListening(true)
+ serviceListing.reload()
}
}
@@ -118,12 +121,7 @@
backgroundExecutor.execute {
Log.d(TAG, "Subscribing callback")
callbacks.add(listener)
- if (callbacks.size == 1) {
- serviceListing.setListening(true)
- serviceListing.reload()
- } else {
- listener.onServicesUpdated(getCurrentServices())
- }
+ listener.onServicesUpdated(getCurrentServices())
}
}
@@ -136,9 +134,6 @@
backgroundExecutor.execute {
Log.d(TAG, "Unsubscribing callback")
callbacks.remove(listener)
- if (callbacks.size == 0) {
- serviceListing.setListening(false)
- }
}
}
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/dagger/DependencyBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java
index 2877ed0..5b3d5c5 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyBinder.java
@@ -44,8 +44,6 @@
import com.android.systemui.statusbar.phone.StatusBarIconController;
import com.android.systemui.statusbar.phone.StatusBarIconControllerImpl;
import com.android.systemui.statusbar.phone.StatusBarRemoteInputCallback;
-import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.statusbar.policy.BatteryControllerImpl;
import com.android.systemui.statusbar.policy.BluetoothController;
import com.android.systemui.statusbar.policy.BluetoothControllerImpl;
import com.android.systemui.statusbar.policy.CastController;
@@ -179,12 +177,6 @@
/**
*/
@Binds
- public abstract BatteryController provideBatteryController(
- BatteryControllerImpl controllerImpl);
-
- /**
- */
- @Binds
public abstract ManagedProfileController provideManagedProfileController(
ManagedProfileControllerImpl controllerImpl);
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
index b4e5125..956b4aa 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIDefaultModule.java
@@ -43,6 +43,8 @@
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.ShadeControllerImpl;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.BatteryControllerImpl;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.DeviceProvisionedControllerImpl;
@@ -78,6 +80,11 @@
NotificationLockscreenUserManagerImpl notificationLockscreenUserManager);
@Binds
+ @Singleton
+ public abstract BatteryController provideBatteryController(
+ BatteryControllerImpl controllerImpl);
+
+ @Binds
abstract DockManager bindDockManager(DockManagerImpl dockManager);
@Binds
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index c28a719..700a861 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -49,6 +49,7 @@
import com.android.systemui.util.wakelock.WakeLock;
import java.io.PrintWriter;
+import java.util.Collection;
import java.util.List;
import java.util.function.Consumer;
@@ -261,7 +262,7 @@
private final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
@Override
- public void onChange(boolean selfChange, Iterable<Uri> uris, int flags, int userId) {
+ public void onChange(boolean selfChange, Collection<Uri> uris, int flags, int userId) {
if (userId != ActivityManager.getCurrentUser()) {
return;
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
index 3933af0..00b977e 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
@@ -33,10 +33,10 @@
import android.content.Context;
import android.graphics.Rect;
import android.os.Handler;
+import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;
-import android.view.DisplayInfo;
import android.view.ITaskOrganizer;
import android.view.IWindowContainer;
import android.view.SurfaceControl;
@@ -47,7 +47,9 @@
import com.android.systemui.pip.phone.PipUpdateThread;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;
@@ -76,9 +78,9 @@
private final PipBoundsHandler mPipBoundsHandler;
private final PipAnimationController mPipAnimationController;
private final List<PipTransitionCallback> mPipTransitionCallbacks = new ArrayList<>();
- private final Rect mDisplayBounds = new Rect();
private final Rect mLastReportedBounds = new Rect();
private final int mCornerRadius;
+ private final Map<IBinder, Rect> mBoundsToRestore = new HashMap<>();
// These callbacks are called on the update thread
private final PipAnimationController.PipAnimationCallback mPipAnimationCallback =
@@ -201,29 +203,6 @@
}
/**
- * Updates the display dimension with given {@link DisplayInfo}
- */
- @SuppressWarnings("unchecked")
- public void onDisplayInfoChanged(DisplayInfo displayInfo) {
- final Rect newDisplayBounds = new Rect(0, 0,
- displayInfo.logicalWidth, displayInfo.logicalHeight);
- if (!mDisplayBounds.equals(newDisplayBounds)) {
- // Updates the exiting PiP animation in case the screen rotation changes in the middle.
- // It's a legit case that PiP window is in portrait mode on home screen and
- // the application requests landscape once back to fullscreen mode.
- final PipAnimationController.PipTransitionAnimator animator =
- mPipAnimationController.getCurrentAnimator();
- if (animator != null
- && animator.getAnimationType() == ANIM_TYPE_BOUNDS
- && animator.getDestinationBounds().equals(mDisplayBounds)) {
- animator.updateEndValue(newDisplayBounds);
- animator.setDestinationBounds(newDisplayBounds);
- }
- }
- mDisplayBounds.set(newDisplayBounds);
- }
-
- /**
* Callback to issue the final {@link WindowContainerTransaction} on end of movements.
* @param destinationBounds the final bounds.
*/
@@ -252,8 +231,9 @@
} catch (RemoteException e) {
throw new RuntimeException("Unable to get leash", e);
}
+ final Rect currentBounds = mTaskInfo.configuration.windowConfiguration.getBounds();
+ mBoundsToRestore.put(mToken.asBinder(), currentBounds);
if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) {
- final Rect currentBounds = mTaskInfo.configuration.windowConfiguration.getBounds();
scheduleAnimateResizePip(currentBounds, destinationBounds,
TRANSITION_DIRECTION_TO_PIP, DURATION_DEFAULT_MS, null);
} else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) {
@@ -271,13 +251,15 @@
}
@Override
- public void taskVanished(IWindowContainer token) {
+ public void taskVanished(ActivityManager.RunningTaskInfo info) {
+ IWindowContainer token = info.token;
Objects.requireNonNull(token, "Requires valid IWindowContainer");
if (token.asBinder() != mToken.asBinder()) {
Log.wtf(TAG, "Unrecognized token: " + token);
return;
}
- scheduleAnimateResizePip(mLastReportedBounds, mDisplayBounds,
+ final Rect boundsToRestore = mBoundsToRestore.remove(mToken.asBinder());
+ scheduleAnimateResizePip(mLastReportedBounds, boundsToRestore,
TRANSITION_DIRECTION_TO_FULLSCREEN, DURATION_DEFAULT_MS, null);
mInPip = false;
}
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 4b97d13..1fdf92e 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -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 */);
}
};
@@ -185,10 +190,7 @@
@Override
public void onDisplayInfoChanged(DisplayInfo displayInfo) {
- mHandler.post(() -> {
- mPipBoundsHandler.onDisplayInfoChanged(displayInfo);
- mPipTaskOrganizer.onDisplayInfoChanged(displayInfo);
- });
+ mHandler.post(() -> mPipBoundsHandler.onDisplayInfoChanged(displayInfo));
}
@Override
@@ -352,7 +354,6 @@
mTouchHandler.onMovementBoundsChanged(mTmpInsetBounds, mTmpNormalBounds,
animatingBounds, fromImeAdjustment, fromShelfAdjustment,
mTmpDisplayInfo.rotation);
- mPipTaskOrganizer.onDisplayInfoChanged(mTmpDisplayInfo);
}
public void dump(PrintWriter pw) {
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..0c5a4d7 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -680,7 +680,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 c6eecf26..fb68153 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -129,217 +129,213 @@
}
};
- private DisplayImeController.ImePositionProcessor mImePositionProcessor =
- new DisplayImeController.ImePositionProcessor() {
- /**
- * These are the y positions of the top of the IME surface when it is hidden and
- * when it is shown respectively. These are NOT necessarily the top of the visible
- * IME itself.
- */
- private int mHiddenTop = 0;
- private int mShownTop = 0;
+ private class DividerImeController implements DisplayImeController.ImePositionProcessor {
+ /**
+ * These are the y positions of the top of the IME surface when it is hidden and when it is
+ * shown respectively. These are NOT necessarily the top of the visible IME itself.
+ */
+ private int mHiddenTop = 0;
+ private int mShownTop = 0;
- // The following are target states (what we are curretly animating towards).
- /**
- * {@code true} if, at the end of the animation, the split task positions should be
- * adjusted by height of the IME. This happens when the secondary split is the IME
- * target.
- */
- private boolean mTargetAdjusted = false;
- /**
- * {@code true} if, at the end of the animation, the IME should be shown/visible
- * regardless of what has focus.
- */
- private boolean mTargetShown = false;
+ // The following are target states (what we are curretly animating towards).
+ /**
+ * {@code true} if, at the end of the animation, the split task positions should be
+ * adjusted by height of the IME. This happens when the secondary split is the IME target.
+ */
+ private boolean mTargetAdjusted = false;
+ /**
+ * {@code true} if, at the end of the animation, the IME should be shown/visible
+ * regardless of what has focus.
+ */
+ private boolean mTargetShown = false;
- // The following are the current (most recent) states set during animation
- /**
- * {@code true} if the secondary split has IME focus.
- */
- private boolean mSecondaryHasFocus = false;
- /** The dimming currently applied to the primary/secondary splits. */
- private float mLastPrimaryDim = 0.f;
- private float mLastSecondaryDim = 0.f;
- /** The most recent y position of the top of the IME surface */
- private int mLastAdjustTop = -1;
+ // The following are the current (most recent) states set during animation
+ /** {@code true} if the secondary split has IME focus. */
+ private boolean mSecondaryHasFocus = false;
+ /** The dimming currently applied to the primary/secondary splits. */
+ private float mLastPrimaryDim = 0.f;
+ private float mLastSecondaryDim = 0.f;
+ /** The most recent y position of the top of the IME surface */
+ private int mLastAdjustTop = -1;
- // The following are states reached last time an animation fully completed.
- /** {@code true} if the IME was shown/visible by the last-completed animation. */
- private boolean mImeWasShown = false;
- /**
- * {@code true} if the split positions were adjusted by the last-completed
- * animation.
- */
- private boolean mAdjusted = false;
+ // The following are states reached last time an animation fully completed.
+ /** {@code true} if the IME was shown/visible by the last-completed animation. */
+ private boolean mImeWasShown = false;
+ /** {@code true} if the split positions were adjusted by the last-completed animation. */
+ private boolean mAdjusted = false;
- /**
- * When some aspect of split-screen needs to animate independent from the IME,
- * this will be non-null and control split animation.
- */
- @Nullable
- private ValueAnimator mAnimation = null;
+ /**
+ * When some aspect of split-screen needs to animate independent from the IME,
+ * this will be non-null and control split animation.
+ */
+ @Nullable
+ private ValueAnimator mAnimation = null;
- private boolean getSecondaryHasFocus(int displayId) {
- try {
- IWindowContainer imeSplit = ActivityTaskManager.getTaskOrganizerController()
- .getImeTarget(displayId);
- return imeSplit != null
- && (imeSplit.asBinder() == mSplits.mSecondary.token.asBinder());
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed to get IME target", e);
- }
- return false;
- }
+ private boolean getSecondaryHasFocus(int displayId) {
+ try {
+ IWindowContainer imeSplit = ActivityTaskManager.getTaskOrganizerController()
+ .getImeTarget(displayId);
+ return imeSplit != null
+ && (imeSplit.asBinder() == mSplits.mSecondary.token.asBinder());
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to get IME target", e);
+ }
+ return false;
+ }
+ @Override
+ public void onImeStartPositioning(int displayId, int hiddenTop, int shownTop,
+ boolean imeShouldShow, SurfaceControl.Transaction t) {
+ mSecondaryHasFocus = getSecondaryHasFocus(displayId);
+ mTargetAdjusted = imeShouldShow && mSecondaryHasFocus
+ && !mSplitLayout.mDisplayLayout.isLandscape();
+ mHiddenTop = hiddenTop;
+ mShownTop = shownTop;
+ mTargetShown = imeShouldShow;
+ if (mLastAdjustTop < 0) {
+ mLastAdjustTop = imeShouldShow ? hiddenTop : shownTop;
+ }
+ if (mAnimation != null || (mImeWasShown && imeShouldShow
+ && mTargetAdjusted != mAdjusted)) {
+ // We need to animate adjustment independently of the IME position, so
+ // start our own animation to drive adjustment. This happens when a
+ // different split's editor has gained focus while the IME is still visible.
+ startAsyncAnimation();
+ }
+ updateImeAdjustState();
+ }
+
+ private void updateImeAdjustState() {
+ // Reposition the server's secondary split position so that it evaluates
+ // insets properly.
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ if (mTargetAdjusted) {
+ mSplitLayout.updateAdjustedBounds(mShownTop, mHiddenTop, mShownTop);
+ wct.setBounds(mSplits.mSecondary.token, mSplitLayout.mAdjustedSecondary);
+ // "Freeze" the configuration size so that the app doesn't get a config
+ // or relaunch. This is required because normally nav-bar contributes
+ // to configuration bounds (via nondecorframe).
+ Rect adjustAppBounds = new Rect(mSplits.mSecondary.configuration
+ .windowConfiguration.getAppBounds());
+ adjustAppBounds.offset(0, mSplitLayout.mAdjustedSecondary.top
+ - mSplitLayout.mSecondary.top);
+ wct.setAppBounds(mSplits.mSecondary.token, adjustAppBounds);
+ wct.setScreenSizeDp(mSplits.mSecondary.token,
+ mSplits.mSecondary.configuration.screenWidthDp,
+ mSplits.mSecondary.configuration.screenHeightDp);
+ } else {
+ wct.setBounds(mSplits.mSecondary.token, mSplitLayout.mSecondary);
+ wct.setAppBounds(mSplits.mSecondary.token, null);
+ wct.setScreenSizeDp(mSplits.mSecondary.token,
+ SCREEN_WIDTH_DP_UNDEFINED, SCREEN_HEIGHT_DP_UNDEFINED);
+ }
+ try {
+ ActivityTaskManager.getTaskOrganizerController()
+ .applyContainerTransaction(wct, null /* organizer */);
+ } catch (RemoteException e) {
+ }
+
+ // Update all the adjusted-for-ime states
+ mView.setAdjustedForIme(mTargetShown, mTargetShown
+ ? DisplayImeController.ANIMATION_DURATION_SHOW_MS
+ : DisplayImeController.ANIMATION_DURATION_HIDE_MS);
+ setAdjustedForIme(mTargetShown);
+ }
+
+ @Override
+ public void onImePositionChanged(int displayId, int imeTop,
+ SurfaceControl.Transaction t) {
+ if (mAnimation != null) {
+ // Not synchronized with IME anymore, so return.
+ return;
+ }
+ final float fraction = ((float) imeTop - mHiddenTop) / (mShownTop - mHiddenTop);
+ final float progress = mTargetShown ? fraction : 1.f - fraction;
+ onProgress(progress, t);
+ }
+
+ @Override
+ public void onImeEndPositioning(int displayId, boolean cancelled,
+ SurfaceControl.Transaction t) {
+ if (mAnimation != null) {
+ // Not synchronized with IME anymore, so return.
+ return;
+ }
+ onEnd(cancelled, t);
+ }
+
+ private void onProgress(float progress, SurfaceControl.Transaction t) {
+ if (mTargetAdjusted != mAdjusted) {
+ final float fraction = mTargetAdjusted ? progress : 1.f - progress;
+ mLastAdjustTop = (int) (fraction * mShownTop + (1.f - fraction) * mHiddenTop);
+ mSplitLayout.updateAdjustedBounds(mLastAdjustTop, mHiddenTop, mShownTop);
+ mView.resizeSplitSurfaces(t, mSplitLayout.mAdjustedPrimary,
+ 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);
+ mView.setResizeDimLayer(t, false /* primary */,
+ mLastSecondaryDim * invProg + progress * targetSecondaryDim);
+ }
+
+ private void onEnd(boolean cancelled, SurfaceControl.Transaction t) {
+ if (!cancelled) {
+ onProgress(1.f, t);
+ mAdjusted = mTargetAdjusted;
+ mImeWasShown = mTargetShown;
+ mLastAdjustTop = mAdjusted ? mShownTop : mHiddenTop;
+ mLastPrimaryDim =
+ (mSecondaryHasFocus && mTargetShown) ? ADJUSTED_NONFOCUS_DIM : 0.f;
+ mLastSecondaryDim =
+ (!mSecondaryHasFocus && mTargetShown) ? ADJUSTED_NONFOCUS_DIM : 0.f;
+ }
+ }
+
+ private void startAsyncAnimation() {
+ if (mAnimation != null) {
+ mAnimation.cancel();
+ }
+ mAnimation = ValueAnimator.ofFloat(0.f, 1.f);
+ mAnimation.setDuration(DisplayImeController.ANIMATION_DURATION_SHOW_MS);
+ if (mTargetAdjusted != mAdjusted) {
+ final float fraction =
+ ((float) mLastAdjustTop - mHiddenTop) / (mShownTop - mHiddenTop);
+ final float progress = mTargetAdjusted ? fraction : 1.f - fraction;
+ mAnimation.setCurrentFraction(progress);
+ }
+
+ mAnimation.addUpdateListener(animation -> {
+ SurfaceControl.Transaction t = mTransactionPool.acquire();
+ float value = (float) animation.getAnimatedValue();
+ onProgress(value, t);
+ t.apply();
+ mTransactionPool.release(t);
+ });
+ mAnimation.setInterpolator(DisplayImeController.INTERPOLATOR);
+ mAnimation.addListener(new AnimatorListenerAdapter() {
+ private boolean mCancel = false;
@Override
- public void onImeStartPositioning(int displayId, int hiddenTop, int shownTop,
- boolean imeShouldShow, SurfaceControl.Transaction t) {
- mSecondaryHasFocus = getSecondaryHasFocus(displayId);
- mTargetAdjusted = imeShouldShow && mSecondaryHasFocus
- && !mSplitLayout.mDisplayLayout.isLandscape();
- mHiddenTop = hiddenTop;
- mShownTop = shownTop;
- mTargetShown = imeShouldShow;
- if (mLastAdjustTop < 0) {
- mLastAdjustTop = imeShouldShow ? hiddenTop : shownTop;
- }
- if (mAnimation != null || (mImeWasShown && imeShouldShow
- && mTargetAdjusted != mAdjusted)) {
- // We need to animate adjustment independently of the IME position, so
- // start our own animation to drive adjustment. This happens when a
- // different split's editor has gained focus while the IME is still visible.
- startAsyncAnimation();
- }
- // Reposition the server's secondary split position so that it evaluates
- // insets properly.
- WindowContainerTransaction wct = new WindowContainerTransaction();
- if (mTargetAdjusted) {
- mSplitLayout.updateAdjustedBounds(mShownTop, mHiddenTop, mShownTop);
- wct.setBounds(mSplits.mSecondary.token, mSplitLayout.mAdjustedSecondary);
- // "Freeze" the configuration size so that the app doesn't get a config
- // or relaunch. This is required because normally nav-bar contributes
- // to configuration bounds (via nondecorframe).
- Rect adjustAppBounds = new Rect(mSplits.mSecondary.configuration
- .windowConfiguration.getAppBounds());
- adjustAppBounds.offset(0, mSplitLayout.mAdjustedSecondary.top
- - mSplitLayout.mSecondary.top);
- wct.setAppBounds(mSplits.mSecondary.token, adjustAppBounds);
- wct.setScreenSizeDp(mSplits.mSecondary.token,
- mSplits.mSecondary.configuration.screenWidthDp,
- mSplits.mSecondary.configuration.screenHeightDp);
- } else {
- wct.setBounds(mSplits.mSecondary.token, mSplitLayout.mSecondary);
- wct.setAppBounds(mSplits.mSecondary.token, null);
- wct.setScreenSizeDp(mSplits.mSecondary.token,
- SCREEN_WIDTH_DP_UNDEFINED, SCREEN_HEIGHT_DP_UNDEFINED);
- }
- try {
- ActivityTaskManager.getTaskOrganizerController()
- .applyContainerTransaction(wct, null /* organizer */);
- } catch (RemoteException e) {
- }
-
- // Update all the adjusted-for-ime states
- mView.setAdjustedForIme(mTargetShown, mTargetShown
- ? DisplayImeController.ANIMATION_DURATION_SHOW_MS
- : DisplayImeController.ANIMATION_DURATION_HIDE_MS);
- setAdjustedForIme(mTargetShown);
+ public void onAnimationCancel(Animator animation) {
+ mCancel = true;
}
-
@Override
- public void onImePositionChanged(int displayId, int imeTop,
- SurfaceControl.Transaction t) {
- if (mAnimation != null) {
- // Not synchronized with IME anymore, so return.
- return;
- }
- final float fraction = ((float) imeTop - mHiddenTop) / (mShownTop - mHiddenTop);
- final float progress = mTargetShown ? fraction : 1.f - fraction;
- onProgress(progress, t);
+ public void onAnimationEnd(Animator animation) {
+ SurfaceControl.Transaction t = mTransactionPool.acquire();
+ onEnd(mCancel, t);
+ t.apply();
+ mTransactionPool.release(t);
+ mAnimation = null;
}
-
- @Override
- public void onImeEndPositioning(int displayId, boolean cancelled,
- SurfaceControl.Transaction t) {
- if (mAnimation != null) {
- // Not synchronized with IME anymore, so return.
- return;
- }
- onEnd(cancelled, t);
- }
-
- private void onProgress(float progress, SurfaceControl.Transaction t) {
- if (mTargetAdjusted != mAdjusted) {
- final float fraction = mTargetAdjusted ? progress : 1.f - progress;
- mLastAdjustTop =
- (int) (fraction * mShownTop + (1.f - fraction) * mHiddenTop);
- mSplitLayout.updateAdjustedBounds(mLastAdjustTop, mHiddenTop, mShownTop);
- mView.resizeSplitSurfaces(t, mSplitLayout.mAdjustedPrimary,
- 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);
- mView.setResizeDimLayer(t, false /* primary */,
- mLastSecondaryDim * invProg + progress * targetSecondaryDim);
- }
-
- private void onEnd(boolean cancelled, SurfaceControl.Transaction t) {
- if (!cancelled) {
- onProgress(1.f, t);
- mAdjusted = mTargetAdjusted;
- mImeWasShown = mTargetShown;
- mLastAdjustTop = mAdjusted ? mShownTop : mHiddenTop;
- mLastPrimaryDim =
- (mSecondaryHasFocus && mTargetShown) ? ADJUSTED_NONFOCUS_DIM : 0.f;
- mLastSecondaryDim =
- (!mSecondaryHasFocus && mTargetShown) ? ADJUSTED_NONFOCUS_DIM : 0.f;
- }
- }
-
- private void startAsyncAnimation() {
- if (mAnimation != null) {
- mAnimation.cancel();
- }
- mAnimation = ValueAnimator.ofFloat(0.f, 1.f);
- mAnimation.setDuration(DisplayImeController.ANIMATION_DURATION_SHOW_MS);
- if (mTargetAdjusted != mAdjusted) {
- final float fraction =
- ((float) mLastAdjustTop - mHiddenTop) / (mShownTop - mHiddenTop);
- final float progress = mTargetAdjusted ? fraction : 1.f - fraction;
- mAnimation.setCurrentFraction(progress);
- }
-
- mAnimation.addUpdateListener(animation -> {
- SurfaceControl.Transaction t = mTransactionPool.acquire();
- float value = (float) animation.getAnimatedValue();
- onProgress(value, t);
- t.apply();
- mTransactionPool.release(t);
- });
- mAnimation.setInterpolator(DisplayImeController.INTERPOLATOR);
- mAnimation.addListener(new AnimatorListenerAdapter() {
- private boolean mCancel = false;
- @Override
- public void onAnimationCancel(Animator animation) {
- mCancel = true;
- }
- @Override
- public void onAnimationEnd(Animator animation) {
- SurfaceControl.Transaction t = mTransactionPool.acquire();
- onEnd(mCancel, t);
- t.apply();
- mTransactionPool.release(t);
- mAnimation = null;
- }
- });
- mAnimation.start();
- }
- };
+ });
+ mAnimation.start();
+ }
+ }
+ private final DividerImeController mImePositionProcessor = new DividerImeController();
public Divider(Context context, Optional<Lazy<Recents>> recentsOptionalLazy,
DisplayController displayController, SystemWindows systemWindows,
@@ -513,44 +509,39 @@
}
}
- private void setHomeStackResizable(boolean resizable) {
- if (mHomeStackResizable == resizable) {
- return;
- }
- mHomeStackResizable = resizable;
- if (!inSplitMode()) {
- return;
- }
- WindowManagerProxy.applyHomeTasksMinimized(mSplitLayout, mSplits.mSecondary.token);
- }
-
- private void updateMinimizedDockedStack(final boolean minimized, final long animDuration,
- final boolean isHomeStackResizable) {
- setHomeStackResizable(isHomeStackResizable);
- if (animDuration > 0) {
- mView.setMinimizedDockStack(minimized, animDuration, isHomeStackResizable);
- } else {
- mView.setMinimizedDockStack(minimized, isHomeStackResizable);
- }
- updateTouchable();
- }
-
/** Switch to minimized state if appropriate */
public void setMinimized(final boolean minimized) {
mHandler.post(() -> {
- if (!inSplitMode()) {
- return;
- }
- if (mMinimized == minimized) {
- return;
- }
- mMinimized = minimized;
- WindowManagerProxy.applyPrimaryFocusable(mSplits, !mMinimized);
- mView.setMinimizedDockStack(minimized, getAnimDuration(), mHomeStackResizable);
- updateTouchable();
+ setHomeMinimized(minimized, mHomeStackResizable);
});
}
+ private void setHomeMinimized(final boolean minimized, boolean homeStackResizable) {
+ WindowContainerTransaction wct = new WindowContainerTransaction();
+ // Update minimized state
+ if (mMinimized != minimized) {
+ mMinimized = minimized;
+ }
+ // Always set this because we could be entering split when mMinimized is already true
+ wct.setFocusable(mSplits.mPrimary.token, !mMinimized);
+
+ // Update home-stack resizability
+ if (mHomeStackResizable != homeStackResizable) {
+ mHomeStackResizable = homeStackResizable;
+ if (inSplitMode()) {
+ WindowManagerProxy.applyHomeTasksMinimized(
+ mSplitLayout, mSplits.mSecondary.token, wct);
+ }
+ }
+
+ // Sync state to DividerView if it exists.
+ if (mView != null) {
+ mView.setMinimizedDockStack(minimized, getAnimDuration(), homeStackResizable);
+ }
+ updateTouchable();
+ WindowManagerProxy.applyContainerTransaction(wct);
+ }
+
void setAdjustedForIme(boolean adjustedForIme) {
if (mAdjustedForIme == adjustedForIme) {
return;
@@ -646,46 +637,24 @@
}
void ensureMinimizedSplit() {
- final boolean wasMinimized = mMinimized;
- mMinimized = true;
- setHomeStackResizable(mSplits.mSecondary.isResizable());
- WindowManagerProxy.applyPrimaryFocusable(mSplits, false /* focusable */);
+ setHomeMinimized(true /* minimized */, mSplits.mSecondary.isResizable());
if (!inSplitMode()) {
// Wasn't in split-mode yet, so enter now.
if (DEBUG) {
Log.d(TAG, " entering split mode with minimized=true");
}
updateVisibility(true /* visible */);
- } else if (!wasMinimized) {
- if (DEBUG) {
- Log.d(TAG, " in split mode, but minimizing ");
- }
- // Was already in split-mode, update just minimized state.
- updateMinimizedDockedStack(mMinimized, getAnimDuration(),
- mHomeStackResizable);
}
}
void ensureNormalSplit() {
- if (mMinimized) {
- WindowManagerProxy.applyPrimaryFocusable(mSplits, true /* focusable */);
- }
+ setHomeMinimized(false /* minimized */, mHomeStackResizable);
if (!inSplitMode()) {
// Wasn't in split-mode, so enter now.
if (DEBUG) {
Log.d(TAG, " enter split mode unminimized ");
}
- mMinimized = false;
updateVisibility(true /* visible */);
}
- if (mMinimized) {
- // Was in minimized state, so leave that.
- if (DEBUG) {
- Log.d(TAG, " in split mode already, but unminimizing ");
- }
- mMinimized = false;
- updateMinimizedDockedStack(mMinimized, getAnimDuration(),
- mHomeStackResizable);
- }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java
index 3020a25..729df38 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java
@@ -88,6 +88,9 @@
}
public void setTouchable(boolean touchable) {
+ if (mView == null) {
+ return;
+ }
boolean changed = false;
if (!touchable && (mLp.flags & FLAG_NOT_TOUCHABLE) == 0) {
mLp.flags |= FLAG_NOT_TOUCHABLE;
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
index 5cc8799..48ea4ae 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
@@ -88,7 +88,7 @@
}
@Override
- public void taskVanished(IWindowContainer container) {
+ public void taskVanished(RunningTaskInfo taskInfo) {
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
index 167c33a..fea57a3 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
@@ -21,6 +21,7 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.view.Display.DEFAULT_DISPLAY;
+import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.graphics.Rect;
@@ -137,17 +138,13 @@
return resizable;
}
- static void applyHomeTasksMinimized(SplitDisplayLayout layout, IWindowContainer parent) {
- applyHomeTasksMinimized(layout, parent, null /* transaction */);
- }
-
/**
* Assign a fixed override-bounds to home tasks that reflect their geometry while the primary
* split is minimized. This actually "sticks out" of the secondary split area, but when in
* minimized mode, the secondary split gets a 'negative' crop to expose it.
*/
static boolean applyHomeTasksMinimized(SplitDisplayLayout layout, IWindowContainer parent,
- WindowContainerTransaction t) {
+ @NonNull WindowContainerTransaction wct) {
// Resize the home/recents stacks to the larger minimized-state size
final Rect homeBounds;
final ArrayList<IWindowContainer> homeStacks = new ArrayList<>();
@@ -158,19 +155,9 @@
homeBounds = new Rect(0, 0, layout.mDisplayLayout.width(),
layout.mDisplayLayout.height());
}
- WindowContainerTransaction wct = t != null ? t : new WindowContainerTransaction();
for (int i = homeStacks.size() - 1; i >= 0; --i) {
wct.setBounds(homeStacks.get(i), homeBounds);
}
- if (t != null) {
- return isHomeResizable;
- }
- try {
- ActivityTaskManager.getTaskOrganizerController().applyContainerTransaction(wct,
- null /* organizer */);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to resize home stacks ", e);
- }
return isHomeResizable;
}
@@ -301,10 +288,8 @@
}
}
- static void applyPrimaryFocusable(SplitScreenTaskOrganizer splits, boolean focusable) {
+ static void applyContainerTransaction(WindowContainerTransaction wct) {
try {
- WindowContainerTransaction wct = new WindowContainerTransaction();
- wct.setFocusable(splits.mPrimary.token, focusable);
ActivityTaskManager.getTaskOrganizerController().applyContainerTransaction(wct,
null /* organizer */);
} catch (RemoteException e) {
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 3c0ac7e..e425ee9 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
@@ -45,6 +45,8 @@
import com.android.systemui.statusbar.notification.init.NotificationsControllerImpl;
import com.android.systemui.statusbar.notification.init.NotificationsControllerStub;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
+import com.android.systemui.statusbar.notification.logging.NotificationPanelLogger;
+import com.android.systemui.statusbar.notification.logging.NotificationPanelLoggerImpl;
import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
@@ -146,13 +148,22 @@
@UiBackground Executor uiBgExecutor,
NotificationEntryManager entryManager,
StatusBarStateController statusBarStateController,
- NotificationLogger.ExpansionStateLogger expansionStateLogger) {
+ NotificationLogger.ExpansionStateLogger expansionStateLogger,
+ NotificationPanelLogger notificationPanelLogger) {
return new NotificationLogger(
notificationListener,
uiBgExecutor,
entryManager,
statusBarStateController,
- expansionStateLogger);
+ expansionStateLogger,
+ notificationPanelLogger);
+ }
+
+ /** Provides an instance of {@link NotificationPanelLogger} */
+ @Singleton
+ @Provides
+ static NotificationPanelLogger provideNotificationPanelLogger() {
+ return new NotificationPanelLoggerImpl();
}
/** Provides an instance of {@link com.android.internal.logging.UiEventLogger} */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
index 6e161c9..ad04788 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
@@ -70,6 +70,7 @@
private final NotificationListenerService mNotificationListener;
private final Executor mUiBgExecutor;
private final NotificationEntryManager mEntryManager;
+ private final NotificationPanelLogger mNotificationPanelLogger;
private HeadsUpManager mHeadsUpManager;
private final ExpansionStateLogger mExpansionStateLogger;
@@ -198,13 +199,15 @@
@UiBackground Executor uiBgExecutor,
NotificationEntryManager entryManager,
StatusBarStateController statusBarStateController,
- ExpansionStateLogger expansionStateLogger) {
+ ExpansionStateLogger expansionStateLogger,
+ NotificationPanelLogger notificationPanelLogger) {
mNotificationListener = notificationListener;
mUiBgExecutor = uiBgExecutor;
mEntryManager = entryManager;
mBarService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
mExpansionStateLogger = expansionStateLogger;
+ mNotificationPanelLogger = notificationPanelLogger;
// Not expected to be destroyed, don't need to unsubscribe
statusBarStateController.addCallback(this);
@@ -264,6 +267,8 @@
// (Note that in cases where the scroller does emit events, this
// additional event doesn't break anything.)
mNotificationLocationsChangedListener.onChildLocationsChanged();
+ mNotificationPanelLogger.logPanelShown(mListContainer.hasPulsingNotifications(),
+ mEntryManager.getVisibleNotifications());
}
private void setDozing(boolean dozing) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java
new file mode 100644
index 0000000..9a25c48
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLogger.java
@@ -0,0 +1,95 @@
+/*
+ * 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.logging;
+
+import android.annotation.Nullable;
+import android.service.notification.StatusBarNotification;
+
+import com.android.internal.logging.UiEvent;
+import com.android.internal.logging.UiEventLogger;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.logging.nano.Notifications;
+
+import java.util.List;
+/**
+ * Statsd logging for notification panel.
+ */
+public interface NotificationPanelLogger {
+
+ /**
+ * Log a NOTIFICATION_PANEL_REPORTED statsd event.
+ * @param visibleNotifications as provided by NotificationEntryManager.getVisibleNotifications()
+ */
+ void logPanelShown(boolean isLockscreen,
+ @Nullable List<NotificationEntry> visibleNotifications);
+
+ enum NotificationPanelEvent implements UiEventLogger.UiEventEnum {
+ @UiEvent(doc = "Notification panel shown from status bar.")
+ NOTIFICATION_PANEL_OPEN_STATUS_BAR(200),
+ @UiEvent(doc = "Notification panel shown from lockscreen.")
+ NOTIFICATION_PANEL_OPEN_LOCKSCREEN(201);
+
+ private final int mId;
+ NotificationPanelEvent(int id) {
+ mId = id;
+ }
+ @Override public int getId() {
+ return mId;
+ }
+
+ public static NotificationPanelEvent fromLockscreen(boolean isLockscreen) {
+ return isLockscreen ? NOTIFICATION_PANEL_OPEN_LOCKSCREEN :
+ NOTIFICATION_PANEL_OPEN_STATUS_BAR;
+ }
+ }
+
+ /**
+ * Composes a NotificationsList proto from the list of visible notifications.
+ * @param visibleNotifications as provided by NotificationEntryManager.getVisibleNotifications()
+ * @return NotificationList proto suitable for SysUiStatsLog.write(NOTIFICATION_PANEL_REPORTED)
+ */
+ static Notifications.NotificationList toNotificationProto(
+ @Nullable List<NotificationEntry> visibleNotifications) {
+ Notifications.NotificationList notificationList = new Notifications.NotificationList();
+ if (visibleNotifications == null) {
+ return notificationList;
+ }
+ final Notifications.Notification[] proto_array =
+ new Notifications.Notification[visibleNotifications.size()];
+ int i = 0;
+ for (NotificationEntry ne : visibleNotifications) {
+ final StatusBarNotification n = ne.getSbn();
+ if (n != null) {
+ final Notifications.Notification proto = new Notifications.Notification();
+ proto.uid = n.getUid();
+ proto.packageName = n.getPackageName();
+ if (n.getInstanceId() != null) {
+ proto.instanceId = n.getInstanceId().getId();
+ }
+ // TODO set np.groupInstanceId
+ if (n.getNotification() != null) {
+ proto.isGroupSummary = n.getNotification().isGroupSummary();
+ }
+ proto.section = 1 + ne.getBucket(); // We want 0 to mean not set / unknown
+ proto_array[i] = proto;
+ }
+ ++i;
+ }
+ notificationList.notifications = proto_array;
+ return notificationList;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerImpl.java
new file mode 100644
index 0000000..75a6019
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerImpl.java
@@ -0,0 +1,41 @@
+/*
+ * 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.logging;
+
+import com.android.systemui.shared.system.SysUiStatsLog;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.logging.nano.Notifications;
+
+import com.google.protobuf.nano.MessageNano;
+
+import java.util.List;
+
+/**
+ * Normal implementation of NotificationPanelLogger.
+ */
+public class NotificationPanelLoggerImpl implements NotificationPanelLogger {
+ @Override
+ public void logPanelShown(boolean isLockscreen,
+ List<NotificationEntry> visibleNotifications) {
+ final Notifications.NotificationList proto = NotificationPanelLogger.toNotificationProto(
+ visibleNotifications);
+ SysUiStatsLog.write(SysUiStatsLog.NOTIFICATION_PANEL_REPORTED,
+ /* int event_id */ NotificationPanelEvent.fromLockscreen(isLockscreen).getId(),
+ /* int num_notifications*/ proto.notifications.length,
+ /* byte[] notifications*/ MessageNano.toByteArray(proto));
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/Notifications.proto b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/Notifications.proto
new file mode 100644
index 0000000..552a5fb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/Notifications.proto
@@ -0,0 +1,49 @@
+/*
+ * 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.logging;
+
+/**
+ * NotificationList proto from atoms.proto, duplicated here so that it's accessible in the build.
+ * Must be kept in sync with the version in atoms.proto.
+ */
+
+message Notification {
+ // The notifying app's uid and package.
+ optional int32 uid = 1;
+ optional string package_name = 2;
+ // A small system-assigned identifier for the notification.
+ optional int32 instance_id = 3;
+
+ // Grouping information.
+ optional int32 group_instance_id = 4;
+ optional bool is_group_summary = 5;
+
+ // The section of the shade that the notification is in.
+ // See NotificationSectionsManager.PriorityBucket.
+ enum NotificationSection {
+ SECTION_UNKNOWN = 0;
+ SECTION_HEADS_UP = 1;
+ SECTION_PEOPLE = 2;
+ SECTION_ALERTING = 3;
+ SECTION_SILENT = 4;
+ }
+ optional NotificationSection section = 6;
+}
+
+message NotificationList {
+ repeated Notification notifications = 1; // An ordered sequence of notifications.
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
index cf9d8e1..24b9685 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
@@ -53,6 +53,12 @@
boolean isAodPowerSave();
/**
+ * Set reverse state.
+ * @param isReverse true if turn on reverse, false otherwise
+ */
+ default void setReverseState(boolean isReverse) {}
+
+ /**
* A listener that will be notified whenever a change in battery level or power save mode has
* occurred.
*/
@@ -63,6 +69,9 @@
default void onPowerSaveChanged(boolean isPowerSave) {
}
+
+ default void onReverseChanged(boolean isReverse, int level, String name) {
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
index d3e6f53..35954d8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java
@@ -59,13 +59,13 @@
private final EnhancedEstimates mEstimates;
private final BroadcastDispatcher mBroadcastDispatcher;
- private final ArrayList<BatteryController.BatteryStateChangeCallback>
+ protected final ArrayList<BatteryController.BatteryStateChangeCallback>
mChangeCallbacks = new ArrayList<>();
private final ArrayList<EstimateFetchCompletion> mFetchCallbacks = new ArrayList<>();
private final PowerManager mPowerManager;
private final Handler mMainHandler;
private final Handler mBgHandler;
- private final Context mContext;
+ protected final Context mContext;
private int mLevel;
private boolean mPluggedIn;
@@ -80,7 +80,7 @@
@VisibleForTesting
@Inject
- BatteryControllerImpl(Context context, EnhancedEstimates enhancedEstimates,
+ protected BatteryControllerImpl(Context context, EnhancedEstimates enhancedEstimates,
PowerManager powerManager, BroadcastDispatcher broadcastDispatcher,
@Main Handler mainHandler, @Background Handler bgHandler) {
mContext = context;
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..73ffe42 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/AudioRecordingDisclosureBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/AudioRecordingDisclosureBar.java
@@ -43,7 +43,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 +97,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;
@@ -116,10 +134,14 @@
}
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 +159,13 @@
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;
}
}
private void onDoneRecording(String packageName) {
- if (!mAudioRecordingApps.remove(packageName)) {
+ if (!mActiveAudioRecordingPackages.remove(packageName)) {
// Was not marked as an active recorder, do nothing
return;
}
@@ -151,7 +173,8 @@
// 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();
}
}
@@ -303,11 +326,12 @@
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();
}
}
@@ -326,6 +350,12 @@
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());
+ }
}
private void startPulsatingAnimation() {
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index 30db37c..f31f8eb 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -43,6 +43,7 @@
import org.json.JSONException;
import org.json.JSONObject;
+import java.util.Collection;
import java.util.Map;
import java.util.Set;
@@ -101,7 +102,7 @@
new ContentObserver(mBgHandler) {
@Override
- public void onChange(boolean selfChange, Iterable<Uri> uris, int flags,
+ public void onChange(boolean selfChange, Collection<Uri> uris, int flags,
int userId) {
if (DEBUG) Log.d(TAG, "Overlay changed for user: " + userId);
if (ActivityManager.getCurrentUser() == userId) {
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
index b2a5f5b..2452218 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerServiceImpl.java
@@ -262,7 +262,8 @@
}
@Override
- public void onChange(boolean selfChange, Iterable<Uri> uris, int flags, int userId) {
+ public void onChange(boolean selfChange, java.util.Collection<Uri> uris,
+ int flags, int userId) {
if (userId == ActivityManager.getCurrentUser()) {
for (Uri u : uris) {
reloadSetting(u);
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/controls/management/ControlsListingControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
index 85e937e..13a7708 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
@@ -30,7 +30,6 @@
import com.android.systemui.util.time.FakeSystemClock
import org.junit.After
import org.junit.Assert.assertEquals
-import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -38,6 +37,7 @@
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.`when`
+import org.mockito.Mockito.inOrder
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
@@ -98,74 +98,18 @@
}
@Test
+ fun testInitialStateListening() {
+ verify(mockSL).setListening(true)
+ verify(mockSL).reload()
+ }
+
+ @Test
fun testStartsOnUser() {
assertEquals(user, controller.currentUserId)
}
@Test
- fun testNoServices_notListening() {
- assertTrue(controller.getCurrentServices().isEmpty())
- }
-
- @Test
- fun testStartListening_onFirstCallback() {
- controller.addCallback(mockCallback)
- executor.runAllReady()
-
- verify(mockSL).setListening(true)
- }
-
- @Test
- fun testStartListening_onlyOnce() {
- controller.addCallback(mockCallback)
- controller.addCallback(mockCallbackOther)
-
- executor.runAllReady()
-
- verify(mockSL).setListening(true)
- }
-
- @Test
- fun testStopListening_callbackRemoved() {
- controller.addCallback(mockCallback)
-
- executor.runAllReady()
-
- controller.removeCallback(mockCallback)
-
- executor.runAllReady()
-
- verify(mockSL).setListening(false)
- }
-
- @Test
- fun testStopListening_notWhileRemainingCallbacks() {
- controller.addCallback(mockCallback)
- controller.addCallback(mockCallbackOther)
-
- executor.runAllReady()
-
- controller.removeCallback(mockCallback)
-
- executor.runAllReady()
-
- verify(mockSL, never()).setListening(false)
- }
-
- @Test
- fun testReloadOnFirstCallbackAdded() {
- controller.addCallback(mockCallback)
- executor.runAllReady()
-
- verify(mockSL).reload()
- }
-
- @Test
fun testCallbackCalledWhenAdded() {
- `when`(mockSL.reload()).then {
- serviceListingCallbackCaptor.value.onServicesReloaded(emptyList())
- }
-
controller.addCallback(mockCallback)
executor.runAllReady()
verify(mockCallback).onServicesUpdated(any())
@@ -209,5 +153,11 @@
controller.changeUser(UserHandle.of(otherUser))
executor.runAllReady()
assertEquals(otherUser, controller.currentUserId)
+
+ val inOrder = inOrder(mockSL)
+ inOrder.verify(mockSL).setListening(false)
+ inOrder.verify(mockSL).addCallback(any()) // We add a callback because we replaced the SL
+ inOrder.verify(mockSL).setListening(true)
+ inOrder.verify(mockSL).reload()
}
}
\ No newline at end of file
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/SbnBuilder.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SbnBuilder.java
index 62f406f..1b0ed11 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/SbnBuilder.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/SbnBuilder.java
@@ -22,6 +22,8 @@
import android.os.UserHandle;
import android.service.notification.StatusBarNotification;
+import com.android.internal.logging.InstanceId;
+
/**
* Convenience builder for {@link StatusBarNotification} since its constructor is terrifying.
*
@@ -40,6 +42,7 @@
private UserHandle mUser = UserHandle.of(0);
private String mOverrideGroupKey;
private long mPostTime;
+ private InstanceId mInstanceId;
public SbnBuilder() {
}
@@ -55,6 +58,7 @@
mUser = source.getUser();
mOverrideGroupKey = source.getOverrideGroupKey();
mPostTime = source.getPostTime();
+ mInstanceId = source.getInstanceId();
}
public StatusBarNotification build() {
@@ -71,7 +75,7 @@
notification.setBubbleMetadata(mBubbleMetadata);
}
- return new StatusBarNotification(
+ StatusBarNotification result = new StatusBarNotification(
mPkg,
mOpPkg,
mId,
@@ -82,6 +86,10 @@
mUser,
mOverrideGroupKey,
mPostTime);
+ if (mInstanceId != null) {
+ result.setInstanceId(mInstanceId);
+ }
+ return result;
}
public SbnBuilder setPkg(String pkg) {
@@ -175,4 +183,9 @@
mBubbleMetadata = data;
return this;
}
+
+ public SbnBuilder setInstanceId(InstanceId instanceId) {
+ mInstanceId = instanceId;
+ return this;
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
index 92a9080..261dc82 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryBuilder.java
@@ -26,6 +26,7 @@
import android.service.notification.SnoozeCriterion;
import android.service.notification.StatusBarNotification;
+import com.android.internal.logging.InstanceId;
import com.android.systemui.statusbar.RankingBuilder;
import com.android.systemui.statusbar.SbnBuilder;
@@ -141,6 +142,11 @@
return this;
}
+ public NotificationEntryBuilder setInstanceId(InstanceId instanceId) {
+ mSbnBuilder.setInstanceId(instanceId);
+ return this;
+ }
+
/* Delegated to Notification.Builder (via SbnBuilder) */
public NotificationEntryBuilder setContentTitle(Context context, String contentTitle) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
index d826ce1..d39b2c2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
@@ -16,7 +16,10 @@
package com.android.systemui.statusbar.notification.logging;
+import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING;
+
import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
@@ -34,6 +37,7 @@
import androidx.test.filters.SmallTest;
+import com.android.internal.logging.InstanceId;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.SysuiTestCase;
@@ -43,6 +47,7 @@
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import com.android.systemui.statusbar.notification.logging.nano.Notifications;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.util.concurrency.FakeExecutor;
@@ -81,9 +86,10 @@
private NotificationEntry mEntry;
private TestableNotificationLogger mLogger;
- private NotificationEntryListener mNotificationEntryListener;
private ConcurrentLinkedQueue<AssertionError> mErrorQueue = new ConcurrentLinkedQueue<>();
private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
+ private NotificationPanelLoggerFake mNotificationPanelLoggerFake =
+ new NotificationPanelLoggerFake();
@Before
public void setUp() {
@@ -97,6 +103,7 @@
.setUid(TEST_UID)
.setNotification(new Notification())
.setUser(UserHandle.CURRENT)
+ .setInstanceId(InstanceId.fakeInstanceId(1))
.build();
mEntry.setRow(mRow);
@@ -105,7 +112,6 @@
mExpansionStateLogger);
mLogger.setUpWithContainer(mListContainer);
verify(mEntryManager).addNotificationEntryListener(mEntryListenerCaptor.capture());
- mNotificationEntryListener = mEntryListenerCaptor.getValue();
}
@Test
@@ -164,6 +170,41 @@
verify(mBarService, times(1)).onNotificationVisibilityChanged(any(), any());
}
+ @Test
+ public void testLogPanelShownOnLoggingStart() {
+ when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(mEntry));
+ mLogger.startNotificationLogging();
+ assertEquals(1, mNotificationPanelLoggerFake.getCalls().size());
+ assertEquals(false, mNotificationPanelLoggerFake.get(0).isLockscreen);
+ assertEquals(1, mNotificationPanelLoggerFake.get(0).list.notifications.length);
+ Notifications.Notification n = mNotificationPanelLoggerFake.get(0).list.notifications[0];
+ assertEquals(TEST_PACKAGE_NAME, n.packageName);
+ assertEquals(TEST_UID, n.uid);
+ assertEquals(1, n.instanceId);
+ assertEquals(false, n.isGroupSummary);
+ assertEquals(1 + BUCKET_ALERTING, n.section);
+ }
+
+ @Test
+ public void testLogPanelShownHandlesNullInstanceIds() {
+ // Construct a NotificationEntry like mEntry, but with a null instance id.
+ NotificationEntry entry = new NotificationEntryBuilder()
+ .setPkg(TEST_PACKAGE_NAME)
+ .setOpPkg(TEST_PACKAGE_NAME)
+ .setUid(TEST_UID)
+ .setNotification(new Notification())
+ .setUser(UserHandle.CURRENT)
+ .build();
+ entry.setRow(mRow);
+
+ when(mEntryManager.getVisibleNotifications()).thenReturn(Lists.newArrayList(entry));
+ mLogger.startNotificationLogging();
+ assertEquals(1, mNotificationPanelLoggerFake.getCalls().size());
+ assertEquals(1, mNotificationPanelLoggerFake.get(0).list.notifications.length);
+ Notifications.Notification n = mNotificationPanelLoggerFake.get(0).list.notifications[0];
+ assertEquals(0, n.instanceId);
+ }
+
private class TestableNotificationLogger extends NotificationLogger {
TestableNotificationLogger(NotificationListener notificationListener,
@@ -173,7 +214,7 @@
IStatusBarService barService,
ExpansionStateLogger expansionStateLogger) {
super(notificationListener, uiBgExecutor, entryManager, statusBarStateController,
- expansionStateLogger);
+ expansionStateLogger, mNotificationPanelLoggerFake);
mBarService = barService;
// Make this on the current thread so we can wait for it during tests.
mHandler = Handler.createAsync(Looper.myLooper());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerFake.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerFake.java
new file mode 100644
index 0000000..7e97629
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationPanelLoggerFake.java
@@ -0,0 +1,51 @@
+/*
+ * 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.logging;
+
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.logging.nano.Notifications;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class NotificationPanelLoggerFake implements NotificationPanelLogger {
+ private List<CallRecord> mCalls = new ArrayList<>();
+
+ List<CallRecord> getCalls() {
+ return mCalls;
+ }
+
+ CallRecord get(int index) {
+ return mCalls.get(index);
+ }
+
+ @Override
+ public void logPanelShown(boolean isLockscreen,
+ List<NotificationEntry> visibleNotifications) {
+ mCalls.add(new CallRecord(isLockscreen,
+ NotificationPanelLogger.toNotificationProto(visibleNotifications)));
+ }
+
+ public static class CallRecord {
+ public boolean isLockscreen;
+ public Notifications.NotificationList list;
+ CallRecord(boolean isLockscreen, Notifications.NotificationList list) {
+ this.isLockscreen = isLockscreen;
+ this.list = list;
+ }
+ }
+}
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 0d7734e..e407927 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
@@ -122,6 +122,7 @@
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.init.NotificationsController;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
+import com.android.systemui.statusbar.notification.logging.NotificationPanelLoggerFake;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
@@ -273,7 +274,7 @@
mMetricsLogger = new FakeMetricsLogger();
NotificationLogger notificationLogger = new NotificationLogger(mNotificationListener,
mUiBgExecutor, mock(NotificationEntryManager.class), mStatusBarStateController,
- mExpansionStateLogger);
+ mExpansionStateLogger, new NotificationPanelLoggerFake());
notificationLogger.setVisibilityReporter(mock(Runnable.class));
when(mCommandQueue.asBinder()).thenReturn(new Binder());
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/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 5619478..538082d 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -2681,7 +2681,7 @@
response, filterText, response.getInlineActions(), mCurrentViewId,
this, () -> {
synchronized (mLock) {
- requestHideFillUi(mCurrentViewId);
+ mInlineSuggestionSession.hideInlineSuggestionsUi(mCurrentViewId);
}
}, remoteRenderService);
if (inlineSuggestionsResponse == null) {
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 82e5003..ee59d89 100644
--- a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
+++ b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java
@@ -167,8 +167,7 @@
inlineSuggestions.add(inlineSuggestion);
}
- // We should only add inline actions if there is at least one suggestion.
- if (!inlineSuggestions.isEmpty() && inlineActions != null) {
+ if (inlineActions != null) {
for (InlineAction inlineAction : inlineActions) {
final InlineSuggestion inlineActionSuggestion = createInlineAction(isAugmented,
mergedInlinePresentation(request, 0, inlineAction.getInlinePresentation()),
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 4cc6590..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/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
index b464422..2cfe404 100644
--- a/services/core/java/com/android/server/PackageWatchdog.java
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -161,6 +161,9 @@
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
@@ -624,17 +627,22 @@
* @see #syncRequestsAsync
*/
private void syncRequests() {
- Set<String> packages = null;
+ boolean syncRequired = false;
synchronized (mLock) {
if (mIsPackagesReady) {
- packages = getPackagesPendingHealthChecksLocked();
+ Set<String> packages = getPackagesPendingHealthChecksLocked();
+ if (!packages.equals(mRequestedHealthCheckPackages)) {
+ syncRequired = true;
+ mRequestedHealthCheckPackages = packages;
+ }
} // else, we will sync requests when packages become ready
}
// Call outside lock to avoid holding lock when calling into the controller.
- if (packages != null) {
- Slog.i(TAG, "Syncing health check requests for packages: " + packages);
- mHealthCheckController.syncRequests(packages);
+ if (syncRequired) {
+ Slog.i(TAG, "Syncing health check requests for packages: "
+ + mRequestedHealthCheckPackages);
+ mHealthCheckController.syncRequests(mRequestedHealthCheckPackages);
}
}
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/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 91348aa..b584ea5 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -1708,11 +1708,6 @@
// TOP process passes all capabilities to the service.
capability |= PROCESS_CAPABILITY_ALL;
}
- } else if (clientProcState
- <= PROCESS_STATE_FOREGROUND_SERVICE) {
- if (cr.notHasFlag(Context.BIND_INCLUDE_CAPABILITIES)) {
- clientProcState = PROCESS_STATE_FOREGROUND_SERVICE;
- }
}
} else if ((cr.flags & Context.BIND_IMPORTANT_BACKGROUND) == 0) {
if (clientProcState <
@@ -2036,7 +2031,7 @@
case PROCESS_STATE_TOP:
return PROCESS_CAPABILITY_ALL;
case PROCESS_STATE_BOUND_TOP:
- return PROCESS_CAPABILITY_ALL_IMPLICIT;
+ return PROCESS_CAPABILITY_NONE;
case PROCESS_STATE_FOREGROUND_SERVICE:
if (app.hasForegroundServices()) {
// Capability from FGS are conditional depending on foreground service type in
@@ -2044,10 +2039,12 @@
return PROCESS_CAPABILITY_NONE;
} else {
// process has no FGS, the PROCESS_STATE_FOREGROUND_SERVICE is from client.
+ // the implicit capability could be removed in the future, client should use
+ // BIND_INCLUDE_CAPABILITY flag.
return PROCESS_CAPABILITY_ALL_IMPLICIT;
}
case PROCESS_STATE_BOUND_FOREGROUND_SERVICE:
- return PROCESS_CAPABILITY_ALL_IMPLICIT;
+ return PROCESS_CAPABILITY_NONE;
default:
return PROCESS_CAPABILITY_NONE;
}
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/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index b90681d..79a4da2 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -388,7 +388,7 @@
for (int i = ArrayUtils.size(intents) - 1; i >= 0; i--) {
IntentFilter intentFilter = intents.get(i);
if (intentFilter.match(intent.getAction(), intent.getType(), intent.getScheme(),
- intent.getData(), intent.getCategories(), "AppsFilter") > 0) {
+ intent.getData(), intent.getCategories(), "AppsFilter", true) > 0) {
return true;
}
}
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/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/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 d3ff912..21d300a 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -288,6 +288,7 @@
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
@@ -680,7 +681,7 @@
}
@Override
- public void onChange(boolean selfChange, Iterable<Uri> uris, int flags,
+ public void onChange(boolean selfChange, Collection<Uri> uris, int flags,
@UserIdInt int userId) {
for (Uri uri : uris) {
if (mFontScaleUri.equals(uri)) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 3352bd5..36fdb2d 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -4934,6 +4934,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..a094c81 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;
@@ -1469,8 +1470,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();
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 b38c18b..4093fe5 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -128,7 +128,7 @@
void removeTask(Task t) {
try {
- mOrganizer.taskVanished(t.getRemoteToken());
+ mOrganizer.taskVanished(t.getTaskInfo());
} catch (Exception e) {
Slog.e(TAG, "Exception sending taskVanished callback" + e);
}
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/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/MmsQueryHelper.java b/services/people/java/com/android/server/people/data/MmsQueryHelper.java
index 1e485c0..39dba9c 100644
--- a/services/people/java/com/android/server/people/data/MmsQueryHelper.java
+++ b/services/people/java/com/android/server/people/data/MmsQueryHelper.java
@@ -21,6 +21,7 @@
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
+import android.os.Binder;
import android.provider.Telephony.BaseMmsColumns;
import android.provider.Telephony.Mms;
import android.telephony.PhoneNumberUtils;
@@ -71,31 +72,36 @@
// NOTE: The field Mms.DATE is stored in seconds, not milliseconds.
String[] selectionArgs = new String[] { Long.toString(sinceTime / MILLIS_PER_SECONDS) };
boolean hasResults = false;
- try (Cursor cursor = mContext.getContentResolver().query(
- Mms.CONTENT_URI, projection, selection, selectionArgs, null)) {
- if (cursor == null) {
- Slog.w(TAG, "Cursor is null when querying MMS table.");
- return false;
- }
- while (cursor.moveToNext()) {
- // ID
- int msgIdIndex = cursor.getColumnIndex(Mms._ID);
- String msgId = cursor.getString(msgIdIndex);
+ Binder.allowBlockingForCurrentThread();
+ try {
+ try (Cursor cursor = mContext.getContentResolver().query(
+ Mms.CONTENT_URI, projection, selection, selectionArgs, null)) {
+ if (cursor == null) {
+ Slog.w(TAG, "Cursor is null when querying MMS table.");
+ return false;
+ }
+ while (cursor.moveToNext()) {
+ // ID
+ int msgIdIndex = cursor.getColumnIndex(Mms._ID);
+ String msgId = cursor.getString(msgIdIndex);
- // Date
- int dateIndex = cursor.getColumnIndex(Mms.DATE);
- long date = cursor.getLong(dateIndex) * MILLIS_PER_SECONDS;
+ // Date
+ int dateIndex = cursor.getColumnIndex(Mms.DATE);
+ long date = cursor.getLong(dateIndex) * MILLIS_PER_SECONDS;
- // Message box
- int msgBoxIndex = cursor.getColumnIndex(Mms.MESSAGE_BOX);
- int msgBox = cursor.getInt(msgBoxIndex);
+ // Message box
+ int msgBoxIndex = cursor.getColumnIndex(Mms.MESSAGE_BOX);
+ int msgBox = cursor.getInt(msgBoxIndex);
- mLastMessageTimestamp = Math.max(mLastMessageTimestamp, date);
- String address = getMmsAddress(msgId, msgBox);
- if (address != null && addEvent(address, date, msgBox)) {
- hasResults = true;
+ mLastMessageTimestamp = Math.max(mLastMessageTimestamp, date);
+ String address = getMmsAddress(msgId, msgBox);
+ if (address != null && addEvent(address, date, msgBox)) {
+ hasResults = true;
+ }
}
}
+ } finally {
+ Binder.defaultBlockingForCurrentThread();
}
return hasResults;
}
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/SmsQueryHelper.java b/services/people/java/com/android/server/people/data/SmsQueryHelper.java
index c38c846..a5eb3a5 100644
--- a/services/people/java/com/android/server/people/data/SmsQueryHelper.java
+++ b/services/people/java/com/android/server/people/data/SmsQueryHelper.java
@@ -19,6 +19,7 @@
import android.annotation.WorkerThread;
import android.content.Context;
import android.database.Cursor;
+import android.os.Binder;
import android.provider.Telephony.Sms;
import android.provider.Telephony.TextBasedSmsColumns;
import android.telephony.PhoneNumberUtils;
@@ -65,35 +66,40 @@
String selection = Sms.DATE + " > ?";
String[] selectionArgs = new String[] { Long.toString(sinceTime) };
boolean hasResults = false;
- try (Cursor cursor = mContext.getContentResolver().query(
- Sms.CONTENT_URI, projection, selection, selectionArgs, null)) {
- if (cursor == null) {
- Slog.w(TAG, "Cursor is null when querying SMS table.");
- return false;
- }
- while (cursor.moveToNext()) {
- // ID
- int msgIdIndex = cursor.getColumnIndex(Sms._ID);
- String msgId = cursor.getString(msgIdIndex);
+ Binder.allowBlockingForCurrentThread();
+ try {
+ try (Cursor cursor = mContext.getContentResolver().query(
+ Sms.CONTENT_URI, projection, selection, selectionArgs, null)) {
+ if (cursor == null) {
+ Slog.w(TAG, "Cursor is null when querying SMS table.");
+ return false;
+ }
+ while (cursor.moveToNext()) {
+ // ID
+ int msgIdIndex = cursor.getColumnIndex(Sms._ID);
+ String msgId = cursor.getString(msgIdIndex);
- // Date
- int dateIndex = cursor.getColumnIndex(Sms.DATE);
- long date = cursor.getLong(dateIndex);
+ // Date
+ int dateIndex = cursor.getColumnIndex(Sms.DATE);
+ long date = cursor.getLong(dateIndex);
- // Type
- int typeIndex = cursor.getColumnIndex(Sms.TYPE);
- int type = cursor.getInt(typeIndex);
+ // Type
+ int typeIndex = cursor.getColumnIndex(Sms.TYPE);
+ int type = cursor.getInt(typeIndex);
- // Address
- int addressIndex = cursor.getColumnIndex(Sms.ADDRESS);
- String address = PhoneNumberUtils.formatNumberToE164(
- cursor.getString(addressIndex), mCurrentCountryIso);
+ // Address
+ int addressIndex = cursor.getColumnIndex(Sms.ADDRESS);
+ String address = PhoneNumberUtils.formatNumberToE164(
+ cursor.getString(addressIndex), mCurrentCountryIso);
- mLastMessageTimestamp = Math.max(mLastMessageTimestamp, date);
- if (address != null && addEvent(address, date, type)) {
- hasResults = true;
+ mLastMessageTimestamp = Math.max(mLastMessageTimestamp, date);
+ if (address != null && addEvent(address, date, type)) {
+ hasResults = true;
+ }
}
}
+ } finally {
+ Binder.defaultBlockingForCurrentThread();
}
return hasResults;
}
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/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 049c8e1..1c267a0 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;
@@ -892,7 +893,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();
@@ -1019,7 +1020,7 @@
public void taskAppeared(ActivityManager.RunningTaskInfo info) {
}
@Override
- public void taskVanished(IWindowContainer wc) {
+ public void taskVanished(ActivityManager.RunningTaskInfo info) {
}
@Override
public void transactionReady(int id, SurfaceControl.Transaction t) {
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 48a583c..53a3682 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
@@ -129,7 +129,7 @@
final Task task = createTaskInStack(stack, 0 /* userId */);
final ITaskOrganizer organizer = registerMockOrganizer(WINDOWING_MODE_MULTI_WINDOW);
final ITaskOrganizer organizer2 = registerMockOrganizer(WINDOWING_MODE_PINNED);
-
+
stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
verify(organizer).taskAppeared(any());
stack.setWindowingMode(WINDOWING_MODE_PINNED);
@@ -345,7 +345,7 @@
public void taskAppeared(RunningTaskInfo taskInfo) { }
@Override
- public void taskVanished(IWindowContainer container) { }
+ public void taskVanished(RunningTaskInfo container) { }
@Override
public void transactionReady(int id, SurfaceControl.Transaction t) { }
@@ -399,7 +399,7 @@
public void taskAppeared(RunningTaskInfo taskInfo) { }
@Override
- public void taskVanished(IWindowContainer container) { }
+ public void taskVanished(RunningTaskInfo container) { }
@Override
public void transactionReady(int id, SurfaceControl.Transaction t) { }
@@ -539,7 +539,7 @@
mInfo = info;
}
@Override
- public void taskVanished(IWindowContainer wc) {
+ public void taskVanished(RunningTaskInfo info) {
}
@Override
public void transactionReady(int id, SurfaceControl.Transaction t) {
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 2d31d95..c20748b 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1568,6 +1568,7 @@
/**
* The string is used to compare with operator name.
* If it matches the pattern then show specific data icon.
+ * @hide
*/
public static final String KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING =
"show_carrier_data_icon_pattern_string";
@@ -2978,9 +2979,9 @@
* UE wants to display 5G_Plus icon for scenario#1, and 5G icon for scenario#2; otherwise not
* define.
* The configuration is: "connected_mmwave:5G_Plus,connected:5G"
+ * @hide
*/
- public static final String KEY_5G_ICON_CONFIGURATION_STRING =
- "5g_icon_configuration_string";
+ public static final String KEY_5G_ICON_CONFIGURATION_STRING = "5g_icon_configuration_string";
/**
* Timeout in seconds for displaying 5G icon, default value is 0 which means the timer is
@@ -2992,12 +2993,14 @@
*
* If 5G is reacquired during this timer, the timer is canceled and restarted when 5G is next
* lost. Allows us to momentarily lose 5G without blinking the icon.
+ * @hide
*/
public static final String KEY_5G_ICON_DISPLAY_GRACE_PERIOD_SEC_INT =
"5g_icon_display_grace_period_sec_int";
/**
* Controls time in milliseconds until DcTracker reevaluates 5G connection state.
+ * @hide
*/
public static final String KEY_5G_WATCHDOG_TIME_MS_LONG = "5g_watchdog_time_long";
@@ -3527,6 +3530,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.
*/
@@ -4083,6 +4095,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.
diff --git a/telephony/java/android/telephony/CdmaEriInformation.java b/telephony/java/android/telephony/CdmaEriInformation.java
index 1cd9d30..fd0b905 100644
--- a/telephony/java/android/telephony/CdmaEriInformation.java
+++ b/telephony/java/android/telephony/CdmaEriInformation.java
@@ -40,7 +40,6 @@
*
* @hide
*/
-@SystemApi
public final class CdmaEriInformation implements Parcelable {
/** @hide */
@Retention(RetentionPolicy.SOURCE)
diff --git a/telephony/java/android/telephony/DataSpecificRegistrationInfo.java b/telephony/java/android/telephony/DataSpecificRegistrationInfo.java
index 270eafe..c667165 100644
--- a/telephony/java/android/telephony/DataSpecificRegistrationInfo.java
+++ b/telephony/java/android/telephony/DataSpecificRegistrationInfo.java
@@ -208,7 +208,6 @@
* @return {@code true} if using carrier aggregation.
* @hide
*/
- @SystemApi
public boolean isUsingCarrierAggregation() {
return mIsUsingCarrierAggregation;
}
diff --git a/telephony/java/android/telephony/NetworkRegistrationInfo.java b/telephony/java/android/telephony/NetworkRegistrationInfo.java
index c74e17f..1a79bf7 100644
--- a/telephony/java/android/telephony/NetworkRegistrationInfo.java
+++ b/telephony/java/android/telephony/NetworkRegistrationInfo.java
@@ -367,6 +367,7 @@
* Get the 5G NR connection state.
*
* @return the 5G NR connection state.
+ * @hide
*/
public @NRState int getNrState() {
return mNrState;
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 9b1baef..45cba51 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -689,8 +689,9 @@
* @return true if registration indicates roaming, false otherwise
* @hide
*/
- @SystemApi
public boolean getDataRoamingFromRegistration() {
+ // TODO: all callers should refactor to get roaming state directly from modem
+ // this should not be exposed as a public API
return mIsDataRoamingFromRegistration;
}
@@ -1422,7 +1423,6 @@
* @return the frequency range of 5G NR.
* @hide
*/
- @SystemApi
public @FrequencyRange int getNrFrequencyRange() {
return mNrFrequencyRange;
}
@@ -2026,6 +2026,7 @@
* The long format can be up to 16 characters long.
*
* @return long raw name of operator, null if unregistered or unknown
+ * @hide
*/
@Nullable
public String getOperatorAlphaLongRaw() {
@@ -2045,6 +2046,7 @@
* The short format can be up to 8 characters long.
*
* @return short raw name of operator, null if unregistered or unknown
+ * @hide
*/
@Nullable
public String getOperatorAlphaShortRaw() {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 3c40e35..631eaac 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -5606,7 +5606,6 @@
* @hide
*/
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
- @SystemApi
@NonNull
public CdmaEriInformation getCdmaEriInformation() {
return new CdmaEriInformation(
@@ -8726,7 +8725,6 @@
*
* @hide
*/
- @SystemApi
@Nullable
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public PinResult supplyPinReportPinResult(@NonNull String pin) {
@@ -8751,7 +8749,6 @@
*
* @hide
*/
- @SystemApi
@Nullable
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public PinResult supplyPukReportPinResult(@NonNull String puk, @NonNull String pin) {
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/ImsCallSessionListener.java b/telephony/java/android/telephony/ims/ImsCallSessionListener.java
index 025721c..81af99f 100644
--- a/telephony/java/android/telephony/ims/ImsCallSessionListener.java
+++ b/telephony/java/android/telephony/ims/ImsCallSessionListener.java
@@ -58,7 +58,7 @@
try {
mListener.callSessionProgressing(profile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -71,7 +71,7 @@
try {
mListener.callSessionInitiated(profile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -85,7 +85,7 @@
try {
mListener.callSessionInitiatedFailed(reasonInfo);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -98,7 +98,7 @@
try {
mListener.callSessionTerminated(reasonInfo);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -115,7 +115,7 @@
try {
mListener.callSessionHeld(profile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -128,7 +128,7 @@
try {
mListener.callSessionHoldFailed(reasonInfo);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -141,7 +141,7 @@
try {
mListener.callSessionHoldReceived(profile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -155,7 +155,7 @@
try {
mListener.callSessionResumed(profile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -169,7 +169,7 @@
try {
mListener.callSessionResumeFailed(reasonInfo);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -182,7 +182,7 @@
try {
mListener.callSessionResumeReceived(profile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -201,7 +201,7 @@
mListener.callSessionMergeStarted(newSession != null ?
newSession.getServiceImpl() : null, profile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -216,7 +216,7 @@
try {
mListener.callSessionMergeStarted(newSession, profile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -232,7 +232,7 @@
mListener.callSessionMergeComplete(newSession != null ?
newSession.getServiceImpl() : null);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -247,7 +247,7 @@
try {
mListener.callSessionMergeComplete(newSession);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -260,7 +260,7 @@
try {
mListener.callSessionMergeFailed(reasonInfo);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -273,7 +273,7 @@
try {
mListener.callSessionUpdated(profile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -286,7 +286,7 @@
try {
mListener.callSessionUpdateFailed(reasonInfo);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -299,7 +299,7 @@
try {
mListener.callSessionUpdateReceived(profile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -319,7 +319,7 @@
mListener.callSessionConferenceExtended(
newSession != null ? newSession.getServiceImpl() : null, profile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -333,7 +333,7 @@
try {
mListener.callSessionConferenceExtended(newSession, profile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -347,7 +347,7 @@
try {
mListener.callSessionConferenceExtendFailed(reasonInfo);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -364,7 +364,7 @@
mListener.callSessionConferenceExtendReceived(newSession != null
? newSession.getServiceImpl() : null, profile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -379,7 +379,7 @@
try {
mListener.callSessionConferenceExtendReceived(newSession, profile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -391,7 +391,7 @@
try {
mListener.callSessionInviteParticipantsRequestDelivered();
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -407,7 +407,7 @@
try {
mListener.callSessionInviteParticipantsRequestFailed(reasonInfo);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -419,7 +419,7 @@
try {
mListener.callSessionRemoveParticipantsRequestDelivered();
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -435,7 +435,7 @@
try {
mListener.callSessionInviteParticipantsRequestFailed(reasonInfo);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -448,7 +448,7 @@
try {
mListener.callSessionConferenceStateUpdated(state);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -465,7 +465,7 @@
try {
mListener.callSessionUssdMessageReceived(mode, ussdMessage);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -501,7 +501,7 @@
try {
mListener.callSessionMayHandover(srcNetworkType, targetNetworkType);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -537,7 +537,7 @@
try {
mListener.callSessionHandover(srcNetworkType, targetNetworkType, reasonInfo);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -570,7 +570,7 @@
try {
mListener.callSessionHandoverFailed(srcNetworkType, targetNetworkType, reasonInfo);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -587,7 +587,7 @@
try {
mListener.callSessionTtyModeReceived(mode);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -600,7 +600,7 @@
try {
mListener.callSessionMultipartyStateChanged(isMultiParty);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -614,7 +614,7 @@
try {
mListener.callSessionSuppServiceReceived(suppSrvNotification);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -628,7 +628,7 @@
try {
mListener.callSessionRttModifyRequestReceived(callProfile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -641,7 +641,7 @@
try {
mListener.callSessionRttModifyResponseReceived(status);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -654,7 +654,7 @@
try {
mListener.callSessionRttMessageReceived(rttMessage);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -667,7 +667,7 @@
try {
mListener.callSessionRttAudioIndicatorChanged(profile);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
@@ -680,7 +680,7 @@
try {
mListener.callQualityChanged(callQuality);
} catch (RemoteException e) {
- throw new RuntimeException(e);
+ e.rethrowFromSystemServer();
}
}
}
diff --git a/test-mock/src/android/test/mock/MockContentResolver.java b/test-mock/src/android/test/mock/MockContentResolver.java
index 8283019..8f4bccc 100644
--- a/test-mock/src/android/test/mock/MockContentResolver.java
+++ b/test-mock/src/android/test/mock/MockContentResolver.java
@@ -25,6 +25,7 @@
import android.database.ContentObserver;
import android.net.Uri;
+import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
@@ -172,7 +173,7 @@
* from observers elsewhere in the system.
*/
@Override
- public void notifyChange(@NonNull Iterable<Uri> uris, @Nullable ContentObserver observer,
+ public void notifyChange(@NonNull Collection<Uri> uris, @Nullable ContentObserver observer,
@NotifyFlags int flags) {
}
}
diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
index 8cc8cf4..819fc02 100644
--- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
+++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java
@@ -1063,6 +1063,52 @@
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()
@@ -1219,6 +1265,7 @@
private Consumer<String> mPassedConsumer;
private Consumer<List<PackageConfig>> mSupportedConsumer;
private Runnable mNotifySyncRunnable;
+ private List<Set> mSyncRequests = new ArrayList<>();
@Override
public void setEnabled(boolean enabled) {
@@ -1238,6 +1285,7 @@
@Override
public void syncRequests(Set<String> packages) {
+ mSyncRequests.add(packages);
mRequestedPackages.clear();
if (mIsEnabled) {
packages.retainAll(mSupportedPackages);
@@ -1268,6 +1316,10 @@
return Collections.emptyList();
}
}
+
+ public List<Set> getSyncRequests() {
+ return mSyncRequests;
+ }
}
private static class TestClock implements PackageWatchdog.SystemClock {
diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java
index 8f7bebb..6eb4587 100644
--- a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java
+++ b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java
@@ -139,7 +139,7 @@
mTaskView2.reparentTask(ti.token);
}
}
- public void taskVanished(IWindowContainer wc) {
+ public void taskVanished(ActivityManager.RunningTaskInfo ti) {
}
public void transactionReady(int id, SurfaceControl.Transaction t) {
mergedTransaction.merge(t);
diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java
index bd17751..ade5c2e 100644
--- a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java
+++ b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java
@@ -49,7 +49,7 @@
} catch (Exception e) {
}
}
- public void taskVanished(IWindowContainer wc) {
+ public void taskVanished(ActivityManager.RunningTaskInfo ti) {
}
public void transactionReady(int id, SurfaceControl.Transaction t) {
}
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/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/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/IScoreChangeCallback.aidl b/wifi/java/android/net/wifi/IScoreUpdateObserver.aidl
similarity index 82%
rename from wifi/java/android/net/wifi/IScoreChangeCallback.aidl
rename to wifi/java/android/net/wifi/IScoreUpdateObserver.aidl
index d691f41..775fed7 100644
--- a/wifi/java/android/net/wifi/IScoreChangeCallback.aidl
+++ b/wifi/java/android/net/wifi/IScoreUpdateObserver.aidl
@@ -21,9 +21,9 @@
*
* @hide
*/
-oneway interface IScoreChangeCallback
+oneway interface IScoreUpdateObserver
{
- void onScoreChange(int sessionId, int score);
+ void notifyScoreUpdate(int sessionId, int score);
- void onTriggerUpdateOfWifiUsabilityStats(int sessionId);
+ void triggerUpdateOfWifiUsabilityStats(int sessionId);
}
diff --git a/wifi/java/android/net/wifi/IWifiConnectedNetworkScorer.aidl b/wifi/java/android/net/wifi/IWifiConnectedNetworkScorer.aidl
index d9a3b01..f96d037 100644
--- a/wifi/java/android/net/wifi/IWifiConnectedNetworkScorer.aidl
+++ b/wifi/java/android/net/wifi/IWifiConnectedNetworkScorer.aidl
@@ -16,7 +16,7 @@
package android.net.wifi;
-import android.net.wifi.IScoreChangeCallback;
+import android.net.wifi.IScoreUpdateObserver;
/**
* Interface for Wi-Fi connected network scorer.
@@ -25,9 +25,9 @@
*/
oneway interface IWifiConnectedNetworkScorer
{
- void start(int sessionId);
+ void onStart(int sessionId);
- void stop(int sessionId);
+ void onStop(int sessionId);
- void setScoreChangeCallback(IScoreChangeCallback cbImpl);
+ void onSetScoreUpdateObserver(IScoreUpdateObserver observerImpl);
}
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index ceb2907..e0b433d 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -498,7 +498,9 @@
allowedProtocols.set(WifiConfiguration.Protocol.RSN);
allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SAE);
allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
+ allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.GCMP_256);
allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
+ allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
requirePmf = true;
break;
case SECURITY_TYPE_EAP_SUITE_B:
@@ -517,7 +519,9 @@
allowedProtocols.set(WifiConfiguration.Protocol.RSN);
allowedKeyManagement.set(WifiConfiguration.KeyMgmt.OWE);
allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
+ allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.GCMP_256);
allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
+ allowedGroupCiphers.set(WifiConfiguration.GroupCipher.GCMP_256);
requirePmf = true;
break;
case SECURITY_TYPE_WAPI_PSK:
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index ff62296..96beacd 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -2735,27 +2735,30 @@
}
/**
- * 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,
+ networkSuggestionsToMatch, scanResults,
mContext.getOpPackageName(), mContext.getFeatureId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -2826,7 +2829,7 @@
*/
@Nullable
@SystemApi
- @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL)
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
public String getCountryCode() {
try {
return mService.getCountryCode();
@@ -3372,7 +3375,7 @@
*/
@NonNull
@SystemApi
- @RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
public SoftApConfiguration getSoftApConfiguration() {
try {
return mService.getSoftApConfiguration();
@@ -4989,7 +4992,7 @@
* @hide
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL)
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
public void factoryReset() {
try {
mService.factoryReset(mContext.getOpPackageName());
@@ -5986,22 +5989,22 @@
}
/**
- * Callback interface for framework to receive network status changes and trigger of updating
+ * Callback interface for framework to receive network status updates and trigger of updating
* {@link WifiUsabilityStatsEntry}.
*
* @hide
*/
@SystemApi
- public interface ScoreChangeCallback {
+ public interface ScoreUpdateObserver {
/**
* Called by applications to indicate network status.
*
* @param sessionId The ID to indicate current Wi-Fi network connection obtained from
- * {@link WifiConnectedNetworkScorer#start(int)}.
+ * {@link WifiConnectedNetworkScorer#onStart(int)}.
* @param score The score representing link quality of current Wi-Fi network connection.
* Populated by connected network scorer in applications..
*/
- void onScoreChange(int sessionId, int score);
+ void notifyScoreUpdate(int sessionId, int score);
/**
* Called by applications to trigger an update of {@link WifiUsabilityStatsEntry}.
@@ -6009,36 +6012,36 @@
* {@link addOnWifiUsabilityStatsListener(Executor, OnWifiUsabilityStatsListener)}.
*
* @param sessionId The ID to indicate current Wi-Fi network connection obtained from
- * {@link WifiConnectedNetworkScorer#start(int)}.
+ * {@link WifiConnectedNetworkScorer#onStart(int)}.
*/
- void onTriggerUpdateOfWifiUsabilityStats(int sessionId);
+ void triggerUpdateOfWifiUsabilityStats(int sessionId);
}
/**
- * Callback proxy for {@link ScoreChangeCallback} objects.
+ * Callback proxy for {@link ScoreUpdateObserver} objects.
*
* @hide
*/
- private class ScoreChangeCallbackProxy implements ScoreChangeCallback {
- private final IScoreChangeCallback mScoreChangeCallback;
+ private class ScoreUpdateObserverProxy implements ScoreUpdateObserver {
+ private final IScoreUpdateObserver mScoreUpdateObserver;
- private ScoreChangeCallbackProxy(IScoreChangeCallback callback) {
- mScoreChangeCallback = callback;
+ private ScoreUpdateObserverProxy(IScoreUpdateObserver observer) {
+ mScoreUpdateObserver = observer;
}
@Override
- public void onScoreChange(int sessionId, int score) {
+ public void notifyScoreUpdate(int sessionId, int score) {
try {
- mScoreChangeCallback.onScoreChange(sessionId, score);
+ mScoreUpdateObserver.notifyScoreUpdate(sessionId, score);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
@Override
- public void onTriggerUpdateOfWifiUsabilityStats(int sessionId) {
+ public void triggerUpdateOfWifiUsabilityStats(int sessionId) {
try {
- mScoreChangeCallback.onTriggerUpdateOfWifiUsabilityStats(sessionId);
+ mScoreUpdateObserver.triggerUpdateOfWifiUsabilityStats(sessionId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -6058,21 +6061,21 @@
* Called by framework to indicate the start of a network connection.
* @param sessionId The ID to indicate current Wi-Fi network connection.
*/
- void start(int sessionId);
+ void onStart(int sessionId);
/**
* Called by framework to indicate the end of a network connection.
* @param sessionId The ID to indicate current Wi-Fi network connection obtained from
- * {@link WifiConnectedNetworkScorer#start(int)}.
+ * {@link WifiConnectedNetworkScorer#onStart(int)}.
*/
- void stop(int sessionId);
+ void onStop(int sessionId);
/**
* Framework sets callback for score change events after application sets its scorer.
- * @param cbImpl The instance for {@link WifiManager#ScoreChangeCallback}. Should be
+ * @param observerImpl The instance for {@link WifiManager#ScoreUpdateObserver}. Should be
* implemented and instantiated by framework.
*/
- void setScoreChangeCallback(@NonNull ScoreChangeCallback cbImpl);
+ void onSetScoreUpdateObserver(@NonNull ScoreUpdateObserver observerImpl);
}
/**
@@ -6090,32 +6093,32 @@
}
@Override
- public void start(int sessionId) {
+ public void onStart(int sessionId) {
if (mVerboseLoggingEnabled) {
- Log.v(TAG, "WifiConnectedNetworkScorer: " + "start: sessionId=" + sessionId);
+ Log.v(TAG, "WifiConnectedNetworkScorer: " + "onStart: sessionId=" + sessionId);
}
Binder.clearCallingIdentity();
- mExecutor.execute(() -> mScorer.start(sessionId));
+ mExecutor.execute(() -> mScorer.onStart(sessionId));
}
@Override
- public void stop(int sessionId) {
+ public void onStop(int sessionId) {
if (mVerboseLoggingEnabled) {
- Log.v(TAG, "WifiConnectedNetworkScorer: " + "stop: sessionId=" + sessionId);
+ Log.v(TAG, "WifiConnectedNetworkScorer: " + "onStop: sessionId=" + sessionId);
}
Binder.clearCallingIdentity();
- mExecutor.execute(() -> mScorer.stop(sessionId));
+ mExecutor.execute(() -> mScorer.onStop(sessionId));
}
@Override
- public void setScoreChangeCallback(IScoreChangeCallback cbImpl) {
+ public void onSetScoreUpdateObserver(IScoreUpdateObserver observerImpl) {
if (mVerboseLoggingEnabled) {
Log.v(TAG, "WifiConnectedNetworkScorer: "
- + "setScoreChangeCallback: cbImpl=" + cbImpl);
+ + "onSetScoreUpdateObserver: observerImpl=" + observerImpl);
}
Binder.clearCallingIdentity();
- mExecutor.execute(() -> mScorer.setScoreChangeCallback(
- new ScoreChangeCallbackProxy(cbImpl)));
+ mExecutor.execute(() -> mScorer.onSetScoreUpdateObserver(
+ new ScoreUpdateObserverProxy(observerImpl)));
}
}
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index 9c2cad9..a310ff6 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -1805,9 +1805,7 @@
* @hide
*/
@SystemApi
- @RequiresPermission(allOf = {
- android.Manifest.permission.CONNECTIVITY_INTERNAL,
- android.Manifest.permission.CONFIGURE_WIFI_DISPLAY})
+ @RequiresPermission(android.Manifest.permission.CONFIGURE_WIFI_DISPLAY)
public void setMiracastMode(@MiracastMode int mode) {
try {
mService.setMiracastMode(mode);
diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
index 91c74f3..e210e4f 100644
--- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
@@ -423,7 +423,9 @@
assertTrue(config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.SAE));
assertTrue(config.allowedPairwiseCiphers.get(WifiConfiguration.PairwiseCipher.CCMP));
+ assertTrue(config.allowedPairwiseCiphers.get(WifiConfiguration.PairwiseCipher.GCMP_256));
assertTrue(config.allowedGroupCiphers.get(WifiConfiguration.GroupCipher.CCMP));
+ assertTrue(config.allowedGroupCiphers.get(WifiConfiguration.GroupCipher.GCMP_256));
assertTrue(config.requirePmf);
}
@@ -440,7 +442,9 @@
assertTrue(config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.OWE));
assertTrue(config.allowedPairwiseCiphers.get(WifiConfiguration.PairwiseCipher.CCMP));
+ assertTrue(config.allowedPairwiseCiphers.get(WifiConfiguration.PairwiseCipher.GCMP_256));
assertTrue(config.allowedGroupCiphers.get(WifiConfiguration.GroupCipher.CCMP));
+ assertTrue(config.allowedGroupCiphers.get(WifiConfiguration.GroupCipher.GCMP_256));
assertTrue(config.requirePmf);
}
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index 76ac837..90d6241 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -2349,23 +2349,24 @@
}
/**
- * Verify that Wi-Fi connected scorer receives score change callback after registeration.
+ * Verify that Wi-Fi connected scorer receives score update observer after registeration.
*/
@Test
- public void verifyScorerReceiveScoreChangeCallbackAfterRegistration() throws Exception {
+ public void verifyScorerReceiveScoreUpdateObserverAfterRegistration() throws Exception {
mExecutor = new SynchronousExecutor();
mWifiManager.setWifiConnectedNetworkScorer(mExecutor, mWifiConnectedNetworkScorer);
ArgumentCaptor<IWifiConnectedNetworkScorer.Stub> scorerCaptor =
ArgumentCaptor.forClass(IWifiConnectedNetworkScorer.Stub.class);
verify(mWifiService).setWifiConnectedNetworkScorer(any(IBinder.class),
scorerCaptor.capture());
- scorerCaptor.getValue().setScoreChangeCallback(any());
+ scorerCaptor.getValue().onSetScoreUpdateObserver(any());
mLooper.dispatchAll();
- verify(mWifiConnectedNetworkScorer).setScoreChangeCallback(any());
+ verify(mWifiConnectedNetworkScorer).onSetScoreUpdateObserver(any());
}
/**
- * Verify that Wi-Fi connected scorer receives session ID when start/stop methods are called.
+ * Verify that Wi-Fi connected scorer receives session ID when onStart/onStop methods
+ * are called.
*/
@Test
public void verifyScorerReceiveSessionIdWhenStartStopIsCalled() throws Exception {
@@ -2375,11 +2376,11 @@
ArgumentCaptor.forClass(IWifiConnectedNetworkScorer.Stub.class);
verify(mWifiService).setWifiConnectedNetworkScorer(any(IBinder.class),
callbackCaptor.capture());
- callbackCaptor.getValue().start(0);
- callbackCaptor.getValue().stop(10);
+ callbackCaptor.getValue().onStart(0);
+ callbackCaptor.getValue().onStop(10);
mLooper.dispatchAll();
- verify(mWifiConnectedNetworkScorer).start(0);
- verify(mWifiConnectedNetworkScorer).stop(10);
+ verify(mWifiConnectedNetworkScorer).onStart(0);
+ verify(mWifiConnectedNetworkScorer).onStop(10);
}
@Test