Merge "Flesh out the IRS some more."
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user