diff options
| author | 2018-03-21 16:07:32 +0000 | |
|---|---|---|
| committer | 2018-03-21 16:07:32 +0000 | |
| commit | 17d3b47e2036f589f29b7436bcbcd27eb0ad1a3e (patch) | |
| tree | 848b2bdd7d7b9b10f58daf2255a1ecd8cf021d2c | |
| parent | 65808f321055d1d1a73812002ef440e3724e8d20 (diff) | |
| parent | 1918ef7569e90c70246e535478b26732b82d92d3 (diff) | |
Merge "UsageEvents for slices pinning" into pi-dev
7 files changed, 105 insertions, 29 deletions
diff --git a/api/system-current.txt b/api/system-current.txt index a5be12fdfc9c..1e2fe3df0d2c 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -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 } diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java index 8550ac0f32cd..b354e8122a98 100644 --- a/core/java/android/app/usage/UsageEvents.java +++ b/core/java/android/app/usage/UsageEvents.java @@ -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; diff --git a/services/core/java/com/android/server/slice/SliceManagerService.java b/services/core/java/com/android/server/slice/SliceManagerService.java index a7dfd35acf1b..0b7d9d02f1cb 100644 --- a/services/core/java/com/android/server/slice/SliceManagerService.java +++ b/services/core/java/com/android/server/slice/SliceManagerService.java @@ -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,36 +368,43 @@ 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(); + 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 { - 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(); + holder = activityManager.getContentProviderExternal( + providerName, getUserIdFromUri(uri, user), token); + if (holder != null && holder.info != null) { + return holder.info.packageName; + } else { + return null; } } finally { - // I know, the double finally seems ugly, but seems safest for the identity. - Binder.restoreCallingIdentity(ident); + 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); } - return PERMISSION_GRANTED; } private void enforceCrossUser(String pkg, Uri uri) { diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java index edf1f746fb4b..552c915f8480 100644 --- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java +++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java @@ -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; @@ -406,6 +408,30 @@ public class AppStandbyControllerTests { } @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); // Set it to timeout or usage, so that prediction can override it diff --git a/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java index 4f446a9afb98..1073a800527a 100644 --- a/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/slice/SliceManagerServiceTest.java @@ -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 diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java index e836677e38fc..1af5f469c0f0 100644 --- a/services/usage/java/com/android/server/usage/AppStandbyController.java +++ b/services/usage/java/com/android/server/usage/AppStandbyController.java @@ -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, diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java index d9742825ac70..c2e38f2f0bd8 100644 --- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java @@ -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"; } |