Make ServiceInfo cache more permanent.

There's no need to keep re-querying PackageManager when we know nothing
has changed for an app. Make the ServiceInfo cache more permanent so we
can avoid unnecessary calls to PackageManager.

Bug: 138469672
Test: atest CtsJobSchedulerTestCases
Test: atest com.android.server.job.controllers.QuotaControllerTest
Test: atest com.android.server.job.controllers.JobStatusTest
Change-Id: I93962c632b7ccd867c9c7dfffbc19a6b48cd2565
This commit is contained in:
Kweku Adams
2020-09-18 09:33:15 -07:00
parent 8f4f0d7e71
commit 6416cab21b

View File

@@ -77,6 +77,9 @@ public class ComponentController extends StateController {
}
};
private final SparseArrayMap<ComponentName, ServiceInfo> mServiceInfoCache =
new SparseArrayMap<>();
private final ComponentStateUpdateFunctor mComponentStateUpdateFunctor =
new ComponentStateUpdateFunctor();
@@ -98,40 +101,33 @@ public class ComponentController extends StateController {
@Override
public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
updateComponentEnabledStateLocked(jobStatus, null);
updateComponentEnabledStateLocked(jobStatus);
}
@Override
public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob,
boolean forUpdate) {
}
@Nullable
private ServiceInfo getServiceInfo(JobStatus jobStatus,
@Nullable SparseArrayMap<ComponentName, ServiceInfo> cache) {
final ComponentName cn = jobStatus.getServiceComponent();
ServiceInfo si = null;
if (cache != null) {
si = cache.get(jobStatus.getUserId(), cn);
}
private ServiceInfo getServiceInfo(JobStatus jobStatus) {
final ComponentName service = jobStatus.getServiceComponent();
final int userId = jobStatus.getUserId();
ServiceInfo si = mServiceInfoCache.get(userId, service);
if (si == null) {
try {
si = AppGlobals.getPackageManager().getServiceInfo(
cn, PackageManager.MATCH_DIRECT_BOOT_AUTO, jobStatus.getUserId());
service, PackageManager.MATCH_DIRECT_BOOT_AUTO, userId);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
if (cache != null) {
cache.add(jobStatus.getUserId(), cn, si);
}
mServiceInfoCache.add(userId, service, si);
}
return si;
}
private boolean updateComponentEnabledStateLocked(JobStatus jobStatus,
@Nullable SparseArrayMap<ComponentName, ServiceInfo> cache) {
final ServiceInfo service = getServiceInfo(jobStatus, cache);
private boolean updateComponentEnabledStateLocked(JobStatus jobStatus) {
final ServiceInfo service = getServiceInfo(jobStatus);
if (DEBUG && service == null) {
Slog.v(TAG, jobStatus.toShortString() + " component not present");
@@ -142,40 +138,51 @@ public class ComponentController extends StateController {
}
private void updateComponentStateForPackage(final String pkg) {
updateComponentStates(
jobStatus -> jobStatus.getServiceComponent().getPackageName().equals(pkg));
synchronized (mLock) {
for (int u = mServiceInfoCache.numMaps() - 1; u >= 0; --u) {
final int userId = mServiceInfoCache.keyAt(u);
for (int c = mServiceInfoCache.numElementsForKey(userId) - 1; c >= 0; --c) {
final ComponentName cn = mServiceInfoCache.keyAt(u, c);
if (cn.getPackageName().equals(pkg)) {
mServiceInfoCache.delete(userId, cn);
}
}
}
updateComponentStatesLocked(
jobStatus -> jobStatus.getServiceComponent().getPackageName().equals(pkg));
}
}
private void updateComponentStateForUser(final int userId) {
updateComponentStates(jobStatus -> {
// Using user ID instead of source user ID because the service will run under the
// user ID, not source user ID.
return jobStatus.getUserId() == userId;
});
synchronized (mLock) {
mServiceInfoCache.delete(userId);
updateComponentStatesLocked(jobStatus -> {
// Using user ID instead of source user ID because the service will run under the
// user ID, not source user ID.
return jobStatus.getUserId() == userId;
});
}
}
private void updateComponentStates(@NonNull Predicate<JobStatus> filter) {
synchronized (mLock) {
mComponentStateUpdateFunctor.reset();
mService.getJobStore().forEachJob(filter, mComponentStateUpdateFunctor);
if (mComponentStateUpdateFunctor.mChanged) {
mStateChangedListener.onControllerStateChanged();
}
private void updateComponentStatesLocked(@NonNull Predicate<JobStatus> filter) {
mComponentStateUpdateFunctor.reset();
mService.getJobStore().forEachJob(filter, mComponentStateUpdateFunctor);
if (mComponentStateUpdateFunctor.mChanged) {
mStateChangedListener.onControllerStateChanged();
}
}
final class ComponentStateUpdateFunctor implements Consumer<JobStatus> {
boolean mChanged;
final SparseArrayMap<ComponentName, ServiceInfo> mTempCache = new SparseArrayMap<>();
@Override
public void accept(JobStatus jobStatus) {
mChanged |= updateComponentEnabledStateLocked(jobStatus, mTempCache);
mChanged |= updateComponentEnabledStateLocked(jobStatus);
}
private void reset() {
mChanged = false;
mTempCache.clear();
}
}