Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a9d0dfcd authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Clean up ComponentController and fix some bugs." into sc-dev

parents 69f97fa1 d9701f80
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -2234,7 +2234,8 @@ public class JobSchedulerService extends com.android.server.SystemService
    }

    /** Returns true if both the calling and source users for the job are started. */
    private boolean areUsersStartedLocked(final JobStatus job) {
    @GuardedBy("mLock")
    public boolean areUsersStartedLocked(final JobStatus job) {
        boolean sourceStarted = ArrayUtils.contains(mStartedUsers, job.getSourceUserId());
        if (job.getUserId() == job.getSourceUserId()) {
            return sourceStarted;
+93 −29
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ import android.util.Slog;
import android.util.SparseArrayMap;
import android.util.proto.ProtoOutputStream;

import com.android.internal.annotations.GuardedBy;
import com.android.server.job.JobSchedulerService;

import java.util.Objects;
@@ -58,13 +59,28 @@ public class ComponentController extends StateController {
                return;
            }
            switch (action) {
                case Intent.ACTION_PACKAGE_ADDED:
                    if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
                        // Only do this for app updates since new installs won't have any jobs
                        // scheduled.
                        final Uri uri = intent.getData();
                        final String pkg = uri != null ? uri.getSchemeSpecificPart() : null;
                        if (pkg != null) {
                            final int pkgUid = intent.getIntExtra(Intent.EXTRA_UID, -1);
                            final int userId = UserHandle.getUserId(pkgUid);
                            updateComponentStateForPackage(userId, pkg);
                        }
                    }
                    break;
                case Intent.ACTION_PACKAGE_CHANGED:
                    final Uri uri = intent.getData();
                    final String pkg = uri != null ? uri.getSchemeSpecificPart() : null;
                    final String[] changedComponents = intent.getStringArrayExtra(
                            Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST);
                    if (pkg != null && changedComponents != null && changedComponents.length > 0) {
                        updateComponentStateForPackage(pkg);
                        final int pkgUid = intent.getIntExtra(Intent.EXTRA_UID, -1);
                        final int userId = UserHandle.getUserId(pkgUid);
                        updateComponentStateForPackage(userId, pkg);
                    }
                    break;
                case Intent.ACTION_USER_UNLOCKED:
@@ -86,6 +102,7 @@ public class ComponentController extends StateController {
        super(service);

        final IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_PACKAGE_ADDED);
        filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
        filter.addDataScheme("package");
        mContext.registerReceiverAsUser(
@@ -99,6 +116,7 @@ public class ComponentController extends StateController {
    }

    @Override
    @GuardedBy("mLock")
    public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
        updateComponentEnabledStateLocked(jobStatus);
    }
@@ -108,12 +126,30 @@ public class ComponentController extends StateController {
            boolean forUpdate) {
    }

    @Override
    @GuardedBy("mLock")
    public void onAppRemovedLocked(String packageName, int uid) {
        clearComponentsForPackageLocked(UserHandle.getUserId(uid), packageName);
    }

    @Override
    @GuardedBy("mLock")
    public void onUserRemovedLocked(int userId) {
        mServiceInfoCache.delete(userId);
    }

    @Nullable
    private ServiceInfo getServiceInfo(JobStatus jobStatus) {
    @GuardedBy("mLock")
    private ServiceInfo getServiceInfoLocked(JobStatus jobStatus) {
        final ComponentName service = jobStatus.getServiceComponent();
        final int userId = jobStatus.getUserId();
        ServiceInfo si = mServiceInfoCache.get(userId, service);
        if (si == null) {
        if (mServiceInfoCache.contains(userId, service)) {
            // Return whatever is in the cache, even if it's null. When something changes, we
            // clear the cache.
            return mServiceInfoCache.get(userId, service);
        }

        ServiceInfo si;
        try {
            // createContextAsUser may potentially be expensive
            // TODO: cache user context or improve ContextImpl implementation if this becomes
@@ -122,16 +158,21 @@ public class ComponentController extends StateController {
                    .getPackageManager()
                    .getServiceInfo(service, PackageManager.MATCH_DIRECT_BOOT_AUTO);
        } catch (NameNotFoundException e) {
            if (mService.areUsersStartedLocked(jobStatus)) {
                // User is fully unlocked but PM still says the package doesn't exist.
                Slog.e(TAG, "Job exists for non-existent package: " + service.getPackageName());
                return null;
            }
            mServiceInfoCache.add(userId, service, si);
            // Write null to the cache so we don't keep querying PM.
            si = null;
        }
        mServiceInfoCache.add(userId, service, si);

        return si;
    }

    @GuardedBy("mLock")
    private boolean updateComponentEnabledStateLocked(JobStatus jobStatus) {
        final ServiceInfo service = getServiceInfo(jobStatus);
        final ServiceInfo service = getServiceInfoLocked(jobStatus);

        if (DEBUG && service == null) {
            Slog.v(TAG, jobStatus.toShortString() + " component not present");
@@ -141,20 +182,26 @@ public class ComponentController extends StateController {
        return !Objects.equals(ogService, service);
    }

    private void updateComponentStateForPackage(final String pkg) {
        synchronized (mLock) {
            for (int u = mServiceInfoCache.numMaps() - 1; u >= 0; --u) {
                final int userId = mServiceInfoCache.keyAt(u);

    @GuardedBy("mLock")
    private void clearComponentsForPackageLocked(final int userId, final String pkg) {
        final int uIdx = mServiceInfoCache.indexOfKey(userId);
        for (int c = mServiceInfoCache.numElementsForKey(userId) - 1; c >= 0; --c) {
                    final ComponentName cn = mServiceInfoCache.keyAt(u, c);
            final ComponentName cn = mServiceInfoCache.keyAt(uIdx, c);
            if (cn.getPackageName().equals(pkg)) {
                mServiceInfoCache.delete(userId, cn);
            }
        }
    }
            updateComponentStatesLocked(
                    jobStatus -> jobStatus.getServiceComponent().getPackageName().equals(pkg));

    private void updateComponentStateForPackage(final int userId, final String pkg) {
        synchronized (mLock) {
            clearComponentsForPackageLocked(userId, pkg);
            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
                        && jobStatus.getServiceComponent().getPackageName().equals(pkg);
            });
        }
    }

@@ -169,6 +216,7 @@ public class ComponentController extends StateController {
        }
    }

    @GuardedBy("mLock")
    private void updateComponentStatesLocked(@NonNull Predicate<JobStatus> filter) {
        mComponentStateUpdateFunctor.reset();
        mService.getJobStore().forEachJob(filter, mComponentStateUpdateFunctor);
@@ -178,24 +226,40 @@ public class ComponentController extends StateController {
    }

    final class ComponentStateUpdateFunctor implements Consumer<JobStatus> {
        @GuardedBy("mLock")
        boolean mChanged;

        @Override
        @GuardedBy("mLock")
        public void accept(JobStatus jobStatus) {
            mChanged |= updateComponentEnabledStateLocked(jobStatus);
        }

        @GuardedBy("mLock")
        private void reset() {
            mChanged = false;
        }
    }

    @Override
    @GuardedBy("mLock")
    public void dumpControllerStateLocked(IndentingPrintWriter pw, Predicate<JobStatus> predicate) {

        for (int u = 0; u < mServiceInfoCache.numMaps(); ++u) {
            final int userId = mServiceInfoCache.keyAt(u);
            for (int p = 0; p < mServiceInfoCache.numElementsForKey(userId); ++p) {
                final ComponentName componentName = mServiceInfoCache.keyAt(u, p);
                pw.print(userId);
                pw.print("-");
                pw.print(componentName);
                pw.print(": ");
                pw.print(mServiceInfoCache.valueAt(u, p));
                pw.println();
            }
        }
    }

    @Override
    @GuardedBy("mLock")
    public void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId,
            Predicate<JobStatus> predicate) {