Use taskRootPackageName instead of packageName to load uid when usage

resource is USAGE_SOURCE_TASK_ROOT_ACTIVITY and taskRootPackageName is
not empty.

This logic is consistent with digital wellbeing: assign the screen-on
time onto task root activity when usage resource is
USAGE_SOURCE_TASK_ROOT_ACTIVITY.

Bug: 260964679
Test: make RunSettingsRoboTests + manual
Change-Id: I4c7ed342d8c00951879f5826bf79575f330ce86e
This commit is contained in:
Kuan Wang
2022-12-19 14:54:50 +08:00
parent a1a7cba6a6
commit 2c7f06e9b3
3 changed files with 122 additions and 13 deletions

View File

@@ -17,7 +17,9 @@ package com.android.settings.fuelgauge.batteryusage;
import android.annotation.IntDef;
import android.annotation.Nullable;
import android.app.usage.IUsageStatsManager;
import android.app.usage.UsageEvents.Event;
import android.app.usage.UsageStatsManager;
import android.content.ContentValues;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -25,7 +27,9 @@ import android.database.Cursor;
import android.os.BatteryUsageStats;
import android.os.Build;
import android.os.LocaleList;
import android.os.RemoteException;
import android.os.UserHandle;
import android.text.TextUtils;
import android.text.format.DateFormat;
import android.util.Base64;
import android.util.Log;
@@ -167,8 +171,10 @@ public final class ConvertUtils {
/** Converts to {@link AppUsageEvent} from {@link Event} */
@Nullable
public static AppUsageEvent convertToAppUsageEvent(
Context context, final Event event, final long userId) {
if (event.getPackageName() == null) {
Context context, final IUsageStatsManager usageStatsManager, final Event event,
final long userId) {
final String packageName = event.getPackageName();
if (packageName == null) {
// See b/190609174: Event package names should never be null, but sometimes they are.
// Note that system events like device shutting down should still come with the android
// package name.
@@ -182,13 +188,20 @@ public final class ConvertUtils {
appUsageEventBuilder
.setTimestamp(event.getTimeStamp())
.setType(getAppUsageEventType(event.getEventType()))
.setPackageName(event.getPackageName())
.setPackageName(packageName)
.setUserId(userId);
final String taskRootPackageName = getTaskRootPackageName(event);
if (taskRootPackageName != null) {
appUsageEventBuilder.setTaskRootPackageName(taskRootPackageName);
}
final String effectivePackageName =
getEffectivePackageName(usageStatsManager, packageName, taskRootPackageName);
try {
final long uid = context
.getPackageManager()
.getPackageUidAsUser(event.getPackageName(), (int) userId);
.getPackageUidAsUser(effectivePackageName, (int) userId);
appUsageEventBuilder.setUid(uid);
} catch (PackageManager.NameNotFoundException e) {
Log.w(TAG, String.format(
@@ -201,10 +214,6 @@ public final class ConvertUtils {
} catch (NoClassDefFoundError | NoSuchMethodError e) {
Log.w(TAG, "UsageEvent instance ID API error");
}
String taskRootPackageName = getTaskRootPackageName(event);
if (taskRootPackageName != null) {
appUsageEventBuilder.setTaskRootPackageName(taskRootPackageName);
}
return appUsageEventBuilder.build();
}
@@ -267,6 +276,35 @@ public final class ConvertUtils {
: Locale.getDefault();
}
/**
* Returns the package name the app usage should be attributed to.
*
* <ul>
* <li>If {@link UsageStatsManager#getUsageSource()} returns {@link
* UsageStatsManager#USAGE_SOURCE_CURRENT_ACTIVITY}, this method will return packageName.
* <li>If {@link UsageStatsManager#getUsageSource()} returns {@link
* UsageStatsManager#USAGE_SOURCE_TASK_ROOT_ACTIVITY}, this method will return
* taskRootPackageName if it exists, or packageName otherwise.
* </ul>
*/
@VisibleForTesting
static String getEffectivePackageName(
final IUsageStatsManager usageStatsManager, final String packageName,
final String taskRootPackageName) {
int usageSource = getUsageSource(usageStatsManager);
switch (usageSource) {
case UsageStatsManager.USAGE_SOURCE_TASK_ROOT_ACTIVITY:
return !TextUtils.isEmpty(taskRootPackageName)
? taskRootPackageName
: packageName;
case UsageStatsManager.USAGE_SOURCE_CURRENT_ACTIVITY:
return packageName;
default:
Log.e(TAG, "Unexpected usage source: " + usageSource);
return packageName;
}
}
/**
* Returns the package name of the task root when this event was reported when {@code event} is
* one of:
@@ -298,6 +336,20 @@ public final class ConvertUtils {
}
}
/**
* Returns what App Usage Observers will consider the source of usage for an activity.
*
* @see UsageStatsManager#getUsageSource()
*/
private static int getUsageSource(final IUsageStatsManager usageStatsManager) {
try {
return usageStatsManager.getUsageSource();
} catch (RemoteException e) {
Log.e(TAG, "Failed to getUsageSource", e);
return UsageStatsManager.USAGE_SOURCE_CURRENT_ACTIVITY;
}
}
private static AppUsageEventType getAppUsageEventType(final int eventType) {
switch (eventType) {
case Event.ACTIVITY_RESUMED:

View File

@@ -256,7 +256,8 @@ public final class DataProcessor {
break;
}
final AppUsageEvent appUsageEvent =
ConvertUtils.convertToAppUsageEvent(context, event, userId);
ConvertUtils.convertToAppUsageEvent(
context, sUsageStatsManager, event, userId);
if (appUsageEvent != null) {
numEventsFetched++;
appUsageEventList.add(appUsageEvent);

View File

@@ -15,6 +15,9 @@
*/
package com.android.settings.fuelgauge.batteryusage;
import static android.app.usage.UsageStatsManager.USAGE_SOURCE_CURRENT_ACTIVITY;
import static android.app.usage.UsageStatsManager.USAGE_SOURCE_TASK_ROOT_ACTIVITY;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -22,6 +25,7 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.app.usage.IUsageStatsManager;
import android.app.usage.UsageEvents;
import android.app.usage.UsageEvents.Event;
import android.content.ContentValues;
@@ -31,6 +35,7 @@ import android.database.MatrixCursor;
import android.os.BatteryManager;
import android.os.BatteryUsageStats;
import android.os.LocaleList;
import android.os.RemoteException;
import android.os.UserHandle;
import com.android.settings.fuelgauge.batteryusage.db.AppUsageEventEntity;
@@ -56,6 +61,8 @@ public final class ConvertUtilsTest {
@Mock
private BatteryUsageStats mBatteryUsageStats;
@Mock
private IUsageStatsManager mUsageStatsManager;
@Mock
private BatteryEntry mMockBatteryEntry;
@Before
@@ -278,7 +285,7 @@ public final class ConvertUtilsTest {
final long userId = 2;
final AppUsageEvent appUsageEvent = ConvertUtils.convertToAppUsageEvent(
mContext, event, userId);
mContext, mUsageStatsManager, event, userId);
assertThat(appUsageEvent.getTimestamp()).isEqualTo(101L);
assertThat(appUsageEvent.getType()).isEqualTo(AppUsageEventType.ACTIVITY_RESUMED);
assertThat(appUsageEvent.getPackageName()).isEqualTo("com.android.settings1");
@@ -299,7 +306,7 @@ public final class ConvertUtilsTest {
final long userId = 1;
final AppUsageEvent appUsageEvent = ConvertUtils.convertToAppUsageEvent(
mContext, event, userId);
mContext, mUsageStatsManager, event, userId);
assertThat(appUsageEvent.getTimestamp()).isEqualTo(101L);
assertThat(appUsageEvent.getType()).isEqualTo(AppUsageEventType.DEVICE_SHUTDOWN);
assertThat(appUsageEvent.getPackageName()).isEqualTo("com.android.settings1");
@@ -315,7 +322,7 @@ public final class ConvertUtilsTest {
event.mPackage = null;
final AppUsageEvent appUsageEvent = ConvertUtils.convertToAppUsageEvent(
mContext, event, /*userId=*/ 0);
mContext, mUsageStatsManager, event, /*userId=*/ 0);
assertThat(appUsageEvent).isNull();
}
@@ -331,7 +338,7 @@ public final class ConvertUtilsTest {
final long userId = 1;
final AppUsageEvent appUsageEvent = ConvertUtils.convertToAppUsageEvent(
mContext, event, userId);
mContext, mUsageStatsManager, event, userId);
assertThat(appUsageEvent).isNull();
}
@@ -415,4 +422,53 @@ public final class ConvertUtilsTest {
mContext.getResources().getConfiguration().setLocales(new LocaleList());
assertThat(ConvertUtils.getLocale(mContext)).isEqualTo(Locale.getDefault());
}
@Test
public void getEffectivePackageName_currentActivity_returnPackageName() throws RemoteException {
when(mUsageStatsManager.getUsageSource()).thenReturn(USAGE_SOURCE_CURRENT_ACTIVITY);
final String packageName = "com.android.settings1";
final String taskRootPackageName = "com.android.settings2";
assertThat(ConvertUtils.getEffectivePackageName(
mUsageStatsManager, packageName, taskRootPackageName))
.isEqualTo(packageName);
}
@Test
public void getEffectivePackageName_usageSourceThrowException_returnPackageName()
throws RemoteException {
when(mUsageStatsManager.getUsageSource()).thenThrow(new RemoteException());
final String packageName = "com.android.settings1";
final String taskRootPackageName = "com.android.settings2";
assertThat(ConvertUtils.getEffectivePackageName(
mUsageStatsManager, packageName, taskRootPackageName))
.isEqualTo(packageName);
}
@Test
public void getEffectivePackageName_rootActivity_returnTaskRootPackageName()
throws RemoteException {
when(mUsageStatsManager.getUsageSource()).thenReturn(USAGE_SOURCE_TASK_ROOT_ACTIVITY);
final String packageName = "com.android.settings1";
final String taskRootPackageName = "com.android.settings2";
assertThat(ConvertUtils.getEffectivePackageName(
mUsageStatsManager, packageName, taskRootPackageName))
.isEqualTo(taskRootPackageName);
}
@Test
public void getEffectivePackageName_nullOrEmptyTaskRoot_returnPackageName()
throws RemoteException {
when(mUsageStatsManager.getUsageSource()).thenReturn(USAGE_SOURCE_TASK_ROOT_ACTIVITY);
final String packageName = "com.android.settings1";
assertThat(ConvertUtils.getEffectivePackageName(
mUsageStatsManager, packageName, /*taskRootPackageName=*/ null))
.isEqualTo(packageName);
assertThat(ConvertUtils.getEffectivePackageName(
mUsageStatsManager, packageName, /*taskRootPackageName=*/ ""))
.isEqualTo(packageName);
}
}