PageRenderTime 279ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/android/upstream/android/content/ContentService.java

https://bitbucket.org/festevezga/xobotos
Java | 716 lines | 598 code | 56 blank | 62 comment | 109 complexity | 849d8ebac419c3a660f86024cc3d9fca MD5 | raw file
  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. package android.content;
  17. import android.accounts.Account;
  18. import android.database.IContentObserver;
  19. import android.database.sqlite.SQLiteException;
  20. import android.net.Uri;
  21. import android.os.Binder;
  22. import android.os.Bundle;
  23. import android.os.IBinder;
  24. import android.os.Parcel;
  25. import android.os.RemoteException;
  26. import android.os.ServiceManager;
  27. import android.util.Log;
  28. import android.util.SparseIntArray;
  29. import android.Manifest;
  30. import java.io.FileDescriptor;
  31. import java.io.PrintWriter;
  32. import java.util.ArrayList;
  33. import java.util.Collections;
  34. import java.util.Comparator;
  35. import java.util.List;
  36. /**
  37. * {@hide}
  38. */
  39. public final class ContentService extends IContentService.Stub {
  40. private static final String TAG = "ContentService";
  41. private Context mContext;
  42. private boolean mFactoryTest;
  43. private final ObserverNode mRootNode = new ObserverNode("");
  44. private SyncManager mSyncManager = null;
  45. private final Object mSyncManagerLock = new Object();
  46. private SyncManager getSyncManager() {
  47. synchronized(mSyncManagerLock) {
  48. try {
  49. // Try to create the SyncManager, return null if it fails (e.g. the disk is full).
  50. if (mSyncManager == null) mSyncManager = new SyncManager(mContext, mFactoryTest);
  51. } catch (SQLiteException e) {
  52. Log.e(TAG, "Can't create SyncManager", e);
  53. }
  54. return mSyncManager;
  55. }
  56. }
  57. @Override
  58. protected synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
  59. mContext.enforceCallingOrSelfPermission(Manifest.permission.DUMP,
  60. "caller doesn't have the DUMP permission");
  61. // This makes it so that future permission checks will be in the context of this
  62. // process rather than the caller's process. We will restore this before returning.
  63. long identityToken = clearCallingIdentity();
  64. try {
  65. if (mSyncManager == null) {
  66. pw.println("No SyncManager created! (Disk full?)");
  67. } else {
  68. mSyncManager.dump(fd, pw);
  69. }
  70. pw.println();
  71. pw.println("Observer tree:");
  72. synchronized (mRootNode) {
  73. int[] counts = new int[2];
  74. final SparseIntArray pidCounts = new SparseIntArray();
  75. mRootNode.dumpLocked(fd, pw, args, "", " ", counts, pidCounts);
  76. pw.println();
  77. ArrayList<Integer> sorted = new ArrayList<Integer>();
  78. for (int i=0; i<pidCounts.size(); i++) {
  79. sorted.add(pidCounts.keyAt(i));
  80. }
  81. Collections.sort(sorted, new Comparator<Integer>() {
  82. @Override
  83. public int compare(Integer lhs, Integer rhs) {
  84. int lc = pidCounts.get(lhs);
  85. int rc = pidCounts.get(rhs);
  86. if (lc < rc) {
  87. return 1;
  88. } else if (lc > rc) {
  89. return -1;
  90. }
  91. return 0;
  92. }
  93. });
  94. for (int i=0; i<sorted.size(); i++) {
  95. int pid = sorted.get(i);
  96. pw.print(" pid "); pw.print(pid); pw.print(": ");
  97. pw.print(pidCounts.get(pid)); pw.println(" observers");
  98. }
  99. pw.println();
  100. pw.print(" Total number of nodes: "); pw.println(counts[0]);
  101. pw.print(" Total number of observers: "); pw.println(counts[1]);
  102. }
  103. } finally {
  104. restoreCallingIdentity(identityToken);
  105. }
  106. }
  107. @Override
  108. public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
  109. throws RemoteException {
  110. try {
  111. return super.onTransact(code, data, reply, flags);
  112. } catch (RuntimeException e) {
  113. // The content service only throws security exceptions, so let's
  114. // log all others.
  115. if (!(e instanceof SecurityException)) {
  116. Log.e(TAG, "Content Service Crash", e);
  117. }
  118. throw e;
  119. }
  120. }
  121. /*package*/ ContentService(Context context, boolean factoryTest) {
  122. mContext = context;
  123. mFactoryTest = factoryTest;
  124. getSyncManager();
  125. }
  126. public void registerContentObserver(Uri uri, boolean notifyForDescendents,
  127. IContentObserver observer) {
  128. if (observer == null || uri == null) {
  129. throw new IllegalArgumentException("You must pass a valid uri and observer");
  130. }
  131. synchronized (mRootNode) {
  132. mRootNode.addObserverLocked(uri, observer, notifyForDescendents, mRootNode,
  133. Binder.getCallingUid(), Binder.getCallingPid());
  134. if (false) Log.v(TAG, "Registered observer " + observer + " at " + uri +
  135. " with notifyForDescendents " + notifyForDescendents);
  136. }
  137. }
  138. public void unregisterContentObserver(IContentObserver observer) {
  139. if (observer == null) {
  140. throw new IllegalArgumentException("You must pass a valid observer");
  141. }
  142. synchronized (mRootNode) {
  143. mRootNode.removeObserverLocked(observer);
  144. if (false) Log.v(TAG, "Unregistered observer " + observer);
  145. }
  146. }
  147. public void notifyChange(Uri uri, IContentObserver observer,
  148. boolean observerWantsSelfNotifications, boolean syncToNetwork) {
  149. if (Log.isLoggable(TAG, Log.VERBOSE)) {
  150. Log.v(TAG, "Notifying update of " + uri + " from observer " + observer
  151. + ", syncToNetwork " + syncToNetwork);
  152. }
  153. // This makes it so that future permission checks will be in the context of this
  154. // process rather than the caller's process. We will restore this before returning.
  155. long identityToken = clearCallingIdentity();
  156. try {
  157. ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>();
  158. synchronized (mRootNode) {
  159. mRootNode.collectObserversLocked(uri, 0, observer, observerWantsSelfNotifications,
  160. calls);
  161. }
  162. final int numCalls = calls.size();
  163. for (int i=0; i<numCalls; i++) {
  164. ObserverCall oc = calls.get(i);
  165. try {
  166. oc.mObserver.onChange(oc.mSelfNotify);
  167. if (Log.isLoggable(TAG, Log.VERBOSE)) {
  168. Log.v(TAG, "Notified " + oc.mObserver + " of " + "update at " + uri);
  169. }
  170. } catch (RemoteException ex) {
  171. synchronized (mRootNode) {
  172. Log.w(TAG, "Found dead observer, removing");
  173. IBinder binder = oc.mObserver.asBinder();
  174. final ArrayList<ObserverNode.ObserverEntry> list
  175. = oc.mNode.mObservers;
  176. int numList = list.size();
  177. for (int j=0; j<numList; j++) {
  178. ObserverNode.ObserverEntry oe = list.get(j);
  179. if (oe.observer.asBinder() == binder) {
  180. list.remove(j);
  181. j--;
  182. numList--;
  183. }
  184. }
  185. }
  186. }
  187. }
  188. if (syncToNetwork) {
  189. SyncManager syncManager = getSyncManager();
  190. if (syncManager != null) {
  191. syncManager.scheduleLocalSync(null /* all accounts */, uri.getAuthority());
  192. }
  193. }
  194. } finally {
  195. restoreCallingIdentity(identityToken);
  196. }
  197. }
  198. /**
  199. * Hide this class since it is not part of api,
  200. * but current unittest framework requires it to be public
  201. * @hide
  202. *
  203. */
  204. public static final class ObserverCall {
  205. final ObserverNode mNode;
  206. final IContentObserver mObserver;
  207. final boolean mSelfNotify;
  208. ObserverCall(ObserverNode node, IContentObserver observer,
  209. boolean selfNotify) {
  210. mNode = node;
  211. mObserver = observer;
  212. mSelfNotify = selfNotify;
  213. }
  214. }
  215. public void requestSync(Account account, String authority, Bundle extras) {
  216. ContentResolver.validateSyncExtrasBundle(extras);
  217. // This makes it so that future permission checks will be in the context of this
  218. // process rather than the caller's process. We will restore this before returning.
  219. long identityToken = clearCallingIdentity();
  220. try {
  221. SyncManager syncManager = getSyncManager();
  222. if (syncManager != null) {
  223. syncManager.scheduleSync(account, authority, extras, 0 /* no delay */,
  224. false /* onlyThoseWithUnkownSyncableState */);
  225. }
  226. } finally {
  227. restoreCallingIdentity(identityToken);
  228. }
  229. }
  230. /**
  231. * Clear all scheduled sync operations that match the uri and cancel the active sync
  232. * if they match the authority and account, if they are present.
  233. * @param account filter the pending and active syncs to cancel using this account
  234. * @param authority filter the pending and active syncs to cancel using this authority
  235. */
  236. public void cancelSync(Account account, String authority) {
  237. // This makes it so that future permission checks will be in the context of this
  238. // process rather than the caller's process. We will restore this before returning.
  239. long identityToken = clearCallingIdentity();
  240. try {
  241. SyncManager syncManager = getSyncManager();
  242. if (syncManager != null) {
  243. syncManager.clearScheduledSyncOperations(account, authority);
  244. syncManager.cancelActiveSync(account, authority);
  245. }
  246. } finally {
  247. restoreCallingIdentity(identityToken);
  248. }
  249. }
  250. /**
  251. * Get information about the SyncAdapters that are known to the system.
  252. * @return an array of SyncAdapters that have registered with the system
  253. */
  254. public SyncAdapterType[] getSyncAdapterTypes() {
  255. // This makes it so that future permission checks will be in the context of this
  256. // process rather than the caller's process. We will restore this before returning.
  257. long identityToken = clearCallingIdentity();
  258. try {
  259. SyncManager syncManager = getSyncManager();
  260. return syncManager.getSyncAdapterTypes();
  261. } finally {
  262. restoreCallingIdentity(identityToken);
  263. }
  264. }
  265. public boolean getSyncAutomatically(Account account, String providerName) {
  266. mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
  267. "no permission to read the sync settings");
  268. long identityToken = clearCallingIdentity();
  269. try {
  270. SyncManager syncManager = getSyncManager();
  271. if (syncManager != null) {
  272. return syncManager.getSyncStorageEngine().getSyncAutomatically(
  273. account, providerName);
  274. }
  275. } finally {
  276. restoreCallingIdentity(identityToken);
  277. }
  278. return false;
  279. }
  280. public void setSyncAutomatically(Account account, String providerName, boolean sync) {
  281. mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
  282. "no permission to write the sync settings");
  283. long identityToken = clearCallingIdentity();
  284. try {
  285. SyncManager syncManager = getSyncManager();
  286. if (syncManager != null) {
  287. syncManager.getSyncStorageEngine().setSyncAutomatically(
  288. account, providerName, sync);
  289. }
  290. } finally {
  291. restoreCallingIdentity(identityToken);
  292. }
  293. }
  294. public void addPeriodicSync(Account account, String authority, Bundle extras,
  295. long pollFrequency) {
  296. mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
  297. "no permission to write the sync settings");
  298. long identityToken = clearCallingIdentity();
  299. try {
  300. getSyncManager().getSyncStorageEngine().addPeriodicSync(
  301. account, authority, extras, pollFrequency);
  302. } finally {
  303. restoreCallingIdentity(identityToken);
  304. }
  305. }
  306. public void removePeriodicSync(Account account, String authority, Bundle extras) {
  307. mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
  308. "no permission to write the sync settings");
  309. long identityToken = clearCallingIdentity();
  310. try {
  311. getSyncManager().getSyncStorageEngine().removePeriodicSync(account, authority, extras);
  312. } finally {
  313. restoreCallingIdentity(identityToken);
  314. }
  315. }
  316. public List<PeriodicSync> getPeriodicSyncs(Account account, String providerName) {
  317. mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
  318. "no permission to read the sync settings");
  319. long identityToken = clearCallingIdentity();
  320. try {
  321. return getSyncManager().getSyncStorageEngine().getPeriodicSyncs(
  322. account, providerName);
  323. } finally {
  324. restoreCallingIdentity(identityToken);
  325. }
  326. }
  327. public int getIsSyncable(Account account, String providerName) {
  328. mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
  329. "no permission to read the sync settings");
  330. long identityToken = clearCallingIdentity();
  331. try {
  332. SyncManager syncManager = getSyncManager();
  333. if (syncManager != null) {
  334. return syncManager.getSyncStorageEngine().getIsSyncable(
  335. account, providerName);
  336. }
  337. } finally {
  338. restoreCallingIdentity(identityToken);
  339. }
  340. return -1;
  341. }
  342. public void setIsSyncable(Account account, String providerName, int syncable) {
  343. mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
  344. "no permission to write the sync settings");
  345. long identityToken = clearCallingIdentity();
  346. try {
  347. SyncManager syncManager = getSyncManager();
  348. if (syncManager != null) {
  349. syncManager.getSyncStorageEngine().setIsSyncable(
  350. account, providerName, syncable);
  351. }
  352. } finally {
  353. restoreCallingIdentity(identityToken);
  354. }
  355. }
  356. public boolean getMasterSyncAutomatically() {
  357. mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
  358. "no permission to read the sync settings");
  359. long identityToken = clearCallingIdentity();
  360. try {
  361. SyncManager syncManager = getSyncManager();
  362. if (syncManager != null) {
  363. return syncManager.getSyncStorageEngine().getMasterSyncAutomatically();
  364. }
  365. } finally {
  366. restoreCallingIdentity(identityToken);
  367. }
  368. return false;
  369. }
  370. public void setMasterSyncAutomatically(boolean flag) {
  371. mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
  372. "no permission to write the sync settings");
  373. long identityToken = clearCallingIdentity();
  374. try {
  375. SyncManager syncManager = getSyncManager();
  376. if (syncManager != null) {
  377. syncManager.getSyncStorageEngine().setMasterSyncAutomatically(flag);
  378. }
  379. } finally {
  380. restoreCallingIdentity(identityToken);
  381. }
  382. }
  383. public boolean isSyncActive(Account account, String authority) {
  384. mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
  385. "no permission to read the sync stats");
  386. long identityToken = clearCallingIdentity();
  387. try {
  388. SyncManager syncManager = getSyncManager();
  389. if (syncManager != null) {
  390. return syncManager.getSyncStorageEngine().isSyncActive(
  391. account, authority);
  392. }
  393. } finally {
  394. restoreCallingIdentity(identityToken);
  395. }
  396. return false;
  397. }
  398. public List<SyncInfo> getCurrentSyncs() {
  399. mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
  400. "no permission to read the sync stats");
  401. long identityToken = clearCallingIdentity();
  402. try {
  403. return getSyncManager().getSyncStorageEngine().getCurrentSyncs();
  404. } finally {
  405. restoreCallingIdentity(identityToken);
  406. }
  407. }
  408. public SyncStatusInfo getSyncStatus(Account account, String authority) {
  409. mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
  410. "no permission to read the sync stats");
  411. long identityToken = clearCallingIdentity();
  412. try {
  413. SyncManager syncManager = getSyncManager();
  414. if (syncManager != null) {
  415. return syncManager.getSyncStorageEngine().getStatusByAccountAndAuthority(
  416. account, authority);
  417. }
  418. } finally {
  419. restoreCallingIdentity(identityToken);
  420. }
  421. return null;
  422. }
  423. public boolean isSyncPending(Account account, String authority) {
  424. mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
  425. "no permission to read the sync stats");
  426. long identityToken = clearCallingIdentity();
  427. try {
  428. SyncManager syncManager = getSyncManager();
  429. if (syncManager != null) {
  430. return syncManager.getSyncStorageEngine().isSyncPending(account, authority);
  431. }
  432. } finally {
  433. restoreCallingIdentity(identityToken);
  434. }
  435. return false;
  436. }
  437. public void addStatusChangeListener(int mask, ISyncStatusObserver callback) {
  438. long identityToken = clearCallingIdentity();
  439. try {
  440. SyncManager syncManager = getSyncManager();
  441. if (syncManager != null && callback != null) {
  442. syncManager.getSyncStorageEngine().addStatusChangeListener(mask, callback);
  443. }
  444. } finally {
  445. restoreCallingIdentity(identityToken);
  446. }
  447. }
  448. public void removeStatusChangeListener(ISyncStatusObserver callback) {
  449. long identityToken = clearCallingIdentity();
  450. try {
  451. SyncManager syncManager = getSyncManager();
  452. if (syncManager != null && callback != null) {
  453. syncManager.getSyncStorageEngine().removeStatusChangeListener(callback);
  454. }
  455. } finally {
  456. restoreCallingIdentity(identityToken);
  457. }
  458. }
  459. public static IContentService main(Context context, boolean factoryTest) {
  460. ContentService service = new ContentService(context, factoryTest);
  461. ServiceManager.addService(ContentResolver.CONTENT_SERVICE_NAME, service);
  462. return service;
  463. }
  464. /**
  465. * Hide this class since it is not part of api,
  466. * but current unittest framework requires it to be public
  467. * @hide
  468. */
  469. public static final class ObserverNode {
  470. private class ObserverEntry implements IBinder.DeathRecipient {
  471. public final IContentObserver observer;
  472. public final int uid;
  473. public final int pid;
  474. public final boolean notifyForDescendents;
  475. private final Object observersLock;
  476. public ObserverEntry(IContentObserver o, boolean n, Object observersLock,
  477. int _uid, int _pid) {
  478. this.observersLock = observersLock;
  479. observer = o;
  480. uid = _uid;
  481. pid = _pid;
  482. notifyForDescendents = n;
  483. try {
  484. observer.asBinder().linkToDeath(this, 0);
  485. } catch (RemoteException e) {
  486. binderDied();
  487. }
  488. }
  489. public void binderDied() {
  490. synchronized (observersLock) {
  491. removeObserverLocked(observer);
  492. }
  493. }
  494. public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
  495. String name, String prefix, SparseIntArray pidCounts) {
  496. pidCounts.put(pid, pidCounts.get(pid)+1);
  497. pw.print(prefix); pw.print(name); pw.print(": pid=");
  498. pw.print(pid); pw.print(" uid=");
  499. pw.print(uid); pw.print(" target=");
  500. pw.println(Integer.toHexString(System.identityHashCode(
  501. observer != null ? observer.asBinder() : null)));
  502. }
  503. }
  504. public static final int INSERT_TYPE = 0;
  505. public static final int UPDATE_TYPE = 1;
  506. public static final int DELETE_TYPE = 2;
  507. private String mName;
  508. private ArrayList<ObserverNode> mChildren = new ArrayList<ObserverNode>();
  509. private ArrayList<ObserverEntry> mObservers = new ArrayList<ObserverEntry>();
  510. public ObserverNode(String name) {
  511. mName = name;
  512. }
  513. public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
  514. String name, String prefix, int[] counts, SparseIntArray pidCounts) {
  515. String innerName = null;
  516. if (mObservers.size() > 0) {
  517. if ("".equals(name)) {
  518. innerName = mName;
  519. } else {
  520. innerName = name + "/" + mName;
  521. }
  522. for (int i=0; i<mObservers.size(); i++) {
  523. counts[1]++;
  524. mObservers.get(i).dumpLocked(fd, pw, args, innerName, prefix,
  525. pidCounts);
  526. }
  527. }
  528. if (mChildren.size() > 0) {
  529. if (innerName == null) {
  530. if ("".equals(name)) {
  531. innerName = mName;
  532. } else {
  533. innerName = name + "/" + mName;
  534. }
  535. }
  536. for (int i=0; i<mChildren.size(); i++) {
  537. counts[0]++;
  538. mChildren.get(i).dumpLocked(fd, pw, args, innerName, prefix,
  539. counts, pidCounts);
  540. }
  541. }
  542. }
  543. private String getUriSegment(Uri uri, int index) {
  544. if (uri != null) {
  545. if (index == 0) {
  546. return uri.getAuthority();
  547. } else {
  548. return uri.getPathSegments().get(index - 1);
  549. }
  550. } else {
  551. return null;
  552. }
  553. }
  554. private int countUriSegments(Uri uri) {
  555. if (uri == null) {
  556. return 0;
  557. }
  558. return uri.getPathSegments().size() + 1;
  559. }
  560. public void addObserverLocked(Uri uri, IContentObserver observer,
  561. boolean notifyForDescendents, Object observersLock, int uid, int pid) {
  562. addObserverLocked(uri, 0, observer, notifyForDescendents, observersLock, uid, pid);
  563. }
  564. private void addObserverLocked(Uri uri, int index, IContentObserver observer,
  565. boolean notifyForDescendents, Object observersLock, int uid, int pid) {
  566. // If this is the leaf node add the observer
  567. if (index == countUriSegments(uri)) {
  568. mObservers.add(new ObserverEntry(observer, notifyForDescendents, observersLock,
  569. uid, pid));
  570. return;
  571. }
  572. // Look to see if the proper child already exists
  573. String segment = getUriSegment(uri, index);
  574. if (segment == null) {
  575. throw new IllegalArgumentException("Invalid Uri (" + uri + ") used for observer");
  576. }
  577. int N = mChildren.size();
  578. for (int i = 0; i < N; i++) {
  579. ObserverNode node = mChildren.get(i);
  580. if (node.mName.equals(segment)) {
  581. node.addObserverLocked(uri, index + 1, observer, notifyForDescendents,
  582. observersLock, uid, pid);
  583. return;
  584. }
  585. }
  586. // No child found, create one
  587. ObserverNode node = new ObserverNode(segment);
  588. mChildren.add(node);
  589. node.addObserverLocked(uri, index + 1, observer, notifyForDescendents,
  590. observersLock, uid, pid);
  591. }
  592. public boolean removeObserverLocked(IContentObserver observer) {
  593. int size = mChildren.size();
  594. for (int i = 0; i < size; i++) {
  595. boolean empty = mChildren.get(i).removeObserverLocked(observer);
  596. if (empty) {
  597. mChildren.remove(i);
  598. i--;
  599. size--;
  600. }
  601. }
  602. IBinder observerBinder = observer.asBinder();
  603. size = mObservers.size();
  604. for (int i = 0; i < size; i++) {
  605. ObserverEntry entry = mObservers.get(i);
  606. if (entry.observer.asBinder() == observerBinder) {
  607. mObservers.remove(i);
  608. // We no longer need to listen for death notifications. Remove it.
  609. observerBinder.unlinkToDeath(entry, 0);
  610. break;
  611. }
  612. }
  613. if (mChildren.size() == 0 && mObservers.size() == 0) {
  614. return true;
  615. }
  616. return false;
  617. }
  618. private void collectMyObserversLocked(boolean leaf, IContentObserver observer,
  619. boolean selfNotify, ArrayList<ObserverCall> calls) {
  620. int N = mObservers.size();
  621. IBinder observerBinder = observer == null ? null : observer.asBinder();
  622. for (int i = 0; i < N; i++) {
  623. ObserverEntry entry = mObservers.get(i);
  624. // Don't notify the observer if it sent the notification and isn't interesed
  625. // in self notifications
  626. if (entry.observer.asBinder() == observerBinder && !selfNotify) {
  627. continue;
  628. }
  629. // Make sure the observer is interested in the notification
  630. if (leaf || (!leaf && entry.notifyForDescendents)) {
  631. calls.add(new ObserverCall(this, entry.observer, selfNotify));
  632. }
  633. }
  634. }
  635. public void collectObserversLocked(Uri uri, int index, IContentObserver observer,
  636. boolean selfNotify, ArrayList<ObserverCall> calls) {
  637. String segment = null;
  638. int segmentCount = countUriSegments(uri);
  639. if (index >= segmentCount) {
  640. // This is the leaf node, notify all observers
  641. collectMyObserversLocked(true, observer, selfNotify, calls);
  642. } else if (index < segmentCount){
  643. segment = getUriSegment(uri, index);
  644. // Notify any observers at this level who are interested in descendents
  645. collectMyObserversLocked(false, observer, selfNotify, calls);
  646. }
  647. int N = mChildren.size();
  648. for (int i = 0; i < N; i++) {
  649. ObserverNode node = mChildren.get(i);
  650. if (segment == null || node.mName.equals(segment)) {
  651. // We found the child,
  652. node.collectObserversLocked(uri, index + 1, observer, selfNotify, calls);
  653. if (segment != null) {
  654. break;
  655. }
  656. }
  657. }
  658. }
  659. }
  660. }