Merge "Flesh out the IRS some more."

This commit is contained in:
Kweku Adams
2021-06-03 23:44:37 +00:00
committed by Android (Google) Code Review
2 changed files with 286 additions and 2 deletions

View File

@@ -53,7 +53,7 @@ interface EconomyManagerInternal {
* Return {@code true} if the app has a balance equal to or greater than the specified min
* balance.
*/
boolean hasBalanceAtLeast(int userId, @NonNull String pkgName, double minBalance);
boolean hasBalanceAtLeast(int userId, @NonNull String pkgName, int minBalance);
/**
* Note that an instantaneous event has occurred. The event must be specified in one of the

View File

@@ -17,10 +17,32 @@
package com.android.server.tare;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.BatteryManagerInternal;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.UserHandle;
import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
import android.util.SparseSetArray;
import com.android.internal.annotations.GuardedBy;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.tare.EconomyManagerInternal.BalanceChangeListener;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* Responsible for handling app's ARC count based on events, ensuring ARCs are credited when
@@ -33,11 +55,82 @@ import com.android.server.SystemService;
*/
public class InternalResourceService extends SystemService {
public static final String TAG = "TARE-IRS";
public static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
public static final boolean DEBUG = Log.isLoggable("TARE", Log.DEBUG);
/** Global local for all resource economy state. */
private final Object mLock = new Object();
private final Handler mHandler;
private final BatteryManagerInternal mBatteryManagerInternal;
private final PackageManager mPackageManager;
@GuardedBy("mLock")
private final CopyOnWriteArraySet<BalanceChangeListener> mBalanceChangeListeners =
new CopyOnWriteArraySet<>();
@NonNull
private List<PackageInfo> mPkgCache = new ArrayList<>();
/** Cached mapping of UIDs (for all users) to a list of packages in the UID. */
private final SparseSetArray<String> mUidToPackageCache = new SparseSetArray<>();
@GuardedBy("mLock")
private boolean mIsSetup;
// In the range [0,100] to represent 0% to 100% battery.
@GuardedBy("mLock")
private int mCurrentBatteryLevel;
@SuppressWarnings("FieldCanBeLocal")
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Nullable
private String getPackageName(Intent intent) {
Uri uri = intent.getData();
return uri != null ? uri.getSchemeSpecificPart() : null;
}
@Override
public void onReceive(Context context, Intent intent) {
switch (intent.getAction()) {
case Intent.ACTION_BATTERY_LEVEL_CHANGED:
onBatteryLevelChanged();
break;
case Intent.ACTION_PACKAGE_FULLY_REMOVED: {
final String pkgName = getPackageName(intent);
final int pkgUid = intent.getIntExtra(Intent.EXTRA_UID, -1);
onPackageRemoved(pkgUid, pkgName);
}
break;
case Intent.ACTION_PACKAGE_ADDED: {
if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
final String pkgName = getPackageName(intent);
final int pkgUid = intent.getIntExtra(Intent.EXTRA_UID, -1);
onPackageAdded(pkgUid, pkgName);
}
}
break;
case Intent.ACTION_PACKAGE_RESTARTED: {
final String pkgName = getPackageName(intent);
final int pkgUid = intent.getIntExtra(Intent.EXTRA_UID, -1);
final int userId = UserHandle.getUserId(pkgUid);
onPackageForceStopped(userId, pkgName);
}
break;
case Intent.ACTION_USER_ADDED: {
final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
onUserAdded(userId);
}
break;
case Intent.ACTION_USER_REMOVED: {
final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
onUserRemoved(userId);
}
break;
}
}
};
private static final int MSG_NOTIFY_BALANCE_CHANGE_LISTENERS = 0;
/**
* Initializes the system service.
* <p>
@@ -49,6 +142,25 @@ public class InternalResourceService extends SystemService {
*/
public InternalResourceService(Context context) {
super(context);
mHandler = new IrsHandler(TareHandlerThread.get().getLooper());
mBatteryManagerInternal = LocalServices.getService(BatteryManagerInternal.class);
mPackageManager = context.getPackageManager();
final IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_BATTERY_LEVEL_CHANGED);
context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
final IntentFilter pkgFilter = new IntentFilter();
pkgFilter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
pkgFilter.addDataScheme("package");
context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, pkgFilter, null, null);
final IntentFilter userFilter = new IntentFilter(Intent.ACTION_USER_REMOVED);
userFilter.addAction(Intent.ACTION_USER_ADDED);
context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, userFilter, null, null);
publishLocalService(EconomyManagerInternal.class, new LocalService());
}
@Override
@@ -60,4 +172,176 @@ public class InternalResourceService extends SystemService {
Object getLock() {
return mLock;
}
@NonNull
List<PackageInfo> getInstalledPackages() {
synchronized (mLock) {
return mPkgCache;
}
}
@Nullable
@GuardedBy("mLock")
ArraySet<String> getPackagesForUidLocked(final int uid) {
ArraySet<String> packages = mUidToPackageCache.get(uid);
if (packages == null) {
String[] pkgs = mPackageManager.getPackagesForUid(uid);
if (pkgs != null) {
for (String pkg : pkgs) {
mUidToPackageCache.add(uid, pkg);
}
packages = mUidToPackageCache.get(uid);
}
}
return packages;
}
void onAppStateChanged(final int userId, @NonNull final ArraySet<String> pkgNames) {
}
void onBatteryLevelChanged() {
synchronized (mLock) {
final int newBatteryLevel = getCurrentBatteryLevel();
mCurrentBatteryLevel = newBatteryLevel;
}
}
void onDeviceStateChanged() {
}
void onPackageAdded(final int uid, @NonNull final String pkgName) {
final int userId = UserHandle.getUserId(uid);
final PackageInfo packageInfo;
try {
packageInfo = mPackageManager.getPackageInfoAsUser(pkgName, 0, userId);
} catch (PackageManager.NameNotFoundException e) {
Slog.wtf(TAG, "PM couldn't find newly added package: " + pkgName);
return;
}
synchronized (mLock) {
mPkgCache.add(packageInfo);
mUidToPackageCache.add(uid, pkgName);
}
}
void onPackageForceStopped(final int userId, @NonNull final String pkgName) {
synchronized (mLock) {
// TODO: reduce ARC count by some amount
}
}
void onPackageRemoved(final int uid, @NonNull final String pkgName) {
final int userId = UserHandle.getUserId(uid);
synchronized (mLock) {
mUidToPackageCache.remove(uid, pkgName);
for (int i = 0; i < mPkgCache.size(); ++i) {
PackageInfo pkgInfo = mPkgCache.get(i);
if (UserHandle.getUserId(pkgInfo.applicationInfo.uid) == userId
&& pkgName.equals(pkgInfo.packageName)) {
mPkgCache.remove(i);
break;
}
}
}
}
void onUserAdded(final int userId) {
synchronized (mLock) {
loadInstalledPackageListLocked();
}
}
void onUserRemoved(final int userId) {
synchronized (mLock) {
ArrayList<String> removedPkgs = new ArrayList<>();
for (int i = mPkgCache.size() - 1; i >= 0; --i) {
PackageInfo pkgInfo = mPkgCache.get(i);
if (UserHandle.getUserId(pkgInfo.applicationInfo.uid) == userId) {
removedPkgs.add(pkgInfo.packageName);
mUidToPackageCache.remove(pkgInfo.applicationInfo.uid);
mPkgCache.remove(i);
break;
}
}
loadInstalledPackageListLocked();
}
}
void postSolvencyChanged(final int userId, @NonNull final String pkgName, boolean nowSolvent) {
mHandler.obtainMessage(
MSG_NOTIFY_BALANCE_CHANGE_LISTENERS, userId, nowSolvent ? 1 : 0, pkgName)
.sendToTarget();
}
private int getCurrentBatteryLevel() {
return mBatteryManagerInternal.getBatteryLevel();
}
@GuardedBy("mLock")
private void loadInstalledPackageListLocked() {
mPkgCache = mPackageManager.getInstalledPackages(0);
}
private void setupEconomy() {
synchronized (mLock) {
loadInstalledPackageListLocked();
mIsSetup = true;
}
}
private final class IrsHandler extends Handler {
IrsHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_NOTIFY_BALANCE_CHANGE_LISTENERS:
final int userId = msg.arg1;
final String pkgName = (String) msg.obj;
final boolean nowSolvent = msg.arg2 == 1;
for (BalanceChangeListener listener : mBalanceChangeListeners) {
if (nowSolvent) {
listener.onSolvent(userId, pkgName);
} else {
listener.onBankruptcy(userId, pkgName);
}
}
break;
}
}
}
// TODO: implement
private final class LocalService implements EconomyManagerInternal {
@Override
public void registerBalanceChangeListener(@NonNull BalanceChangeListener listener) {
}
@Override
public void unregisterBalanceChangeListener(@NonNull BalanceChangeListener listener) {
}
@Override
public boolean hasBalanceAtLeast(int userId, @NonNull String pkgName, int minBalance) {
return false;
}
@Override
public void noteInstantaneousEvent(int userId, @NonNull String pkgName,
@NonNull String event, @Nullable String tag) {
}
@Override
public void noteOngoingEventStarted(int userId, @NonNull String pkgName,
@NonNull String event, @Nullable String tag) {
}
@Override
public void noteOngoingEventStopped(int userId, @NonNull String pkgName,
@NonNull String event, @Nullable String tag) {
}
}
}