• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 android.content;
18 
19 import android.accounts.Account;
20 import android.app.ActivityManager;
21 import android.database.IContentObserver;
22 import android.database.sqlite.SQLiteException;
23 import android.net.Uri;
24 import android.os.Binder;
25 import android.os.Bundle;
26 import android.os.IBinder;
27 import android.os.Parcel;
28 import android.os.RemoteException;
29 import android.os.ServiceManager;
30 import android.os.UserHandle;
31 import android.util.Log;
32 import android.util.SparseIntArray;
33 import android.Manifest;
34 
35 import java.io.FileDescriptor;
36 import java.io.PrintWriter;
37 import java.security.InvalidParameterException;
38 import java.util.ArrayList;
39 import java.util.Collections;
40 import java.util.Comparator;
41 import java.util.List;
42 
43 /**
44  * {@hide}
45  */
46 public final class ContentService extends IContentService.Stub {
47     private static final String TAG = "ContentService";
48     private Context mContext;
49     private boolean mFactoryTest;
50     private final ObserverNode mRootNode = new ObserverNode("");
51     private SyncManager mSyncManager = null;
52     private final Object mSyncManagerLock = new Object();
53 
getSyncManager()54     private SyncManager getSyncManager() {
55         synchronized(mSyncManagerLock) {
56             try {
57                 // Try to create the SyncManager, return null if it fails (e.g. the disk is full).
58                 if (mSyncManager == null) mSyncManager = new SyncManager(mContext, mFactoryTest);
59             } catch (SQLiteException e) {
60                 Log.e(TAG, "Can't create SyncManager", e);
61             }
62             return mSyncManager;
63         }
64     }
65 
66     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)67     protected synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
68         mContext.enforceCallingOrSelfPermission(Manifest.permission.DUMP,
69                 "caller doesn't have the DUMP permission");
70 
71         // This makes it so that future permission checks will be in the context of this
72         // process rather than the caller's process. We will restore this before returning.
73         long identityToken = clearCallingIdentity();
74         try {
75             if (mSyncManager == null) {
76                 pw.println("No SyncManager created!  (Disk full?)");
77             } else {
78                 mSyncManager.dump(fd, pw);
79             }
80             pw.println();
81             pw.println("Observer tree:");
82             synchronized (mRootNode) {
83                 int[] counts = new int[2];
84                 final SparseIntArray pidCounts = new SparseIntArray();
85                 mRootNode.dumpLocked(fd, pw, args, "", "  ", counts, pidCounts);
86                 pw.println();
87                 ArrayList<Integer> sorted = new ArrayList<Integer>();
88                 for (int i=0; i<pidCounts.size(); i++) {
89                     sorted.add(pidCounts.keyAt(i));
90                 }
91                 Collections.sort(sorted, new Comparator<Integer>() {
92                     @Override
93                     public int compare(Integer lhs, Integer rhs) {
94                         int lc = pidCounts.get(lhs);
95                         int rc = pidCounts.get(rhs);
96                         if (lc < rc) {
97                             return 1;
98                         } else if (lc > rc) {
99                             return -1;
100                         }
101                         return 0;
102                     }
103 
104                 });
105                 for (int i=0; i<sorted.size(); i++) {
106                     int pid = sorted.get(i);
107                     pw.print("  pid "); pw.print(pid); pw.print(": ");
108                             pw.print(pidCounts.get(pid)); pw.println(" observers");
109                 }
110                 pw.println();
111                 pw.print(" Total number of nodes: "); pw.println(counts[0]);
112                 pw.print(" Total number of observers: "); pw.println(counts[1]);
113             }
114         } finally {
115             restoreCallingIdentity(identityToken);
116         }
117     }
118 
119     @Override
onTransact(int code, Parcel data, Parcel reply, int flags)120     public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
121             throws RemoteException {
122         try {
123             return super.onTransact(code, data, reply, flags);
124         } catch (RuntimeException e) {
125             // The content service only throws security exceptions, so let's
126             // log all others.
127             if (!(e instanceof SecurityException)) {
128                 Log.e(TAG, "Content Service Crash", e);
129             }
130             throw e;
131         }
132     }
133 
ContentService(Context context, boolean factoryTest)134     /*package*/ ContentService(Context context, boolean factoryTest) {
135         mContext = context;
136         mFactoryTest = factoryTest;
137     }
138 
systemReady()139     public void systemReady() {
140         getSyncManager();
141     }
142 
143     /**
144      * Register a content observer tied to a specific user's view of the provider.
145      * @param userHandle the user whose view of the provider is to be observed.  May be
146      *     the calling user without requiring any permission, otherwise the caller needs to
147      *     hold the INTERACT_ACROSS_USERS_FULL permission.  Pseudousers USER_ALL and
148      *     USER_CURRENT are properly handled; all other pseudousers are forbidden.
149      */
150     @Override
registerContentObserver(Uri uri, boolean notifyForDescendants, IContentObserver observer, int userHandle)151     public void registerContentObserver(Uri uri, boolean notifyForDescendants,
152             IContentObserver observer, int userHandle) {
153         if (observer == null || uri == null) {
154             throw new IllegalArgumentException("You must pass a valid uri and observer");
155         }
156 
157         final int callingUser = UserHandle.getCallingUserId();
158         if (callingUser != userHandle) {
159             mContext.enforceCallingOrSelfPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL,
160                     "no permission to observe other users' provider view");
161         }
162 
163         if (userHandle < 0) {
164             if (userHandle == UserHandle.USER_CURRENT) {
165                 userHandle = ActivityManager.getCurrentUser();
166             } else if (userHandle != UserHandle.USER_ALL) {
167                 throw new InvalidParameterException("Bad user handle for registerContentObserver: "
168                         + userHandle);
169             }
170         }
171 
172         synchronized (mRootNode) {
173             mRootNode.addObserverLocked(uri, observer, notifyForDescendants, mRootNode,
174                     Binder.getCallingUid(), Binder.getCallingPid(), userHandle);
175             if (false) Log.v(TAG, "Registered observer " + observer + " at " + uri +
176                     " with notifyForDescendants " + notifyForDescendants);
177         }
178     }
179 
registerContentObserver(Uri uri, boolean notifyForDescendants, IContentObserver observer)180     public void registerContentObserver(Uri uri, boolean notifyForDescendants,
181             IContentObserver observer) {
182         registerContentObserver(uri, notifyForDescendants, observer,
183                 UserHandle.getCallingUserId());
184     }
185 
unregisterContentObserver(IContentObserver observer)186     public void unregisterContentObserver(IContentObserver observer) {
187         if (observer == null) {
188             throw new IllegalArgumentException("You must pass a valid observer");
189         }
190         synchronized (mRootNode) {
191             mRootNode.removeObserverLocked(observer);
192             if (false) Log.v(TAG, "Unregistered observer " + observer);
193         }
194     }
195 
196     /**
197      * Notify observers of a particular user's view of the provider.
198      * @param userHandle the user whose view of the provider is to be notified.  May be
199      *     the calling user without requiring any permission, otherwise the caller needs to
200      *     hold the INTERACT_ACROSS_USERS_FULL permission.  Pseudousers USER_ALL and
201      *     USER_CURRENT are properly interpreted; no other pseudousers are allowed.
202      */
203     @Override
notifyChange(Uri uri, IContentObserver observer, boolean observerWantsSelfNotifications, boolean syncToNetwork, int userHandle)204     public void notifyChange(Uri uri, IContentObserver observer,
205             boolean observerWantsSelfNotifications, boolean syncToNetwork,
206             int userHandle) {
207         if (Log.isLoggable(TAG, Log.VERBOSE)) {
208             Log.v(TAG, "Notifying update of " + uri + " for user " + userHandle
209                     + " from observer " + observer + ", syncToNetwork " + syncToNetwork);
210         }
211 
212         // Notify for any user other than the caller's own requires permission.
213         final int callingUserHandle = UserHandle.getCallingUserId();
214         if (userHandle != callingUserHandle) {
215             mContext.enforceCallingOrSelfPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL,
216                     "no permission to notify other users");
217         }
218 
219         // We passed the permission check; resolve pseudouser targets as appropriate
220         if (userHandle < 0) {
221             if (userHandle == UserHandle.USER_CURRENT) {
222                 userHandle = ActivityManager.getCurrentUser();
223             } else if (userHandle != UserHandle.USER_ALL) {
224                 throw new InvalidParameterException("Bad user handle for notifyChange: "
225                         + userHandle);
226             }
227         }
228 
229         // This makes it so that future permission checks will be in the context of this
230         // process rather than the caller's process. We will restore this before returning.
231         long identityToken = clearCallingIdentity();
232         try {
233             ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>();
234             synchronized (mRootNode) {
235                 mRootNode.collectObserversLocked(uri, 0, observer, observerWantsSelfNotifications,
236                         userHandle, calls);
237             }
238             final int numCalls = calls.size();
239             for (int i=0; i<numCalls; i++) {
240                 ObserverCall oc = calls.get(i);
241                 try {
242                     oc.mObserver.onChange(oc.mSelfChange, uri);
243                     if (Log.isLoggable(TAG, Log.VERBOSE)) {
244                         Log.v(TAG, "Notified " + oc.mObserver + " of " + "update at " + uri);
245                     }
246                 } catch (RemoteException ex) {
247                     synchronized (mRootNode) {
248                         Log.w(TAG, "Found dead observer, removing");
249                         IBinder binder = oc.mObserver.asBinder();
250                         final ArrayList<ObserverNode.ObserverEntry> list
251                                 = oc.mNode.mObservers;
252                         int numList = list.size();
253                         for (int j=0; j<numList; j++) {
254                             ObserverNode.ObserverEntry oe = list.get(j);
255                             if (oe.observer.asBinder() == binder) {
256                                 list.remove(j);
257                                 j--;
258                                 numList--;
259                             }
260                         }
261                     }
262                 }
263             }
264             if (syncToNetwork) {
265                 SyncManager syncManager = getSyncManager();
266                 if (syncManager != null) {
267                     syncManager.scheduleLocalSync(null /* all accounts */, callingUserHandle,
268                             uri.getAuthority());
269                 }
270             }
271         } finally {
272             restoreCallingIdentity(identityToken);
273         }
274     }
275 
notifyChange(Uri uri, IContentObserver observer, boolean observerWantsSelfNotifications, boolean syncToNetwork)276     public void notifyChange(Uri uri, IContentObserver observer,
277             boolean observerWantsSelfNotifications, boolean syncToNetwork) {
278         notifyChange(uri, observer, observerWantsSelfNotifications, syncToNetwork,
279                 UserHandle.getCallingUserId());
280     }
281 
282     /**
283      * Hide this class since it is not part of api,
284      * but current unittest framework requires it to be public
285      * @hide
286      *
287      */
288     public static final class ObserverCall {
289         final ObserverNode mNode;
290         final IContentObserver mObserver;
291         final boolean mSelfChange;
292 
ObserverCall(ObserverNode node, IContentObserver observer, boolean selfChange)293         ObserverCall(ObserverNode node, IContentObserver observer, boolean selfChange) {
294             mNode = node;
295             mObserver = observer;
296             mSelfChange = selfChange;
297         }
298     }
299 
requestSync(Account account, String authority, Bundle extras)300     public void requestSync(Account account, String authority, Bundle extras) {
301         ContentResolver.validateSyncExtrasBundle(extras);
302         int userId = UserHandle.getCallingUserId();
303 
304         // This makes it so that future permission checks will be in the context of this
305         // process rather than the caller's process. We will restore this before returning.
306         long identityToken = clearCallingIdentity();
307         try {
308             SyncManager syncManager = getSyncManager();
309             if (syncManager != null) {
310                 syncManager.scheduleSync(account, userId, authority, extras, 0 /* no delay */,
311                         false /* onlyThoseWithUnkownSyncableState */);
312             }
313         } finally {
314             restoreCallingIdentity(identityToken);
315         }
316     }
317 
318     /**
319      * Clear all scheduled sync operations that match the uri and cancel the active sync
320      * if they match the authority and account, if they are present.
321      * @param account filter the pending and active syncs to cancel using this account
322      * @param authority filter the pending and active syncs to cancel using this authority
323      */
cancelSync(Account account, String authority)324     public void cancelSync(Account account, String authority) {
325         int userId = UserHandle.getCallingUserId();
326 
327         // This makes it so that future permission checks will be in the context of this
328         // process rather than the caller's process. We will restore this before returning.
329         long identityToken = clearCallingIdentity();
330         try {
331             SyncManager syncManager = getSyncManager();
332             if (syncManager != null) {
333                 syncManager.clearScheduledSyncOperations(account, userId, authority);
334                 syncManager.cancelActiveSync(account, userId, authority);
335             }
336         } finally {
337             restoreCallingIdentity(identityToken);
338         }
339     }
340 
341     /**
342      * Get information about the SyncAdapters that are known to the system.
343      * @return an array of SyncAdapters that have registered with the system
344      */
getSyncAdapterTypes()345     public SyncAdapterType[] getSyncAdapterTypes() {
346         // This makes it so that future permission checks will be in the context of this
347         // process rather than the caller's process. We will restore this before returning.
348         final int userId = UserHandle.getCallingUserId();
349         final long identityToken = clearCallingIdentity();
350         try {
351             SyncManager syncManager = getSyncManager();
352             return syncManager.getSyncAdapterTypes(userId);
353         } finally {
354             restoreCallingIdentity(identityToken);
355         }
356     }
357 
getSyncAutomatically(Account account, String providerName)358     public boolean getSyncAutomatically(Account account, String providerName) {
359         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
360                 "no permission to read the sync settings");
361         int userId = UserHandle.getCallingUserId();
362 
363         long identityToken = clearCallingIdentity();
364         try {
365             SyncManager syncManager = getSyncManager();
366             if (syncManager != null) {
367                 return syncManager.getSyncStorageEngine().getSyncAutomatically(
368                         account, userId, providerName);
369             }
370         } finally {
371             restoreCallingIdentity(identityToken);
372         }
373         return false;
374     }
375 
setSyncAutomatically(Account account, String providerName, boolean sync)376     public void setSyncAutomatically(Account account, String providerName, boolean sync) {
377         mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
378                 "no permission to write the sync settings");
379         int userId = UserHandle.getCallingUserId();
380 
381         long identityToken = clearCallingIdentity();
382         try {
383             SyncManager syncManager = getSyncManager();
384             if (syncManager != null) {
385                 syncManager.getSyncStorageEngine().setSyncAutomatically(
386                         account, userId, providerName, sync);
387             }
388         } finally {
389             restoreCallingIdentity(identityToken);
390         }
391     }
392 
addPeriodicSync(Account account, String authority, Bundle extras, long pollFrequency)393     public void addPeriodicSync(Account account, String authority, Bundle extras,
394             long pollFrequency) {
395         mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
396                 "no permission to write the sync settings");
397         int userId = UserHandle.getCallingUserId();
398 
399         long identityToken = clearCallingIdentity();
400         try {
401             getSyncManager().getSyncStorageEngine().addPeriodicSync(
402                     account, userId, authority, extras, pollFrequency);
403         } finally {
404             restoreCallingIdentity(identityToken);
405         }
406     }
407 
removePeriodicSync(Account account, String authority, Bundle extras)408     public void removePeriodicSync(Account account, String authority, Bundle extras) {
409         mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
410                 "no permission to write the sync settings");
411         int userId = UserHandle.getCallingUserId();
412 
413         long identityToken = clearCallingIdentity();
414         try {
415             getSyncManager().getSyncStorageEngine().removePeriodicSync(account, userId, authority,
416                     extras);
417         } finally {
418             restoreCallingIdentity(identityToken);
419         }
420     }
421 
getPeriodicSyncs(Account account, String providerName)422     public List<PeriodicSync> getPeriodicSyncs(Account account, String providerName) {
423         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
424                 "no permission to read the sync settings");
425         int userId = UserHandle.getCallingUserId();
426 
427         long identityToken = clearCallingIdentity();
428         try {
429             return getSyncManager().getSyncStorageEngine().getPeriodicSyncs(
430                     account, userId, providerName);
431         } finally {
432             restoreCallingIdentity(identityToken);
433         }
434     }
435 
getIsSyncable(Account account, String providerName)436     public int getIsSyncable(Account account, String providerName) {
437         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
438                 "no permission to read the sync settings");
439         int userId = UserHandle.getCallingUserId();
440 
441         long identityToken = clearCallingIdentity();
442         try {
443             SyncManager syncManager = getSyncManager();
444             if (syncManager != null) {
445                 return syncManager.getSyncStorageEngine().getIsSyncable(
446                         account, userId, providerName);
447             }
448         } finally {
449             restoreCallingIdentity(identityToken);
450         }
451         return -1;
452     }
453 
setIsSyncable(Account account, String providerName, int syncable)454     public void setIsSyncable(Account account, String providerName, int syncable) {
455         mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
456                 "no permission to write the sync settings");
457         int userId = UserHandle.getCallingUserId();
458 
459         long identityToken = clearCallingIdentity();
460         try {
461             SyncManager syncManager = getSyncManager();
462             if (syncManager != null) {
463                 syncManager.getSyncStorageEngine().setIsSyncable(
464                         account, userId, providerName, syncable);
465             }
466         } finally {
467             restoreCallingIdentity(identityToken);
468         }
469     }
470 
getMasterSyncAutomatically()471     public boolean getMasterSyncAutomatically() {
472         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
473                 "no permission to read the sync settings");
474         int userId = UserHandle.getCallingUserId();
475 
476         long identityToken = clearCallingIdentity();
477         try {
478             SyncManager syncManager = getSyncManager();
479             if (syncManager != null) {
480                 return syncManager.getSyncStorageEngine().getMasterSyncAutomatically(userId);
481             }
482         } finally {
483             restoreCallingIdentity(identityToken);
484         }
485         return false;
486     }
487 
setMasterSyncAutomatically(boolean flag)488     public void setMasterSyncAutomatically(boolean flag) {
489         mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
490                 "no permission to write the sync settings");
491         int userId = UserHandle.getCallingUserId();
492 
493         long identityToken = clearCallingIdentity();
494         try {
495             SyncManager syncManager = getSyncManager();
496             if (syncManager != null) {
497                 syncManager.getSyncStorageEngine().setMasterSyncAutomatically(flag, userId);
498             }
499         } finally {
500             restoreCallingIdentity(identityToken);
501         }
502     }
503 
isSyncActive(Account account, String authority)504     public boolean isSyncActive(Account account, String authority) {
505         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
506                 "no permission to read the sync stats");
507         int userId = UserHandle.getCallingUserId();
508 
509         long identityToken = clearCallingIdentity();
510         try {
511             SyncManager syncManager = getSyncManager();
512             if (syncManager != null) {
513                 return syncManager.getSyncStorageEngine().isSyncActive(
514                         account, userId, authority);
515             }
516         } finally {
517             restoreCallingIdentity(identityToken);
518         }
519         return false;
520     }
521 
getCurrentSyncs()522     public List<SyncInfo> getCurrentSyncs() {
523         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
524                 "no permission to read the sync stats");
525         int userId = UserHandle.getCallingUserId();
526 
527         long identityToken = clearCallingIdentity();
528         try {
529             return getSyncManager().getSyncStorageEngine().getCurrentSyncs(userId);
530         } finally {
531             restoreCallingIdentity(identityToken);
532         }
533     }
534 
getSyncStatus(Account account, String authority)535     public SyncStatusInfo getSyncStatus(Account account, String authority) {
536         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
537                 "no permission to read the sync stats");
538         int userId = UserHandle.getCallingUserId();
539 
540         long identityToken = clearCallingIdentity();
541         try {
542             SyncManager syncManager = getSyncManager();
543             if (syncManager != null) {
544                 return syncManager.getSyncStorageEngine().getStatusByAccountAndAuthority(
545                         account, userId, authority);
546             }
547         } finally {
548             restoreCallingIdentity(identityToken);
549         }
550         return null;
551     }
552 
isSyncPending(Account account, String authority)553     public boolean isSyncPending(Account account, String authority) {
554         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
555                 "no permission to read the sync stats");
556         int userId = UserHandle.getCallingUserId();
557 
558         long identityToken = clearCallingIdentity();
559         try {
560             SyncManager syncManager = getSyncManager();
561             if (syncManager != null) {
562                 return syncManager.getSyncStorageEngine().isSyncPending(account, userId, authority);
563             }
564         } finally {
565             restoreCallingIdentity(identityToken);
566         }
567         return false;
568     }
569 
addStatusChangeListener(int mask, ISyncStatusObserver callback)570     public void addStatusChangeListener(int mask, ISyncStatusObserver callback) {
571         long identityToken = clearCallingIdentity();
572         try {
573             SyncManager syncManager = getSyncManager();
574             if (syncManager != null && callback != null) {
575                 syncManager.getSyncStorageEngine().addStatusChangeListener(mask, callback);
576             }
577         } finally {
578             restoreCallingIdentity(identityToken);
579         }
580     }
581 
removeStatusChangeListener(ISyncStatusObserver callback)582     public void removeStatusChangeListener(ISyncStatusObserver callback) {
583         long identityToken = clearCallingIdentity();
584         try {
585             SyncManager syncManager = getSyncManager();
586             if (syncManager != null && callback != null) {
587                 syncManager.getSyncStorageEngine().removeStatusChangeListener(callback);
588             }
589         } finally {
590             restoreCallingIdentity(identityToken);
591         }
592     }
593 
main(Context context, boolean factoryTest)594     public static ContentService main(Context context, boolean factoryTest) {
595         ContentService service = new ContentService(context, factoryTest);
596         ServiceManager.addService(ContentResolver.CONTENT_SERVICE_NAME, service);
597         return service;
598     }
599 
600     /**
601      * Hide this class since it is not part of api,
602      * but current unittest framework requires it to be public
603      * @hide
604      */
605     public static final class ObserverNode {
606         private class ObserverEntry implements IBinder.DeathRecipient {
607             public final IContentObserver observer;
608             public final int uid;
609             public final int pid;
610             public final boolean notifyForDescendants;
611             private final int userHandle;
612             private final Object observersLock;
613 
ObserverEntry(IContentObserver o, boolean n, Object observersLock, int _uid, int _pid, int _userHandle)614             public ObserverEntry(IContentObserver o, boolean n, Object observersLock,
615                     int _uid, int _pid, int _userHandle) {
616                 this.observersLock = observersLock;
617                 observer = o;
618                 uid = _uid;
619                 pid = _pid;
620                 userHandle = _userHandle;
621                 notifyForDescendants = n;
622                 try {
623                     observer.asBinder().linkToDeath(this, 0);
624                 } catch (RemoteException e) {
625                     binderDied();
626                 }
627             }
628 
binderDied()629             public void binderDied() {
630                 synchronized (observersLock) {
631                     removeObserverLocked(observer);
632                 }
633             }
634 
dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args, String name, String prefix, SparseIntArray pidCounts)635             public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
636                     String name, String prefix, SparseIntArray pidCounts) {
637                 pidCounts.put(pid, pidCounts.get(pid)+1);
638                 pw.print(prefix); pw.print(name); pw.print(": pid=");
639                         pw.print(pid); pw.print(" uid=");
640                         pw.print(uid); pw.print(" user=");
641                         pw.print(userHandle); pw.print(" target=");
642                         pw.println(Integer.toHexString(System.identityHashCode(
643                                 observer != null ? observer.asBinder() : null)));
644             }
645         }
646 
647         public static final int INSERT_TYPE = 0;
648         public static final int UPDATE_TYPE = 1;
649         public static final int DELETE_TYPE = 2;
650 
651         private String mName;
652         private ArrayList<ObserverNode> mChildren = new ArrayList<ObserverNode>();
653         private ArrayList<ObserverEntry> mObservers = new ArrayList<ObserverEntry>();
654 
ObserverNode(String name)655         public ObserverNode(String name) {
656             mName = name;
657         }
658 
dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args, String name, String prefix, int[] counts, SparseIntArray pidCounts)659         public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
660                 String name, String prefix, int[] counts, SparseIntArray pidCounts) {
661             String innerName = null;
662             if (mObservers.size() > 0) {
663                 if ("".equals(name)) {
664                     innerName = mName;
665                 } else {
666                     innerName = name + "/" + mName;
667                 }
668                 for (int i=0; i<mObservers.size(); i++) {
669                     counts[1]++;
670                     mObservers.get(i).dumpLocked(fd, pw, args, innerName, prefix,
671                             pidCounts);
672                 }
673             }
674             if (mChildren.size() > 0) {
675                 if (innerName == null) {
676                     if ("".equals(name)) {
677                         innerName = mName;
678                     } else {
679                         innerName = name + "/" + mName;
680                     }
681                 }
682                 for (int i=0; i<mChildren.size(); i++) {
683                     counts[0]++;
684                     mChildren.get(i).dumpLocked(fd, pw, args, innerName, prefix,
685                             counts, pidCounts);
686                 }
687             }
688         }
689 
getUriSegment(Uri uri, int index)690         private String getUriSegment(Uri uri, int index) {
691             if (uri != null) {
692                 if (index == 0) {
693                     return uri.getAuthority();
694                 } else {
695                     return uri.getPathSegments().get(index - 1);
696                 }
697             } else {
698                 return null;
699             }
700         }
701 
countUriSegments(Uri uri)702         private int countUriSegments(Uri uri) {
703             if (uri == null) {
704                 return 0;
705             }
706             return uri.getPathSegments().size() + 1;
707         }
708 
709         // Invariant:  userHandle is either a hard user number or is USER_ALL
addObserverLocked(Uri uri, IContentObserver observer, boolean notifyForDescendants, Object observersLock, int uid, int pid, int userHandle)710         public void addObserverLocked(Uri uri, IContentObserver observer,
711                 boolean notifyForDescendants, Object observersLock,
712                 int uid, int pid, int userHandle) {
713             addObserverLocked(uri, 0, observer, notifyForDescendants, observersLock,
714                     uid, pid, userHandle);
715         }
716 
addObserverLocked(Uri uri, int index, IContentObserver observer, boolean notifyForDescendants, Object observersLock, int uid, int pid, int userHandle)717         private void addObserverLocked(Uri uri, int index, IContentObserver observer,
718                 boolean notifyForDescendants, Object observersLock,
719                 int uid, int pid, int userHandle) {
720             // If this is the leaf node add the observer
721             if (index == countUriSegments(uri)) {
722                 mObservers.add(new ObserverEntry(observer, notifyForDescendants, observersLock,
723                         uid, pid, userHandle));
724                 return;
725             }
726 
727             // Look to see if the proper child already exists
728             String segment = getUriSegment(uri, index);
729             if (segment == null) {
730                 throw new IllegalArgumentException("Invalid Uri (" + uri + ") used for observer");
731             }
732             int N = mChildren.size();
733             for (int i = 0; i < N; i++) {
734                 ObserverNode node = mChildren.get(i);
735                 if (node.mName.equals(segment)) {
736                     node.addObserverLocked(uri, index + 1, observer, notifyForDescendants,
737                             observersLock, uid, pid, userHandle);
738                     return;
739                 }
740             }
741 
742             // No child found, create one
743             ObserverNode node = new ObserverNode(segment);
744             mChildren.add(node);
745             node.addObserverLocked(uri, index + 1, observer, notifyForDescendants,
746                     observersLock, uid, pid, userHandle);
747         }
748 
removeObserverLocked(IContentObserver observer)749         public boolean removeObserverLocked(IContentObserver observer) {
750             int size = mChildren.size();
751             for (int i = 0; i < size; i++) {
752                 boolean empty = mChildren.get(i).removeObserverLocked(observer);
753                 if (empty) {
754                     mChildren.remove(i);
755                     i--;
756                     size--;
757                 }
758             }
759 
760             IBinder observerBinder = observer.asBinder();
761             size = mObservers.size();
762             for (int i = 0; i < size; i++) {
763                 ObserverEntry entry = mObservers.get(i);
764                 if (entry.observer.asBinder() == observerBinder) {
765                     mObservers.remove(i);
766                     // We no longer need to listen for death notifications. Remove it.
767                     observerBinder.unlinkToDeath(entry, 0);
768                     break;
769                 }
770             }
771 
772             if (mChildren.size() == 0 && mObservers.size() == 0) {
773                 return true;
774             }
775             return false;
776         }
777 
collectMyObserversLocked(boolean leaf, IContentObserver observer, boolean observerWantsSelfNotifications, int targetUserHandle, ArrayList<ObserverCall> calls)778         private void collectMyObserversLocked(boolean leaf, IContentObserver observer,
779                 boolean observerWantsSelfNotifications, int targetUserHandle,
780                 ArrayList<ObserverCall> calls) {
781             int N = mObservers.size();
782             IBinder observerBinder = observer == null ? null : observer.asBinder();
783             for (int i = 0; i < N; i++) {
784                 ObserverEntry entry = mObservers.get(i);
785 
786                 // Don't notify the observer if it sent the notification and isn't interested
787                 // in self notifications
788                 boolean selfChange = (entry.observer.asBinder() == observerBinder);
789                 if (selfChange && !observerWantsSelfNotifications) {
790                     continue;
791                 }
792 
793                 // Does this observer match the target user?
794                 if (targetUserHandle == UserHandle.USER_ALL
795                         || entry.userHandle == UserHandle.USER_ALL
796                         || targetUserHandle == entry.userHandle) {
797                     // Make sure the observer is interested in the notification
798                     if (leaf || (!leaf && entry.notifyForDescendants)) {
799                         calls.add(new ObserverCall(this, entry.observer, selfChange));
800                     }
801                 }
802             }
803         }
804 
805         /**
806          * targetUserHandle is either a hard user handle or is USER_ALL
807          */
collectObserversLocked(Uri uri, int index, IContentObserver observer, boolean observerWantsSelfNotifications, int targetUserHandle, ArrayList<ObserverCall> calls)808         public void collectObserversLocked(Uri uri, int index, IContentObserver observer,
809                 boolean observerWantsSelfNotifications, int targetUserHandle,
810                 ArrayList<ObserverCall> calls) {
811             String segment = null;
812             int segmentCount = countUriSegments(uri);
813             if (index >= segmentCount) {
814                 // This is the leaf node, notify all observers
815                 collectMyObserversLocked(true, observer, observerWantsSelfNotifications,
816                         targetUserHandle, calls);
817             } else if (index < segmentCount){
818                 segment = getUriSegment(uri, index);
819                 // Notify any observers at this level who are interested in descendants
820                 collectMyObserversLocked(false, observer, observerWantsSelfNotifications,
821                         targetUserHandle, calls);
822             }
823 
824             int N = mChildren.size();
825             for (int i = 0; i < N; i++) {
826                 ObserverNode node = mChildren.get(i);
827                 if (segment == null || node.mName.equals(segment)) {
828                     // We found the child,
829                     node.collectObserversLocked(uri, index + 1,
830                             observer, observerWantsSelfNotifications, targetUserHandle, calls);
831                     if (segment != null) {
832                         break;
833                     }
834                 }
835             }
836         }
837     }
838 }
839