OSDN Git Service

ad74ff88e80faeaa5608ca2cffa4a834c715cf05
[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
650         long identityToken = clearCallingIdentity();
651         try {
652             SyncStorageEngine.EndPoint info;
653             Bundle extras = new Bundle(request.getBundle());
654             Account account = request.getAccount();
655             String provider = request.getProvider();
656             info = new SyncStorageEngine.EndPoint(account, provider, userId);
657             if (request.isPeriodic()) {
658                 // Remove periodic sync.
659                 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
660                         "no permission to write the sync settings");
661                 getSyncManager().removePeriodicSync(info, extras);
662             }
663             // Cancel active syncs and clear pending syncs from the queue.
664             syncManager.cancelScheduledSyncOperation(info, extras);
665             syncManager.cancelActiveSync(info, extras, "API");
666         } finally {
667             restoreCallingIdentity(identityToken);
668         }
669     }
670
671     /**
672      * Get information about the SyncAdapters that are known to the system.
673      * @return an array of SyncAdapters that have registered with the system
674      */
675     @Override
676     public SyncAdapterType[] getSyncAdapterTypes() {
677         return getSyncAdapterTypesAsUser(UserHandle.getCallingUserId());
678     }
679
680     /**
681      * Get information about the SyncAdapters that are known to the system for a particular user.
682      *
683      * <p> If the user id supplied is different to the calling user, the caller must hold the
684      * INTERACT_ACROSS_USERS_FULL permission.
685      *
686      * @return an array of SyncAdapters that have registered with the system
687      */
688     @Override
689     public SyncAdapterType[] getSyncAdapterTypesAsUser(int userId) {
690         enforceCrossUserPermission(userId,
691                 "no permission to read sync settings for user " + userId);
692         // This makes it so that future permission checks will be in the context of this
693         // process rather than the caller's process. We will restore this before returning.
694         final long identityToken = clearCallingIdentity();
695         try {
696             SyncManager syncManager = getSyncManager();
697             return syncManager.getSyncAdapterTypes(userId);
698         } finally {
699             restoreCallingIdentity(identityToken);
700         }
701     }
702
703     @Override
704     public String[] getSyncAdapterPackagesForAuthorityAsUser(String authority, int userId) {
705         enforceCrossUserPermission(userId,
706                 "no permission to read sync settings for user " + userId);
707         // This makes it so that future permission checks will be in the context of this
708         // process rather than the caller's process. We will restore this before returning.
709         final long identityToken = clearCallingIdentity();
710         try {
711             SyncManager syncManager = getSyncManager();
712             return syncManager.getSyncAdapterPackagesForAuthorityAsUser(authority, userId);
713         } finally {
714             restoreCallingIdentity(identityToken);
715         }
716     }
717
718     @Override
719     public boolean getSyncAutomatically(Account account, String providerName) {
720         return getSyncAutomaticallyAsUser(account, providerName, UserHandle.getCallingUserId());
721     }
722
723     /**
724      * If the user id supplied is different to the calling user, the caller must hold the
725      * INTERACT_ACROSS_USERS_FULL permission.
726      */
727     @Override
728     public boolean getSyncAutomaticallyAsUser(Account account, String providerName, int userId) {
729         enforceCrossUserPermission(userId,
730                 "no permission to read the sync settings for user " + userId);
731         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
732                 "no permission to read the sync settings");
733
734         long identityToken = clearCallingIdentity();
735         try {
736             SyncManager syncManager = getSyncManager();
737             if (syncManager != null) {
738                 return syncManager.getSyncStorageEngine()
739                         .getSyncAutomatically(account, userId, providerName);
740             }
741         } finally {
742             restoreCallingIdentity(identityToken);
743         }
744         return false;
745     }
746
747     @Override
748     public void setSyncAutomatically(Account account, String providerName, boolean sync) {
749         setSyncAutomaticallyAsUser(account, providerName, sync, UserHandle.getCallingUserId());
750     }
751
752     @Override
753     public void setSyncAutomaticallyAsUser(Account account, String providerName, boolean sync,
754                                            int userId) {
755         if (TextUtils.isEmpty(providerName)) {
756             throw new IllegalArgumentException("Authority must be non-empty");
757         }
758         mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
759                 "no permission to write the sync settings");
760         enforceCrossUserPermission(userId,
761                 "no permission to modify the sync settings for user " + userId);
762
763         long identityToken = clearCallingIdentity();
764         try {
765             SyncManager syncManager = getSyncManager();
766             if (syncManager != null) {
767                 syncManager.getSyncStorageEngine().setSyncAutomatically(account, userId,
768                         providerName, sync);
769             }
770         } finally {
771             restoreCallingIdentity(identityToken);
772         }
773     }
774
775     /** Old API. Schedule periodic sync with default flexMillis time. */
776     @Override
777     public void addPeriodicSync(Account account, String authority, Bundle extras,
778                                 long pollFrequency) {
779         Bundle.setDefusable(extras, true);
780         if (account == null) {
781             throw new IllegalArgumentException("Account must not be null");
782         }
783         if (TextUtils.isEmpty(authority)) {
784             throw new IllegalArgumentException("Authority must not be empty.");
785         }
786         mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
787                 "no permission to write the sync settings");
788
789         int userId = UserHandle.getCallingUserId();
790
791         pollFrequency = clampPeriod(pollFrequency);
792         long defaultFlex = SyncStorageEngine.calculateDefaultFlexTime(pollFrequency);
793
794         long identityToken = clearCallingIdentity();
795         try {
796             SyncStorageEngine.EndPoint info =
797                     new SyncStorageEngine.EndPoint(account, authority, userId);
798             getSyncManager().updateOrAddPeriodicSync(info, pollFrequency,
799                     defaultFlex, extras);
800         } finally {
801             restoreCallingIdentity(identityToken);
802         }
803     }
804
805     @Override
806     public void removePeriodicSync(Account account, String authority, Bundle extras) {
807         Bundle.setDefusable(extras, true);
808         if (account == null) {
809             throw new IllegalArgumentException("Account must not be null");
810         }
811         if (TextUtils.isEmpty(authority)) {
812             throw new IllegalArgumentException("Authority must not be empty");
813         }
814         mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
815                 "no permission to write the sync settings");
816
817         int userId = UserHandle.getCallingUserId();
818         long identityToken = clearCallingIdentity();
819         try {
820             getSyncManager()
821                     .removePeriodicSync(
822                             new SyncStorageEngine.EndPoint(account, authority, userId),
823                             extras);
824         } finally {
825             restoreCallingIdentity(identityToken);
826         }
827     }
828
829     @Override
830     public List<PeriodicSync> getPeriodicSyncs(Account account, String providerName,
831                                                ComponentName cname) {
832         if (account == null) {
833             throw new IllegalArgumentException("Account must not be null");
834         }
835         if (TextUtils.isEmpty(providerName)) {
836             throw new IllegalArgumentException("Authority must not be empty");
837         }
838         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
839                 "no permission to read the sync settings");
840
841         int userId = UserHandle.getCallingUserId();
842         long identityToken = clearCallingIdentity();
843         try {
844             return getSyncManager().getPeriodicSyncs(
845                     new SyncStorageEngine.EndPoint(account, providerName, userId));
846         } finally {
847             restoreCallingIdentity(identityToken);
848         }
849     }
850
851     @Override
852     public int getIsSyncable(Account account, String providerName) {
853         return getIsSyncableAsUser(account, providerName, UserHandle.getCallingUserId());
854     }
855
856     /**
857      * If the user id supplied is different to the calling user, the caller must hold the
858      * INTERACT_ACROSS_USERS_FULL permission.
859      */
860     @Override
861     public int getIsSyncableAsUser(Account account, String providerName, int userId) {
862         enforceCrossUserPermission(userId,
863                 "no permission to read the sync settings for user " + userId);
864         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
865                 "no permission to read the sync settings");
866
867         long identityToken = clearCallingIdentity();
868         try {
869             SyncManager syncManager = getSyncManager();
870             if (syncManager != null) {
871                 return syncManager.computeSyncable(
872                         account, userId, providerName, false);
873             }
874         } finally {
875             restoreCallingIdentity(identityToken);
876         }
877         return -1;
878     }
879
880     @Override
881     public void setIsSyncable(Account account, String providerName, int syncable) {
882         if (TextUtils.isEmpty(providerName)) {
883             throw new IllegalArgumentException("Authority must not be empty");
884         }
885         mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
886                 "no permission to write the sync settings");
887
888         syncable = normalizeSyncable(syncable);
889
890         int userId = UserHandle.getCallingUserId();
891         long identityToken = clearCallingIdentity();
892         try {
893             SyncManager syncManager = getSyncManager();
894             if (syncManager != null) {
895                 syncManager.getSyncStorageEngine().setIsSyncable(
896                         account, userId, providerName, syncable);
897             }
898         } finally {
899             restoreCallingIdentity(identityToken);
900         }
901     }
902
903     @Override
904     public boolean getMasterSyncAutomatically() {
905         return getMasterSyncAutomaticallyAsUser(UserHandle.getCallingUserId());
906     }
907
908     /**
909      * If the user id supplied is different to the calling user, the caller must hold the
910      * INTERACT_ACROSS_USERS_FULL permission.
911      */
912     @Override
913     public boolean getMasterSyncAutomaticallyAsUser(int userId) {
914         enforceCrossUserPermission(userId,
915                 "no permission to read the sync settings for user " + userId);
916         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
917                 "no permission to read the sync settings");
918
919         long identityToken = clearCallingIdentity();
920         try {
921             SyncManager syncManager = getSyncManager();
922             if (syncManager != null) {
923                 return syncManager.getSyncStorageEngine().getMasterSyncAutomatically(userId);
924             }
925         } finally {
926             restoreCallingIdentity(identityToken);
927         }
928         return false;
929     }
930
931     @Override
932     public void setMasterSyncAutomatically(boolean flag) {
933         setMasterSyncAutomaticallyAsUser(flag, UserHandle.getCallingUserId());
934     }
935
936     @Override
937     public void setMasterSyncAutomaticallyAsUser(boolean flag, int userId) {
938         enforceCrossUserPermission(userId,
939                 "no permission to set the sync status for user " + userId);
940         mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
941                 "no permission to write the sync settings");
942
943         long identityToken = clearCallingIdentity();
944         try {
945             SyncManager syncManager = getSyncManager();
946             if (syncManager != null) {
947                 syncManager.getSyncStorageEngine().setMasterSyncAutomatically(flag, userId);
948             }
949         } finally {
950             restoreCallingIdentity(identityToken);
951         }
952     }
953
954     @Override
955     public boolean isSyncActive(Account account, String authority, ComponentName cname) {
956         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
957                 "no permission to read the sync stats");
958         int userId = UserHandle.getCallingUserId();
959         long identityToken = clearCallingIdentity();
960         try {
961             SyncManager syncManager = getSyncManager();
962             if (syncManager == null) {
963                 return false;
964             }
965             return syncManager.getSyncStorageEngine().isSyncActive(
966                     new SyncStorageEngine.EndPoint(account, authority, userId));
967         } finally {
968             restoreCallingIdentity(identityToken);
969         }
970     }
971
972     @Override
973     public List<SyncInfo> getCurrentSyncs() {
974         return getCurrentSyncsAsUser(UserHandle.getCallingUserId());
975     }
976
977     /**
978      * If the user id supplied is different to the calling user, the caller must hold the
979      * INTERACT_ACROSS_USERS_FULL permission.
980      */
981     @Override
982     public List<SyncInfo> getCurrentSyncsAsUser(int userId) {
983         enforceCrossUserPermission(userId,
984                 "no permission to read the sync settings for user " + userId);
985         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
986                 "no permission to read the sync stats");
987
988         final boolean canAccessAccounts =
989             mContext.checkCallingOrSelfPermission(Manifest.permission.GET_ACCOUNTS)
990                 == PackageManager.PERMISSION_GRANTED;
991         long identityToken = clearCallingIdentity();
992         try {
993             return getSyncManager().getSyncStorageEngine()
994                 .getCurrentSyncsCopy(userId, canAccessAccounts);
995         } finally {
996             restoreCallingIdentity(identityToken);
997         }
998     }
999
1000     @Override
1001     public SyncStatusInfo getSyncStatus(Account account, String authority, ComponentName cname) {
1002         return getSyncStatusAsUser(account, authority, cname, UserHandle.getCallingUserId());
1003     }
1004
1005     /**
1006      * If the user id supplied is different to the calling user, the caller must hold the
1007      * INTERACT_ACROSS_USERS_FULL permission.
1008      */
1009     @Override
1010     public SyncStatusInfo getSyncStatusAsUser(Account account, String authority,
1011                                               ComponentName cname, int userId) {
1012         if (TextUtils.isEmpty(authority)) {
1013             throw new IllegalArgumentException("Authority must not be empty");
1014         }
1015
1016         enforceCrossUserPermission(userId,
1017                 "no permission to read the sync stats for user " + userId);
1018         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
1019                 "no permission to read the sync stats");
1020
1021         long identityToken = clearCallingIdentity();
1022         try {
1023             SyncManager syncManager = getSyncManager();
1024             if (syncManager == null) {
1025                 return null;
1026             }
1027             SyncStorageEngine.EndPoint info;
1028             if (!(account == null || authority == null)) {
1029                 info = new SyncStorageEngine.EndPoint(account, authority, userId);
1030             } else {
1031                 throw new IllegalArgumentException("Must call sync status with valid authority");
1032             }
1033             return syncManager.getSyncStorageEngine().getStatusByAuthority(info);
1034         } finally {
1035             restoreCallingIdentity(identityToken);
1036         }
1037     }
1038
1039     @Override
1040     public boolean isSyncPending(Account account, String authority, ComponentName cname) {
1041         return isSyncPendingAsUser(account, authority, cname, UserHandle.getCallingUserId());
1042     }
1043
1044     @Override
1045     public boolean isSyncPendingAsUser(Account account, String authority, ComponentName cname,
1046                                        int userId) {
1047         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
1048                 "no permission to read the sync stats");
1049         enforceCrossUserPermission(userId,
1050                 "no permission to retrieve the sync settings for user " + userId);
1051         long identityToken = clearCallingIdentity();
1052         SyncManager syncManager = getSyncManager();
1053         if (syncManager == null) return false;
1054
1055         try {
1056             SyncStorageEngine.EndPoint info;
1057             if (!(account == null || authority == null)) {
1058                 info = new SyncStorageEngine.EndPoint(account, authority, userId);
1059             } else {
1060                 throw new IllegalArgumentException("Invalid authority specified");
1061             }
1062             return syncManager.getSyncStorageEngine().isSyncPending(info);
1063         } finally {
1064             restoreCallingIdentity(identityToken);
1065         }
1066     }
1067
1068     @Override
1069     public void addStatusChangeListener(int mask, ISyncStatusObserver callback) {
1070         long identityToken = clearCallingIdentity();
1071         try {
1072             SyncManager syncManager = getSyncManager();
1073             if (syncManager != null && callback != null) {
1074                 syncManager.getSyncStorageEngine().addStatusChangeListener(mask, callback);
1075             }
1076         } finally {
1077             restoreCallingIdentity(identityToken);
1078         }
1079     }
1080
1081     @Override
1082     public void removeStatusChangeListener(ISyncStatusObserver callback) {
1083         long identityToken = clearCallingIdentity();
1084         try {
1085             SyncManager syncManager = getSyncManager();
1086             if (syncManager != null && callback != null) {
1087                 syncManager.getSyncStorageEngine().removeStatusChangeListener(callback);
1088             }
1089         } finally {
1090             restoreCallingIdentity(identityToken);
1091         }
1092     }
1093
1094     private @Nullable String getProviderPackageName(Uri uri) {
1095         final ProviderInfo pi = mContext.getPackageManager()
1096                 .resolveContentProvider(uri.getAuthority(), 0);
1097         return (pi != null) ? pi.packageName : null;
1098     }
1099
1100     private ArrayMap<Pair<String, Uri>, Bundle> findOrCreateCacheLocked(int userId,
1101             String providerPackageName) {
1102         ArrayMap<String, ArrayMap<Pair<String, Uri>, Bundle>> userCache = mCache.get(userId);
1103         if (userCache == null) {
1104             userCache = new ArrayMap<>();
1105             mCache.put(userId, userCache);
1106         }
1107         ArrayMap<Pair<String, Uri>, Bundle> packageCache = userCache.get(providerPackageName);
1108         if (packageCache == null) {
1109             packageCache = new ArrayMap<>();
1110             userCache.put(providerPackageName, packageCache);
1111         }
1112         return packageCache;
1113     }
1114
1115     private void invalidateCacheLocked(int userId, String providerPackageName, Uri uri) {
1116         ArrayMap<String, ArrayMap<Pair<String, Uri>, Bundle>> userCache = mCache.get(userId);
1117         if (userCache == null) return;
1118
1119         ArrayMap<Pair<String, Uri>, Bundle> packageCache = userCache.get(providerPackageName);
1120         if (packageCache == null) return;
1121
1122         if (uri != null) {
1123             for (int i = 0; i < packageCache.size();) {
1124                 final Pair<String, Uri> key = packageCache.keyAt(i);
1125                 if (key.second != null && key.second.toString().startsWith(uri.toString())) {
1126                     if (DEBUG) Slog.d(TAG, "Invalidating cache for key " + key);
1127                     packageCache.removeAt(i);
1128                 } else {
1129                     i++;
1130                 }
1131             }
1132         } else {
1133             if (DEBUG) Slog.d(TAG, "Invalidating cache for package " + providerPackageName);
1134             packageCache.clear();
1135         }
1136     }
1137
1138     @Override
1139     public void putCache(String packageName, Uri key, Bundle value, int userId) {
1140         Bundle.setDefusable(value, true);
1141         enforceCrossUserPermission(userId, TAG);
1142         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CACHE_CONTENT, TAG);
1143         mContext.getSystemService(AppOpsManager.class).checkPackage(Binder.getCallingUid(),
1144                 packageName);
1145
1146         final String providerPackageName = getProviderPackageName(key);
1147         final Pair<String, Uri> fullKey = Pair.create(packageName, key);
1148
1149         synchronized (mCache) {
1150             final ArrayMap<Pair<String, Uri>, Bundle> cache = findOrCreateCacheLocked(userId,
1151                     providerPackageName);
1152             if (value != null) {
1153                 cache.put(fullKey, value);
1154             } else {
1155                 cache.remove(fullKey);
1156             }
1157         }
1158     }
1159
1160     @Override
1161     public Bundle getCache(String packageName, Uri key, int userId) {
1162         enforceCrossUserPermission(userId, TAG);
1163         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CACHE_CONTENT, TAG);
1164         mContext.getSystemService(AppOpsManager.class).checkPackage(Binder.getCallingUid(),
1165                 packageName);
1166
1167         final String providerPackageName = getProviderPackageName(key);
1168         final Pair<String, Uri> fullKey = Pair.create(packageName, key);
1169
1170         synchronized (mCache) {
1171             final ArrayMap<Pair<String, Uri>, Bundle> cache = findOrCreateCacheLocked(userId,
1172                     providerPackageName);
1173             return cache.get(fullKey);
1174         }
1175     }
1176
1177     private int handleIncomingUser(Uri uri, int pid, int uid, int modeFlags, boolean allowNonFull,
1178             int userId) {
1179         if (userId == UserHandle.USER_CURRENT) {
1180             userId = ActivityManager.getCurrentUser();
1181         }
1182
1183         if (userId == UserHandle.USER_ALL) {
1184             mContext.enforceCallingOrSelfPermission(
1185                     Manifest.permission.INTERACT_ACROSS_USERS_FULL, TAG);
1186         } else if (userId < 0) {
1187             throw new IllegalArgumentException("Invalid user: " + userId);
1188         } else if (userId != UserHandle.getCallingUserId()) {
1189             if (checkUriPermission(uri, pid, uid, modeFlags,
1190                     userId) != PackageManager.PERMISSION_GRANTED) {
1191                 boolean allow = false;
1192                 if (mContext.checkCallingOrSelfPermission(
1193                         Manifest.permission.INTERACT_ACROSS_USERS_FULL)
1194                                 == PackageManager.PERMISSION_GRANTED) {
1195                     allow = true;
1196                 } else if (allowNonFull && mContext.checkCallingOrSelfPermission(
1197                         Manifest.permission.INTERACT_ACROSS_USERS)
1198                                 == PackageManager.PERMISSION_GRANTED) {
1199                     allow = true;
1200                 }
1201                 if (!allow) {
1202                     final String permissions = allowNonFull
1203                             ? (Manifest.permission.INTERACT_ACROSS_USERS_FULL + " or " +
1204                                     Manifest.permission.INTERACT_ACROSS_USERS)
1205                             : Manifest.permission.INTERACT_ACROSS_USERS_FULL;
1206                     throw new SecurityException(TAG + "Neither user " + uid
1207                             + " nor current process has " + permissions);
1208                 }
1209             }
1210         }
1211
1212         return userId;
1213     }
1214
1215     /**
1216      * Checks if the request is from the system or an app that has INTERACT_ACROSS_USERS_FULL
1217      * permission, if the userHandle is not for the caller.
1218      *
1219      * @param userHandle the user handle of the user we want to act on behalf of.
1220      * @param message the message to log on security exception.
1221      */
1222     private void enforceCrossUserPermission(int userHandle, String message) {
1223         final int callingUser = UserHandle.getCallingUserId();
1224         if (callingUser != userHandle) {
1225             mContext.enforceCallingOrSelfPermission(
1226                     Manifest.permission.INTERACT_ACROSS_USERS_FULL, message);
1227         }
1228     }
1229
1230     private static int normalizeSyncable(int syncable) {
1231         if (syncable > 0) {
1232             return SyncStorageEngine.AuthorityInfo.SYNCABLE;
1233         } else if (syncable == 0) {
1234             return SyncStorageEngine.AuthorityInfo.NOT_SYNCABLE;
1235         }
1236         return SyncStorageEngine.AuthorityInfo.UNDEFINED;
1237     }
1238
1239     /**
1240      * Hide this class since it is not part of api,
1241      * but current unittest framework requires it to be public
1242      * @hide
1243      */
1244     public static final class ObserverNode {
1245         private class ObserverEntry implements IBinder.DeathRecipient {
1246             public final IContentObserver observer;
1247             public final int uid;
1248             public final int pid;
1249             public final boolean notifyForDescendants;
1250             private final int userHandle;
1251             private final Object observersLock;
1252
1253             public ObserverEntry(IContentObserver o, boolean n, Object observersLock,
1254                                  int _uid, int _pid, int _userHandle) {
1255                 this.observersLock = observersLock;
1256                 observer = o;
1257                 uid = _uid;
1258                 pid = _pid;
1259                 userHandle = _userHandle;
1260                 notifyForDescendants = n;
1261                 try {
1262                     observer.asBinder().linkToDeath(this, 0);
1263                 } catch (RemoteException e) {
1264                     binderDied();
1265                 }
1266             }
1267
1268             @Override
1269             public void binderDied() {
1270                 synchronized (observersLock) {
1271                     removeObserverLocked(observer);
1272                 }
1273             }
1274
1275             public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
1276                                    String name, String prefix, SparseIntArray pidCounts) {
1277                 pidCounts.put(pid, pidCounts.get(pid)+1);
1278                 pw.print(prefix); pw.print(name); pw.print(": pid=");
1279                 pw.print(pid); pw.print(" uid=");
1280                 pw.print(uid); pw.print(" user=");
1281                 pw.print(userHandle); pw.print(" target=");
1282                 pw.println(Integer.toHexString(System.identityHashCode(
1283                         observer != null ? observer.asBinder() : null)));
1284             }
1285         }
1286
1287         public static final int INSERT_TYPE = 0;
1288         public static final int UPDATE_TYPE = 1;
1289         public static final int DELETE_TYPE = 2;
1290
1291         private String mName;
1292         private ArrayList<ObserverNode> mChildren = new ArrayList<ObserverNode>();
1293         private ArrayList<ObserverEntry> mObservers = new ArrayList<ObserverEntry>();
1294
1295         public ObserverNode(String name) {
1296             mName = name;
1297         }
1298
1299         public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
1300                                String name, String prefix, int[] counts, SparseIntArray pidCounts) {
1301             String innerName = null;
1302             if (mObservers.size() > 0) {
1303                 if ("".equals(name)) {
1304                     innerName = mName;
1305                 } else {
1306                     innerName = name + "/" + mName;
1307                 }
1308                 for (int i=0; i<mObservers.size(); i++) {
1309                     counts[1]++;
1310                     mObservers.get(i).dumpLocked(fd, pw, args, innerName, prefix,
1311                             pidCounts);
1312                 }
1313             }
1314             if (mChildren.size() > 0) {
1315                 if (innerName == null) {
1316                     if ("".equals(name)) {
1317                         innerName = mName;
1318                     } else {
1319                         innerName = name + "/" + mName;
1320                     }
1321                 }
1322                 for (int i=0; i<mChildren.size(); i++) {
1323                     counts[0]++;
1324                     mChildren.get(i).dumpLocked(fd, pw, args, innerName, prefix,
1325                             counts, pidCounts);
1326                 }
1327             }
1328         }
1329
1330         private String getUriSegment(Uri uri, int index) {
1331             if (uri != null) {
1332                 if (index == 0) {
1333                     return uri.getAuthority();
1334                 } else {
1335                     return uri.getPathSegments().get(index - 1);
1336                 }
1337             } else {
1338                 return null;
1339             }
1340         }
1341
1342         private int countUriSegments(Uri uri) {
1343             if (uri == null) {
1344                 return 0;
1345             }
1346             return uri.getPathSegments().size() + 1;
1347         }
1348
1349         // Invariant:  userHandle is either a hard user number or is USER_ALL
1350         public void addObserverLocked(Uri uri, IContentObserver observer,
1351                                       boolean notifyForDescendants, Object observersLock,
1352                                       int uid, int pid, int userHandle) {
1353             addObserverLocked(uri, 0, observer, notifyForDescendants, observersLock,
1354                     uid, pid, userHandle);
1355         }
1356
1357         private void addObserverLocked(Uri uri, int index, IContentObserver observer,
1358                                        boolean notifyForDescendants, Object observersLock,
1359                                        int uid, int pid, int userHandle) {
1360             // If this is the leaf node add the observer
1361             if (index == countUriSegments(uri)) {
1362                 mObservers.add(new ObserverEntry(observer, notifyForDescendants, observersLock,
1363                         uid, pid, userHandle));
1364                 return;
1365             }
1366
1367             // Look to see if the proper child already exists
1368             String segment = getUriSegment(uri, index);
1369             if (segment == null) {
1370                 throw new IllegalArgumentException("Invalid Uri (" + uri + ") used for observer");
1371             }
1372             int N = mChildren.size();
1373             for (int i = 0; i < N; i++) {
1374                 ObserverNode node = mChildren.get(i);
1375                 if (node.mName.equals(segment)) {
1376                     node.addObserverLocked(uri, index + 1, observer, notifyForDescendants,
1377                             observersLock, uid, pid, userHandle);
1378                     return;
1379                 }
1380             }
1381
1382             // No child found, create one
1383             ObserverNode node = new ObserverNode(segment);
1384             mChildren.add(node);
1385             node.addObserverLocked(uri, index + 1, observer, notifyForDescendants,
1386                     observersLock, uid, pid, userHandle);
1387         }
1388
1389         public boolean removeObserverLocked(IContentObserver observer) {
1390             int size = mChildren.size();
1391             for (int i = 0; i < size; i++) {
1392                 boolean empty = mChildren.get(i).removeObserverLocked(observer);
1393                 if (empty) {
1394                     mChildren.remove(i);
1395                     i--;
1396                     size--;
1397                 }
1398             }
1399
1400             IBinder observerBinder = observer.asBinder();
1401             size = mObservers.size();
1402             for (int i = 0; i < size; i++) {
1403                 ObserverEntry entry = mObservers.get(i);
1404                 if (entry.observer.asBinder() == observerBinder) {
1405                     mObservers.remove(i);
1406                     // We no longer need to listen for death notifications. Remove it.
1407                     observerBinder.unlinkToDeath(entry, 0);
1408                     break;
1409                 }
1410             }
1411
1412             if (mChildren.size() == 0 && mObservers.size() == 0) {
1413                 return true;
1414             }
1415             return false;
1416         }
1417
1418         private void collectMyObserversLocked(boolean leaf, IContentObserver observer,
1419                                               boolean observerWantsSelfNotifications, int flags,
1420                                               int targetUserHandle, ArrayList<ObserverCall> calls) {
1421             int N = mObservers.size();
1422             IBinder observerBinder = observer == null ? null : observer.asBinder();
1423             for (int i = 0; i < N; i++) {
1424                 ObserverEntry entry = mObservers.get(i);
1425
1426                 // Don't notify the observer if it sent the notification and isn't interested
1427                 // in self notifications
1428                 boolean selfChange = (entry.observer.asBinder() == observerBinder);
1429                 if (selfChange && !observerWantsSelfNotifications) {
1430                     continue;
1431                 }
1432
1433                 // Does this observer match the target user?
1434                 if (targetUserHandle == UserHandle.USER_ALL
1435                         || entry.userHandle == UserHandle.USER_ALL
1436                         || targetUserHandle == entry.userHandle) {
1437                     // Make sure the observer is interested in the notification
1438                     if (leaf) {
1439                         // If we are at the leaf: we always report, unless the sender has asked
1440                         // to skip observers that are notifying for descendants (since they will
1441                         // be sending another more specific URI for them).
1442                         if ((flags&ContentResolver.NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS) != 0
1443                                 && entry.notifyForDescendants) {
1444                             if (DEBUG) Slog.d(TAG, "Skipping " + entry.observer
1445                                     + ": skip notify for descendants");
1446                             continue;
1447                         }
1448                     } else {
1449                         // If we are not at the leaf: we report if the observer says it wants
1450                         // to be notified for all descendants.
1451                         if (!entry.notifyForDescendants) {
1452                             if (DEBUG) Slog.d(TAG, "Skipping " + entry.observer
1453                                     + ": not monitor descendants");
1454                             continue;
1455                         }
1456                     }
1457                     if (DEBUG) Slog.d(TAG, "Reporting to " + entry.observer + ": leaf=" + leaf
1458                             + " flags=" + Integer.toHexString(flags)
1459                             + " desc=" + entry.notifyForDescendants);
1460                     calls.add(new ObserverCall(this, entry.observer, selfChange,
1461                             UserHandle.getUserId(entry.uid)));
1462                 }
1463             }
1464         }
1465
1466         /**
1467          * targetUserHandle is either a hard user handle or is USER_ALL
1468          */
1469         public void collectObserversLocked(Uri uri, int index, IContentObserver observer,
1470                                            boolean observerWantsSelfNotifications, int flags,
1471                                            int targetUserHandle, ArrayList<ObserverCall> calls) {
1472             String segment = null;
1473             int segmentCount = countUriSegments(uri);
1474             if (index >= segmentCount) {
1475                 // This is the leaf node, notify all observers
1476                 if (DEBUG) Slog.d(TAG, "Collecting leaf observers @ #" + index + ", node " + mName);
1477                 collectMyObserversLocked(true, observer, observerWantsSelfNotifications,
1478                         flags, targetUserHandle, calls);
1479             } else if (index < segmentCount){
1480                 segment = getUriSegment(uri, index);
1481                 if (DEBUG) Slog.d(TAG, "Collecting non-leaf observers @ #" + index + " / "
1482                         + segment);
1483                 // Notify any observers at this level who are interested in descendants
1484                 collectMyObserversLocked(false, observer, observerWantsSelfNotifications,
1485                         flags, targetUserHandle, calls);
1486             }
1487
1488             int N = mChildren.size();
1489             for (int i = 0; i < N; i++) {
1490                 ObserverNode node = mChildren.get(i);
1491                 if (segment == null || node.mName.equals(segment)) {
1492                     // We found the child,
1493                     node.collectObserversLocked(uri, index + 1, observer,
1494                             observerWantsSelfNotifications, flags, targetUserHandle, calls);
1495                     if (segment != null) {
1496                         break;
1497                     }
1498                 }
1499             }
1500         }
1501     }
1502 }