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