OSDN Git Service

SyncManager: detect suspicious periodic sync removal.
[android-x86/frameworks-base.git] / services / core / java / com / android / server / content / ContentService.java
1 /*
2  * Copyright (C) 2006 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package com.android.server.content;
18
19 import android.Manifest;
20 import android.accounts.Account;
21 import android.annotation.Nullable;
22 import android.app.ActivityManager;
23 import android.app.ActivityManagerInternal;
24 import android.app.AppOpsManager;
25 import android.app.job.JobInfo;
26 import android.content.BroadcastReceiver;
27 import android.content.ComponentName;
28 import android.content.ContentResolver;
29 import android.content.Context;
30 import android.content.IContentService;
31 import android.content.ISyncStatusObserver;
32 import android.content.Intent;
33 import android.content.IntentFilter;
34 import android.content.PeriodicSync;
35 import android.content.SyncAdapterType;
36 import android.content.SyncInfo;
37 import android.content.SyncRequest;
38 import android.content.SyncStatusInfo;
39 import android.content.pm.PackageManager;
40 import android.content.pm.PackageManagerInternal;
41 import android.content.pm.ProviderInfo;
42 import android.database.IContentObserver;
43 import android.database.sqlite.SQLiteException;
44 import android.net.Uri;
45 import android.os.Binder;
46 import android.os.Build;
47 import android.os.Bundle;
48 import android.os.FactoryTest;
49 import android.os.IBinder;
50 import android.os.Parcel;
51 import android.os.RemoteException;
52 import android.os.SystemProperties;
53 import android.os.UserHandle;
54 import android.text.TextUtils;
55 import android.util.ArrayMap;
56 import android.util.Log;
57 import android.util.Pair;
58 import android.util.Slog;
59 import android.util.SparseArray;
60 import android.util.SparseIntArray;
61
62 import com.android.internal.annotations.GuardedBy;
63 import com.android.internal.util.ArrayUtils;
64 import com.android.internal.util.DumpUtils;
65 import com.android.internal.util.IndentingPrintWriter;
66 import com.android.server.LocalServices;
67 import com.android.server.SystemService;
68
69 import java.io.FileDescriptor;
70 import java.io.PrintWriter;
71 import java.util.ArrayList;
72 import java.util.Collections;
73 import java.util.Comparator;
74 import java.util.List;
75
76 /**
77  * {@hide}
78  */
79 public final class ContentService extends IContentService.Stub {
80     static final String TAG = "ContentService";
81     static final boolean DEBUG = false;
82
83     public static class Lifecycle extends SystemService {
84         private ContentService mService;
85
86         public Lifecycle(Context context) {
87             super(context);
88         }
89
90         @Override
91         public void onStart() {
92             final boolean factoryTest = (FactoryTest
93                     .getMode() == FactoryTest.FACTORY_TEST_LOW_LEVEL);
94             mService = new ContentService(getContext(), factoryTest);
95             publishBinderService(ContentResolver.CONTENT_SERVICE_NAME, mService);
96         }
97
98         @Override
99         public void onBootPhase(int phase) {
100             if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
101                 mService.systemReady();
102             }
103         }
104
105
106         @Override
107         public void onStartUser(int userHandle) {
108             mService.onStartUser(userHandle);
109         }
110
111         @Override
112         public void onUnlockUser(int userHandle) {
113             mService.onUnlockUser(userHandle);
114         }
115
116         @Override
117         public void onStopUser(int userHandle) {
118             mService.onStopUser(userHandle);
119         }
120
121         @Override
122         public void onCleanupUser(int userHandle) {
123             synchronized (mService.mCache) {
124                 mService.mCache.remove(userHandle);
125             }
126         }
127     }
128
129     private Context mContext;
130     private boolean mFactoryTest;
131
132     private final ObserverNode mRootNode = new ObserverNode("");
133
134     private SyncManager mSyncManager = null;
135     private final Object mSyncManagerLock = new Object();
136
137     /**
138      * Map from userId to providerPackageName to [clientPackageName, uri] to
139      * value. This structure is carefully optimized to keep invalidation logic
140      * as cheap as possible.
141      */
142     @GuardedBy("mCache")
143     private final SparseArray<ArrayMap<String, ArrayMap<Pair<String, Uri>, Bundle>>>
144             mCache = new SparseArray<>();
145
146     private BroadcastReceiver mCacheReceiver = new BroadcastReceiver() {
147         @Override
148         public void onReceive(Context context, Intent intent) {
149             synchronized (mCache) {
150                 if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
151                     mCache.clear();
152                 } else {
153                     final Uri data = intent.getData();
154                     if (data != null) {
155                         final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
156                                 UserHandle.USER_NULL);
157                         final String packageName = data.getSchemeSpecificPart();
158                         invalidateCacheLocked(userId, packageName, null);
159                     }
160                 }
161             }
162         }
163     };
164
165     private SyncManager getSyncManager() {
166         if (SystemProperties.getBoolean("config.disable_network", false)) {
167             return null;
168         }
169
170         synchronized(mSyncManagerLock) {
171             try {
172                 // Try to create the SyncManager, return null if it fails (e.g. the disk is full).
173                 if (mSyncManager == null) mSyncManager = new SyncManager(mContext, mFactoryTest);
174             } catch (SQLiteException e) {
175                 Log.e(TAG, "Can't create SyncManager", e);
176             }
177             return mSyncManager;
178         }
179     }
180
181     void onStartUser(int userHandle) {
182         if (mSyncManager != null) mSyncManager.onStartUser(userHandle);
183     }
184
185     void onUnlockUser(int userHandle) {
186         if (mSyncManager != null) mSyncManager.onUnlockUser(userHandle);
187     }
188
189     void onStopUser(int userHandle) {
190         if (mSyncManager != null) mSyncManager.onStopUser(userHandle);
191     }
192
193     @Override
194     protected synchronized void dump(FileDescriptor fd, PrintWriter pw_, String[] args) {
195         if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw_)) return;
196         final IndentingPrintWriter pw = new IndentingPrintWriter(pw_, "  ");
197
198         final boolean dumpAll = ArrayUtils.contains(args, "-a");
199
200         // This makes it so that future permission checks will be in the context of this
201         // process rather than the caller's process. We will restore this before returning.
202         final long identityToken = clearCallingIdentity();
203         try {
204             if (mSyncManager == null) {
205                 pw.println("No SyncManager created!  (Disk full?)");
206             } else {
207                 mSyncManager.dump(fd, pw, dumpAll);
208             }
209             pw.println();
210             pw.println("Observer tree:");
211             synchronized (mRootNode) {
212                 int[] counts = new int[2];
213                 final SparseIntArray pidCounts = new SparseIntArray();
214                 mRootNode.dumpLocked(fd, pw, args, "", "  ", counts, pidCounts);
215                 pw.println();
216                 ArrayList<Integer> sorted = new ArrayList<Integer>();
217                 for (int i=0; i<pidCounts.size(); i++) {
218                     sorted.add(pidCounts.keyAt(i));
219                 }
220                 Collections.sort(sorted, new Comparator<Integer>() {
221                     @Override
222                     public int compare(Integer lhs, Integer rhs) {
223                         int lc = pidCounts.get(lhs);
224                         int rc = pidCounts.get(rhs);
225                         if (lc < rc) {
226                             return 1;
227                         } else if (lc > rc) {
228                             return -1;
229                         }
230                         return 0;
231                     }
232
233                 });
234                 for (int i=0; i<sorted.size(); i++) {
235                     int pid = sorted.get(i);
236                     pw.print("  pid "); pw.print(pid); pw.print(": ");
237                     pw.print(pidCounts.get(pid)); pw.println(" observers");
238                 }
239                 pw.println();
240                 pw.print(" Total number of nodes: "); pw.println(counts[0]);
241                 pw.print(" Total number of observers: "); pw.println(counts[1]);
242             }
243
244             synchronized (mCache) {
245                 pw.println();
246                 pw.println("Cached content:");
247                 pw.increaseIndent();
248                 for (int i = 0; i < mCache.size(); i++) {
249                     pw.println("User " + mCache.keyAt(i) + ":");
250                     pw.increaseIndent();
251                     pw.println(mCache.valueAt(i));
252                     pw.decreaseIndent();
253                 }
254                 pw.decreaseIndent();
255             }
256         } finally {
257             restoreCallingIdentity(identityToken);
258         }
259     }
260
261     @Override
262     public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
263             throws RemoteException {
264         try {
265             return super.onTransact(code, data, reply, flags);
266         } catch (RuntimeException e) {
267             // The content service only throws security exceptions, so let's
268             // log all others.
269             if (!(e instanceof SecurityException)) {
270                 Slog.wtf(TAG, "Content Service Crash", e);
271             }
272             throw e;
273         }
274     }
275
276     /*package*/ ContentService(Context context, boolean factoryTest) {
277         mContext = context;
278         mFactoryTest = factoryTest;
279
280         // Let the package manager query for the sync adapters for a given authority
281         // as we grant default permissions to sync adapters for specific authorities.
282         PackageManagerInternal packageManagerInternal = LocalServices.getService(
283                 PackageManagerInternal.class);
284         packageManagerInternal.setSyncAdapterPackagesprovider(
285                 new PackageManagerInternal.SyncAdapterPackagesProvider() {
286                     @Override
287                     public String[] getPackages(String authority, int userId) {
288                         return getSyncAdapterPackagesForAuthorityAsUser(authority, userId);
289                     }
290                 });
291
292         final IntentFilter packageFilter = new IntentFilter();
293         packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
294         packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
295         packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
296         packageFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED);
297         packageFilter.addDataScheme("package");
298         mContext.registerReceiverAsUser(mCacheReceiver, UserHandle.ALL,
299                 packageFilter, null, null);
300
301         final IntentFilter localeFilter = new IntentFilter();
302         localeFilter.addAction(Intent.ACTION_LOCALE_CHANGED);
303         mContext.registerReceiverAsUser(mCacheReceiver, UserHandle.ALL,
304                 localeFilter, null, null);
305     }
306
307     void systemReady() {
308         getSyncManager();
309     }
310
311     /**
312      * Register a content observer tied to a specific user's view of the provider.
313      * @param userHandle the user whose view of the provider is to be observed.  May be
314      *     the calling user without requiring any permission, otherwise the caller needs to
315      *     hold the INTERACT_ACROSS_USERS_FULL permission or hold a read uri grant to the uri.
316      *     Pseudousers USER_ALL and USER_CURRENT are properly handled; all other pseudousers
317      *     are forbidden.
318      */
319     @Override
320     public void registerContentObserver(Uri uri, boolean notifyForDescendants,
321             IContentObserver observer, int userHandle, int targetSdkVersion) {
322         if (observer == null || uri == null) {
323             throw new IllegalArgumentException("You must pass a valid uri and observer");
324         }
325
326         final int uid = Binder.getCallingUid();
327         final int pid = Binder.getCallingPid();
328
329         userHandle = handleIncomingUser(uri, pid, uid,
330                 Intent.FLAG_GRANT_READ_URI_PERMISSION, true, userHandle);
331
332         final String msg = LocalServices.getService(ActivityManagerInternal.class)
333                 .checkContentProviderAccess(uri.getAuthority(), userHandle);
334         if (msg != null) {
335             if (targetSdkVersion >= Build.VERSION_CODES.O) {
336                 throw new SecurityException(msg);
337             } else {
338                 if (msg.startsWith("Failed to find provider")) {
339                     // Sigh, we need to quietly let apps targeting older API
340                     // levels notify on non-existent providers.
341                 } else {
342                     Log.w(TAG, "Ignoring content changes for " + uri + " from " + uid + ": " + msg);
343                     return;
344                 }
345             }
346         }
347
348         synchronized (mRootNode) {
349             mRootNode.addObserverLocked(uri, observer, notifyForDescendants, mRootNode,
350                     uid, pid, userHandle);
351             if (false) Log.v(TAG, "Registered observer " + observer + " at " + uri +
352                     " with notifyForDescendants " + notifyForDescendants);
353         }
354     }
355
356     public void registerContentObserver(Uri uri, boolean notifyForDescendants,
357                                         IContentObserver observer) {
358         registerContentObserver(uri, notifyForDescendants, observer,
359                 UserHandle.getCallingUserId(), Build.VERSION_CODES.CUR_DEVELOPMENT);
360     }
361
362     @Override
363     public void unregisterContentObserver(IContentObserver observer) {
364         if (observer == null) {
365             throw new IllegalArgumentException("You must pass a valid observer");
366         }
367         synchronized (mRootNode) {
368             mRootNode.removeObserverLocked(observer);
369             if (false) Log.v(TAG, "Unregistered observer " + observer);
370         }
371     }
372
373     /**
374      * Notify observers of a particular user's view of the provider.
375      * @param userHandle the user whose view of the provider is to be notified.  May be
376      *     the calling user without requiring any permission, otherwise the caller needs to
377      *     hold the INTERACT_ACROSS_USERS_FULL permission or hold a write uri grant to the uri.
378      *     Pseudousers USER_ALL and USER_CURRENT are properly interpreted; no other pseudousers are
379      *     allowed.
380      */
381     @Override
382     public void notifyChange(Uri uri, IContentObserver observer,
383             boolean observerWantsSelfNotifications, int flags, int userHandle,
384             int targetSdkVersion) {
385         if (DEBUG) Slog.d(TAG, "Notifying update of " + uri + " for user " + userHandle
386                 + " from observer " + observer + ", flags " + Integer.toHexString(flags));
387
388         if (uri == null) {
389             throw new NullPointerException("Uri must not be null");
390         }
391
392         final int uid = Binder.getCallingUid();
393         final int pid = Binder.getCallingPid();
394         final int callingUserHandle = UserHandle.getCallingUserId();
395
396         userHandle = handleIncomingUser(uri, pid, uid,
397                 Intent.FLAG_GRANT_WRITE_URI_PERMISSION, true, userHandle);
398
399         final String msg = LocalServices.getService(ActivityManagerInternal.class)
400                 .checkContentProviderAccess(uri.getAuthority(), userHandle);
401         if (msg != null) {
402             if (targetSdkVersion >= Build.VERSION_CODES.O) {
403                 throw new SecurityException(msg);
404             } else {
405                 if (msg.startsWith("Failed to find provider")) {
406                     // Sigh, we need to quietly let apps targeting older API
407                     // levels notify on non-existent providers.
408                 } else {
409                     Log.w(TAG, "Ignoring notify for " + uri + " from " + uid + ": " + msg);
410                     return;
411                 }
412             }
413         }
414
415         // This makes it so that future permission checks will be in the context of this
416         // process rather than the caller's process. We will restore this before returning.
417         long identityToken = clearCallingIdentity();
418         try {
419             ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>();
420             synchronized (mRootNode) {
421                 mRootNode.collectObserversLocked(uri, 0, observer, observerWantsSelfNotifications,
422                         flags, userHandle, calls);
423             }
424             final int numCalls = calls.size();
425             for (int i=0; i<numCalls; i++) {
426                 ObserverCall oc = calls.get(i);
427                 try {
428                     oc.mObserver.onChange(oc.mSelfChange, uri, userHandle);
429                     if (DEBUG) Slog.d(TAG, "Notified " + oc.mObserver + " of " + "update at "
430                             + uri);
431                 } catch (RemoteException ex) {
432                     synchronized (mRootNode) {
433                         Log.w(TAG, "Found dead observer, removing");
434                         IBinder binder = oc.mObserver.asBinder();
435                         final ArrayList<ObserverNode.ObserverEntry> list
436                                 = oc.mNode.mObservers;
437                         int numList = list.size();
438                         for (int j=0; j<numList; j++) {
439                             ObserverNode.ObserverEntry oe = list.get(j);
440                             if (oe.observer.asBinder() == binder) {
441                                 list.remove(j);
442                                 j--;
443                                 numList--;
444                             }
445                         }
446                     }
447                 }
448             }
449             if ((flags&ContentResolver.NOTIFY_SYNC_TO_NETWORK) != 0) {
450                 SyncManager syncManager = getSyncManager();
451                 if (syncManager != null) {
452                     syncManager.scheduleLocalSync(null /* all accounts */, callingUserHandle, uid,
453                             uri.getAuthority());
454                 }
455             }
456
457             synchronized (mCache) {
458                 final String providerPackageName = getProviderPackageName(uri);
459                 invalidateCacheLocked(userHandle, providerPackageName, uri);
460             }
461         } finally {
462             restoreCallingIdentity(identityToken);
463         }
464     }
465
466     private int checkUriPermission(Uri uri, int pid, int uid, int modeFlags, int userHandle) {
467         try {
468             return ActivityManager.getService().checkUriPermission(
469                     uri, pid, uid, modeFlags, userHandle, null);
470         } catch (RemoteException e) {
471             return PackageManager.PERMISSION_DENIED;
472         }
473     }
474
475     public void notifyChange(Uri uri, IContentObserver observer,
476                              boolean observerWantsSelfNotifications, boolean syncToNetwork) {
477         notifyChange(uri, observer, observerWantsSelfNotifications,
478                 syncToNetwork ? ContentResolver.NOTIFY_SYNC_TO_NETWORK : 0,
479                 UserHandle.getCallingUserId(), Build.VERSION_CODES.CUR_DEVELOPMENT);
480     }
481
482     /**
483      * Hide this class since it is not part of api,
484      * but current unittest framework requires it to be public
485      * @hide
486      *
487      */
488     public static final class ObserverCall {
489         final ObserverNode mNode;
490         final IContentObserver mObserver;
491         final boolean mSelfChange;
492         final int mObserverUserId;
493
494         ObserverCall(ObserverNode node, IContentObserver observer, boolean selfChange, int observerUserId) {
495             mNode = node;
496             mObserver = observer;
497             mSelfChange = selfChange;
498             mObserverUserId = observerUserId;
499         }
500     }
501
502     @Override
503     public void requestSync(Account account, String authority, Bundle extras) {
504         Bundle.setDefusable(extras, true);
505         ContentResolver.validateSyncExtrasBundle(extras);
506         int userId = UserHandle.getCallingUserId();
507         int uId = Binder.getCallingUid();
508
509         // This makes it so that future permission checks will be in the context of this
510         // process rather than the caller's process. We will restore this before returning.
511         long identityToken = clearCallingIdentity();
512         try {
513             SyncManager syncManager = getSyncManager();
514             if (syncManager != null) {
515                 syncManager.scheduleSync(account, userId, uId, authority, extras,
516                         SyncStorageEngine.AuthorityInfo.UNDEFINED);
517             }
518         } finally {
519             restoreCallingIdentity(identityToken);
520         }
521     }
522
523     /**
524      * Request a sync with a generic {@link android.content.SyncRequest} object. This will be
525      * either:
526      *   periodic OR one-off sync.
527      * and
528      *   anonymous OR provider sync.
529      * Depending on the request, we enqueue to suit in the SyncManager.
530      * @param request The request object. Validation of this object is done by its builder.
531      */
532     @Override
533     public void sync(SyncRequest request) {
534         syncAsUser(request, UserHandle.getCallingUserId());
535     }
536
537     private long clampPeriod(long period) {
538         long minPeriod = JobInfo.getMinPeriodMillis() / 1000;
539         if (period < minPeriod) {
540             Slog.w(TAG, "Requested poll frequency of " + period
541                     + " seconds being rounded up to " + minPeriod + "s.");
542             period = minPeriod;
543         }
544         return period;
545     }
546
547     /**
548      * If the user id supplied is different to the calling user, the caller must hold the
549      * INTERACT_ACROSS_USERS_FULL permission.
550      */
551     @Override
552     public void syncAsUser(SyncRequest request, int userId) {
553         enforceCrossUserPermission(userId, "no permission to request sync as user: " + userId);
554         int callerUid = Binder.getCallingUid();
555         // This makes it so that future permission checks will be in the context of this
556         // process rather than the caller's process. We will restore this before returning.
557         long identityToken = clearCallingIdentity();
558         try {
559             SyncManager syncManager = getSyncManager();
560             if (syncManager == null) {
561                 return;
562             }
563
564             Bundle extras = request.getBundle();
565             long flextime = request.getSyncFlexTime();
566             long runAtTime = request.getSyncRunTime();
567             if (request.isPeriodic()) {
568                 mContext.enforceCallingOrSelfPermission(
569                         Manifest.permission.WRITE_SYNC_SETTINGS,
570                         "no permission to write the sync settings");
571                 SyncStorageEngine.EndPoint info;
572                 info = new SyncStorageEngine.EndPoint(
573                         request.getAccount(), request.getProvider(), userId);
574
575                 runAtTime = clampPeriod(runAtTime);
576                 // Schedule periodic sync.
577                 getSyncManager().updateOrAddPeriodicSync(info, runAtTime,
578                         flextime, extras);
579             } else {
580                 syncManager.scheduleSync(
581                         request.getAccount(), userId, callerUid, request.getProvider(), extras,
582                         SyncStorageEngine.AuthorityInfo.UNDEFINED);
583             }
584         } finally {
585             restoreCallingIdentity(identityToken);
586         }
587     }
588
589     /**
590      * Clear all scheduled sync operations that match the uri and cancel the active sync
591      * if they match the authority and account, if they are present.
592      *
593      * @param account filter the pending and active syncs to cancel using this account, or null.
594      * @param authority filter the pending and active syncs to cancel using this authority, or
595      * null.
596      * @param cname cancel syncs running on this service, or null for provider/account.
597      */
598     @Override
599     public void cancelSync(Account account, String authority, ComponentName cname) {
600         cancelSyncAsUser(account, authority, cname, UserHandle.getCallingUserId());
601     }
602
603     /**
604      * Clear all scheduled sync operations that match the uri and cancel the active sync
605      * if they match the authority and account, if they are present.
606      *
607      * <p> If the user id supplied is different to the calling user, the caller must hold the
608      * INTERACT_ACROSS_USERS_FULL permission.
609      *
610      * @param account filter the pending and active syncs to cancel using this account, or null.
611      * @param authority filter the pending and active syncs to cancel using this authority, or
612      * null.
613      * @param userId the user id for which to cancel sync operations.
614      * @param cname cancel syncs running on this service, or null for provider/account.
615      */
616     @Override
617     public void cancelSyncAsUser(Account account, String authority, ComponentName cname,
618                                  int userId) {
619         if (authority != null && authority.length() == 0) {
620             throw new IllegalArgumentException("Authority must be non-empty");
621         }
622         enforceCrossUserPermission(userId,
623                 "no permission to modify the sync settings for user " + userId);
624         // This makes it so that future permission checks will be in the context of this
625         // process rather than the caller's process. We will restore this before returning.
626         long identityToken = clearCallingIdentity();
627         if (cname != null) {
628             Slog.e(TAG, "cname not null.");
629             return;
630         }
631         try {
632             SyncManager syncManager = getSyncManager();
633             if (syncManager != null) {
634                 SyncStorageEngine.EndPoint info;
635                 info = new SyncStorageEngine.EndPoint(account, authority, userId);
636                 syncManager.clearScheduledSyncOperations(info);
637                 syncManager.cancelActiveSync(info, null /* all syncs for this adapter */, "API");
638             }
639         } finally {
640             restoreCallingIdentity(identityToken);
641         }
642     }
643
644     @Override
645     public void cancelRequest(SyncRequest request) {
646         SyncManager syncManager = getSyncManager();
647         if (syncManager == null) return;
648         int userId = UserHandle.getCallingUserId();
649         final int callingUid = Binder.getCallingUid();
650
651         long identityToken = clearCallingIdentity();
652         try {
653             SyncStorageEngine.EndPoint info;
654             Bundle extras = new Bundle(request.getBundle());
655             Account account = request.getAccount();
656             String provider = request.getProvider();
657             info = new SyncStorageEngine.EndPoint(account, provider, userId);
658             if (request.isPeriodic()) {
659                 // Remove periodic sync.
660                 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
661                         "no permission to write the sync settings");
662                 getSyncManager().removePeriodicSync(info, extras,
663                         "cancelRequest() by uid=" + callingUid);
664             }
665             // Cancel active syncs and clear pending syncs from the queue.
666             syncManager.cancelScheduledSyncOperation(info, extras);
667             syncManager.cancelActiveSync(info, extras, "API");
668         } finally {
669             restoreCallingIdentity(identityToken);
670         }
671     }
672
673     /**
674      * Get information about the SyncAdapters that are known to the system.
675      * @return an array of SyncAdapters that have registered with the system
676      */
677     @Override
678     public SyncAdapterType[] getSyncAdapterTypes() {
679         return getSyncAdapterTypesAsUser(UserHandle.getCallingUserId());
680     }
681
682     /**
683      * Get information about the SyncAdapters that are known to the system for a particular user.
684      *
685      * <p> If the user id supplied is different to the calling user, the caller must hold the
686      * INTERACT_ACROSS_USERS_FULL permission.
687      *
688      * @return an array of SyncAdapters that have registered with the system
689      */
690     @Override
691     public SyncAdapterType[] getSyncAdapterTypesAsUser(int userId) {
692         enforceCrossUserPermission(userId,
693                 "no permission to read sync settings for user " + userId);
694         // This makes it so that future permission checks will be in the context of this
695         // process rather than the caller's process. We will restore this before returning.
696         final long identityToken = clearCallingIdentity();
697         try {
698             SyncManager syncManager = getSyncManager();
699             return syncManager.getSyncAdapterTypes(userId);
700         } finally {
701             restoreCallingIdentity(identityToken);
702         }
703     }
704
705     @Override
706     public String[] getSyncAdapterPackagesForAuthorityAsUser(String authority, int userId) {
707         enforceCrossUserPermission(userId,
708                 "no permission to read sync settings for user " + userId);
709         // This makes it so that future permission checks will be in the context of this
710         // process rather than the caller's process. We will restore this before returning.
711         final long identityToken = clearCallingIdentity();
712         try {
713             SyncManager syncManager = getSyncManager();
714             return syncManager.getSyncAdapterPackagesForAuthorityAsUser(authority, userId);
715         } finally {
716             restoreCallingIdentity(identityToken);
717         }
718     }
719
720     @Override
721     public boolean getSyncAutomatically(Account account, String providerName) {
722         return getSyncAutomaticallyAsUser(account, providerName, UserHandle.getCallingUserId());
723     }
724
725     /**
726      * If the user id supplied is different to the calling user, the caller must hold the
727      * INTERACT_ACROSS_USERS_FULL permission.
728      */
729     @Override
730     public boolean getSyncAutomaticallyAsUser(Account account, String providerName, int userId) {
731         enforceCrossUserPermission(userId,
732                 "no permission to read the sync settings for user " + userId);
733         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
734                 "no permission to read the sync settings");
735
736         long identityToken = clearCallingIdentity();
737         try {
738             SyncManager syncManager = getSyncManager();
739             if (syncManager != null) {
740                 return syncManager.getSyncStorageEngine()
741                         .getSyncAutomatically(account, userId, providerName);
742             }
743         } finally {
744             restoreCallingIdentity(identityToken);
745         }
746         return false;
747     }
748
749     @Override
750     public void setSyncAutomatically(Account account, String providerName, boolean sync) {
751         setSyncAutomaticallyAsUser(account, providerName, sync, UserHandle.getCallingUserId());
752     }
753
754     @Override
755     public void setSyncAutomaticallyAsUser(Account account, String providerName, boolean sync,
756                                            int userId) {
757         if (TextUtils.isEmpty(providerName)) {
758             throw new IllegalArgumentException("Authority must be non-empty");
759         }
760         mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
761                 "no permission to write the sync settings");
762         enforceCrossUserPermission(userId,
763                 "no permission to modify the sync settings for user " + userId);
764
765         long identityToken = clearCallingIdentity();
766         try {
767             SyncManager syncManager = getSyncManager();
768             if (syncManager != null) {
769                 syncManager.getSyncStorageEngine().setSyncAutomatically(account, userId,
770                         providerName, sync);
771             }
772         } finally {
773             restoreCallingIdentity(identityToken);
774         }
775     }
776
777     /** Old API. Schedule periodic sync with default flexMillis time. */
778     @Override
779     public void addPeriodicSync(Account account, String authority, Bundle extras,
780                                 long pollFrequency) {
781         Bundle.setDefusable(extras, true);
782         if (account == null) {
783             throw new IllegalArgumentException("Account must not be null");
784         }
785         if (TextUtils.isEmpty(authority)) {
786             throw new IllegalArgumentException("Authority must not be empty.");
787         }
788         mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
789                 "no permission to write the sync settings");
790
791         int userId = UserHandle.getCallingUserId();
792
793         pollFrequency = clampPeriod(pollFrequency);
794         long defaultFlex = SyncStorageEngine.calculateDefaultFlexTime(pollFrequency);
795
796         long identityToken = clearCallingIdentity();
797         try {
798             SyncStorageEngine.EndPoint info =
799                     new SyncStorageEngine.EndPoint(account, authority, userId);
800             getSyncManager().updateOrAddPeriodicSync(info, pollFrequency,
801                     defaultFlex, extras);
802         } finally {
803             restoreCallingIdentity(identityToken);
804         }
805     }
806
807     @Override
808     public void removePeriodicSync(Account account, String authority, Bundle extras) {
809         Bundle.setDefusable(extras, true);
810         if (account == null) {
811             throw new IllegalArgumentException("Account must not be null");
812         }
813         if (TextUtils.isEmpty(authority)) {
814             throw new IllegalArgumentException("Authority must not be empty");
815         }
816         mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
817                 "no permission to write the sync settings");
818
819         final int callingUid = Binder.getCallingUid();
820
821         int userId = UserHandle.getCallingUserId();
822         long identityToken = clearCallingIdentity();
823         try {
824             getSyncManager()
825                     .removePeriodicSync(
826                             new SyncStorageEngine.EndPoint(account, authority, userId),
827                             extras, "removePeriodicSync() by uid=" + callingUid);
828         } finally {
829             restoreCallingIdentity(identityToken);
830         }
831     }
832
833     @Override
834     public List<PeriodicSync> getPeriodicSyncs(Account account, String providerName,
835                                                ComponentName cname) {
836         if (account == null) {
837             throw new IllegalArgumentException("Account must not be null");
838         }
839         if (TextUtils.isEmpty(providerName)) {
840             throw new IllegalArgumentException("Authority must not be empty");
841         }
842         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
843                 "no permission to read the sync settings");
844
845         int userId = UserHandle.getCallingUserId();
846         long identityToken = clearCallingIdentity();
847         try {
848             return getSyncManager().getPeriodicSyncs(
849                     new SyncStorageEngine.EndPoint(account, providerName, userId));
850         } finally {
851             restoreCallingIdentity(identityToken);
852         }
853     }
854
855     @Override
856     public int getIsSyncable(Account account, String providerName) {
857         return getIsSyncableAsUser(account, providerName, UserHandle.getCallingUserId());
858     }
859
860     /**
861      * If the user id supplied is different to the calling user, the caller must hold the
862      * INTERACT_ACROSS_USERS_FULL permission.
863      */
864     @Override
865     public int getIsSyncableAsUser(Account account, String providerName, int userId) {
866         enforceCrossUserPermission(userId,
867                 "no permission to read the sync settings for user " + userId);
868         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
869                 "no permission to read the sync settings");
870
871         long identityToken = clearCallingIdentity();
872         try {
873             SyncManager syncManager = getSyncManager();
874             if (syncManager != null) {
875                 return syncManager.computeSyncable(
876                         account, userId, providerName, false);
877             }
878         } finally {
879             restoreCallingIdentity(identityToken);
880         }
881         return -1;
882     }
883
884     @Override
885     public void setIsSyncable(Account account, String providerName, int syncable) {
886         if (TextUtils.isEmpty(providerName)) {
887             throw new IllegalArgumentException("Authority must not be empty");
888         }
889         mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
890                 "no permission to write the sync settings");
891
892         syncable = normalizeSyncable(syncable);
893
894         int userId = UserHandle.getCallingUserId();
895         long identityToken = clearCallingIdentity();
896         try {
897             SyncManager syncManager = getSyncManager();
898             if (syncManager != null) {
899                 syncManager.getSyncStorageEngine().setIsSyncable(
900                         account, userId, providerName, syncable);
901             }
902         } finally {
903             restoreCallingIdentity(identityToken);
904         }
905     }
906
907     @Override
908     public boolean getMasterSyncAutomatically() {
909         return getMasterSyncAutomaticallyAsUser(UserHandle.getCallingUserId());
910     }
911
912     /**
913      * If the user id supplied is different to the calling user, the caller must hold the
914      * INTERACT_ACROSS_USERS_FULL permission.
915      */
916     @Override
917     public boolean getMasterSyncAutomaticallyAsUser(int userId) {
918         enforceCrossUserPermission(userId,
919                 "no permission to read the sync settings for user " + userId);
920         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
921                 "no permission to read the sync settings");
922
923         long identityToken = clearCallingIdentity();
924         try {
925             SyncManager syncManager = getSyncManager();
926             if (syncManager != null) {
927                 return syncManager.getSyncStorageEngine().getMasterSyncAutomatically(userId);
928             }
929         } finally {
930             restoreCallingIdentity(identityToken);
931         }
932         return false;
933     }
934
935     @Override
936     public void setMasterSyncAutomatically(boolean flag) {
937         setMasterSyncAutomaticallyAsUser(flag, UserHandle.getCallingUserId());
938     }
939
940     @Override
941     public void setMasterSyncAutomaticallyAsUser(boolean flag, int userId) {
942         enforceCrossUserPermission(userId,
943                 "no permission to set the sync status for user " + userId);
944         mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
945                 "no permission to write the sync settings");
946
947         long identityToken = clearCallingIdentity();
948         try {
949             SyncManager syncManager = getSyncManager();
950             if (syncManager != null) {
951                 syncManager.getSyncStorageEngine().setMasterSyncAutomatically(flag, userId);
952             }
953         } finally {
954             restoreCallingIdentity(identityToken);
955         }
956     }
957
958     @Override
959     public boolean isSyncActive(Account account, String authority, ComponentName cname) {
960         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
961                 "no permission to read the sync stats");
962         int userId = UserHandle.getCallingUserId();
963         long identityToken = clearCallingIdentity();
964         try {
965             SyncManager syncManager = getSyncManager();
966             if (syncManager == null) {
967                 return false;
968             }
969             return syncManager.getSyncStorageEngine().isSyncActive(
970                     new SyncStorageEngine.EndPoint(account, authority, userId));
971         } finally {
972             restoreCallingIdentity(identityToken);
973         }
974     }
975
976     @Override
977     public List<SyncInfo> getCurrentSyncs() {
978         return getCurrentSyncsAsUser(UserHandle.getCallingUserId());
979     }
980
981     /**
982      * If the user id supplied is different to the calling user, the caller must hold the
983      * INTERACT_ACROSS_USERS_FULL permission.
984      */
985     @Override
986     public List<SyncInfo> getCurrentSyncsAsUser(int userId) {
987         enforceCrossUserPermission(userId,
988                 "no permission to read the sync settings for user " + userId);
989         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
990                 "no permission to read the sync stats");
991
992         final boolean canAccessAccounts =
993             mContext.checkCallingOrSelfPermission(Manifest.permission.GET_ACCOUNTS)
994                 == PackageManager.PERMISSION_GRANTED;
995         long identityToken = clearCallingIdentity();
996         try {
997             return getSyncManager().getSyncStorageEngine()
998                 .getCurrentSyncsCopy(userId, canAccessAccounts);
999         } finally {
1000             restoreCallingIdentity(identityToken);
1001         }
1002     }
1003
1004     @Override
1005     public SyncStatusInfo getSyncStatus(Account account, String authority, ComponentName cname) {
1006         return getSyncStatusAsUser(account, authority, cname, UserHandle.getCallingUserId());
1007     }
1008
1009     /**
1010      * If the user id supplied is different to the calling user, the caller must hold the
1011      * INTERACT_ACROSS_USERS_FULL permission.
1012      */
1013     @Override
1014     public SyncStatusInfo getSyncStatusAsUser(Account account, String authority,
1015                                               ComponentName cname, int userId) {
1016         if (TextUtils.isEmpty(authority)) {
1017             throw new IllegalArgumentException("Authority must not be empty");
1018         }
1019
1020         enforceCrossUserPermission(userId,
1021                 "no permission to read the sync stats for user " + userId);
1022         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
1023                 "no permission to read the sync stats");
1024
1025         long identityToken = clearCallingIdentity();
1026         try {
1027             SyncManager syncManager = getSyncManager();
1028             if (syncManager == null) {
1029                 return null;
1030             }
1031             SyncStorageEngine.EndPoint info;
1032             if (!(account == null || authority == null)) {
1033                 info = new SyncStorageEngine.EndPoint(account, authority, userId);
1034             } else {
1035                 throw new IllegalArgumentException("Must call sync status with valid authority");
1036             }
1037             return syncManager.getSyncStorageEngine().getStatusByAuthority(info);
1038         } finally {
1039             restoreCallingIdentity(identityToken);
1040         }
1041     }
1042
1043     @Override
1044     public boolean isSyncPending(Account account, String authority, ComponentName cname) {
1045         return isSyncPendingAsUser(account, authority, cname, UserHandle.getCallingUserId());
1046     }
1047
1048     @Override
1049     public boolean isSyncPendingAsUser(Account account, String authority, ComponentName cname,
1050                                        int userId) {
1051         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
1052                 "no permission to read the sync stats");
1053         enforceCrossUserPermission(userId,
1054                 "no permission to retrieve the sync settings for user " + userId);
1055         long identityToken = clearCallingIdentity();
1056         SyncManager syncManager = getSyncManager();
1057         if (syncManager == null) return false;
1058
1059         try {
1060             SyncStorageEngine.EndPoint info;
1061             if (!(account == null || authority == null)) {
1062                 info = new SyncStorageEngine.EndPoint(account, authority, userId);
1063             } else {
1064                 throw new IllegalArgumentException("Invalid authority specified");
1065             }
1066             return syncManager.getSyncStorageEngine().isSyncPending(info);
1067         } finally {
1068             restoreCallingIdentity(identityToken);
1069         }
1070     }
1071
1072     @Override
1073     public void addStatusChangeListener(int mask, ISyncStatusObserver callback) {
1074         long identityToken = clearCallingIdentity();
1075         try {
1076             SyncManager syncManager = getSyncManager();
1077             if (syncManager != null && callback != null) {
1078                 syncManager.getSyncStorageEngine().addStatusChangeListener(mask, callback);
1079             }
1080         } finally {
1081             restoreCallingIdentity(identityToken);
1082         }
1083     }
1084
1085     @Override
1086     public void removeStatusChangeListener(ISyncStatusObserver callback) {
1087         long identityToken = clearCallingIdentity();
1088         try {
1089             SyncManager syncManager = getSyncManager();
1090             if (syncManager != null && callback != null) {
1091                 syncManager.getSyncStorageEngine().removeStatusChangeListener(callback);
1092             }
1093         } finally {
1094             restoreCallingIdentity(identityToken);
1095         }
1096     }
1097
1098     private @Nullable String getProviderPackageName(Uri uri) {
1099         final ProviderInfo pi = mContext.getPackageManager()
1100                 .resolveContentProvider(uri.getAuthority(), 0);
1101         return (pi != null) ? pi.packageName : null;
1102     }
1103
1104     private ArrayMap<Pair<String, Uri>, Bundle> findOrCreateCacheLocked(int userId,
1105             String providerPackageName) {
1106         ArrayMap<String, ArrayMap<Pair<String, Uri>, Bundle>> userCache = mCache.get(userId);
1107         if (userCache == null) {
1108             userCache = new ArrayMap<>();
1109             mCache.put(userId, userCache);
1110         }
1111         ArrayMap<Pair<String, Uri>, Bundle> packageCache = userCache.get(providerPackageName);
1112         if (packageCache == null) {
1113             packageCache = new ArrayMap<>();
1114             userCache.put(providerPackageName, packageCache);
1115         }
1116         return packageCache;
1117     }
1118
1119     private void invalidateCacheLocked(int userId, String providerPackageName, Uri uri) {
1120         ArrayMap<String, ArrayMap<Pair<String, Uri>, Bundle>> userCache = mCache.get(userId);
1121         if (userCache == null) return;
1122
1123         ArrayMap<Pair<String, Uri>, Bundle> packageCache = userCache.get(providerPackageName);
1124         if (packageCache == null) return;
1125
1126         if (uri != null) {
1127             for (int i = 0; i < packageCache.size();) {
1128                 final Pair<String, Uri> key = packageCache.keyAt(i);
1129                 if (key.second != null && key.second.toString().startsWith(uri.toString())) {
1130                     if (DEBUG) Slog.d(TAG, "Invalidating cache for key " + key);
1131                     packageCache.removeAt(i);
1132                 } else {
1133                     i++;
1134                 }
1135             }
1136         } else {
1137             if (DEBUG) Slog.d(TAG, "Invalidating cache for package " + providerPackageName);
1138             packageCache.clear();
1139         }
1140     }
1141
1142     @Override
1143     public void putCache(String packageName, Uri key, Bundle value, int userId) {
1144         Bundle.setDefusable(value, true);
1145         enforceCrossUserPermission(userId, TAG);
1146         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CACHE_CONTENT, TAG);
1147         mContext.getSystemService(AppOpsManager.class).checkPackage(Binder.getCallingUid(),
1148                 packageName);
1149
1150         final String providerPackageName = getProviderPackageName(key);
1151         final Pair<String, Uri> fullKey = Pair.create(packageName, key);
1152
1153         synchronized (mCache) {
1154             final ArrayMap<Pair<String, Uri>, Bundle> cache = findOrCreateCacheLocked(userId,
1155                     providerPackageName);
1156             if (value != null) {
1157                 cache.put(fullKey, value);
1158             } else {
1159                 cache.remove(fullKey);
1160             }
1161         }
1162     }
1163
1164     @Override
1165     public Bundle getCache(String packageName, Uri key, int userId) {
1166         enforceCrossUserPermission(userId, TAG);
1167         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CACHE_CONTENT, TAG);
1168         mContext.getSystemService(AppOpsManager.class).checkPackage(Binder.getCallingUid(),
1169                 packageName);
1170
1171         final String providerPackageName = getProviderPackageName(key);
1172         final Pair<String, Uri> fullKey = Pair.create(packageName, key);
1173
1174         synchronized (mCache) {
1175             final ArrayMap<Pair<String, Uri>, Bundle> cache = findOrCreateCacheLocked(userId,
1176                     providerPackageName);
1177             return cache.get(fullKey);
1178         }
1179     }
1180
1181     private int handleIncomingUser(Uri uri, int pid, int uid, int modeFlags, boolean allowNonFull,
1182             int userId) {
1183         if (userId == UserHandle.USER_CURRENT) {
1184             userId = ActivityManager.getCurrentUser();
1185         }
1186
1187         if (userId == UserHandle.USER_ALL) {
1188             mContext.enforceCallingOrSelfPermission(
1189                     Manifest.permission.INTERACT_ACROSS_USERS_FULL, TAG);
1190         } else if (userId < 0) {
1191             throw new IllegalArgumentException("Invalid user: " + userId);
1192         } else if (userId != UserHandle.getCallingUserId()) {
1193             if (checkUriPermission(uri, pid, uid, modeFlags,
1194                     userId) != PackageManager.PERMISSION_GRANTED) {
1195                 boolean allow = false;
1196                 if (mContext.checkCallingOrSelfPermission(
1197                         Manifest.permission.INTERACT_ACROSS_USERS_FULL)
1198                                 == PackageManager.PERMISSION_GRANTED) {
1199                     allow = true;
1200                 } else if (allowNonFull && mContext.checkCallingOrSelfPermission(
1201                         Manifest.permission.INTERACT_ACROSS_USERS)
1202                                 == PackageManager.PERMISSION_GRANTED) {
1203                     allow = true;
1204                 }
1205                 if (!allow) {
1206                     final String permissions = allowNonFull
1207                             ? (Manifest.permission.INTERACT_ACROSS_USERS_FULL + " or " +
1208                                     Manifest.permission.INTERACT_ACROSS_USERS)
1209                             : Manifest.permission.INTERACT_ACROSS_USERS_FULL;
1210                     throw new SecurityException(TAG + "Neither user " + uid
1211                             + " nor current process has " + permissions);
1212                 }
1213             }
1214         }
1215
1216         return userId;
1217     }
1218
1219     /**
1220      * Checks if the request is from the system or an app that has INTERACT_ACROSS_USERS_FULL
1221      * permission, if the userHandle is not for the caller.
1222      *
1223      * @param userHandle the user handle of the user we want to act on behalf of.
1224      * @param message the message to log on security exception.
1225      */
1226     private void enforceCrossUserPermission(int userHandle, String message) {
1227         final int callingUser = UserHandle.getCallingUserId();
1228         if (callingUser != userHandle) {
1229             mContext.enforceCallingOrSelfPermission(
1230                     Manifest.permission.INTERACT_ACROSS_USERS_FULL, message);
1231         }
1232     }
1233
1234     private static int normalizeSyncable(int syncable) {
1235         if (syncable > 0) {
1236             return SyncStorageEngine.AuthorityInfo.SYNCABLE;
1237         } else if (syncable == 0) {
1238             return SyncStorageEngine.AuthorityInfo.NOT_SYNCABLE;
1239         }
1240         return SyncStorageEngine.AuthorityInfo.UNDEFINED;
1241     }
1242
1243     /**
1244      * Hide this class since it is not part of api,
1245      * but current unittest framework requires it to be public
1246      * @hide
1247      */
1248     public static final class ObserverNode {
1249         private class ObserverEntry implements IBinder.DeathRecipient {
1250             public final IContentObserver observer;
1251             public final int uid;
1252             public final int pid;
1253             public final boolean notifyForDescendants;
1254             private final int userHandle;
1255             private final Object observersLock;
1256
1257             public ObserverEntry(IContentObserver o, boolean n, Object observersLock,
1258                                  int _uid, int _pid, int _userHandle) {
1259                 this.observersLock = observersLock;
1260                 observer = o;
1261                 uid = _uid;
1262                 pid = _pid;
1263                 userHandle = _userHandle;
1264                 notifyForDescendants = n;
1265                 try {
1266                     observer.asBinder().linkToDeath(this, 0);
1267                 } catch (RemoteException e) {
1268                     binderDied();
1269                 }
1270             }
1271
1272             @Override
1273             public void binderDied() {
1274                 synchronized (observersLock) {
1275                     removeObserverLocked(observer);
1276                 }
1277             }
1278
1279             public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
1280                                    String name, String prefix, SparseIntArray pidCounts) {
1281                 pidCounts.put(pid, pidCounts.get(pid)+1);
1282                 pw.print(prefix); pw.print(name); pw.print(": pid=");
1283                 pw.print(pid); pw.print(" uid=");
1284                 pw.print(uid); pw.print(" user=");
1285                 pw.print(userHandle); pw.print(" target=");
1286                 pw.println(Integer.toHexString(System.identityHashCode(
1287                         observer != null ? observer.asBinder() : null)));
1288             }
1289         }
1290
1291         public static final int INSERT_TYPE = 0;
1292         public static final int UPDATE_TYPE = 1;
1293         public static final int DELETE_TYPE = 2;
1294
1295         private String mName;
1296         private ArrayList<ObserverNode> mChildren = new ArrayList<ObserverNode>();
1297         private ArrayList<ObserverEntry> mObservers = new ArrayList<ObserverEntry>();
1298
1299         public ObserverNode(String name) {
1300             mName = name;
1301         }
1302
1303         public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
1304                                String name, String prefix, int[] counts, SparseIntArray pidCounts) {
1305             String innerName = null;
1306             if (mObservers.size() > 0) {
1307                 if ("".equals(name)) {
1308                     innerName = mName;
1309                 } else {
1310                     innerName = name + "/" + mName;
1311                 }
1312                 for (int i=0; i<mObservers.size(); i++) {
1313                     counts[1]++;
1314                     mObservers.get(i).dumpLocked(fd, pw, args, innerName, prefix,
1315                             pidCounts);
1316                 }
1317             }
1318             if (mChildren.size() > 0) {
1319                 if (innerName == null) {
1320                     if ("".equals(name)) {
1321                         innerName = mName;
1322                     } else {
1323                         innerName = name + "/" + mName;
1324                     }
1325                 }
1326                 for (int i=0; i<mChildren.size(); i++) {
1327                     counts[0]++;
1328                     mChildren.get(i).dumpLocked(fd, pw, args, innerName, prefix,
1329                             counts, pidCounts);
1330                 }
1331             }
1332         }
1333
1334         private String getUriSegment(Uri uri, int index) {
1335             if (uri != null) {
1336                 if (index == 0) {
1337                     return uri.getAuthority();
1338                 } else {
1339                     return uri.getPathSegments().get(index - 1);
1340                 }
1341             } else {
1342                 return null;
1343             }
1344         }
1345
1346         private int countUriSegments(Uri uri) {
1347             if (uri == null) {
1348                 return 0;
1349             }
1350             return uri.getPathSegments().size() + 1;
1351         }
1352
1353         // Invariant:  userHandle is either a hard user number or is USER_ALL
1354         public void addObserverLocked(Uri uri, IContentObserver observer,
1355                                       boolean notifyForDescendants, Object observersLock,
1356                                       int uid, int pid, int userHandle) {
1357             addObserverLocked(uri, 0, observer, notifyForDescendants, observersLock,
1358                     uid, pid, userHandle);
1359         }
1360
1361         private void addObserverLocked(Uri uri, int index, IContentObserver observer,
1362                                        boolean notifyForDescendants, Object observersLock,
1363                                        int uid, int pid, int userHandle) {
1364             // If this is the leaf node add the observer
1365             if (index == countUriSegments(uri)) {
1366                 mObservers.add(new ObserverEntry(observer, notifyForDescendants, observersLock,
1367                         uid, pid, userHandle));
1368                 return;
1369             }
1370
1371             // Look to see if the proper child already exists
1372             String segment = getUriSegment(uri, index);
1373             if (segment == null) {
1374                 throw new IllegalArgumentException("Invalid Uri (" + uri + ") used for observer");
1375             }
1376             int N = mChildren.size();
1377             for (int i = 0; i < N; i++) {
1378                 ObserverNode node = mChildren.get(i);
1379                 if (node.mName.equals(segment)) {
1380                     node.addObserverLocked(uri, index + 1, observer, notifyForDescendants,
1381                             observersLock, uid, pid, userHandle);
1382                     return;
1383                 }
1384             }
1385
1386             // No child found, create one
1387             ObserverNode node = new ObserverNode(segment);
1388             mChildren.add(node);
1389             node.addObserverLocked(uri, index + 1, observer, notifyForDescendants,
1390                     observersLock, uid, pid, userHandle);
1391         }
1392
1393         public boolean removeObserverLocked(IContentObserver observer) {
1394             int size = mChildren.size();
1395             for (int i = 0; i < size; i++) {
1396                 boolean empty = mChildren.get(i).removeObserverLocked(observer);
1397                 if (empty) {
1398                     mChildren.remove(i);
1399                     i--;
1400                     size--;
1401                 }
1402             }
1403
1404             IBinder observerBinder = observer.asBinder();
1405             size = mObservers.size();
1406             for (int i = 0; i < size; i++) {
1407                 ObserverEntry entry = mObservers.get(i);
1408                 if (entry.observer.asBinder() == observerBinder) {
1409                     mObservers.remove(i);
1410                     // We no longer need to listen for death notifications. Remove it.
1411                     observerBinder.unlinkToDeath(entry, 0);
1412                     break;
1413                 }
1414             }
1415
1416             if (mChildren.size() == 0 && mObservers.size() == 0) {
1417                 return true;
1418             }
1419             return false;
1420         }
1421
1422         private void collectMyObserversLocked(boolean leaf, IContentObserver observer,
1423                                               boolean observerWantsSelfNotifications, int flags,
1424                                               int targetUserHandle, ArrayList<ObserverCall> calls) {
1425             int N = mObservers.size();
1426             IBinder observerBinder = observer == null ? null : observer.asBinder();
1427             for (int i = 0; i < N; i++) {
1428                 ObserverEntry entry = mObservers.get(i);
1429
1430                 // Don't notify the observer if it sent the notification and isn't interested
1431                 // in self notifications
1432                 boolean selfChange = (entry.observer.asBinder() == observerBinder);
1433                 if (selfChange && !observerWantsSelfNotifications) {
1434                     continue;
1435                 }
1436
1437                 // Does this observer match the target user?
1438                 if (targetUserHandle == UserHandle.USER_ALL
1439                         || entry.userHandle == UserHandle.USER_ALL
1440                         || targetUserHandle == entry.userHandle) {
1441                     // Make sure the observer is interested in the notification
1442                     if (leaf) {
1443                         // If we are at the leaf: we always report, unless the sender has asked
1444                         // to skip observers that are notifying for descendants (since they will
1445                         // be sending another more specific URI for them).
1446                         if ((flags&ContentResolver.NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS) != 0
1447                                 && entry.notifyForDescendants) {
1448                             if (DEBUG) Slog.d(TAG, "Skipping " + entry.observer
1449                                     + ": skip notify for descendants");
1450                             continue;
1451                         }
1452                     } else {
1453                         // If we are not at the leaf: we report if the observer says it wants
1454                         // to be notified for all descendants.
1455                         if (!entry.notifyForDescendants) {
1456                             if (DEBUG) Slog.d(TAG, "Skipping " + entry.observer
1457                                     + ": not monitor descendants");
1458                             continue;
1459                         }
1460                     }
1461                     if (DEBUG) Slog.d(TAG, "Reporting to " + entry.observer + ": leaf=" + leaf
1462                             + " flags=" + Integer.toHexString(flags)
1463                             + " desc=" + entry.notifyForDescendants);
1464                     calls.add(new ObserverCall(this, entry.observer, selfChange,
1465                             UserHandle.getUserId(entry.uid)));
1466                 }
1467             }
1468         }
1469
1470         /**
1471          * targetUserHandle is either a hard user handle or is USER_ALL
1472          */
1473         public void collectObserversLocked(Uri uri, int index, IContentObserver observer,
1474                                            boolean observerWantsSelfNotifications, int flags,
1475                                            int targetUserHandle, ArrayList<ObserverCall> calls) {
1476             String segment = null;
1477             int segmentCount = countUriSegments(uri);
1478             if (index >= segmentCount) {
1479                 // This is the leaf node, notify all observers
1480                 if (DEBUG) Slog.d(TAG, "Collecting leaf observers @ #" + index + ", node " + mName);
1481                 collectMyObserversLocked(true, observer, observerWantsSelfNotifications,
1482                         flags, targetUserHandle, calls);
1483             } else if (index < segmentCount){
1484                 segment = getUriSegment(uri, index);
1485                 if (DEBUG) Slog.d(TAG, "Collecting non-leaf observers @ #" + index + " / "
1486                         + segment);
1487                 // Notify any observers at this level who are interested in descendants
1488                 collectMyObserversLocked(false, observer, observerWantsSelfNotifications,
1489                         flags, targetUserHandle, calls);
1490             }
1491
1492             int N = mChildren.size();
1493             for (int i = 0; i < N; i++) {
1494                 ObserverNode node = mChildren.get(i);
1495                 if (segment == null || node.mName.equals(segment)) {
1496                     // We found the child,
1497                     node.collectObserversLocked(uri, index + 1, observer,
1498                             observerWantsSelfNotifications, flags, targetUserHandle, calls);
1499                     if (segment != null) {
1500                         break;
1501                     }
1502                 }
1503             }
1504         }
1505     }
1506 }