From eb3f8c28e579cf21e45ff9074373fdbd57db9928 Mon Sep 17 00:00:00 2001 From: Kweku Adams Date: Fri, 12 Aug 2022 19:59:59 +0000 Subject: [PATCH] Reduce package cache memory usage. Only retain the information TARE cares about so we don't waste memory. The cache serves to reduce the number of calls to PackageManager, especially while the device is charging. Bug: 239951405 Test: atest frameworks/base/services/tests/mockingservicestests/src/com/android/server/tare Test: atest frameworks/base/services/tests/servicestests/src/com/android/server/tare Change-Id: I9e345cc3a88c192e00d401a93cbbe0df74f1596b --- .../java/com/android/server/tare/Agent.java | 19 ++++----- .../server/tare/InstalledPackageInfo.java | 38 ++++++++++++++++++ .../server/tare/InternalResourceService.java | 39 +++++++++++-------- .../java/com/android/server/tare/Scribe.java | 9 ++--- .../com/android/server/tare/ScribeTest.java | 4 +- 5 files changed, 74 insertions(+), 35 deletions(-) create mode 100644 apex/jobscheduler/service/java/com/android/server/tare/InstalledPackageInfo.java 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 8b8a57d248b95..66dc08dd7a46a 100644 --- a/apex/jobscheduler/service/java/com/android/server/tare/Agent.java +++ b/apex/jobscheduler/service/java/com/android/server/tare/Agent.java @@ -34,8 +34,6 @@ import static com.android.server.tare.TareUtils.getCurrentTimeMillis; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageInfo; import android.os.Handler; import android.os.Looper; import android.os.Message; @@ -606,13 +604,12 @@ class Agent { } /** Returns true if an app should be given credits in the general distributions. */ - private boolean shouldGiveCredits(@NonNull PackageInfo packageInfo) { - final ApplicationInfo applicationInfo = packageInfo.applicationInfo; + private boolean shouldGiveCredits(@NonNull InstalledPackageInfo packageInfo) { // Skip apps that wouldn't be doing any work. Giving them ARCs would be wasteful. - if (applicationInfo == null || !applicationInfo.hasCode()) { + if (!packageInfo.hasCode) { return false; } - final int userId = UserHandle.getUserId(packageInfo.applicationInfo.uid); + final int userId = UserHandle.getUserId(packageInfo.uid); // No point allocating ARCs to the system. It can do whatever it wants. return !mIrs.isSystem(userId, packageInfo.packageName); } @@ -623,15 +620,15 @@ class Agent { @GuardedBy("mLock") void distributeBasicIncomeLocked(int batteryLevel) { - List pkgs = mIrs.getInstalledPackages(); + final List pkgs = mIrs.getInstalledPackages(); final long now = getCurrentTimeMillis(); for (int i = 0; i < pkgs.size(); ++i) { - final PackageInfo pkgInfo = pkgs.get(i); + final InstalledPackageInfo pkgInfo = pkgs.get(i); if (!shouldGiveCredits(pkgInfo)) { continue; } - final int userId = UserHandle.getUserId(pkgInfo.applicationInfo.uid); + final int userId = UserHandle.getUserId(pkgInfo.uid); final String pkgName = pkgInfo.packageName; final Ledger ledger = mScribe.getLedgerLocked(userId, pkgName); final long minBalance = mIrs.getMinBalanceLocked(userId, pkgName); @@ -659,11 +656,11 @@ class Agent { @GuardedBy("mLock") void grantBirthrightsLocked(final int userId) { - final List pkgs = mIrs.getInstalledPackages(userId); + final List pkgs = mIrs.getInstalledPackages(userId); final long now = getCurrentTimeMillis(); for (int i = 0; i < pkgs.size(); ++i) { - final PackageInfo packageInfo = pkgs.get(i); + final InstalledPackageInfo packageInfo = pkgs.get(i); if (!shouldGiveCredits(packageInfo)) { continue; } diff --git a/apex/jobscheduler/service/java/com/android/server/tare/InstalledPackageInfo.java b/apex/jobscheduler/service/java/com/android/server/tare/InstalledPackageInfo.java new file mode 100644 index 0000000000000..da544bb6a2eb6 --- /dev/null +++ b/apex/jobscheduler/service/java/com/android/server/tare/InstalledPackageInfo.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.tare; + +import android.annotation.NonNull; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; +import android.os.UserHandle; + +/** POJO to cache only the information about installed packages that TARE cares about. */ +class InstalledPackageInfo { + static final int NO_UID = -1; + + public final int uid; + public final String packageName; + public final boolean hasCode; + + InstalledPackageInfo(@NonNull PackageInfo packageInfo) { + final ApplicationInfo applicationInfo = packageInfo.applicationInfo; + this.uid = applicationInfo == null ? NO_UID : applicationInfo.uid; + this.packageName = packageInfo.packageName; + this.hasCode = applicationInfo != null && applicationInfo.hasCode(); + } +} 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 6d5c16021ea93..e9270bffec65b 100644 --- a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java +++ b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java @@ -131,7 +131,7 @@ public class InternalResourceService extends SystemService { @NonNull @GuardedBy("mLock") - private final List mPkgCache = new ArrayList<>(); + private final List mPkgCache = new ArrayList<>(); /** Cached mapping of UIDs (for all users) to a list of packages in the UID. */ @GuardedBy("mLock") @@ -303,7 +303,7 @@ public class InternalResourceService extends SystemService { } @NonNull - List getInstalledPackages() { + List getInstalledPackages() { synchronized (mLock) { return mPkgCache; } @@ -311,13 +311,12 @@ public class InternalResourceService extends SystemService { /** Returns the installed packages for the specified user. */ @NonNull - List getInstalledPackages(final int userId) { - final List userPkgs = new ArrayList<>(); + List getInstalledPackages(final int userId) { + final List userPkgs = new ArrayList<>(); synchronized (mLock) { for (int i = 0; i < mPkgCache.size(); ++i) { - final PackageInfo packageInfo = mPkgCache.get(i); - if (packageInfo.applicationInfo != null - && UserHandle.getUserId(packageInfo.applicationInfo.uid) == userId) { + final InstalledPackageInfo packageInfo = mPkgCache.get(i); + if (UserHandle.getUserId(packageInfo.uid) == userId) { userPkgs.add(packageInfo); } } @@ -451,7 +450,7 @@ public class InternalResourceService extends SystemService { mPackageToUidCache.add(userId, pkgName, uid); } synchronized (mLock) { - mPkgCache.add(packageInfo); + mPkgCache.add(new InstalledPackageInfo(packageInfo)); mUidToPackageCache.add(uid, pkgName); // TODO: only do this when the user first launches the app (app leaves stopped state) mAgent.grantBirthrightLocked(userId, pkgName); @@ -472,8 +471,8 @@ public class InternalResourceService extends SystemService { 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 + final InstalledPackageInfo pkgInfo = mPkgCache.get(i); + if (UserHandle.getUserId(pkgInfo.uid) == userId && pkgName.equals(pkgInfo.packageName)) { mPkgCache.remove(i); break; @@ -496,8 +495,11 @@ public class InternalResourceService extends SystemService { void onUserAdded(final int userId) { synchronized (mLock) { - mPkgCache.addAll( - mPackageManager.getInstalledPackagesAsUser(PACKAGE_QUERY_FLAGS, userId)); + final List pkgs = + mPackageManager.getInstalledPackagesAsUser(PACKAGE_QUERY_FLAGS, userId); + for (int i = pkgs.size() - 1; i >= 0; --i) { + mPkgCache.add(new InstalledPackageInfo(pkgs.get(i))); + } mAgent.grantBirthrightsLocked(userId); } } @@ -506,10 +508,10 @@ public class InternalResourceService extends SystemService { synchronized (mLock) { ArrayList removedPkgs = new ArrayList<>(); for (int i = mPkgCache.size() - 1; i >= 0; --i) { - PackageInfo pkgInfo = mPkgCache.get(i); - if (UserHandle.getUserId(pkgInfo.applicationInfo.uid) == userId) { + final InstalledPackageInfo pkgInfo = mPkgCache.get(i); + if (UserHandle.getUserId(pkgInfo.uid) == userId) { removedPkgs.add(pkgInfo.packageName); - mUidToPackageCache.remove(pkgInfo.applicationInfo.uid); + mUidToPackageCache.remove(pkgInfo.uid); mPkgCache.remove(i); break; } @@ -659,8 +661,11 @@ public class InternalResourceService extends SystemService { LocalServices.getService(UserManagerInternal.class); final int[] userIds = userManagerInternal.getUserIds(); for (int userId : userIds) { - mPkgCache.addAll( - mPackageManager.getInstalledPackagesAsUser(PACKAGE_QUERY_FLAGS, userId)); + final List pkgs = + mPackageManager.getInstalledPackagesAsUser(PACKAGE_QUERY_FLAGS, userId); + for (int i = pkgs.size() - 1; i >= 0; --i) { + mPkgCache.add(new InstalledPackageInfo(pkgs.get(i))); + } } } diff --git a/apex/jobscheduler/service/java/com/android/server/tare/Scribe.java b/apex/jobscheduler/service/java/com/android/server/tare/Scribe.java index 8f7657e6c4149..ed915cd88ebeb 100644 --- a/apex/jobscheduler/service/java/com/android/server/tare/Scribe.java +++ b/apex/jobscheduler/service/java/com/android/server/tare/Scribe.java @@ -22,7 +22,6 @@ import static com.android.server.tare.TareUtils.appToString; import android.annotation.NonNull; import android.annotation.Nullable; -import android.content.pm.PackageInfo; import android.os.Environment; import android.os.UserHandle; import android.util.ArraySet; @@ -210,11 +209,11 @@ public class Scribe { mRemainingConsumableCakes = 0; final SparseArray> installedPackagesPerUser = new SparseArray<>(); - final List installedPackages = mIrs.getInstalledPackages(); + final List installedPackages = mIrs.getInstalledPackages(); for (int i = 0; i < installedPackages.size(); ++i) { - final PackageInfo packageInfo = installedPackages.get(i); - if (packageInfo.applicationInfo != null) { - final int userId = UserHandle.getUserId(packageInfo.applicationInfo.uid); + final InstalledPackageInfo packageInfo = installedPackages.get(i); + if (packageInfo.uid != InstalledPackageInfo.NO_UID) { + final int userId = UserHandle.getUserId(packageInfo.uid); ArraySet pkgsForUser = installedPackagesPerUser.get(userId); if (pkgsForUser == null) { pkgsForUser = new ArraySet<>(); diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java b/services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java index 13510adbb9603..d90d8b8bfac0f 100644 --- a/services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java @@ -68,7 +68,7 @@ public class ScribeTest { private MockitoSession mMockingSession; private Scribe mScribeUnderTest; private File mTestFileDir; - private final List mInstalledPackages = new ArrayList<>(); + private final List mInstalledPackages = new ArrayList<>(); private final List mReports = new ArrayList<>(); @Mock @@ -455,6 +455,6 @@ public class ScribeTest { ApplicationInfo applicationInfo = new ApplicationInfo(); applicationInfo.uid = UserHandle.getUid(userId, Math.abs(pkgName.hashCode())); pkgInfo.applicationInfo = applicationInfo; - mInstalledPackages.add(pkgInfo); + mInstalledPackages.add(new InstalledPackageInfo(pkgInfo)); } }