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 17package com.android.server.content; 18 19import android.Manifest; 20import android.accounts.Account; 21import android.annotation.Nullable; 22import android.app.ActivityManager; 23import android.app.ActivityManagerInternal; 24import android.app.AppOpsManager; 25import android.app.job.JobInfo; 26import android.content.BroadcastReceiver; 27import android.content.ComponentName; 28import android.content.ContentResolver; 29import android.content.ContentResolver.SyncExemption; 30import android.content.Context; 31import android.content.IContentService; 32import android.content.ISyncStatusObserver; 33import android.content.Intent; 34import android.content.IntentFilter; 35import android.content.PeriodicSync; 36import android.content.SyncAdapterType; 37import android.content.SyncInfo; 38import android.content.SyncRequest; 39import android.content.SyncStatusInfo; 40import android.content.pm.PackageManager; 41import android.content.pm.PackageManagerInternal; 42import android.content.pm.ProviderInfo; 43import android.database.IContentObserver; 44import android.database.sqlite.SQLiteException; 45import android.net.Uri; 46import android.os.Binder; 47import android.os.Build; 48import android.os.Bundle; 49import android.os.FactoryTest; 50import android.os.IBinder; 51import android.os.Parcel; 52import android.os.Process; 53import android.os.RemoteException; 54import android.os.ResultReceiver; 55import android.os.ShellCallback; 56import android.os.UserHandle; 57import android.text.TextUtils; 58import android.util.ArrayMap; 59import android.util.Log; 60import android.util.Pair; 61import android.util.Slog; 62import android.util.SparseArray; 63import android.util.SparseIntArray; 64 65import com.android.internal.annotations.GuardedBy; 66import com.android.internal.util.ArrayUtils; 67import com.android.internal.util.DumpUtils; 68import com.android.internal.util.IndentingPrintWriter; 69import com.android.server.LocalServices; 70import com.android.server.SystemService; 71 72import java.io.FileDescriptor; 73import java.io.PrintWriter; 74import java.util.ArrayList; 75import java.util.Collections; 76import java.util.Comparator; 77import java.util.List; 78 79/** 80 * {@hide} 81 */ 82public final class ContentService extends IContentService.Stub { 83 static final String TAG = "ContentService"; 84 static final boolean DEBUG = false; 85 86 public static class Lifecycle extends SystemService { 87 private ContentService mService; 88 89 public Lifecycle(Context context) { 90 super(context); 91 } 92 93 @Override 94 public void onStart() { 95 final boolean factoryTest = (FactoryTest 96 .getMode() == FactoryTest.FACTORY_TEST_LOW_LEVEL); 97 mService = new ContentService(getContext(), factoryTest); 98 publishBinderService(ContentResolver.CONTENT_SERVICE_NAME, mService); 99 } 100 101 @Override 102 public void onBootPhase(int phase) { 103 mService.onBootPhase(phase); 104 } 105 106 107 @Override 108 public void onStartUser(int userHandle) { 109 mService.onStartUser(userHandle); 110 } 111 112 @Override 113 public void onUnlockUser(int userHandle) { 114 mService.onUnlockUser(userHandle); 115 } 116 117 @Override 118 public void onStopUser(int userHandle) { 119 mService.onStopUser(userHandle); 120 } 121 122 @Override 123 public void onCleanupUser(int userHandle) { 124 synchronized (mService.mCache) { 125 mService.mCache.remove(userHandle); 126 } 127 } 128 } 129 130 private Context mContext; 131 private boolean mFactoryTest; 132 133 private final ObserverNode mRootNode = new ObserverNode(""); 134 135 private SyncManager mSyncManager = null; 136 private final Object mSyncManagerLock = new Object(); 137 138 /** 139 * Map from userId to providerPackageName to [clientPackageName, uri] to 140 * value. This structure is carefully optimized to keep invalidation logic 141 * as cheap as possible. 142 */ 143 @GuardedBy("mCache") 144 private final SparseArray<ArrayMap<String, ArrayMap<Pair<String, Uri>, Bundle>>> 145 mCache = new SparseArray<>(); 146 147 private BroadcastReceiver mCacheReceiver = new BroadcastReceiver() { 148 @Override 149 public void onReceive(Context context, Intent intent) { 150 synchronized (mCache) { 151 if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) { 152 mCache.clear(); 153 } else { 154 final Uri data = intent.getData(); 155 if (data != null) { 156 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 157 UserHandle.USER_NULL); 158 final String packageName = data.getSchemeSpecificPart(); 159 invalidateCacheLocked(userId, packageName, null); 160 } 161 } 162 } 163 } 164 }; 165 166 private SyncManager getSyncManager() { 167 synchronized(mSyncManagerLock) { 168 try { 169 // Try to create the SyncManager, return null if it fails (which it shouldn't). 170 if (mSyncManager == null) mSyncManager = new SyncManager(mContext, mFactoryTest); 171 } catch (SQLiteException e) { 172 Log.e(TAG, "Can't create SyncManager", e); 173 } 174 return mSyncManager; 175 } 176 } 177 178 void onStartUser(int userHandle) { 179 if (mSyncManager != null) mSyncManager.onStartUser(userHandle); 180 } 181 182 void onUnlockUser(int userHandle) { 183 if (mSyncManager != null) mSyncManager.onUnlockUser(userHandle); 184 } 185 186 void onStopUser(int userHandle) { 187 if (mSyncManager != null) mSyncManager.onStopUser(userHandle); 188 } 189 190 @Override 191 protected synchronized void dump(FileDescriptor fd, PrintWriter pw_, String[] args) { 192 if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw_)) return; 193 final IndentingPrintWriter pw = new IndentingPrintWriter(pw_, " "); 194 195 final boolean dumpAll = ArrayUtils.contains(args, "-a"); 196 197 // This makes it so that future permission checks will be in the context of this 198 // process rather than the caller's process. We will restore this before returning. 199 final long identityToken = clearCallingIdentity(); 200 try { 201 if (mSyncManager == null) { 202 pw.println("SyncManager not available yet"); 203 } else { 204 mSyncManager.dump(fd, pw, dumpAll); 205 } 206 pw.println(); 207 pw.println("Observer tree:"); 208 synchronized (mRootNode) { 209 int[] counts = new int[2]; 210 final SparseIntArray pidCounts = new SparseIntArray(); 211 mRootNode.dumpLocked(fd, pw, args, "", " ", counts, pidCounts); 212 pw.println(); 213 ArrayList<Integer> sorted = new ArrayList<Integer>(); 214 for (int i=0; i<pidCounts.size(); i++) { 215 sorted.add(pidCounts.keyAt(i)); 216 } 217 Collections.sort(sorted, new Comparator<Integer>() { 218 @Override 219 public int compare(Integer lhs, Integer rhs) { 220 int lc = pidCounts.get(lhs); 221 int rc = pidCounts.get(rhs); 222 if (lc < rc) { 223 return 1; 224 } else if (lc > rc) { 225 return -1; 226 } 227 return 0; 228 } 229 230 }); 231 for (int i=0; i<sorted.size(); i++) { 232 int pid = sorted.get(i); 233 pw.print(" pid "); pw.print(pid); pw.print(": "); 234 pw.print(pidCounts.get(pid)); pw.println(" observers"); 235 } 236 pw.println(); 237 pw.print(" Total number of nodes: "); pw.println(counts[0]); 238 pw.print(" Total number of observers: "); pw.println(counts[1]); 239 } 240 241 synchronized (mCache) { 242 pw.println(); 243 pw.println("Cached content:"); 244 pw.increaseIndent(); 245 for (int i = 0; i < mCache.size(); i++) { 246 pw.println("User " + mCache.keyAt(i) + ":"); 247 pw.increaseIndent(); 248 pw.println(mCache.valueAt(i)); 249 pw.decreaseIndent(); 250 } 251 pw.decreaseIndent(); 252 } 253 } finally { 254 restoreCallingIdentity(identityToken); 255 } 256 } 257 258 @Override 259 public boolean onTransact(int code, Parcel data, Parcel reply, int flags) 260 throws RemoteException { 261 try { 262 return super.onTransact(code, data, reply, flags); 263 } catch (RuntimeException e) { 264 // The content service only throws security exceptions, so let's 265 // log all others. 266 if (!(e instanceof SecurityException)) { 267 Slog.wtf(TAG, "Content Service Crash", e); 268 } 269 throw e; 270 } 271 } 272 273 /*package*/ ContentService(Context context, boolean factoryTest) { 274 mContext = context; 275 mFactoryTest = factoryTest; 276 277 // Let the package manager query for the sync adapters for a given authority 278 // as we grant default permissions to sync adapters for specific authorities. 279 PackageManagerInternal packageManagerInternal = LocalServices.getService( 280 PackageManagerInternal.class); 281 packageManagerInternal.setSyncAdapterPackagesprovider( 282 new PackageManagerInternal.SyncAdapterPackagesProvider() { 283 @Override 284 public String[] getPackages(String authority, int userId) { 285 return getSyncAdapterPackagesForAuthorityAsUser(authority, userId); 286 } 287 }); 288 289 final IntentFilter packageFilter = new IntentFilter(); 290 packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED); 291 packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); 292 packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 293 packageFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED); 294 packageFilter.addDataScheme("package"); 295 mContext.registerReceiverAsUser(mCacheReceiver, UserHandle.ALL, 296 packageFilter, null, null); 297 298 final IntentFilter localeFilter = new IntentFilter(); 299 localeFilter.addAction(Intent.ACTION_LOCALE_CHANGED); 300 mContext.registerReceiverAsUser(mCacheReceiver, UserHandle.ALL, 301 localeFilter, null, null); 302 } 303 304 void onBootPhase(int phase) { 305 switch (phase) { 306 case SystemService.PHASE_ACTIVITY_MANAGER_READY: 307 getSyncManager(); 308 break; 309 } 310 if (mSyncManager != null) { 311 mSyncManager.onBootPhase(phase); 312 } 313 } 314 315 /** 316 * Register a content observer tied to a specific user's view of the provider. 317 * @param userHandle the user whose view of the provider is to be observed. May be 318 * the calling user without requiring any permission, otherwise the caller needs to 319 * hold the INTERACT_ACROSS_USERS_FULL permission or hold a read uri grant to the uri. 320 * Pseudousers USER_ALL and USER_CURRENT are properly handled; all other pseudousers 321 * are forbidden. 322 */ 323 @Override 324 public void registerContentObserver(Uri uri, boolean notifyForDescendants, 325 IContentObserver observer, int userHandle, int targetSdkVersion) { 326 if (observer == null || uri == null) { 327 throw new IllegalArgumentException("You must pass a valid uri and observer"); 328 } 329 330 final int uid = Binder.getCallingUid(); 331 final int pid = Binder.getCallingPid(); 332 333 userHandle = handleIncomingUser(uri, pid, uid, 334 Intent.FLAG_GRANT_READ_URI_PERMISSION, true, userHandle); 335 336 final String msg = LocalServices.getService(ActivityManagerInternal.class) 337 .checkContentProviderAccess(uri.getAuthority(), userHandle); 338 if (msg != null) { 339 if (targetSdkVersion >= Build.VERSION_CODES.O) { 340 throw new SecurityException(msg); 341 } else { 342 if (msg.startsWith("Failed to find provider")) { 343 // Sigh, we need to quietly let apps targeting older API 344 // levels notify on non-existent providers. 345 } else { 346 Log.w(TAG, "Ignoring content changes for " + uri + " from " + uid + ": " + msg); 347 return; 348 } 349 } 350 } 351 352 synchronized (mRootNode) { 353 mRootNode.addObserverLocked(uri, observer, notifyForDescendants, mRootNode, 354 uid, pid, userHandle); 355 if (false) Log.v(TAG, "Registered observer " + observer + " at " + uri + 356 " with notifyForDescendants " + notifyForDescendants); 357 } 358 } 359 360 public void registerContentObserver(Uri uri, boolean notifyForDescendants, 361 IContentObserver observer) { 362 registerContentObserver(uri, notifyForDescendants, observer, 363 UserHandle.getCallingUserId(), Build.VERSION_CODES.CUR_DEVELOPMENT); 364 } 365 366 @Override 367 public void unregisterContentObserver(IContentObserver observer) { 368 if (observer == null) { 369 throw new IllegalArgumentException("You must pass a valid observer"); 370 } 371 synchronized (mRootNode) { 372 mRootNode.removeObserverLocked(observer); 373 if (false) Log.v(TAG, "Unregistered observer " + observer); 374 } 375 } 376 377 /** 378 * Notify observers of a particular user's view of the provider. 379 * @param userHandle the user whose view of the provider is to be notified. May be 380 * the calling user without requiring any permission, otherwise the caller needs to 381 * hold the INTERACT_ACROSS_USERS_FULL permission or hold a write uri grant to the uri. 382 * Pseudousers USER_ALL and USER_CURRENT are properly interpreted; no other pseudousers are 383 * allowed. 384 */ 385 @Override 386 public void notifyChange(Uri uri, IContentObserver observer, 387 boolean observerWantsSelfNotifications, int flags, int userHandle, 388 int targetSdkVersion) { 389 if (DEBUG) Slog.d(TAG, "Notifying update of " + uri + " for user " + userHandle 390 + " from observer " + observer + ", flags " + Integer.toHexString(flags)); 391 392 if (uri == null) { 393 throw new NullPointerException("Uri must not be null"); 394 } 395 396 final int uid = Binder.getCallingUid(); 397 final int pid = Binder.getCallingPid(); 398 final int callingUserHandle = UserHandle.getCallingUserId(); 399 400 userHandle = handleIncomingUser(uri, pid, uid, 401 Intent.FLAG_GRANT_WRITE_URI_PERMISSION, true, userHandle); 402 403 final String msg = LocalServices.getService(ActivityManagerInternal.class) 404 .checkContentProviderAccess(uri.getAuthority(), userHandle); 405 if (msg != null) { 406 if (targetSdkVersion >= Build.VERSION_CODES.O) { 407 throw new SecurityException(msg); 408 } else { 409 if (msg.startsWith("Failed to find provider")) { 410 // Sigh, we need to quietly let apps targeting older API 411 // levels notify on non-existent providers. 412 } else { 413 Log.w(TAG, "Ignoring notify for " + uri + " from " + uid + ": " + msg); 414 return; 415 } 416 } 417 } 418 419 // This makes it so that future permission checks will be in the context of this 420 // process rather than the caller's process. We will restore this before returning. 421 long identityToken = clearCallingIdentity(); 422 try { 423 ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>(); 424 synchronized (mRootNode) { 425 mRootNode.collectObserversLocked(uri, 0, observer, observerWantsSelfNotifications, 426 flags, userHandle, calls); 427 } 428 final int numCalls = calls.size(); 429 for (int i=0; i<numCalls; i++) { 430 ObserverCall oc = calls.get(i); 431 try { 432 oc.mObserver.onChange(oc.mSelfChange, uri, userHandle); 433 if (DEBUG) Slog.d(TAG, "Notified " + oc.mObserver + " of " + "update at " 434 + uri); 435 } catch (RemoteException ex) { 436 synchronized (mRootNode) { 437 Log.w(TAG, "Found dead observer, removing"); 438 IBinder binder = oc.mObserver.asBinder(); 439 final ArrayList<ObserverNode.ObserverEntry> list 440 = oc.mNode.mObservers; 441 int numList = list.size(); 442 for (int j=0; j<numList; j++) { 443 ObserverNode.ObserverEntry oe = list.get(j); 444 if (oe.observer.asBinder() == binder) { 445 list.remove(j); 446 j--; 447 numList--; 448 } 449 } 450 } 451 } 452 } 453 if ((flags&ContentResolver.NOTIFY_SYNC_TO_NETWORK) != 0) { 454 SyncManager syncManager = getSyncManager(); 455 if (syncManager != null) { 456 syncManager.scheduleLocalSync(null /* all accounts */, callingUserHandle, uid, 457 uri.getAuthority(), getSyncExemptionForCaller(uid)); 458 } 459 } 460 461 synchronized (mCache) { 462 final String providerPackageName = getProviderPackageName(uri); 463 invalidateCacheLocked(userHandle, providerPackageName, uri); 464 } 465 } finally { 466 restoreCallingIdentity(identityToken); 467 } 468 } 469 470 private int checkUriPermission(Uri uri, int pid, int uid, int modeFlags, int userHandle) { 471 try { 472 return ActivityManager.getService().checkUriPermission( 473 uri, pid, uid, modeFlags, userHandle, null); 474 } catch (RemoteException e) { 475 return PackageManager.PERMISSION_DENIED; 476 } 477 } 478 479 public void notifyChange(Uri uri, IContentObserver observer, 480 boolean observerWantsSelfNotifications, boolean syncToNetwork) { 481 notifyChange(uri, observer, observerWantsSelfNotifications, 482 syncToNetwork ? ContentResolver.NOTIFY_SYNC_TO_NETWORK : 0, 483 UserHandle.getCallingUserId(), Build.VERSION_CODES.CUR_DEVELOPMENT); 484 } 485 486 /** 487 * Hide this class since it is not part of api, 488 * but current unittest framework requires it to be public 489 * @hide 490 * 491 */ 492 public static final class ObserverCall { 493 final ObserverNode mNode; 494 final IContentObserver mObserver; 495 final boolean mSelfChange; 496 final int mObserverUserId; 497 498 ObserverCall(ObserverNode node, IContentObserver observer, boolean selfChange, int observerUserId) { 499 mNode = node; 500 mObserver = observer; 501 mSelfChange = selfChange; 502 mObserverUserId = observerUserId; 503 } 504 } 505 506 @Override 507 public void requestSync(Account account, String authority, Bundle extras) { 508 Bundle.setDefusable(extras, true); 509 ContentResolver.validateSyncExtrasBundle(extras); 510 int userId = UserHandle.getCallingUserId(); 511 int uId = Binder.getCallingUid(); 512 513 validateExtras(uId, extras); 514 final int syncExemption = getSyncExemptionAndCleanUpExtrasForCaller(uId, extras); 515 516 // This makes it so that future permission checks will be in the context of this 517 // process rather than the caller's process. We will restore this before returning. 518 long identityToken = clearCallingIdentity(); 519 try { 520 SyncManager syncManager = getSyncManager(); 521 if (syncManager != null) { 522 syncManager.scheduleSync(account, userId, uId, authority, extras, 523 SyncStorageEngine.AuthorityInfo.UNDEFINED, 524 syncExemption); 525 } 526 } finally { 527 restoreCallingIdentity(identityToken); 528 } 529 } 530 531 /** 532 * Request a sync with a generic {@link android.content.SyncRequest} object. This will be 533 * either: 534 * periodic OR one-off sync. 535 * and 536 * anonymous OR provider sync. 537 * Depending on the request, we enqueue to suit in the SyncManager. 538 * @param request The request object. Validation of this object is done by its builder. 539 */ 540 @Override 541 public void sync(SyncRequest request) { 542 syncAsUser(request, UserHandle.getCallingUserId()); 543 } 544 545 private long clampPeriod(long period) { 546 long minPeriod = JobInfo.getMinPeriodMillis() / 1000; 547 if (period < minPeriod) { 548 Slog.w(TAG, "Requested poll frequency of " + period 549 + " seconds being rounded up to " + minPeriod + "s."); 550 period = minPeriod; 551 } 552 return period; 553 } 554 555 /** 556 * If the user id supplied is different to the calling user, the caller must hold the 557 * INTERACT_ACROSS_USERS_FULL permission. 558 */ 559 @Override 560 public void syncAsUser(SyncRequest request, int userId) { 561 enforceCrossUserPermission(userId, "no permission to request sync as user: " + userId); 562 int callerUid = Binder.getCallingUid(); 563 564 final Bundle extras = request.getBundle(); 565 566 validateExtras(callerUid, extras); 567 final int syncExemption = getSyncExemptionAndCleanUpExtrasForCaller(callerUid, extras); 568 569 // This makes it so that future permission checks will be in the context of this 570 // process rather than the caller's process. We will restore this before returning. 571 long identityToken = clearCallingIdentity(); 572 try { 573 SyncManager syncManager = getSyncManager(); 574 if (syncManager == null) { 575 return; 576 } 577 long flextime = request.getSyncFlexTime(); 578 long runAtTime = request.getSyncRunTime(); 579 if (request.isPeriodic()) { 580 mContext.enforceCallingOrSelfPermission( 581 Manifest.permission.WRITE_SYNC_SETTINGS, 582 "no permission to write the sync settings"); 583 SyncStorageEngine.EndPoint info; 584 info = new SyncStorageEngine.EndPoint( 585 request.getAccount(), request.getProvider(), userId); 586 587 runAtTime = clampPeriod(runAtTime); 588 // Schedule periodic sync. 589 getSyncManager().updateOrAddPeriodicSync(info, runAtTime, 590 flextime, extras); 591 } else { 592 syncManager.scheduleSync( 593 request.getAccount(), userId, callerUid, request.getProvider(), extras, 594 SyncStorageEngine.AuthorityInfo.UNDEFINED, 595 syncExemption); 596 } 597 } finally { 598 restoreCallingIdentity(identityToken); 599 } 600 } 601 602 /** 603 * Clear all scheduled sync operations that match the uri and cancel the active sync 604 * if they match the authority and account, if they are present. 605 * 606 * @param account filter the pending and active syncs to cancel using this account, or null. 607 * @param authority filter the pending and active syncs to cancel using this authority, or 608 * null. 609 * @param cname cancel syncs running on this service, or null for provider/account. 610 */ 611 @Override 612 public void cancelSync(Account account, String authority, ComponentName cname) { 613 cancelSyncAsUser(account, authority, cname, UserHandle.getCallingUserId()); 614 } 615 616 /** 617 * Clear all scheduled sync operations that match the uri and cancel the active sync 618 * if they match the authority and account, if they are present. 619 * 620 * <p> If the user id supplied is different to the calling user, the caller must hold the 621 * INTERACT_ACROSS_USERS_FULL permission. 622 * 623 * @param account filter the pending and active syncs to cancel using this account, or null. 624 * @param authority filter the pending and active syncs to cancel using this authority, or 625 * null. 626 * @param userId the user id for which to cancel sync operations. 627 * @param cname cancel syncs running on this service, or null for provider/account. 628 */ 629 @Override 630 public void cancelSyncAsUser(Account account, String authority, ComponentName cname, 631 int userId) { 632 if (authority != null && authority.length() == 0) { 633 throw new IllegalArgumentException("Authority must be non-empty"); 634 } 635 enforceCrossUserPermission(userId, 636 "no permission to modify the sync settings for user " + userId); 637 // This makes it so that future permission checks will be in the context of this 638 // process rather than the caller's process. We will restore this before returning. 639 long identityToken = clearCallingIdentity(); 640 if (cname != null) { 641 Slog.e(TAG, "cname not null."); 642 return; 643 } 644 try { 645 SyncManager syncManager = getSyncManager(); 646 if (syncManager != null) { 647 SyncStorageEngine.EndPoint info; 648 info = new SyncStorageEngine.EndPoint(account, authority, userId); 649 syncManager.clearScheduledSyncOperations(info); 650 syncManager.cancelActiveSync(info, null /* all syncs for this adapter */, "API"); 651 } 652 } finally { 653 restoreCallingIdentity(identityToken); 654 } 655 } 656 657 @Override 658 public void cancelRequest(SyncRequest request) { 659 SyncManager syncManager = getSyncManager(); 660 if (syncManager == null) return; 661 int userId = UserHandle.getCallingUserId(); 662 final int callingUid = Binder.getCallingUid(); 663 664 if (request.isPeriodic()) { 665 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS, 666 "no permission to write the sync settings"); 667 } 668 669 Bundle extras = new Bundle(request.getBundle()); 670 validateExtras(callingUid, extras); 671 672 long identityToken = clearCallingIdentity(); 673 try { 674 SyncStorageEngine.EndPoint info; 675 676 Account account = request.getAccount(); 677 String provider = request.getProvider(); 678 info = new SyncStorageEngine.EndPoint(account, provider, userId); 679 if (request.isPeriodic()) { 680 // Remove periodic sync. 681 getSyncManager().removePeriodicSync(info, extras, 682 "cancelRequest() by uid=" + callingUid); 683 } 684 // Cancel active syncs and clear pending syncs from the queue. 685 syncManager.cancelScheduledSyncOperation(info, extras); 686 syncManager.cancelActiveSync(info, extras, "API"); 687 } finally { 688 restoreCallingIdentity(identityToken); 689 } 690 } 691 692 /** 693 * Get information about the SyncAdapters that are known to the system. 694 * @return an array of SyncAdapters that have registered with the system 695 */ 696 @Override 697 public SyncAdapterType[] getSyncAdapterTypes() { 698 return getSyncAdapterTypesAsUser(UserHandle.getCallingUserId()); 699 } 700 701 /** 702 * Get information about the SyncAdapters that are known to the system for a particular user. 703 * 704 * <p> If the user id supplied is different to the calling user, the caller must hold the 705 * INTERACT_ACROSS_USERS_FULL permission. 706 * 707 * @return an array of SyncAdapters that have registered with the system 708 */ 709 @Override 710 public SyncAdapterType[] getSyncAdapterTypesAsUser(int userId) { 711 enforceCrossUserPermission(userId, 712 "no permission to read sync settings for user " + userId); 713 // This makes it so that future permission checks will be in the context of this 714 // process rather than the caller's process. We will restore this before returning. 715 final long identityToken = clearCallingIdentity(); 716 try { 717 SyncManager syncManager = getSyncManager(); 718 return syncManager.getSyncAdapterTypes(userId); 719 } finally { 720 restoreCallingIdentity(identityToken); 721 } 722 } 723 724 @Override 725 public String[] getSyncAdapterPackagesForAuthorityAsUser(String authority, int userId) { 726 enforceCrossUserPermission(userId, 727 "no permission to read sync settings for user " + userId); 728 // This makes it so that future permission checks will be in the context of this 729 // process rather than the caller's process. We will restore this before returning. 730 final long identityToken = clearCallingIdentity(); 731 try { 732 SyncManager syncManager = getSyncManager(); 733 return syncManager.getSyncAdapterPackagesForAuthorityAsUser(authority, userId); 734 } finally { 735 restoreCallingIdentity(identityToken); 736 } 737 } 738 739 @Override 740 public boolean getSyncAutomatically(Account account, String providerName) { 741 return getSyncAutomaticallyAsUser(account, providerName, UserHandle.getCallingUserId()); 742 } 743 744 /** 745 * If the user id supplied is different to the calling user, the caller must hold the 746 * INTERACT_ACROSS_USERS_FULL permission. 747 */ 748 @Override 749 public boolean getSyncAutomaticallyAsUser(Account account, String providerName, int userId) { 750 enforceCrossUserPermission(userId, 751 "no permission to read the sync settings for user " + userId); 752 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS, 753 "no permission to read the sync settings"); 754 755 long identityToken = clearCallingIdentity(); 756 try { 757 SyncManager syncManager = getSyncManager(); 758 if (syncManager != null) { 759 return syncManager.getSyncStorageEngine() 760 .getSyncAutomatically(account, userId, providerName); 761 } 762 } finally { 763 restoreCallingIdentity(identityToken); 764 } 765 return false; 766 } 767 768 @Override 769 public void setSyncAutomatically(Account account, String providerName, boolean sync) { 770 setSyncAutomaticallyAsUser(account, providerName, sync, UserHandle.getCallingUserId()); 771 } 772 773 @Override 774 public void setSyncAutomaticallyAsUser(Account account, String providerName, boolean sync, 775 int userId) { 776 if (TextUtils.isEmpty(providerName)) { 777 throw new IllegalArgumentException("Authority must be non-empty"); 778 } 779 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS, 780 "no permission to write the sync settings"); 781 enforceCrossUserPermission(userId, 782 "no permission to modify the sync settings for user " + userId); 783 final int callingUid = Binder.getCallingUid(); 784 final int syncExemptionFlag = getSyncExemptionForCaller(callingUid); 785 786 long identityToken = clearCallingIdentity(); 787 try { 788 SyncManager syncManager = getSyncManager(); 789 if (syncManager != null) { 790 syncManager.getSyncStorageEngine().setSyncAutomatically(account, userId, 791 providerName, sync, syncExemptionFlag, callingUid); 792 } 793 } finally { 794 restoreCallingIdentity(identityToken); 795 } 796 } 797 798 /** Old API. Schedule periodic sync with default flexMillis time. */ 799 @Override 800 public void addPeriodicSync(Account account, String authority, Bundle extras, 801 long pollFrequency) { 802 Bundle.setDefusable(extras, true); 803 if (account == null) { 804 throw new IllegalArgumentException("Account must not be null"); 805 } 806 if (TextUtils.isEmpty(authority)) { 807 throw new IllegalArgumentException("Authority must not be empty."); 808 } 809 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS, 810 "no permission to write the sync settings"); 811 812 validateExtras(Binder.getCallingUid(), extras); 813 814 int userId = UserHandle.getCallingUserId(); 815 816 pollFrequency = clampPeriod(pollFrequency); 817 long defaultFlex = SyncStorageEngine.calculateDefaultFlexTime(pollFrequency); 818 819 long identityToken = clearCallingIdentity(); 820 try { 821 SyncStorageEngine.EndPoint info = 822 new SyncStorageEngine.EndPoint(account, authority, userId); 823 getSyncManager().updateOrAddPeriodicSync(info, pollFrequency, 824 defaultFlex, extras); 825 } finally { 826 restoreCallingIdentity(identityToken); 827 } 828 } 829 830 @Override 831 public void removePeriodicSync(Account account, String authority, Bundle extras) { 832 Bundle.setDefusable(extras, true); 833 if (account == null) { 834 throw new IllegalArgumentException("Account must not be null"); 835 } 836 if (TextUtils.isEmpty(authority)) { 837 throw new IllegalArgumentException("Authority must not be empty"); 838 } 839 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS, 840 "no permission to write the sync settings"); 841 842 validateExtras(Binder.getCallingUid(), extras); 843 844 final int callingUid = Binder.getCallingUid(); 845 846 int userId = UserHandle.getCallingUserId(); 847 long identityToken = clearCallingIdentity(); 848 try { 849 getSyncManager() 850 .removePeriodicSync( 851 new SyncStorageEngine.EndPoint(account, authority, userId), 852 extras, "removePeriodicSync() by uid=" + callingUid); 853 } finally { 854 restoreCallingIdentity(identityToken); 855 } 856 } 857 858 @Override 859 public List<PeriodicSync> getPeriodicSyncs(Account account, String providerName, 860 ComponentName cname) { 861 if (account == null) { 862 throw new IllegalArgumentException("Account must not be null"); 863 } 864 if (TextUtils.isEmpty(providerName)) { 865 throw new IllegalArgumentException("Authority must not be empty"); 866 } 867 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS, 868 "no permission to read the sync settings"); 869 870 int userId = UserHandle.getCallingUserId(); 871 long identityToken = clearCallingIdentity(); 872 try { 873 return getSyncManager().getPeriodicSyncs( 874 new SyncStorageEngine.EndPoint(account, providerName, userId)); 875 } finally { 876 restoreCallingIdentity(identityToken); 877 } 878 } 879 880 @Override 881 public int getIsSyncable(Account account, String providerName) { 882 return getIsSyncableAsUser(account, providerName, UserHandle.getCallingUserId()); 883 } 884 885 /** 886 * If the user id supplied is different to the calling user, the caller must hold the 887 * INTERACT_ACROSS_USERS_FULL permission. 888 */ 889 @Override 890 public int getIsSyncableAsUser(Account account, String providerName, int userId) { 891 enforceCrossUserPermission(userId, 892 "no permission to read the sync settings for user " + userId); 893 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS, 894 "no permission to read the sync settings"); 895 896 long identityToken = clearCallingIdentity(); 897 try { 898 SyncManager syncManager = getSyncManager(); 899 if (syncManager != null) { 900 return syncManager.computeSyncable( 901 account, userId, providerName, false); 902 } 903 } finally { 904 restoreCallingIdentity(identityToken); 905 } 906 return -1; 907 } 908 909 @Override 910 public void setIsSyncable(Account account, String providerName, int syncable) { 911 if (TextUtils.isEmpty(providerName)) { 912 throw new IllegalArgumentException("Authority must not be empty"); 913 } 914 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS, 915 "no permission to write the sync settings"); 916 917 syncable = normalizeSyncable(syncable); 918 final int callingUid = Binder.getCallingUid(); 919 920 int userId = UserHandle.getCallingUserId(); 921 long identityToken = clearCallingIdentity(); 922 try { 923 SyncManager syncManager = getSyncManager(); 924 if (syncManager != null) { 925 syncManager.getSyncStorageEngine().setIsSyncable( 926 account, userId, providerName, syncable, callingUid); 927 } 928 } finally { 929 restoreCallingIdentity(identityToken); 930 } 931 } 932 933 @Override 934 public boolean getMasterSyncAutomatically() { 935 return getMasterSyncAutomaticallyAsUser(UserHandle.getCallingUserId()); 936 } 937 938 /** 939 * If the user id supplied is different to the calling user, the caller must hold the 940 * INTERACT_ACROSS_USERS_FULL permission. 941 */ 942 @Override 943 public boolean getMasterSyncAutomaticallyAsUser(int userId) { 944 enforceCrossUserPermission(userId, 945 "no permission to read the sync settings for user " + userId); 946 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS, 947 "no permission to read the sync settings"); 948 949 long identityToken = clearCallingIdentity(); 950 try { 951 SyncManager syncManager = getSyncManager(); 952 if (syncManager != null) { 953 return syncManager.getSyncStorageEngine().getMasterSyncAutomatically(userId); 954 } 955 } finally { 956 restoreCallingIdentity(identityToken); 957 } 958 return false; 959 } 960 961 @Override 962 public void setMasterSyncAutomatically(boolean flag) { 963 setMasterSyncAutomaticallyAsUser(flag, UserHandle.getCallingUserId()); 964 } 965 966 @Override 967 public void setMasterSyncAutomaticallyAsUser(boolean flag, int userId) { 968 enforceCrossUserPermission(userId, 969 "no permission to set the sync status for user " + userId); 970 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS, 971 "no permission to write the sync settings"); 972 973 final int callingUid = Binder.getCallingUid(); 974 975 long identityToken = clearCallingIdentity(); 976 try { 977 SyncManager syncManager = getSyncManager(); 978 if (syncManager != null) { 979 syncManager.getSyncStorageEngine().setMasterSyncAutomatically(flag, userId, 980 getSyncExemptionForCaller(callingUid), callingUid); 981 } 982 } finally { 983 restoreCallingIdentity(identityToken); 984 } 985 } 986 987 @Override 988 public boolean isSyncActive(Account account, String authority, ComponentName cname) { 989 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS, 990 "no permission to read the sync stats"); 991 int userId = UserHandle.getCallingUserId(); 992 long identityToken = clearCallingIdentity(); 993 try { 994 SyncManager syncManager = getSyncManager(); 995 if (syncManager == null) { 996 return false; 997 } 998 return syncManager.getSyncStorageEngine().isSyncActive( 999 new SyncStorageEngine.EndPoint(account, authority, userId)); 1000 } finally { 1001 restoreCallingIdentity(identityToken); 1002 } 1003 } 1004 1005 @Override 1006 public List<SyncInfo> getCurrentSyncs() { 1007 return getCurrentSyncsAsUser(UserHandle.getCallingUserId()); 1008 } 1009 1010 /** 1011 * If the user id supplied is different to the calling user, the caller must hold the 1012 * INTERACT_ACROSS_USERS_FULL permission. 1013 */ 1014 @Override 1015 public List<SyncInfo> getCurrentSyncsAsUser(int userId) { 1016 enforceCrossUserPermission(userId, 1017 "no permission to read the sync settings for user " + userId); 1018 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS, 1019 "no permission to read the sync stats"); 1020 1021 final boolean canAccessAccounts = 1022 mContext.checkCallingOrSelfPermission(Manifest.permission.GET_ACCOUNTS) 1023 == PackageManager.PERMISSION_GRANTED; 1024 long identityToken = clearCallingIdentity(); 1025 try { 1026 return getSyncManager().getSyncStorageEngine() 1027 .getCurrentSyncsCopy(userId, canAccessAccounts); 1028 } finally { 1029 restoreCallingIdentity(identityToken); 1030 } 1031 } 1032 1033 @Override 1034 public SyncStatusInfo getSyncStatus(Account account, String authority, ComponentName cname) { 1035 return getSyncStatusAsUser(account, authority, cname, UserHandle.getCallingUserId()); 1036 } 1037 1038 /** 1039 * If the user id supplied is different to the calling user, the caller must hold the 1040 * INTERACT_ACROSS_USERS_FULL permission. 1041 */ 1042 @Override 1043 public SyncStatusInfo getSyncStatusAsUser(Account account, String authority, 1044 ComponentName cname, int userId) { 1045 if (TextUtils.isEmpty(authority)) { 1046 throw new IllegalArgumentException("Authority must not be empty"); 1047 } 1048 1049 enforceCrossUserPermission(userId, 1050 "no permission to read the sync stats for user " + userId); 1051 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS, 1052 "no permission to read the sync stats"); 1053 1054 long identityToken = clearCallingIdentity(); 1055 try { 1056 SyncManager syncManager = getSyncManager(); 1057 if (syncManager == null) { 1058 return null; 1059 } 1060 SyncStorageEngine.EndPoint info; 1061 if (!(account == null || authority == null)) { 1062 info = new SyncStorageEngine.EndPoint(account, authority, userId); 1063 } else { 1064 throw new IllegalArgumentException("Must call sync status with valid authority"); 1065 } 1066 return syncManager.getSyncStorageEngine().getStatusByAuthority(info); 1067 } finally { 1068 restoreCallingIdentity(identityToken); 1069 } 1070 } 1071 1072 @Override 1073 public boolean isSyncPending(Account account, String authority, ComponentName cname) { 1074 return isSyncPendingAsUser(account, authority, cname, UserHandle.getCallingUserId()); 1075 } 1076 1077 @Override 1078 public boolean isSyncPendingAsUser(Account account, String authority, ComponentName cname, 1079 int userId) { 1080 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS, 1081 "no permission to read the sync stats"); 1082 enforceCrossUserPermission(userId, 1083 "no permission to retrieve the sync settings for user " + userId); 1084 long identityToken = clearCallingIdentity(); 1085 SyncManager syncManager = getSyncManager(); 1086 if (syncManager == null) return false; 1087 1088 try { 1089 SyncStorageEngine.EndPoint info; 1090 if (!(account == null || authority == null)) { 1091 info = new SyncStorageEngine.EndPoint(account, authority, userId); 1092 } else { 1093 throw new IllegalArgumentException("Invalid authority specified"); 1094 } 1095 return syncManager.getSyncStorageEngine().isSyncPending(info); 1096 } finally { 1097 restoreCallingIdentity(identityToken); 1098 } 1099 } 1100 1101 @Override 1102 public void addStatusChangeListener(int mask, ISyncStatusObserver callback) { 1103 long identityToken = clearCallingIdentity(); 1104 try { 1105 SyncManager syncManager = getSyncManager(); 1106 if (syncManager != null && callback != null) { 1107 syncManager.getSyncStorageEngine().addStatusChangeListener(mask, callback); 1108 } 1109 } finally { 1110 restoreCallingIdentity(identityToken); 1111 } 1112 } 1113 1114 @Override 1115 public void removeStatusChangeListener(ISyncStatusObserver callback) { 1116 long identityToken = clearCallingIdentity(); 1117 try { 1118 SyncManager syncManager = getSyncManager(); 1119 if (syncManager != null && callback != null) { 1120 syncManager.getSyncStorageEngine().removeStatusChangeListener(callback); 1121 } 1122 } finally { 1123 restoreCallingIdentity(identityToken); 1124 } 1125 } 1126 1127 private @Nullable String getProviderPackageName(Uri uri) { 1128 final ProviderInfo pi = mContext.getPackageManager() 1129 .resolveContentProvider(uri.getAuthority(), 0); 1130 return (pi != null) ? pi.packageName : null; 1131 } 1132 1133 @GuardedBy("mCache") 1134 private ArrayMap<Pair<String, Uri>, Bundle> findOrCreateCacheLocked(int userId, 1135 String providerPackageName) { 1136 ArrayMap<String, ArrayMap<Pair<String, Uri>, Bundle>> userCache = mCache.get(userId); 1137 if (userCache == null) { 1138 userCache = new ArrayMap<>(); 1139 mCache.put(userId, userCache); 1140 } 1141 ArrayMap<Pair<String, Uri>, Bundle> packageCache = userCache.get(providerPackageName); 1142 if (packageCache == null) { 1143 packageCache = new ArrayMap<>(); 1144 userCache.put(providerPackageName, packageCache); 1145 } 1146 return packageCache; 1147 } 1148 1149 @GuardedBy("mCache") 1150 private void invalidateCacheLocked(int userId, String providerPackageName, Uri uri) { 1151 ArrayMap<String, ArrayMap<Pair<String, Uri>, Bundle>> userCache = mCache.get(userId); 1152 if (userCache == null) return; 1153 1154 ArrayMap<Pair<String, Uri>, Bundle> packageCache = userCache.get(providerPackageName); 1155 if (packageCache == null) return; 1156 1157 if (uri != null) { 1158 for (int i = 0; i < packageCache.size();) { 1159 final Pair<String, Uri> key = packageCache.keyAt(i); 1160 if (key.second != null && key.second.toString().startsWith(uri.toString())) { 1161 if (DEBUG) Slog.d(TAG, "Invalidating cache for key " + key); 1162 packageCache.removeAt(i); 1163 } else { 1164 i++; 1165 } 1166 } 1167 } else { 1168 if (DEBUG) Slog.d(TAG, "Invalidating cache for package " + providerPackageName); 1169 packageCache.clear(); 1170 } 1171 } 1172 1173 @Override 1174 public void putCache(String packageName, Uri key, Bundle value, int userId) { 1175 Bundle.setDefusable(value, true); 1176 enforceCrossUserPermission(userId, TAG); 1177 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CACHE_CONTENT, TAG); 1178 mContext.getSystemService(AppOpsManager.class).checkPackage(Binder.getCallingUid(), 1179 packageName); 1180 1181 final String providerPackageName = getProviderPackageName(key); 1182 final Pair<String, Uri> fullKey = Pair.create(packageName, key); 1183 1184 synchronized (mCache) { 1185 final ArrayMap<Pair<String, Uri>, Bundle> cache = findOrCreateCacheLocked(userId, 1186 providerPackageName); 1187 if (value != null) { 1188 cache.put(fullKey, value); 1189 } else { 1190 cache.remove(fullKey); 1191 } 1192 } 1193 } 1194 1195 @Override 1196 public Bundle getCache(String packageName, Uri key, int userId) { 1197 enforceCrossUserPermission(userId, TAG); 1198 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CACHE_CONTENT, TAG); 1199 mContext.getSystemService(AppOpsManager.class).checkPackage(Binder.getCallingUid(), 1200 packageName); 1201 1202 final String providerPackageName = getProviderPackageName(key); 1203 final Pair<String, Uri> fullKey = Pair.create(packageName, key); 1204 1205 synchronized (mCache) { 1206 final ArrayMap<Pair<String, Uri>, Bundle> cache = findOrCreateCacheLocked(userId, 1207 providerPackageName); 1208 return cache.get(fullKey); 1209 } 1210 } 1211 1212 private int handleIncomingUser(Uri uri, int pid, int uid, int modeFlags, boolean allowNonFull, 1213 int userId) { 1214 if (userId == UserHandle.USER_CURRENT) { 1215 userId = ActivityManager.getCurrentUser(); 1216 } 1217 1218 if (userId == UserHandle.USER_ALL) { 1219 mContext.enforceCallingOrSelfPermission( 1220 Manifest.permission.INTERACT_ACROSS_USERS_FULL, TAG); 1221 } else if (userId < 0) { 1222 throw new IllegalArgumentException("Invalid user: " + userId); 1223 } else if (userId != UserHandle.getCallingUserId()) { 1224 if (checkUriPermission(uri, pid, uid, modeFlags, 1225 userId) != PackageManager.PERMISSION_GRANTED) { 1226 boolean allow = false; 1227 if (mContext.checkCallingOrSelfPermission( 1228 Manifest.permission.INTERACT_ACROSS_USERS_FULL) 1229 == PackageManager.PERMISSION_GRANTED) { 1230 allow = true; 1231 } else if (allowNonFull && mContext.checkCallingOrSelfPermission( 1232 Manifest.permission.INTERACT_ACROSS_USERS) 1233 == PackageManager.PERMISSION_GRANTED) { 1234 allow = true; 1235 } 1236 if (!allow) { 1237 final String permissions = allowNonFull 1238 ? (Manifest.permission.INTERACT_ACROSS_USERS_FULL + " or " + 1239 Manifest.permission.INTERACT_ACROSS_USERS) 1240 : Manifest.permission.INTERACT_ACROSS_USERS_FULL; 1241 throw new SecurityException(TAG + "Neither user " + uid 1242 + " nor current process has " + permissions); 1243 } 1244 } 1245 } 1246 1247 return userId; 1248 } 1249 1250 /** 1251 * Checks if the request is from the system or an app that has INTERACT_ACROSS_USERS_FULL 1252 * permission, if the userHandle is not for the caller. 1253 * 1254 * @param userHandle the user handle of the user we want to act on behalf of. 1255 * @param message the message to log on security exception. 1256 */ 1257 private void enforceCrossUserPermission(int userHandle, String message) { 1258 final int callingUser = UserHandle.getCallingUserId(); 1259 if (callingUser != userHandle) { 1260 mContext.enforceCallingOrSelfPermission( 1261 Manifest.permission.INTERACT_ACROSS_USERS_FULL, message); 1262 } 1263 } 1264 1265 private static int normalizeSyncable(int syncable) { 1266 if (syncable > 0) { 1267 return SyncStorageEngine.AuthorityInfo.SYNCABLE; 1268 } else if (syncable == 0) { 1269 return SyncStorageEngine.AuthorityInfo.NOT_SYNCABLE; 1270 } 1271 return SyncStorageEngine.AuthorityInfo.UNDEFINED; 1272 } 1273 1274 private void validateExtras(int callingUid, Bundle extras) { 1275 if (extras.containsKey(ContentResolver.SYNC_VIRTUAL_EXTRAS_EXEMPTION_FLAG)) { 1276 switch (callingUid) { 1277 case Process.ROOT_UID: 1278 case Process.SHELL_UID: 1279 case Process.SYSTEM_UID: 1280 break; // Okay 1281 default: 1282 final String msg = "Invalid extras specified."; 1283 Log.w(TAG, msg + " requestsync -f/-F needs to run on 'adb shell'"); 1284 throw new SecurityException(msg); 1285 } 1286 } 1287 } 1288 1289 @SyncExemption 1290 private int getSyncExemptionForCaller(int callingUid) { 1291 return getSyncExemptionAndCleanUpExtrasForCaller(callingUid, null); 1292 } 1293 1294 @SyncExemption 1295 private int getSyncExemptionAndCleanUpExtrasForCaller(int callingUid, Bundle extras) { 1296 if (extras != null) { 1297 final int exemption = 1298 extras.getInt(ContentResolver.SYNC_VIRTUAL_EXTRAS_EXEMPTION_FLAG, -1); 1299 1300 // Need to remove the virtual extra. 1301 extras.remove(ContentResolver.SYNC_VIRTUAL_EXTRAS_EXEMPTION_FLAG); 1302 if (exemption != -1) { 1303 return exemption; 1304 } 1305 } 1306 final ActivityManagerInternal ami = 1307 LocalServices.getService(ActivityManagerInternal.class); 1308 final int procState = (ami != null) 1309 ? ami.getUidProcessState(callingUid) 1310 : ActivityManager.PROCESS_STATE_NONEXISTENT; 1311 1312 if (procState <= ActivityManager.PROCESS_STATE_TOP) { 1313 return ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP; 1314 } 1315 if (procState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) { 1316 return ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET; 1317 } 1318 return ContentResolver.SYNC_EXEMPTION_NONE; 1319 } 1320 1321 /** 1322 * Hide this class since it is not part of api, 1323 * but current unittest framework requires it to be public 1324 * @hide 1325 */ 1326 public static final class ObserverNode { 1327 private class ObserverEntry implements IBinder.DeathRecipient { 1328 public final IContentObserver observer; 1329 public final int uid; 1330 public final int pid; 1331 public final boolean notifyForDescendants; 1332 private final int userHandle; 1333 private final Object observersLock; 1334 1335 public ObserverEntry(IContentObserver o, boolean n, Object observersLock, 1336 int _uid, int _pid, int _userHandle) { 1337 this.observersLock = observersLock; 1338 observer = o; 1339 uid = _uid; 1340 pid = _pid; 1341 userHandle = _userHandle; 1342 notifyForDescendants = n; 1343 try { 1344 observer.asBinder().linkToDeath(this, 0); 1345 } catch (RemoteException e) { 1346 binderDied(); 1347 } 1348 } 1349 1350 @Override 1351 public void binderDied() { 1352 synchronized (observersLock) { 1353 removeObserverLocked(observer); 1354 } 1355 } 1356 1357 public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args, 1358 String name, String prefix, SparseIntArray pidCounts) { 1359 pidCounts.put(pid, pidCounts.get(pid)+1); 1360 pw.print(prefix); pw.print(name); pw.print(": pid="); 1361 pw.print(pid); pw.print(" uid="); 1362 pw.print(uid); pw.print(" user="); 1363 pw.print(userHandle); pw.print(" target="); 1364 pw.println(Integer.toHexString(System.identityHashCode( 1365 observer != null ? observer.asBinder() : null))); 1366 } 1367 } 1368 1369 public static final int INSERT_TYPE = 0; 1370 public static final int UPDATE_TYPE = 1; 1371 public static final int DELETE_TYPE = 2; 1372 1373 private String mName; 1374 private ArrayList<ObserverNode> mChildren = new ArrayList<ObserverNode>(); 1375 private ArrayList<ObserverEntry> mObservers = new ArrayList<ObserverEntry>(); 1376 1377 public ObserverNode(String name) { 1378 mName = name; 1379 } 1380 1381 public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args, 1382 String name, String prefix, int[] counts, SparseIntArray pidCounts) { 1383 String innerName = null; 1384 if (mObservers.size() > 0) { 1385 if ("".equals(name)) { 1386 innerName = mName; 1387 } else { 1388 innerName = name + "/" + mName; 1389 } 1390 for (int i=0; i<mObservers.size(); i++) { 1391 counts[1]++; 1392 mObservers.get(i).dumpLocked(fd, pw, args, innerName, prefix, 1393 pidCounts); 1394 } 1395 } 1396 if (mChildren.size() > 0) { 1397 if (innerName == null) { 1398 if ("".equals(name)) { 1399 innerName = mName; 1400 } else { 1401 innerName = name + "/" + mName; 1402 } 1403 } 1404 for (int i=0; i<mChildren.size(); i++) { 1405 counts[0]++; 1406 mChildren.get(i).dumpLocked(fd, pw, args, innerName, prefix, 1407 counts, pidCounts); 1408 } 1409 } 1410 } 1411 1412 private String getUriSegment(Uri uri, int index) { 1413 if (uri != null) { 1414 if (index == 0) { 1415 return uri.getAuthority(); 1416 } else { 1417 return uri.getPathSegments().get(index - 1); 1418 } 1419 } else { 1420 return null; 1421 } 1422 } 1423 1424 private int countUriSegments(Uri uri) { 1425 if (uri == null) { 1426 return 0; 1427 } 1428 return uri.getPathSegments().size() + 1; 1429 } 1430 1431 // Invariant: userHandle is either a hard user number or is USER_ALL 1432 public void addObserverLocked(Uri uri, IContentObserver observer, 1433 boolean notifyForDescendants, Object observersLock, 1434 int uid, int pid, int userHandle) { 1435 addObserverLocked(uri, 0, observer, notifyForDescendants, observersLock, 1436 uid, pid, userHandle); 1437 } 1438 1439 private void addObserverLocked(Uri uri, int index, IContentObserver observer, 1440 boolean notifyForDescendants, Object observersLock, 1441 int uid, int pid, int userHandle) { 1442 // If this is the leaf node add the observer 1443 if (index == countUriSegments(uri)) { 1444 mObservers.add(new ObserverEntry(observer, notifyForDescendants, observersLock, 1445 uid, pid, userHandle)); 1446 return; 1447 } 1448 1449 // Look to see if the proper child already exists 1450 String segment = getUriSegment(uri, index); 1451 if (segment == null) { 1452 throw new IllegalArgumentException("Invalid Uri (" + uri + ") used for observer"); 1453 } 1454 int N = mChildren.size(); 1455 for (int i = 0; i < N; i++) { 1456 ObserverNode node = mChildren.get(i); 1457 if (node.mName.equals(segment)) { 1458 node.addObserverLocked(uri, index + 1, observer, notifyForDescendants, 1459 observersLock, uid, pid, userHandle); 1460 return; 1461 } 1462 } 1463 1464 // No child found, create one 1465 ObserverNode node = new ObserverNode(segment); 1466 mChildren.add(node); 1467 node.addObserverLocked(uri, index + 1, observer, notifyForDescendants, 1468 observersLock, uid, pid, userHandle); 1469 } 1470 1471 public boolean removeObserverLocked(IContentObserver observer) { 1472 int size = mChildren.size(); 1473 for (int i = 0; i < size; i++) { 1474 boolean empty = mChildren.get(i).removeObserverLocked(observer); 1475 if (empty) { 1476 mChildren.remove(i); 1477 i--; 1478 size--; 1479 } 1480 } 1481 1482 IBinder observerBinder = observer.asBinder(); 1483 size = mObservers.size(); 1484 for (int i = 0; i < size; i++) { 1485 ObserverEntry entry = mObservers.get(i); 1486 if (entry.observer.asBinder() == observerBinder) { 1487 mObservers.remove(i); 1488 // We no longer need to listen for death notifications. Remove it. 1489 observerBinder.unlinkToDeath(entry, 0); 1490 break; 1491 } 1492 } 1493 1494 if (mChildren.size() == 0 && mObservers.size() == 0) { 1495 return true; 1496 } 1497 return false; 1498 } 1499 1500 private void collectMyObserversLocked(boolean leaf, IContentObserver observer, 1501 boolean observerWantsSelfNotifications, int flags, 1502 int targetUserHandle, ArrayList<ObserverCall> calls) { 1503 int N = mObservers.size(); 1504 IBinder observerBinder = observer == null ? null : observer.asBinder(); 1505 for (int i = 0; i < N; i++) { 1506 ObserverEntry entry = mObservers.get(i); 1507 1508 // Don't notify the observer if it sent the notification and isn't interested 1509 // in self notifications 1510 boolean selfChange = (entry.observer.asBinder() == observerBinder); 1511 if (selfChange && !observerWantsSelfNotifications) { 1512 continue; 1513 } 1514 1515 // Does this observer match the target user? 1516 if (targetUserHandle == UserHandle.USER_ALL 1517 || entry.userHandle == UserHandle.USER_ALL 1518 || targetUserHandle == entry.userHandle) { 1519 // Make sure the observer is interested in the notification 1520 if (leaf) { 1521 // If we are at the leaf: we always report, unless the sender has asked 1522 // to skip observers that are notifying for descendants (since they will 1523 // be sending another more specific URI for them). 1524 if ((flags&ContentResolver.NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS) != 0 1525 && entry.notifyForDescendants) { 1526 if (DEBUG) Slog.d(TAG, "Skipping " + entry.observer 1527 + ": skip notify for descendants"); 1528 continue; 1529 } 1530 } else { 1531 // If we are not at the leaf: we report if the observer says it wants 1532 // to be notified for all descendants. 1533 if (!entry.notifyForDescendants) { 1534 if (DEBUG) Slog.d(TAG, "Skipping " + entry.observer 1535 + ": not monitor descendants"); 1536 continue; 1537 } 1538 } 1539 if (DEBUG) Slog.d(TAG, "Reporting to " + entry.observer + ": leaf=" + leaf 1540 + " flags=" + Integer.toHexString(flags) 1541 + " desc=" + entry.notifyForDescendants); 1542 calls.add(new ObserverCall(this, entry.observer, selfChange, 1543 UserHandle.getUserId(entry.uid))); 1544 } 1545 } 1546 } 1547 1548 /** 1549 * targetUserHandle is either a hard user handle or is USER_ALL 1550 */ 1551 public void collectObserversLocked(Uri uri, int index, IContentObserver observer, 1552 boolean observerWantsSelfNotifications, int flags, 1553 int targetUserHandle, ArrayList<ObserverCall> calls) { 1554 String segment = null; 1555 int segmentCount = countUriSegments(uri); 1556 if (index >= segmentCount) { 1557 // This is the leaf node, notify all observers 1558 if (DEBUG) Slog.d(TAG, "Collecting leaf observers @ #" + index + ", node " + mName); 1559 collectMyObserversLocked(true, observer, observerWantsSelfNotifications, 1560 flags, targetUserHandle, calls); 1561 } else if (index < segmentCount){ 1562 segment = getUriSegment(uri, index); 1563 if (DEBUG) Slog.d(TAG, "Collecting non-leaf observers @ #" + index + " / " 1564 + segment); 1565 // Notify any observers at this level who are interested in descendants 1566 collectMyObserversLocked(false, observer, observerWantsSelfNotifications, 1567 flags, targetUserHandle, calls); 1568 } 1569 1570 int N = mChildren.size(); 1571 for (int i = 0; i < N; i++) { 1572 ObserverNode node = mChildren.get(i); 1573 if (segment == null || node.mName.equals(segment)) { 1574 // We found the child, 1575 node.collectObserversLocked(uri, index + 1, observer, 1576 observerWantsSelfNotifications, flags, targetUserHandle, calls); 1577 if (segment != null) { 1578 break; 1579 } 1580 } 1581 } 1582 } 1583 } 1584 1585 private void enforceShell(String method) { 1586 final int callingUid = Binder.getCallingUid(); 1587 if (callingUid != Process.SHELL_UID && callingUid != Process.ROOT_UID) { 1588 throw new SecurityException("Non-shell user attempted to call " + method); 1589 } 1590 } 1591 1592 @Override 1593 public void resetTodayStats() { 1594 enforceShell("resetTodayStats"); 1595 1596 if (mSyncManager != null) { 1597 final long token = Binder.clearCallingIdentity(); 1598 try { 1599 mSyncManager.resetTodayStats(); 1600 } finally { 1601 Binder.restoreCallingIdentity(token); 1602 } 1603 } 1604 } 1605 1606 @Override 1607 public void onShellCommand(FileDescriptor in, FileDescriptor out, 1608 FileDescriptor err, String[] args, ShellCallback callback, 1609 ResultReceiver resultReceiver) { 1610 (new ContentShellCommand(this)).exec(this, in, out, err, args, callback, resultReceiver); 1611 } 1612} 1613