OSDN Git Service

We should registerContentObserver with app's user id
authorTony Mak <tonymak@google.com>
Fri, 29 Jul 2016 10:30:47 +0000 (11:30 +0100)
committerTony Mak <tonymak@google.com>
Fri, 29 Jul 2016 22:40:54 +0000 (22:40 +0000)
Change-Id: Icef7a71f1773c102b766625271ed0156d6c59d77
Fix: 30464189

services/core/java/com/android/server/job/controllers/ContentObserverController.java

index a42d0cd..5d209fc 100644 (file)
@@ -16,6 +16,7 @@
 
 package com.android.server.job.controllers;
 
+import android.annotation.UserIdInt;
 import android.app.job.JobInfo;
 import android.content.Context;
 import android.database.ContentObserver;
@@ -23,6 +24,7 @@ import android.net.Uri;
 import android.os.Handler;
 import android.os.UserHandle;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.util.TimeUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -35,6 +37,7 @@ import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * Controller for monitoring changes to content URIs through a ContentObserver.
@@ -59,7 +62,11 @@ public class ContentObserverController extends StateController {
     private static volatile ContentObserverController sController;
 
     final private List<JobStatus> mTrackedTasks = new ArrayList<JobStatus>();
-    ArrayMap<JobInfo.TriggerContentUri, ObserverInstance> mObservers = new ArrayMap<>();
+    /**
+     * Per-userid {@link JobInfo.TriggerContentUri} keyed ContentObserver cache.
+     */
+    SparseArray<ArrayMap<JobInfo.TriggerContentUri, ObserverInstance>> mObservers =
+            new SparseArray<>();
     final Handler mHandler;
 
     public static ContentObserverController get(JobSchedulerService taskManagerService) {
@@ -203,18 +210,21 @@ public class ContentObserverController extends StateController {
 
     final class ObserverInstance extends ContentObserver {
         final JobInfo.TriggerContentUri mUri;
+        final @UserIdInt int mUserId;
         final ArraySet<JobInstance> mJobs = new ArraySet<>();
 
-        public ObserverInstance(Handler handler, JobInfo.TriggerContentUri uri) {
+        public ObserverInstance(Handler handler, JobInfo.TriggerContentUri uri,
+                @UserIdInt int userId) {
             super(handler);
             mUri = uri;
+            mUserId = userId;
         }
 
         @Override
         public void onChange(boolean selfChange, Uri uri) {
             if (DEBUG) {
                 Slog.i(TAG, "onChange(self=" + selfChange + ") for " + uri
-                        + " when mUri=" + mUri);
+                        + " when mUri=" + mUri + " mUserId=" + mUserId);
             }
             synchronized (mLock) {
                 final int N = mJobs.size();
@@ -258,27 +268,38 @@ public class ContentObserverController extends StateController {
 
         boolean mTriggerPending;
 
+        // This constructor must be called with the master job scheduler lock held.
         JobInstance(JobStatus jobStatus) {
             mJobStatus = jobStatus;
             mExecuteRunner = new TriggerRunnable(this);
             mTimeoutRunner = new TriggerRunnable(this);
             final JobInfo.TriggerContentUri[] uris = jobStatus.getJob().getTriggerContentUris();
+            final int sourceUserId = jobStatus.getSourceUserId();
+            ArrayMap<JobInfo.TriggerContentUri, ObserverInstance> observersOfUser =
+                    mObservers.get(sourceUserId);
+            if (observersOfUser == null) {
+                observersOfUser = new ArrayMap<>();
+                mObservers.put(sourceUserId, observersOfUser);
+            }
             if (uris != null) {
                 for (JobInfo.TriggerContentUri uri : uris) {
-                    ObserverInstance obs = mObservers.get(uri);
+                    ObserverInstance obs = observersOfUser.get(uri);
                     if (obs == null) {
-                        obs = new ObserverInstance(mHandler, uri);
-                        mObservers.put(uri, obs);
+                        obs = new ObserverInstance(mHandler, uri, jobStatus.getSourceUserId());
+                        observersOfUser.put(uri, obs);
                         final boolean andDescendants = (uri.getFlags() &
                                 JobInfo.TriggerContentUri.FLAG_NOTIFY_FOR_DESCENDANTS) != 0;
                         if (DEBUG) {
                             Slog.v(TAG, "New observer " + obs + " for " + uri.getUri()
-                                    + " andDescendants=" + andDescendants);
+                                    + " andDescendants=" + andDescendants
+                                    + " sourceUserId=" + sourceUserId);
                         }
                         mContext.getContentResolver().registerContentObserver(
                                 uri.getUri(),
                                 andDescendants,
-                                obs);
+                                obs,
+                                sourceUserId
+                        );
                     } else {
                         if (DEBUG) {
                             final boolean andDescendants = (uri.getFlags() &
@@ -342,7 +363,11 @@ public class ContentObserverController extends StateController {
                         Slog.i(TAG, "Unregistering observer " + obs + " for " + obs.mUri.getUri());
                     }
                     mContext.getContentResolver().unregisterContentObserver(obs);
-                    mObservers.remove(obs.mUri);
+                    ArrayMap<JobInfo.TriggerContentUri, ObserverInstance> observerOfUser =
+                            mObservers.get(obs.mUserId);
+                    if (observerOfUser !=  null) {
+                        observerOfUser.remove(obs.mUri);
+                    }
                 }
             }
         }
@@ -366,60 +391,66 @@ public class ContentObserverController extends StateController {
         int N = mObservers.size();
         if (N > 0) {
             pw.println("  Observers:");
-            for (int i = 0; i < N; i++) {
-                ObserverInstance obs = mObservers.valueAt(i);
-                int M = obs.mJobs.size();
-                boolean shouldDump = false;
-                for (int j=0; j<M; j++) {
-                    JobInstance inst = obs.mJobs.valueAt(j);
-                    if (inst.mJobStatus.shouldDump(filterUid)) {
-                        shouldDump = true;
-                        break;
-                    }
-                }
-                if (!shouldDump) {
-                    continue;
-                }
-                pw.print("    ");
-                JobInfo.TriggerContentUri trigger = mObservers.keyAt(i);
-                pw.print(trigger.getUri());
-                pw.print(" 0x");
-                pw.print(Integer.toHexString(trigger.getFlags()));
-                pw.print(" (");
-                pw.print(System.identityHashCode(obs));
-                pw.println("):");
-                pw.println("      Jobs:");
-                for (int j=0; j<M; j++) {
-                    JobInstance inst = obs.mJobs.valueAt(j);
-                    pw.print("        #");
-                    inst.mJobStatus.printUniqueId(pw);
-                    pw.print(" from ");
-                    UserHandle.formatUid(pw, inst.mJobStatus.getSourceUid());
-                    if (inst.mChangedAuthorities != null) {
-                        pw.println(":");
-                        if (inst.mTriggerPending) {
-                            pw.print("          Trigger pending: update=");
-                            TimeUtils.formatDuration(
-                                    inst.mJobStatus.getTriggerContentUpdateDelay(), pw);
-                            pw.print(", max=");
-                            TimeUtils.formatDuration(
-                                    inst.mJobStatus.getTriggerContentMaxDelay(), pw);
-                            pw.println();
-                        }
-                        pw.println("          Changed Authorities:");
-                        for (int k=0; k<inst.mChangedAuthorities.size(); k++) {
-                            pw.print("          ");
-                            pw.println(inst.mChangedAuthorities.valueAt(k));
+            for (int userIdx = 0; userIdx < N; userIdx++) {
+                final int userId = mObservers.keyAt(userIdx);
+                ArrayMap<JobInfo.TriggerContentUri, ObserverInstance> observersOfUser =
+                        mObservers.get(userId);
+                int numbOfObserversPerUser = observersOfUser.size();
+                for (int observerIdx = 0 ; observerIdx < numbOfObserversPerUser; observerIdx++) {
+                    ObserverInstance obs = observersOfUser.valueAt(observerIdx);
+                    int M = obs.mJobs.size();
+                    boolean shouldDump = false;
+                    for (int j = 0; j < M; j++) {
+                        JobInstance inst = obs.mJobs.valueAt(j);
+                        if (inst.mJobStatus.shouldDump(filterUid)) {
+                            shouldDump = true;
+                            break;
                         }
-                        if (inst.mChangedUris != null) {
-                            pw.println("          Changed URIs:");
-                            for (int k = 0; k<inst.mChangedUris.size(); k++) {
+                    }
+                    if (!shouldDump) {
+                        continue;
+                    }
+                    pw.print("    ");
+                    JobInfo.TriggerContentUri trigger = observersOfUser.keyAt(observerIdx);
+                    pw.print(trigger.getUri());
+                    pw.print(" 0x");
+                    pw.print(Integer.toHexString(trigger.getFlags()));
+                    pw.print(" (");
+                    pw.print(System.identityHashCode(obs));
+                    pw.println("):");
+                    pw.println("      Jobs:");
+                    for (int j = 0; j < M; j++) {
+                        JobInstance inst = obs.mJobs.valueAt(j);
+                        pw.print("        #");
+                        inst.mJobStatus.printUniqueId(pw);
+                        pw.print(" from ");
+                        UserHandle.formatUid(pw, inst.mJobStatus.getSourceUid());
+                        if (inst.mChangedAuthorities != null) {
+                            pw.println(":");
+                            if (inst.mTriggerPending) {
+                                pw.print("          Trigger pending: update=");
+                                TimeUtils.formatDuration(
+                                        inst.mJobStatus.getTriggerContentUpdateDelay(), pw);
+                                pw.print(", max=");
+                                TimeUtils.formatDuration(
+                                        inst.mJobStatus.getTriggerContentMaxDelay(), pw);
+                                pw.println();
+                            }
+                            pw.println("          Changed Authorities:");
+                            for (int k = 0; k < inst.mChangedAuthorities.size(); k++) {
                                 pw.print("          ");
-                                pw.println(inst.mChangedUris.valueAt(k));
+                                pw.println(inst.mChangedAuthorities.valueAt(k));
+                            }
+                            if (inst.mChangedUris != null) {
+                                pw.println("          Changed URIs:");
+                                for (int k = 0; k < inst.mChangedUris.size(); k++) {
+                                    pw.print("          ");
+                                    pw.println(inst.mChangedUris.valueAt(k));
+                                }
                             }
+                        } else {
+                            pw.println();
                         }
-                    } else {
-                        pw.println();
                     }
                 }
             }