From 5f35f0d37a2a02176d40271d19f9621b98a42978 Mon Sep 17 00:00:00 2001 From: Kweku Adams Date: Fri, 30 Jul 2021 11:44:34 -0700 Subject: [PATCH] Add listener for UsageEvents. Add a listener that will grant rewards for various usage events. Bug: 158300259 Test: Check dumpsys for TOP reward grant Change-Id: I2c2b4b3aa40408cb0941db97fb510bce16b1f835 --- .../java/com/android/server/tare/Agent.java | 24 ++++--- .../server/tare/InternalResourceService.java | 71 ++++++++++++++++++- .../com/android/server/tare/TareUtils.java | 6 ++ 3 files changed, 89 insertions(+), 12 deletions(-) diff --git a/apex/jobscheduler/service/java/com/android/server/tare/Agent.java b/apex/jobscheduler/service/java/com/android/server/tare/Agent.java index 59c9c7e943ab0..db0ec36a50521 100644 --- a/apex/jobscheduler/service/java/com/android/server/tare/Agent.java +++ b/apex/jobscheduler/service/java/com/android/server/tare/Agent.java @@ -26,6 +26,7 @@ import static com.android.server.tare.EconomicPolicy.TYPE_ACTION; import static com.android.server.tare.EconomicPolicy.TYPE_REWARD; import static com.android.server.tare.EconomicPolicy.eventToString; import static com.android.server.tare.EconomicPolicy.getEventType; +import static com.android.server.tare.TareUtils.appToString; import static com.android.server.tare.TareUtils.getCurrentTimeMillis; import static com.android.server.tare.TareUtils.narcToString; @@ -232,8 +233,9 @@ class Agent { } @GuardedBy("mLock") - void noteOngoingEventLocked(final int userId, @NonNull final String pkgName, final int eventId, - @Nullable String tag, final long startElapsed, final boolean updateBalanceCheck) { + private void noteOngoingEventLocked(final int userId, @NonNull final String pkgName, + final int eventId, @Nullable String tag, final long startElapsed, + final boolean updateBalanceCheck) { SparseArrayMap ongoingEvents = mCurrentOngoingEvents.get(userId, pkgName); if (ongoingEvents == null) { @@ -392,8 +394,8 @@ class Agent { * registered bills and notify listeners about any changes. */ @GuardedBy("mLock") - void stopOngoingActionLocked(final int userId, @NonNull final String pkgName, final int eventId, - @Nullable String tag, final long nowElapsed, final long now, + private void stopOngoingActionLocked(final int userId, @NonNull final String pkgName, + final int eventId, @Nullable String tag, final long nowElapsed, final long now, final boolean updateBalanceCheck, final boolean notifyOnAffordabilityChange) { final Ledger ledger = getLedgerLocked(userId, pkgName); @@ -402,7 +404,7 @@ class Agent { if (ongoingEvents == null) { // This may occur if TARE goes from disabled to enabled while an event is already // occurring. - Slog.w(TAG, "No ongoing transactions for <" + userId + ">" + pkgName); + Slog.w(TAG, "No ongoing transactions for " + appToString(userId, pkgName)); return; } final OngoingEvent ongoingEvent = ongoingEvents.get(eventId, tag); @@ -411,7 +413,7 @@ class Agent { // occurring. Slog.w(TAG, "Nonexistent ongoing transaction " + eventToString(eventId) + (tag == null ? "" : ":" + tag) - + " for <" + userId + ">" + pkgName + " ended"); + + " for " + appToString(userId, pkgName) + " ended"); return; } ongoingEvent.refCount--; @@ -454,7 +456,8 @@ class Agent { Slog.i(TAG, "Would result in too many credits in circulation. Decreasing transaction " + eventToString(transaction.eventId) + (transaction.tag == null ? "" : ":" + transaction.tag) - + " for <" + userId + ">" + pkgName + " by " + (transaction.delta - newDelta)); + + " for " + appToString(userId, pkgName) + + " by " + (transaction.delta - newDelta)); transaction = new Ledger.Transaction( transaction.startTimeMs, transaction.endTimeMs, transaction.eventId, transaction.tag, newDelta); @@ -467,7 +470,8 @@ class Agent { Slog.i(TAG, "Would result in becoming too rich. Decreasing transaction " + eventToString(transaction.eventId) + (transaction.tag == null ? "" : ":" + transaction.tag) - + " for <" + userId + ">" + pkgName + " by " + (transaction.delta - newDelta)); + + " for " + appToString(userId, pkgName) + + " by " + (transaction.delta - newDelta)); transaction = new Ledger.Transaction( transaction.startTimeMs, transaction.endTimeMs, transaction.eventId, transaction.tag, newDelta); @@ -530,7 +534,7 @@ class Agent { } if (toReclaim > 0) { Slog.i(TAG, "Reclaiming unused wealth! Taking " + toReclaim - + " from <" + userId + ">" + pkgName); + + " from " + appToString(userId, pkgName)); recordTransactionLocked(userId, pkgName, ledger, new Ledger.Transaction( @@ -819,7 +823,7 @@ class Agent { @Override public String toString() { - return "<" + userId + ">" + packageName; + return appToString(userId, packageName); } @Override diff --git a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java index aa11add587af6..4ef77b02c9035 100644 --- a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java +++ b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java @@ -19,12 +19,15 @@ package com.android.server.tare; import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; +import static com.android.server.tare.TareUtils.appToString; import static com.android.server.tare.TareUtils.getCurrentTimeMillis; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.AlarmManager; import android.app.tare.IEconomyManager; +import android.app.usage.UsageEvents; +import android.app.usage.UsageStatsManagerInternal; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; @@ -154,6 +157,18 @@ public class InternalResourceService extends SystemService { } }; + private final UsageStatsManagerInternal.UsageEventListener mSurveillanceAgent = + new UsageStatsManagerInternal.UsageEventListener() { + /** + * Callback to inform listeners of a new event. + */ + @Override + public void onUsageEvent(int userId, @NonNull UsageEvents.Event event) { + mHandler.obtainMessage(MSG_PROCESS_USAGE_EVENT, userId, 0, event) + .sendToTarget(); + } + }; + private final AlarmManager.OnAlarmListener mUnusedWealthReclamationListener = new AlarmManager.OnAlarmListener() { @Override @@ -168,6 +183,7 @@ public class InternalResourceService extends SystemService { private static final int MSG_NOTIFY_AFFORDABILITY_CHANGE_LISTENER = 0; private static final int MSG_SCHEDULE_UNUSED_WEALTH_RECLAMATION_EVENT = 1; + private static final int MSG_PROCESS_USAGE_EVENT = 2; private static final String ALARM_TAG_WEALTH_RECLAMATION = "*tare.reclamation*"; private static final String KEY_PKG = "pkg"; @@ -341,6 +357,42 @@ public class InternalResourceService extends SystemService { msg.sendToTarget(); } + @GuardedBy("mLock") + private void processUsageEventLocked(final int userId, @NonNull UsageEvents.Event event) { + if (!mIsEnabled) { + return; + } + final String pkgName = event.getPackageName(); + if (DEBUG) { + Slog.d(TAG, "Processing event " + event.getEventType() + + " for " + appToString(userId, pkgName)); + } + final long nowElapsed = SystemClock.elapsedRealtime(); + switch (event.getEventType()) { + case UsageEvents.Event.ACTIVITY_RESUMED: + mAgent.noteOngoingEventLocked(userId, pkgName, + EconomicPolicy.REWARD_TOP_ACTIVITY, null, nowElapsed); + break; + case UsageEvents.Event.ACTIVITY_PAUSED: + case UsageEvents.Event.ACTIVITY_STOPPED: + case UsageEvents.Event.ACTIVITY_DESTROYED: + final long now = getCurrentTimeMillis(); + mAgent.stopOngoingActionLocked(userId, pkgName, + EconomicPolicy.REWARD_TOP_ACTIVITY, null, nowElapsed, now); + break; + case UsageEvents.Event.USER_INTERACTION: + case UsageEvents.Event.CHOOSER_ACTION: + mAgent.noteInstantaneousEventLocked(userId, pkgName, + EconomicPolicy.REWARD_OTHER_USER_INTERACTION, null); + break; + case UsageEvents.Event.NOTIFICATION_INTERRUPTION: + case UsageEvents.Event.NOTIFICATION_SEEN: + mAgent.noteInstantaneousEventLocked(userId, pkgName, + EconomicPolicy.REWARD_NOTIFICATION_SEEN, null); + break; + } + } + @GuardedBy("mLock") private void scheduleUnusedWealthReclamationLocked() { final long now = getCurrentTimeMillis(); @@ -386,7 +438,7 @@ public class InternalResourceService extends SystemService { mPkgCache = mPackageManager.getInstalledPackages(0); } - private void registerReceivers() { + private void registerListeners() { final IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_BATTERY_LEVEL_CHANGED); getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null); @@ -403,6 +455,9 @@ public class InternalResourceService extends SystemService { userFilter.addAction(Intent.ACTION_USER_ADDED); getContext() .registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, userFilter, null, null); + + UsageStatsManagerInternal usmi = LocalServices.getService(UsageStatsManagerInternal.class); + usmi.registerListener(mSurveillanceAgent); } /** Perform long-running and/or heavy setup work. This should be called off the main thread. */ @@ -422,7 +477,7 @@ public class InternalResourceService extends SystemService { return; } synchronized (mLock) { - registerReceivers(); + registerListeners(); mCurrentBatteryLevel = getCurrentBatteryLevel(); mHandler.post(this::setupHeavyWork); scheduleUnusedWealthReclamationLocked(); @@ -447,6 +502,9 @@ public class InternalResourceService extends SystemService { mPkgCache.clear(); mUidToPackageCache.clear(); getContext().unregisterReceiver(mBroadcastReceiver); + UsageStatsManagerInternal usmi = + LocalServices.getService(UsageStatsManagerInternal.class); + usmi.unregisterListener(mSurveillanceAgent); } } @@ -472,6 +530,15 @@ public class InternalResourceService extends SystemService { } break; + case MSG_PROCESS_USAGE_EVENT: { + final int userId = msg.arg1; + final UsageEvents.Event event = (UsageEvents.Event) msg.obj; + synchronized (mLock) { + processUsageEventLocked(userId, event); + } + } + break; + case MSG_SCHEDULE_UNUSED_WEALTH_RECLAMATION_EVENT: { removeMessages(MSG_SCHEDULE_UNUSED_WEALTH_RECLAMATION_EVENT); synchronized (mLock) { diff --git a/apex/jobscheduler/service/java/com/android/server/tare/TareUtils.java b/apex/jobscheduler/service/java/com/android/server/tare/TareUtils.java index 3c79bb3a796da..1e047aa60cf8b 100644 --- a/apex/jobscheduler/service/java/com/android/server/tare/TareUtils.java +++ b/apex/jobscheduler/service/java/com/android/server/tare/TareUtils.java @@ -69,4 +69,10 @@ class TareUtils { sb.append(" ARCs"); return sb.toString(); } + + /** Returns a standardized format for printing userId+pkgName combinations. */ + @NonNull + static String appToString(int userId, String pkgName) { + return "<" + userId + ">" + pkgName; + } }