PageRenderTime 64ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/services/core/java/com/android/server/content/ContentService.java

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