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