Loading api/system-current.txt +2 −0 Original line number Diff line number Diff line Loading @@ -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 } Loading core/java/android/app/usage/UsageEvents.java +14 −0 Original line number Diff line number Diff line Loading @@ -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; Loading services/core/java/com/android/server/slice/SliceManagerService.java +48 −25 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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()); Loading @@ -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; Loading Loading @@ -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 Loading Loading @@ -352,6 +368,15 @@ 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). 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(); Loading @@ -362,9 +387,10 @@ public class SliceManagerService extends ISliceManager.Stub { try { holder = activityManager.getContentProviderExternal( providerName, getUserIdFromUri(uri, user), token); if (holder == null || holder.info == null || !Objects.equals(holder.info.packageName, pkg)) { return PERMISSION_DENIED; if (holder != null && holder.info != null) { return holder.info.packageName; } else { return null; } } finally { if (holder != null && holder.provider != null) { Loading @@ -373,16 +399,13 @@ public class SliceManagerService extends ISliceManager.Stub { } } catch (RemoteException e) { // Can't happen. e.rethrowAsRuntimeException(); throw e.rethrowAsRuntimeException(); } } finally { // I know, the double finally seems ugly, but seems safest for the identity. Binder.restoreCallingIdentity(ident); } } } return PERMISSION_GRANTED; } private void enforceCrossUser(String pkg, Uri uri) { int user = Binder.getCallingUserHandle().getIdentifier(); Loading services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java +26 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java +4 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading @@ -77,6 +80,7 @@ public class SliceManagerServiceTest extends UiServiceTestCase { @After public void teardown() { LocalServices.removeServiceForTest(PackageManagerInternal.class); LocalServices.removeServiceForTest(UsageStatsManagerInternal.class); } @Test Loading Loading
api/system-current.txt +2 −0 Original line number Diff line number Diff line Loading @@ -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 } Loading
core/java/android/app/usage/UsageEvents.java +14 −0 Original line number Diff line number Diff line Loading @@ -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; Loading
services/core/java/com/android/server/slice/SliceManagerService.java +48 −25 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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()); Loading @@ -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; Loading Loading @@ -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 Loading Loading @@ -352,6 +368,15 @@ 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). 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(); Loading @@ -362,9 +387,10 @@ public class SliceManagerService extends ISliceManager.Stub { try { holder = activityManager.getContentProviderExternal( providerName, getUserIdFromUri(uri, user), token); if (holder == null || holder.info == null || !Objects.equals(holder.info.packageName, pkg)) { return PERMISSION_DENIED; if (holder != null && holder.info != null) { return holder.info.packageName; } else { return null; } } finally { if (holder != null && holder.provider != null) { Loading @@ -373,16 +399,13 @@ public class SliceManagerService extends ISliceManager.Stub { } } catch (RemoteException e) { // Can't happen. e.rethrowAsRuntimeException(); throw e.rethrowAsRuntimeException(); } } finally { // I know, the double finally seems ugly, but seems safest for the identity. Binder.restoreCallingIdentity(ident); } } } return PERMISSION_GRANTED; } private void enforceCrossUser(String pkg, Uri uri) { int user = Binder.getCallingUserHandle().getIdentifier(); Loading
services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java +26 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading
services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java +4 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading @@ -77,6 +80,7 @@ public class SliceManagerServiceTest extends UiServiceTestCase { @After public void teardown() { LocalServices.removeServiceForTest(PackageManagerInternal.class); LocalServices.removeServiceForTest(UsageStatsManagerInternal.class); } @Test Loading