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 829ad271d23d1..d7c3a86d1d602 100644 --- a/apex/jobscheduler/service/java/com/android/server/tare/Agent.java +++ b/apex/jobscheduler/service/java/com/android/server/tare/Agent.java @@ -238,8 +238,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) { @@ -398,8 +399,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); @@ -408,7 +409,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); @@ -417,7 +418,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--; @@ -472,7 +473,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); @@ -485,7 +487,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); @@ -548,7 +551,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( @@ -845,7 +848,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 a2ba75c68f2fa..b435c9e1a66de 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; @@ -161,6 +164,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 @@ -175,6 +190,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"; @@ -373,6 +389,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(); @@ -418,7 +470,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); @@ -435,6 +487,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. */ @@ -454,7 +509,7 @@ public class InternalResourceService extends SystemService { return; } synchronized (mLock) { - registerReceivers(); + registerListeners(); mCurrentBatteryLevel = getCurrentBatteryLevel(); mHandler.post(this::setupHeavyWork); scheduleUnusedWealthReclamationLocked(); @@ -479,6 +534,9 @@ public class InternalResourceService extends SystemService { mPkgCache.clear(); mUidToPackageCache.clear(); getContext().unregisterReceiver(mBroadcastReceiver); + UsageStatsManagerInternal usmi = + LocalServices.getService(UsageStatsManagerInternal.class); + usmi.unregisterListener(mSurveillanceAgent); } synchronized (mPackageToUidCache) { mPackageToUidCache.clear(); @@ -507,6 +565,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) {