Merge "UsageEvents for slices pinning" into pi-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
17d3b47e20
@@ -725,6 +725,8 @@ package android.app.usage {
|
||||
method public java.lang.String getNotificationChannelId();
|
||||
field public static final int NOTIFICATION_INTERRUPTION = 12; // 0xc
|
||||
field public static final int NOTIFICATION_SEEN = 10; // 0xa
|
||||
field public static final int SLICE_PINNED = 14; // 0xe
|
||||
field public static final int SLICE_PINNED_PRIV = 13; // 0xd
|
||||
field public static final int SYSTEM_INTERACTION = 6; // 0x6
|
||||
}
|
||||
|
||||
|
||||
@@ -125,6 +125,20 @@ public final class UsageEvents implements Parcelable {
|
||||
@SystemApi
|
||||
public static final int NOTIFICATION_INTERRUPTION = 12;
|
||||
|
||||
/**
|
||||
* A Slice was pinned by the default launcher or the default assistant.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public static final int SLICE_PINNED_PRIV = 13;
|
||||
|
||||
/**
|
||||
* A Slice was pinned by an app.
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi
|
||||
public static final int SLICE_PINNED = 14;
|
||||
|
||||
/** @hide */
|
||||
public static final int FLAG_IS_PACKAGE_INSTANT_APP = 1 << 0;
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.server.slice;
|
||||
|
||||
import static android.app.usage.UsageEvents.Event.SLICE_PINNED;
|
||||
import static android.app.usage.UsageEvents.Event.SLICE_PINNED_PRIV;
|
||||
import static android.content.ContentProvider.getUriWithoutUserId;
|
||||
import static android.content.ContentProvider.getUserIdFromUri;
|
||||
import static android.content.ContentProvider.maybeAddUserId;
|
||||
@@ -31,6 +33,7 @@ import android.app.IActivityManager;
|
||||
import android.app.slice.ISliceManager;
|
||||
import android.app.slice.SliceManager;
|
||||
import android.app.slice.SliceSpec;
|
||||
import android.app.usage.UsageStatsManagerInternal;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
@@ -95,6 +98,7 @@ public class SliceManagerService extends ISliceManager.Stub {
|
||||
private final AtomicFile mSliceAccessFile;
|
||||
@GuardedBy("mAccessList")
|
||||
private final SliceFullAccessList mAccessList;
|
||||
private final UsageStatsManagerInternal mAppUsageStats;
|
||||
|
||||
public SliceManagerService(Context context) {
|
||||
this(context, createHandler().getLooper());
|
||||
@@ -112,6 +116,7 @@ public class SliceManagerService extends ISliceManager.Stub {
|
||||
final File systemDir = new File(Environment.getDataDirectory(), "system");
|
||||
mSliceAccessFile = new AtomicFile(new File(systemDir, "slice_access.xml"));
|
||||
mAccessList = new SliceFullAccessList(mContext);
|
||||
mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
|
||||
|
||||
synchronized (mSliceAccessFile) {
|
||||
if (!mSliceAccessFile.exists()) return;
|
||||
@@ -166,8 +171,19 @@ public class SliceManagerService extends ISliceManager.Stub {
|
||||
public void pinSlice(String pkg, Uri uri, SliceSpec[] specs, IBinder token) throws RemoteException {
|
||||
verifyCaller(pkg);
|
||||
enforceAccess(pkg, uri);
|
||||
uri = maybeAddUserId(uri, Binder.getCallingUserHandle().getIdentifier());
|
||||
int user = Binder.getCallingUserHandle().getIdentifier();
|
||||
uri = maybeAddUserId(uri, user);
|
||||
getOrCreatePinnedSlice(uri, pkg).pin(pkg, specs, token);
|
||||
|
||||
Uri finalUri = uri;
|
||||
mHandler.post(() -> {
|
||||
String slicePkg = getProviderPkg(finalUri, user);
|
||||
if (slicePkg != null && !Objects.equals(pkg, slicePkg)) {
|
||||
mAppUsageStats.reportEvent(slicePkg, user,
|
||||
isAssistant(pkg, user) || isDefaultHomeApp(pkg, user)
|
||||
? SLICE_PINNED_PRIV : SLICE_PINNED);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -352,38 +368,45 @@ public class SliceManagerService extends ISliceManager.Stub {
|
||||
if (getContext().checkUriPermission(uri, pid, uid,
|
||||
Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != PERMISSION_GRANTED) {
|
||||
// Last fallback (if the calling app owns the authority, then it can have access).
|
||||
long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
IBinder token = new Binder();
|
||||
IActivityManager activityManager = ActivityManager.getService();
|
||||
ContentProviderHolder holder = null;
|
||||
String providerName = getUriWithoutUserId(uri).getAuthority();
|
||||
try {
|
||||
try {
|
||||
holder = activityManager.getContentProviderExternal(
|
||||
providerName, getUserIdFromUri(uri, user), token);
|
||||
if (holder == null || holder.info == null
|
||||
|| !Objects.equals(holder.info.packageName, pkg)) {
|
||||
return PERMISSION_DENIED;
|
||||
}
|
||||
} finally {
|
||||
if (holder != null && holder.provider != null) {
|
||||
activityManager.removeContentProviderExternal(providerName, token);
|
||||
}
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
// Can't happen.
|
||||
e.rethrowAsRuntimeException();
|
||||
}
|
||||
} finally {
|
||||
// I know, the double finally seems ugly, but seems safest for the identity.
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
if (!Objects.equals(getProviderPkg(uri, user), pkg)) {
|
||||
return PERMISSION_DENIED;
|
||||
}
|
||||
}
|
||||
}
|
||||
return PERMISSION_GRANTED;
|
||||
}
|
||||
|
||||
private String getProviderPkg(Uri uri, int user) {
|
||||
long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
IBinder token = new Binder();
|
||||
IActivityManager activityManager = ActivityManager.getService();
|
||||
ContentProviderHolder holder = null;
|
||||
String providerName = getUriWithoutUserId(uri).getAuthority();
|
||||
try {
|
||||
try {
|
||||
holder = activityManager.getContentProviderExternal(
|
||||
providerName, getUserIdFromUri(uri, user), token);
|
||||
if (holder != null && holder.info != null) {
|
||||
return holder.info.packageName;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} finally {
|
||||
if (holder != null && holder.provider != null) {
|
||||
activityManager.removeContentProviderExternal(providerName, token);
|
||||
}
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
// Can't happen.
|
||||
throw e.rethrowAsRuntimeException();
|
||||
}
|
||||
} finally {
|
||||
// I know, the double finally seems ugly, but seems safest for the identity.
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
}
|
||||
|
||||
private void enforceCrossUser(String pkg, Uri uri) {
|
||||
int user = Binder.getCallingUserHandle().getIdentifier();
|
||||
if (getUserIdFromUri(uri, user) != user) {
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
package com.android.server.usage;
|
||||
|
||||
import static android.app.usage.UsageEvents.Event.NOTIFICATION_SEEN;
|
||||
import static android.app.usage.UsageEvents.Event.SLICE_PINNED;
|
||||
import static android.app.usage.UsageEvents.Event.SLICE_PINNED_PRIV;
|
||||
import static android.app.usage.UsageEvents.Event.USER_INTERACTION;
|
||||
import static android.app.usage.UsageStatsManager.REASON_MAIN_DEFAULT;
|
||||
import static android.app.usage.UsageStatsManager.REASON_MAIN_FORCED;
|
||||
@@ -405,6 +407,30 @@ public class AppStandbyControllerTests {
|
||||
assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSlicePinnedEvent() throws Exception {
|
||||
setChargingState(mController, false);
|
||||
|
||||
reportEvent(mController, USER_INTERACTION, 0);
|
||||
assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController));
|
||||
mInjector.mElapsedRealtime = 1;
|
||||
reportEvent(mController, SLICE_PINNED, mInjector.mElapsedRealtime);
|
||||
assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController));
|
||||
|
||||
mController.forceIdleState(PACKAGE_1, USER_ID, true);
|
||||
reportEvent(mController, SLICE_PINNED, mInjector.mElapsedRealtime);
|
||||
assertEquals(STANDBY_BUCKET_WORKING_SET, getStandbyBucket(mController));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSlicePinnedPrivEvent() throws Exception {
|
||||
setChargingState(mController, false);
|
||||
|
||||
mController.forceIdleState(PACKAGE_1, USER_ID, true);
|
||||
reportEvent(mController, SLICE_PINNED_PRIV, mInjector.mElapsedRealtime);
|
||||
assertEquals(STANDBY_BUCKET_ACTIVE, getStandbyBucket(mController));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPredictionTimedout() throws Exception {
|
||||
setChargingState(mController, false);
|
||||
|
||||
@@ -30,6 +30,7 @@ import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.AppOpsManager;
|
||||
import android.app.slice.SliceSpec;
|
||||
import android.app.usage.UsageStatsManagerInternal;
|
||||
import android.content.pm.PackageManagerInternal;
|
||||
import android.net.Uri;
|
||||
import android.os.Binder;
|
||||
@@ -66,6 +67,8 @@ public class SliceManagerServiceTest extends UiServiceTestCase {
|
||||
@Before
|
||||
public void setup() {
|
||||
LocalServices.addService(PackageManagerInternal.class, mock(PackageManagerInternal.class));
|
||||
LocalServices.addService(UsageStatsManagerInternal.class,
|
||||
mock(UsageStatsManagerInternal.class));
|
||||
mContext.addMockSystemService(AppOpsManager.class, mock(AppOpsManager.class));
|
||||
mContext.getTestablePermissions().setPermission(TEST_URI, PERMISSION_GRANTED);
|
||||
|
||||
@@ -77,6 +80,7 @@ public class SliceManagerServiceTest extends UiServiceTestCase {
|
||||
@After
|
||||
public void teardown() {
|
||||
LocalServices.removeServiceForTest(PackageManagerInternal.class);
|
||||
LocalServices.removeServiceForTest(UsageStatsManagerInternal.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -36,6 +36,7 @@ import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_FREQUENT;
|
||||
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_NEVER;
|
||||
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_RARE;
|
||||
import static android.app.usage.UsageStatsManager.STANDBY_BUCKET_WORKING_SET;
|
||||
|
||||
import static com.android.server.SystemService.PHASE_BOOT_COMPLETED;
|
||||
import static com.android.server.SystemService.PHASE_SYSTEM_SERVICES_READY;
|
||||
|
||||
@@ -43,8 +44,8 @@ import android.annotation.UserIdInt;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.AppGlobals;
|
||||
import android.app.usage.AppStandbyInfo;
|
||||
import android.app.usage.UsageStatsManager.StandbyBuckets;
|
||||
import android.app.usage.UsageEvents;
|
||||
import android.app.usage.UsageStatsManager.StandbyBuckets;
|
||||
import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener;
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.content.BroadcastReceiver;
|
||||
@@ -100,7 +101,6 @@ import java.time.format.DateTimeParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
@@ -690,7 +690,9 @@ public class AppStandbyController {
|
||||
|| event.mEventType == UsageEvents.Event.MOVE_TO_BACKGROUND
|
||||
|| event.mEventType == UsageEvents.Event.SYSTEM_INTERACTION
|
||||
|| event.mEventType == UsageEvents.Event.USER_INTERACTION
|
||||
|| event.mEventType == UsageEvents.Event.NOTIFICATION_SEEN)) {
|
||||
|| event.mEventType == UsageEvents.Event.NOTIFICATION_SEEN
|
||||
|| event.mEventType == UsageEvents.Event.SLICE_PINNED
|
||||
|| event.mEventType == UsageEvents.Event.SLICE_PINNED_PRIV)) {
|
||||
|
||||
final AppUsageHistory appHistory = mAppIdleHistory.getAppUsageHistory(
|
||||
event.mPackage, userId, elapsedRealtime);
|
||||
@@ -699,7 +701,8 @@ public class AppStandbyController {
|
||||
final long nextCheckTime;
|
||||
final int subReason = usageEventToSubReason(event.mEventType);
|
||||
final int reason = REASON_MAIN_USAGE | subReason;
|
||||
if (event.mEventType == UsageEvents.Event.NOTIFICATION_SEEN) {
|
||||
if (event.mEventType == UsageEvents.Event.NOTIFICATION_SEEN
|
||||
|| event.mEventType == UsageEvents.Event.SLICE_PINNED) {
|
||||
// Mild usage elevates to WORKING_SET but doesn't change usage time.
|
||||
mAppIdleHistory.reportUsage(appHistory, event.mPackage,
|
||||
STANDBY_BUCKET_WORKING_SET, subReason,
|
||||
|
||||
@@ -761,6 +761,10 @@ class UserUsageStatsService {
|
||||
return "STANDBY_BUCKET_CHANGED";
|
||||
case UsageEvents.Event.NOTIFICATION_INTERRUPTION:
|
||||
return "NOTIFICATION_INTERRUPTION";
|
||||
case UsageEvents.Event.SLICE_PINNED:
|
||||
return "SLICE_PINNED";
|
||||
case UsageEvents.Event.SLICE_PINNED_PRIV:
|
||||
return "SLICE_PINNED_PRIV";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user