Loading apex/jobscheduler/service/java/com/android/server/tare/EconomyManagerInternal.java +1 −1 Original line number Diff line number Diff line Loading @@ -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 Loading apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java +285 −1 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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> Loading @@ -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 Loading @@ -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) { } } } Loading
apex/jobscheduler/service/java/com/android/server/tare/EconomyManagerInternal.java +1 −1 Original line number Diff line number Diff line Loading @@ -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 Loading
apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java +285 −1 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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> Loading @@ -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 Loading @@ -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) { } } }