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

Commit 7dd11099 authored by Kweku Adams's avatar Kweku Adams Committed by Android (Google) Code Review
Browse files

Merge "Exempt backup jobs for media cloud provider."

parents a47a5ae5 63e99633
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -16,7 +16,7 @@

package com.android.server.job;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.job.JobInfo;
import android.app.job.JobParameters;
import android.util.proto.ProtoOutputStream;
@@ -47,9 +47,9 @@ public interface JobSchedulerInternal {
    void removeBackingUpUid(int uid);
    void clearAllBackingUpUids();

    /** Returns the package responsible for backing up media on the device. */
    @NonNull
    String getMediaBackupPackage();
    /** Returns the package responsible for providing media from the cloud to the device. */
    @Nullable
    String getCloudMediaProviderPackage(int userId);

    /**
     * The user has started interacting with the app.  Take any appropriate action.
+74 −8
Original line number Diff line number Diff line
@@ -52,6 +52,7 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ParceledListSlice;
import android.content.pm.ProviderInfo;
import android.content.pm.ServiceInfo;
import android.net.Uri;
import android.os.BatteryManager;
@@ -70,6 +71,7 @@ import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.WorkSource;
import android.os.storage.StorageManagerInternal;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.text.format.DateUtils;
@@ -86,10 +88,10 @@ import android.util.SparseSetArray;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;

import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
import com.android.internal.os.SomeArgs;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FrameworkStatsLog;
@@ -237,6 +239,7 @@ public class JobSchedulerService extends com.android.server.SystemService
    static final int MSG_UID_ACTIVE = 6;
    static final int MSG_UID_IDLE = 7;
    static final int MSG_CHECK_CHANGED_JOB_LIST = 8;
    static final int MSG_CHECK_MEDIA_EXEMPTION = 9;

    /**
     * Track Services that have currently active or pending jobs. The index is provided by
@@ -271,8 +274,8 @@ public class JobSchedulerService extends com.android.server.SystemService
    @GuardedBy("mLock")
    private final BatteryStateTracker mBatteryStateTracker;

    @NonNull
    private final String mSystemGalleryPackage;
    @GuardedBy("mLock")
    private final SparseArray<String> mCloudMediaProviderPackages = new SparseArray<>();

    private final CountQuotaTracker mQuotaTracker;
    private static final String QUOTA_TRACKER_SCHEDULE_PERSISTED_TAG = ".schedulePersisted()";
@@ -1783,9 +1786,6 @@ public class JobSchedulerService extends com.android.server.SystemService
        mJobRestrictions = new ArrayList<>();
        mJobRestrictions.add(new ThermalStatusRestriction(this));

        mSystemGalleryPackage = Objects.requireNonNull(
                context.getString(R.string.config_systemGallery));

        // If the job store determined that it can't yet reschedule persisted jobs,
        // we need to start watching the clock.
        if (!mJobs.jobTimesInflatedValid()) {
@@ -1855,6 +1855,9 @@ public class JobSchedulerService extends com.android.server.SystemService
            mAppStateTracker = (AppStateTrackerImpl) Objects.requireNonNull(
                    LocalServices.getService(AppStateTracker.class));

            LocalServices.getService(StorageManagerInternal.class)
                    .registerCloudProviderChangeListener(new CloudProviderChangeListener());

            // Register br for package removals and user removals.
            final IntentFilter filter = new IntentFilter();
            filter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
@@ -2353,6 +2356,15 @@ public class JobSchedulerService extends com.android.server.SystemService
                        break;
                    }

                    case MSG_CHECK_MEDIA_EXEMPTION: {
                        final SomeArgs args = (SomeArgs) message.obj;
                        synchronized (mLock) {
                            updateMediaBackupExemptionLocked(
                                    args.argi1, (String) args.arg1, (String) args.arg2);
                        }
                        args.recycle();
                        break;
                    }
                }
                maybeRunPendingJobsLocked();
            }
@@ -2649,12 +2661,31 @@ public class JobSchedulerService extends com.android.server.SystemService
        if (DEBUG) {
            Slog.d(TAG, "Check changed jobs...");
        }
        if (mChangedJobList.size() == 0) {
            return;
        }

        mChangedJobList.forEach(mMaybeQueueFunctor);
        mMaybeQueueFunctor.postProcessLocked();
        mChangedJobList.clear();
    }

    @GuardedBy("mLock")
    private void updateMediaBackupExemptionLocked(int userId, @Nullable String oldPkg,
            @Nullable String newPkg) {
        final Predicate<JobStatus> shouldProcessJob =
                (job) -> job.getSourceUserId() == userId
                        && (job.getSourcePackageName().equals(oldPkg)
                        || job.getSourcePackageName().equals(newPkg));
        mJobs.forEachJob(shouldProcessJob,
                (job) -> {
                    if (job.updateMediaBackupExemptionStatus()) {
                        mChangedJobList.add(job);
                    }
                });
        mHandler.sendEmptyMessage(MSG_CHECK_CHANGED_JOB_LIST);
    }

    /** Returns true if both the calling and source users for the job are started. */
    @GuardedBy("mLock")
    public boolean areUsersStartedLocked(final JobStatus job) {
@@ -3050,8 +3081,8 @@ public class JobSchedulerService extends com.android.server.SystemService
        }

        @Override
        public String getMediaBackupPackage() {
            return mSystemGalleryPackage;
        public String getCloudMediaProviderPackage(int userId) {
            return mCloudMediaProviderPackages.get(userId);
        }

        @Override
@@ -3159,6 +3190,35 @@ public class JobSchedulerService extends com.android.server.SystemService
        return bucket;
    }

    private class CloudProviderChangeListener implements
            StorageManagerInternal.CloudProviderChangeListener {

        @Override
        public void onCloudProviderChanged(int userId, @Nullable String authority) {
            final PackageManager pm = getContext()
                    .createContextAsUser(UserHandle.of(userId), 0)
                    .getPackageManager();
            final ProviderInfo pi = pm.resolveContentProvider(
                    authority, PackageManager.ComponentInfoFlags.of(0));
            final String newPkg = (pi == null) ? null : pi.packageName;
            synchronized (mLock) {
                final String oldPkg = mCloudMediaProviderPackages.get(userId);
                if (!Objects.equals(oldPkg, newPkg)) {
                    if (DEBUG) {
                        Slog.d(TAG, "Cloud provider of user " + userId + " changed from " + oldPkg
                                + " to " + newPkg);
                    }
                    mCloudMediaProviderPackages.put(userId, newPkg);
                    SomeArgs args = SomeArgs.obtain();
                    args.argi1 = userId;
                    args.arg1 = oldPkg;
                    args.arg2 = newPkg;
                    mHandler.obtainMessage(MSG_CHECK_MEDIA_EXEMPTION, args).sendToTarget();
                }
            }
        }
    }

    /**
     * Binder stub trampoline implementation
     */
@@ -3799,6 +3859,12 @@ public class JobSchedulerService extends com.android.server.SystemService
            pw.println();

            pw.println("Started users: " + Arrays.toString(mStartedUsers));
            pw.println();

            pw.print("Media Cloud Providers: ");
            pw.println(mCloudMediaProviderPackages);
            pw.println();

            pw.print("Registered ");
            pw.print(mJobs.size());
            pw.println(" jobs:");
+24 −9
Original line number Diff line number Diff line
@@ -261,11 +261,9 @@ public final class JobStatus {
     *
     * Doesn't exempt jobs with a deadline constraint, as they can be started without any content or
     * network changes, in which case this exemption does not make sense.
     *
     * TODO(b/149519887): Use a more explicit signal, maybe an API flag, that the scheduling package
     * needs to provide at the time of scheduling a job.
     */
    private final boolean mHasMediaBackupExemption;
    private boolean mHasMediaBackupExemption;
    private final boolean mHasExemptedMediaUrisOnly;

    // Set to true if doze constraint was satisfied due to app being whitelisted.
    boolean appHasDozeExemption;
@@ -508,11 +506,9 @@ public final class JobStatus {
        this.mOriginalLatestRunTimeElapsedMillis = latestRunTimeElapsedMillis;
        this.numFailures = numFailures;

        boolean requiresNetwork = false;
        int requiredConstraints = job.getConstraintFlags();
        if (job.getRequiredNetwork() != null) {
            requiredConstraints |= CONSTRAINT_CONNECTIVITY;
            requiresNetwork = true;
        }
        if (earliestRunTimeElapsedMillis != NO_EARLIEST_RUNTIME) {
            requiredConstraints |= CONSTRAINT_TIMING_DELAY;
@@ -531,6 +527,7 @@ public final class JobStatus {
                }
            }
        }
        mHasExemptedMediaUrisOnly = exemptedMediaUrisOnly;
        this.requiredConstraints = requiredConstraints;
        mRequiredConstraintsOfInterest = requiredConstraints & CONSTRAINTS_OF_INTEREST;
        addDynamicConstraints(dynamicConstraints);
@@ -563,9 +560,7 @@ public final class JobStatus {
            job = builder.build(false);
        }

        final JobSchedulerInternal jsi = LocalServices.getService(JobSchedulerInternal.class);
        mHasMediaBackupExemption = !job.hasLateConstraint() && exemptedMediaUrisOnly
                && requiresNetwork && this.sourcePackageName.equals(jsi.getMediaBackupPackage());
        updateMediaBackupExemptionStatus();
    }

    /** Copy constructor: used specifically when cloning JobStatus objects for persistence,
@@ -914,6 +909,25 @@ public final class JobStatus {
        mFirstForceBatchedTimeElapsed = now;
    }

    /**
     * Re-evaluates the media backup exemption status.
     *
     * @return true if the exemption status changed
     */
    public boolean updateMediaBackupExemptionStatus() {
        final JobSchedulerInternal jsi = LocalServices.getService(JobSchedulerInternal.class);
        boolean hasMediaExemption = mHasExemptedMediaUrisOnly
                && !job.hasLateConstraint()
                && job.getRequiredNetwork() != null
                && getEffectivePriority() >= JobInfo.PRIORITY_DEFAULT
                && sourcePackageName.equals(jsi.getCloudMediaProviderPackage(sourceUserId));
        if (mHasMediaBackupExemption == hasMediaExemption) {
            return false;
        }
        mHasMediaBackupExemption = hasMediaExemption;
        return true;
    }

    public String getSourceTag() {
        return sourceTag;
    }
@@ -2027,6 +2041,7 @@ public final class JobStatus {
                    TimeUtils.formatDuration(job.getTriggerContentMaxDelay(), pw);
                    pw.println();
                }
                pw.print("Has media backup exemption", mHasMediaBackupExemption).println();
            }
            if (job.getExtras() != null && !job.getExtras().isDefinitelyEmpty()) {
                pw.print("Extras: ");
+1 −0
Original line number Diff line number Diff line
@@ -415,6 +415,7 @@ package android.os.storage {
    method public long computeStorageCacheBytes(@NonNull java.io.File);
    method public void notifyAppIoBlocked(@NonNull java.util.UUID, int, int, int);
    method public void notifyAppIoResumed(@NonNull java.util.UUID, int, int, int);
    method public void setCloudMediaProvider(@Nullable String);
    field public static final int APP_IO_BLOCKED_REASON_TRANSCODING = 1; // 0x1
    field public static final int APP_IO_BLOCKED_REASON_UNKNOWN = 0; // 0x0
  }
+1 −0
Original line number Diff line number Diff line
@@ -1967,6 +1967,7 @@ package android.os.storage {
    method public long computeStorageCacheBytes(@NonNull java.io.File);
    method @NonNull public static java.util.UUID convert(@NonNull String);
    method @NonNull public static String convert(@NonNull java.util.UUID);
    method @Nullable public String getCloudMediaProvider();
    method public boolean isAppIoBlocked(@NonNull java.util.UUID, int, int, int);
    method public static boolean isUserKeyUnlocked(int);
    field public static final String CACHE_RESERVE_PERCENT_HIGH_KEY = "cache_reserve_percent_high";
Loading