• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.content;
18 
19 import static android.content.PermissionChecker.PERMISSION_GRANTED;
20 
21 import android.Manifest;
22 import android.accounts.Account;
23 import android.accounts.AccountManagerInternal;
24 import android.annotation.NonNull;
25 import android.annotation.Nullable;
26 import android.annotation.RequiresPermission;
27 import android.annotation.UserIdInt;
28 import android.app.ActivityManager;
29 import android.app.ActivityManager.RestrictionLevel;
30 import android.app.ActivityManagerInternal;
31 import android.app.AppGlobals;
32 import android.app.AppOpsManager;
33 import android.app.compat.CompatChanges;
34 import android.app.job.JobInfo;
35 import android.compat.annotation.ChangeId;
36 import android.compat.annotation.EnabledAfter;
37 import android.content.BroadcastReceiver;
38 import android.content.ComponentName;
39 import android.content.ContentResolver;
40 import android.content.ContentResolver.SyncExemption;
41 import android.content.Context;
42 import android.content.IContentService;
43 import android.content.ISyncStatusObserver;
44 import android.content.Intent;
45 import android.content.IntentFilter;
46 import android.content.PeriodicSync;
47 import android.content.SyncAdapterType;
48 import android.content.SyncInfo;
49 import android.content.SyncRequest;
50 import android.content.SyncStatusInfo;
51 import android.content.pm.PackageManager;
52 import android.content.pm.ProviderInfo;
53 import android.database.IContentObserver;
54 import android.database.sqlite.SQLiteException;
55 import android.net.Uri;
56 import android.os.AppBackgroundRestrictionsInfo;
57 import android.os.Binder;
58 import android.os.Build;
59 import android.os.Bundle;
60 import android.os.FactoryTest;
61 import android.os.IBinder;
62 import android.os.Process;
63 import android.os.RemoteException;
64 import android.os.ResultReceiver;
65 import android.os.ShellCallback;
66 import android.os.UserHandle;
67 import android.text.TextUtils;
68 import android.text.format.DateUtils;
69 import android.util.ArrayMap;
70 import android.util.ArraySet;
71 import android.util.Log;
72 import android.util.Pair;
73 import android.util.Slog;
74 import android.util.SparseArray;
75 import android.util.SparseIntArray;
76 
77 import com.android.internal.annotations.GuardedBy;
78 import com.android.internal.annotations.VisibleForTesting;
79 import com.android.internal.os.BackgroundThread;
80 import com.android.internal.os.BinderDeathDispatcher;
81 import com.android.internal.util.ArrayUtils;
82 import com.android.internal.util.DumpUtils;
83 import com.android.internal.util.FrameworkStatsLog;
84 import com.android.internal.util.IndentingPrintWriter;
85 import com.android.server.LocalServices;
86 import com.android.server.SystemService;
87 import com.android.server.pm.permission.LegacyPermissionManagerInternal;
88 
89 import java.io.FileDescriptor;
90 import java.io.PrintWriter;
91 import java.util.ArrayList;
92 import java.util.Arrays;
93 import java.util.Collections;
94 import java.util.Comparator;
95 import java.util.List;
96 import java.util.Objects;
97 
98 /**
99  * {@hide}
100  */
101 public final class ContentService extends IContentService.Stub {
102     static final String TAG = "ContentService";
103     static final boolean DEBUG = false;
104 
105     /** Do a WTF if a single observer is registered more than this times. */
106     private static final int TOO_MANY_OBSERVERS_THRESHOLD = 1000;
107 
108     /**
109      * Delay to apply to content change notifications dispatched to apps running
110      * in the background. This is used to help prevent stampeding when the user
111      * is performing CPU/RAM intensive foreground tasks, such as when capturing
112      * burst photos.
113      */
114     private static final long BACKGROUND_OBSERVER_DELAY = 10 * DateUtils.SECOND_IN_MILLIS;
115 
116     /**
117      * Enables checking for account access for the calling uid on all sync-related APIs.
118      */
119     @ChangeId
120     @EnabledAfter(targetSdkVersion = android.os.Build.VERSION_CODES.S_V2)
121     public static final long ACCOUNT_ACCESS_CHECK_CHANGE_ID = 201794303L;
122 
123     public static class Lifecycle extends SystemService {
124         private ContentService mService;
125 
Lifecycle(Context context)126         public Lifecycle(Context context) {
127             super(context);
128         }
129 
130         @Override
onStart()131         public void onStart() {
132             final boolean factoryTest = (FactoryTest
133                     .getMode() == FactoryTest.FACTORY_TEST_LOW_LEVEL);
134             mService = new ContentService(getContext(), factoryTest);
135             publishBinderService(ContentResolver.CONTENT_SERVICE_NAME, mService);
136         }
137 
138         @Override
onBootPhase(int phase)139         public void onBootPhase(int phase) {
140             mService.onBootPhase(phase);
141         }
142 
143         @Override
onUserStarting(@onNull TargetUser user)144         public void onUserStarting(@NonNull TargetUser user) {
145             mService.onStartUser(user.getUserIdentifier());
146         }
147 
148         @Override
onUserUnlocking(@onNull TargetUser user)149         public void onUserUnlocking(@NonNull TargetUser user) {
150             mService.onUnlockUser(user.getUserIdentifier());
151         }
152 
153         @Override
onUserStopping(@onNull TargetUser user)154         public void onUserStopping(@NonNull TargetUser user) {
155             mService.onStopUser(user.getUserIdentifier());
156         }
157 
158         @Override
onUserStopped(@onNull TargetUser user)159         public void onUserStopped(@NonNull TargetUser user) {
160             synchronized (mService.mCache) {
161                 mService.mCache.remove(user.getUserIdentifier());
162             }
163         }
164     }
165 
166     private Context mContext;
167     private boolean mFactoryTest;
168 
169     private final ObserverNode mRootNode = new ObserverNode("");
170 
171     private SyncManager mSyncManager = null;
172     private final Object mSyncManagerLock = new Object();
173 
174     private final AccountManagerInternal mAccountManagerInternal;
175 
176     private static final BinderDeathDispatcher<IContentObserver> sObserverDeathDispatcher =
177             new BinderDeathDispatcher<>();
178 
179     @GuardedBy("sObserverLeakDetectedUid")
180     private static final ArraySet<Integer> sObserverLeakDetectedUid = new ArraySet<>(0);
181 
182     /**
183      * Map from userId to providerPackageName to [clientPackageName, uri] to
184      * value. This structure is carefully optimized to keep invalidation logic
185      * as cheap as possible.
186      */
187     @GuardedBy("mCache")
188     private final SparseArray<ArrayMap<String, ArrayMap<Pair<String, Uri>, Bundle>>>
189             mCache = new SparseArray<>();
190 
191     private BroadcastReceiver mCacheReceiver = new BroadcastReceiver() {
192         @Override
193         public void onReceive(Context context, Intent intent) {
194             synchronized (mCache) {
195                 if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
196                     mCache.clear();
197                 } else {
198                     final Uri data = intent.getData();
199                     if (data != null) {
200                         final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
201                                 UserHandle.USER_NULL);
202                         final String packageName = data.getSchemeSpecificPart();
203                         invalidateCacheLocked(userId, packageName, null);
204                     }
205                 }
206             }
207         }
208     };
209 
getSyncManager()210     private SyncManager getSyncManager() {
211         synchronized(mSyncManagerLock) {
212             try {
213                 // Try to create the SyncManager, return null if it fails (which it shouldn't).
214                 if (mSyncManager == null) mSyncManager = new SyncManager(mContext, mFactoryTest);
215             } catch (SQLiteException e) {
216                 Log.e(TAG, "Can't create SyncManager", e);
217             }
218             return mSyncManager;
219         }
220     }
221 
onStartUser(int userHandle)222     void onStartUser(int userHandle) {
223         if (mSyncManager != null) mSyncManager.onStartUser(userHandle);
224     }
225 
onUnlockUser(int userHandle)226     void onUnlockUser(int userHandle) {
227         if (mSyncManager != null) mSyncManager.onUnlockUser(userHandle);
228     }
229 
onStopUser(int userHandle)230     void onStopUser(int userHandle) {
231         if (mSyncManager != null) mSyncManager.onStopUser(userHandle);
232     }
233 
234     @Override
dump(FileDescriptor fd, PrintWriter pw_, String[] args)235     protected synchronized void dump(FileDescriptor fd, PrintWriter pw_, String[] args) {
236         if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw_)) return;
237         final IndentingPrintWriter pw = new IndentingPrintWriter(pw_, "  ");
238 
239         final boolean dumpAll = ArrayUtils.contains(args, "-a");
240 
241         // This makes it so that future permission checks will be in the context of this
242         // process rather than the caller's process. We will restore this before returning.
243         final long identityToken = clearCallingIdentity();
244         try {
245             if (mSyncManager == null) {
246                 pw.println("SyncManager not available yet");
247             } else {
248                 mSyncManager.dump(fd, pw, dumpAll);
249             }
250             pw.println();
251             pw.println("Observer tree:");
252             synchronized (mRootNode) {
253                 int[] counts = new int[2];
254                 final SparseIntArray pidCounts = new SparseIntArray();
255                 mRootNode.dumpLocked(fd, pw, args, "", "  ", counts, pidCounts);
256                 pw.println();
257                 ArrayList<Integer> sorted = new ArrayList<Integer>();
258                 for (int i=0; i<pidCounts.size(); i++) {
259                     sorted.add(pidCounts.keyAt(i));
260                 }
261                 Collections.sort(sorted, new Comparator<Integer>() {
262                     @Override
263                     public int compare(Integer lhs, Integer rhs) {
264                         int lc = pidCounts.get(lhs);
265                         int rc = pidCounts.get(rhs);
266                         if (lc < rc) {
267                             return 1;
268                         } else if (lc > rc) {
269                             return -1;
270                         }
271                         return 0;
272                     }
273 
274                 });
275                 for (int i=0; i<sorted.size(); i++) {
276                     int pid = sorted.get(i);
277                     pw.print("  pid "); pw.print(pid); pw.print(": ");
278                     pw.print(pidCounts.get(pid)); pw.println(" observers");
279                 }
280                 pw.println();
281                 pw.increaseIndent();
282                 pw.print("Total number of nodes: "); pw.println(counts[0]);
283                 pw.print("Total number of observers: "); pw.println(counts[1]);
284 
285                 sObserverDeathDispatcher.dump(pw);
286                 pw.decreaseIndent();
287             }
288             synchronized (sObserverLeakDetectedUid) {
289                 pw.println();
290                 pw.print("Observer leaking UIDs: ");
291                 pw.println(sObserverLeakDetectedUid.toString());
292             }
293 
294             synchronized (mCache) {
295                 pw.println();
296                 pw.println("Cached content:");
297                 pw.increaseIndent();
298                 for (int i = 0; i < mCache.size(); i++) {
299                     pw.println("User " + mCache.keyAt(i) + ":");
300                     pw.increaseIndent();
301                     pw.println(mCache.valueAt(i));
302                     pw.decreaseIndent();
303                 }
304                 pw.decreaseIndent();
305             }
306         } finally {
307             restoreCallingIdentity(identityToken);
308         }
309     }
310 
ContentService(Context context, boolean factoryTest)311     /*package*/ ContentService(Context context, boolean factoryTest) {
312         mContext = context;
313         mFactoryTest = factoryTest;
314 
315         // Let the package manager query for the sync adapters for a given authority
316         // as we grant default permissions to sync adapters for specific authorities.
317         final LegacyPermissionManagerInternal permissionManagerInternal =
318                 LocalServices.getService(LegacyPermissionManagerInternal.class);
319         permissionManagerInternal.setSyncAdapterPackagesProvider((authority, userId) -> {
320             return getSyncAdapterPackagesForAuthorityAsUser(authority, userId);
321         });
322 
323         final IntentFilter packageFilter = new IntentFilter();
324         packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
325         packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
326         packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
327         packageFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED);
328         packageFilter.addDataScheme("package");
329         mContext.registerReceiverAsUser(mCacheReceiver, UserHandle.ALL,
330                 packageFilter, null, null);
331 
332         final IntentFilter localeFilter = new IntentFilter();
333         localeFilter.addAction(Intent.ACTION_LOCALE_CHANGED);
334         mContext.registerReceiverAsUser(mCacheReceiver, UserHandle.ALL,
335                 localeFilter, null, null);
336 
337         mAccountManagerInternal = LocalServices.getService(AccountManagerInternal.class);
338     }
339 
onBootPhase(int phase)340     void onBootPhase(int phase) {
341         switch (phase) {
342             case SystemService.PHASE_ACTIVITY_MANAGER_READY:
343                 getSyncManager();
344                 break;
345         }
346         if (mSyncManager != null) {
347             mSyncManager.onBootPhase(phase);
348         }
349     }
350 
351     /**
352      * Register a content observer tied to a specific user's view of the provider.
353      * @param userHandle the user whose view of the provider is to be observed.  May be
354      *     the calling user without requiring any permission, otherwise the caller needs to
355      *     hold the INTERACT_ACROSS_USERS_FULL permission or hold a read uri grant to the uri.
356      *     Pseudousers USER_ALL and USER_CURRENT are properly handled; all other pseudousers
357      *     are forbidden.
358      */
359     @Override
registerContentObserver(Uri uri, boolean notifyForDescendants, IContentObserver observer, int userHandle, int targetSdkVersion)360     public void registerContentObserver(Uri uri, boolean notifyForDescendants,
361             IContentObserver observer, int userHandle, int targetSdkVersion) {
362         if (observer == null || uri == null) {
363             throw new IllegalArgumentException("You must pass a valid uri and observer");
364         }
365 
366         final int uid = Binder.getCallingUid();
367         final int pid = Binder.getCallingPid();
368 
369         userHandle = handleIncomingUser(uri, pid, uid,
370                 Intent.FLAG_GRANT_READ_URI_PERMISSION, true, userHandle);
371 
372         final String msg = LocalServices.getService(ActivityManagerInternal.class)
373                 .checkContentProviderAccess(uri.getAuthority(), userHandle);
374         if (msg != null) {
375             if (targetSdkVersion >= Build.VERSION_CODES.O) {
376                 throw new SecurityException(msg);
377             } else {
378                 if (msg.startsWith("Failed to find provider")) {
379                     // Sigh, we need to quietly let apps targeting older API
380                     // levels notify on non-existent providers.
381                 } else {
382                     Log.w(TAG, "Ignoring content changes for " + uri + " from " + uid + ": " + msg);
383                     return;
384                 }
385             }
386         }
387 
388         synchronized (mRootNode) {
389             mRootNode.addObserverLocked(uri, observer, notifyForDescendants, mRootNode,
390                     uid, pid, userHandle);
391             if (false) Log.v(TAG, "Registered observer " + observer + " at " + uri +
392                     " with notifyForDescendants " + notifyForDescendants);
393         }
394     }
395 
registerContentObserver(Uri uri, boolean notifyForDescendants, IContentObserver observer)396     public void registerContentObserver(Uri uri, boolean notifyForDescendants,
397                                         IContentObserver observer) {
398         registerContentObserver(uri, notifyForDescendants, observer,
399                 UserHandle.getCallingUserId(), Build.VERSION_CODES.CUR_DEVELOPMENT);
400     }
401 
402     @Override
unregisterContentObserver(IContentObserver observer)403     public void unregisterContentObserver(IContentObserver observer) {
404         if (observer == null) {
405             throw new IllegalArgumentException("You must pass a valid observer");
406         }
407         synchronized (mRootNode) {
408             mRootNode.removeObserverLocked(observer);
409             if (false) Log.v(TAG, "Unregistered observer " + observer);
410         }
411     }
412 
413     /**
414      * Notify observers of a particular user's view of the provider.
415      * @param userHandle the user whose view of the provider is to be notified.  May be
416      *     the calling user without requiring any permission, otherwise the caller needs to
417      *     hold the INTERACT_ACROSS_USERS_FULL permission or hold a write uri grant to the uri.
418      *     Pseudousers USER_ALL and USER_CURRENT are properly interpreted; no other pseudousers are
419      *     allowed.
420      */
421     @Override
notifyChange(Uri[] uris, IContentObserver observer, boolean observerWantsSelfNotifications, int flags, int userId, int targetSdkVersion, String callingPackage)422     public void notifyChange(Uri[] uris, IContentObserver observer,
423             boolean observerWantsSelfNotifications, int flags, int userId,
424             int targetSdkVersion, String callingPackage) {
425         if (DEBUG) {
426             Slog.d(TAG, "Notifying update of " + Arrays.toString(uris) + " for user " + userId
427                     + ", observer " + observer + ", flags " + Integer.toHexString(flags));
428         }
429 
430         final int callingUid = Binder.getCallingUid();
431         final int callingPid = Binder.getCallingPid();
432         final int callingUserId = UserHandle.getCallingUserId();
433 
434         // Set of notification events that we need to dispatch
435         final ObserverCollector collector = new ObserverCollector();
436 
437         // Set of content provider authorities that we've validated the caller
438         // has access to, mapped to the package name hosting that provider
439         final ArrayMap<Pair<String, Integer>, String> validatedProviders = new ArrayMap<>();
440 
441         for (Uri uri : uris) {
442             // Validate that calling app has access to this provider
443             final int resolvedUserId = handleIncomingUser(uri, callingPid, callingUid,
444                     Intent.FLAG_GRANT_WRITE_URI_PERMISSION, true, userId);
445             final Pair<String, Integer> provider = Pair.create(uri.getAuthority(), resolvedUserId);
446             if (!validatedProviders.containsKey(provider)) {
447                 final String msg = LocalServices.getService(ActivityManagerInternal.class)
448                         .checkContentProviderAccess(uri.getAuthority(), resolvedUserId);
449                 if (msg != null) {
450                     if (targetSdkVersion >= Build.VERSION_CODES.O) {
451                         throw new SecurityException(msg);
452                     } else {
453                         if (msg.startsWith("Failed to find provider")) {
454                             // Sigh, we need to quietly let apps targeting older API
455                             // levels notify on non-existent providers.
456                         } else {
457                             Log.w(TAG, "Ignoring notify for " + uri + " from "
458                                     + callingUid + ": " + msg);
459                             continue;
460                         }
461                     }
462                 }
463 
464                 // Remember that we've validated this access
465                 final String packageName = getProviderPackageName(uri, resolvedUserId);
466                 validatedProviders.put(provider, packageName);
467             }
468 
469             // No concerns raised above, so caller has access; let's collect the
470             // notifications that should be dispatched
471             synchronized (mRootNode) {
472                 final int segmentCount = ObserverNode.countUriSegments(uri);
473                 mRootNode.collectObserversLocked(uri, segmentCount, 0, observer,
474                         observerWantsSelfNotifications, flags, resolvedUserId, collector);
475             }
476         }
477 
478         final long token = clearCallingIdentity();
479         try {
480             // Actually dispatch all the notifications we collected
481             collector.dispatch();
482 
483             for (int i = 0; i < validatedProviders.size(); i++) {
484                 final String authority = validatedProviders.keyAt(i).first;
485                 final int resolvedUserId = validatedProviders.keyAt(i).second;
486                 final String packageName = validatedProviders.valueAt(i);
487 
488                 // Kick off sync adapters for any authorities we touched
489                 if ((flags & ContentResolver.NOTIFY_SYNC_TO_NETWORK) != 0) {
490                     SyncManager syncManager = getSyncManager();
491                     if (syncManager != null) {
492                         syncManager.scheduleLocalSync(null /* all accounts */, callingUserId,
493                                 callingUid,
494                                 authority, getSyncExemptionForCaller(callingUid),
495                                 callingUid, callingPid, callingPackage);
496                     }
497                 }
498 
499                 // Invalidate caches for any authorities we touched
500                 synchronized (mCache) {
501                     for (Uri uri : uris) {
502                         if (Objects.equals(uri.getAuthority(), authority)) {
503                             invalidateCacheLocked(resolvedUserId, packageName, uri);
504                         }
505                     }
506                 }
507             }
508         } finally {
509             Binder.restoreCallingIdentity(token);
510         }
511     }
512 
checkUriPermission(Uri uri, int pid, int uid, int modeFlags, int userHandle)513     private int checkUriPermission(Uri uri, int pid, int uid, int modeFlags, int userHandle) {
514         try {
515             return ActivityManager.getService().checkUriPermission(
516                     uri, pid, uid, modeFlags, userHandle, null);
517         } catch (RemoteException e) {
518             return PackageManager.PERMISSION_DENIED;
519         }
520     }
521 
522     /**
523      * Collection of detected change notifications that should be delivered.
524      * <p>
525      * To help reduce Binder transaction overhead, this class clusters together
526      * multiple {@link Uri} where all other arguments are identical.
527      */
528     @VisibleForTesting
529     public static class ObserverCollector {
530         private final ArrayMap<Key, List<Uri>> collected = new ArrayMap<>();
531 
532         private static class Key {
533             final IContentObserver observer;
534             final int uid;
535             final boolean selfChange;
536             final int flags;
537             final int userId;
538 
Key(IContentObserver observer, int uid, boolean selfChange, int flags, int userId)539             Key(IContentObserver observer, int uid, boolean selfChange, int flags, int userId) {
540                 this.observer = observer;
541                 this.uid = uid;
542                 this.selfChange = selfChange;
543                 this.flags = flags;
544                 this.userId = userId;
545             }
546 
547             @Override
equals(Object o)548             public boolean equals(Object o) {
549                 if (!(o instanceof Key)) {
550                     return false;
551                 }
552                 final Key other = (Key) o;
553                 return Objects.equals(observer, other.observer)
554                         && (uid == other.uid)
555                         && (selfChange == other.selfChange)
556                         && (flags == other.flags)
557                         && (userId == other.userId);
558             }
559 
560             @Override
hashCode()561             public int hashCode() {
562                 return Objects.hash(observer, uid, selfChange, flags, userId);
563             }
564         }
565 
collect(IContentObserver observer, int uid, boolean selfChange, Uri uri, int flags, int userId)566         public void collect(IContentObserver observer, int uid, boolean selfChange, Uri uri,
567                 int flags, int userId) {
568             final Key key = new Key(observer, uid, selfChange, flags, userId);
569             List<Uri> value = collected.get(key);
570             if (value == null) {
571                 value = new ArrayList<>();
572                 collected.put(key, value);
573             }
574             value.add(uri);
575         }
576 
dispatch()577         public void dispatch() {
578             for (int i = 0; i < collected.size(); i++) {
579                 final Key key = collected.keyAt(i);
580                 final List<Uri> value = collected.valueAt(i);
581 
582                 final Runnable task = () -> {
583                     try {
584                         key.observer.onChangeEtc(key.selfChange,
585                                 value.toArray(new Uri[value.size()]), key.flags, key.userId);
586                     } catch (RemoteException ignored) {
587                     }
588                 };
589 
590                 // Immediately dispatch notifications to foreground apps that
591                 // are important to the user; all other background observers are
592                 // delayed to avoid stampeding
593                 final boolean noDelay = (key.flags & ContentResolver.NOTIFY_NO_DELAY) != 0;
594                 final int procState = LocalServices.getService(ActivityManagerInternal.class)
595                         .getUidProcessState(key.uid);
596                 if (procState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND || noDelay) {
597                     task.run();
598                 } else {
599                     BackgroundThread.getHandler().postDelayed(task, BACKGROUND_OBSERVER_DELAY);
600                 }
601             }
602         }
603     }
604 
605     @Override
requestSync(Account account, String authority, Bundle extras, String callingPackage)606     public void requestSync(Account account, String authority, Bundle extras,
607             String callingPackage) {
608         Bundle.setDefusable(extras, true);
609         ContentResolver.validateSyncExtrasBundle(extras);
610         int userId = UserHandle.getCallingUserId();
611         final int callingUid = Binder.getCallingUid();
612         final int callingPid = Binder.getCallingPid();
613 
614         if (!hasAccountAccess(true, account, callingUid)) {
615             return;
616         }
617 
618         validateExtras(callingUid, extras);
619         final int syncExemption = getSyncExemptionAndCleanUpExtrasForCaller(callingUid, extras);
620 
621         // This makes it so that future permission checks will be in the context of this
622         // process rather than the caller's process. We will restore this before returning.
623         final long identityToken = clearCallingIdentity();
624         try {
625             SyncManager syncManager = getSyncManager();
626             if (syncManager != null) {
627                 syncManager.scheduleSync(account, userId, callingUid, authority, extras,
628                         SyncStorageEngine.AuthorityInfo.UNDEFINED,
629                         syncExemption, callingUid, callingPid, callingPackage);
630             }
631         } finally {
632             restoreCallingIdentity(identityToken);
633         }
634     }
635 
636     /**
637      * Request a sync with a generic {@link android.content.SyncRequest} object. This will be
638      * either:
639      *   periodic OR one-off sync.
640      * and
641      *   anonymous OR provider sync.
642      * Depending on the request, we enqueue to suit in the SyncManager.
643      * @param request The request object. Validation of this object is done by its builder.
644      */
645     @Override
sync(SyncRequest request, String callingPackage)646     public void sync(SyncRequest request, String callingPackage) {
647         syncAsUser(request, UserHandle.getCallingUserId(), callingPackage);
648     }
649 
clampPeriod(long period)650     private long clampPeriod(long period) {
651         long minPeriod = JobInfo.getMinPeriodMillis() / 1000;
652         if (period < minPeriod) {
653             Slog.w(TAG, "Requested poll frequency of " + period
654                     + " seconds being rounded up to " + minPeriod + "s.");
655             period = minPeriod;
656         }
657         return period;
658     }
659 
660     /**
661      * If the user id supplied is different to the calling user, the caller must hold the
662      * INTERACT_ACROSS_USERS_FULL permission.
663      */
664     @Override
syncAsUser(SyncRequest request, int userId, String callingPackage)665     public void syncAsUser(SyncRequest request, int userId, String callingPackage) {
666         enforceCrossUserPermission(userId, "no permission to request sync as user: " + userId);
667 
668         final int callingUid = Binder.getCallingUid();
669         final int callingPid = Binder.getCallingPid();
670         if (!hasAccountAccess(true, request.getAccount(), callingUid)) {
671             return;
672         }
673 
674         final Bundle extras = request.getBundle();
675         validateExtras(callingUid, extras);
676         final int syncExemption = getSyncExemptionAndCleanUpExtrasForCaller(callingUid, extras);
677 
678         // This makes it so that future permission checks will be in the context of this
679         // process rather than the caller's process. We will restore this before returning.
680         final long identityToken = clearCallingIdentity();
681         try {
682             SyncManager syncManager = getSyncManager();
683             if (syncManager == null) {
684                 return;
685             }
686             long flextime = request.getSyncFlexTime();
687             long runAtTime = request.getSyncRunTime();
688             if (request.isPeriodic()) {
689                 mContext.enforceCallingOrSelfPermission(
690                         Manifest.permission.WRITE_SYNC_SETTINGS,
691                         "no permission to write the sync settings");
692                 SyncStorageEngine.EndPoint info;
693                 info = new SyncStorageEngine.EndPoint(
694                         request.getAccount(), request.getProvider(), userId);
695 
696                 runAtTime = clampPeriod(runAtTime);
697                 // Schedule periodic sync.
698                 getSyncManager().updateOrAddPeriodicSync(info, runAtTime,
699                         flextime, extras);
700             } else {
701                 syncManager.scheduleSync(
702                         request.getAccount(), userId, callingUid, request.getProvider(), extras,
703                         SyncStorageEngine.AuthorityInfo.UNDEFINED,
704                         syncExemption, callingUid, callingPid, callingPackage);
705             }
706         } finally {
707             restoreCallingIdentity(identityToken);
708         }
709     }
710 
711     /**
712      * Clear all scheduled sync operations that match the uri and cancel the active sync
713      * if they match the authority and account, if they are present.
714      *
715      * @param account filter the pending and active syncs to cancel using this account, or null.
716      * @param authority filter the pending and active syncs to cancel using this authority, or
717      * null.
718      * @param cname cancel syncs running on this service, or null for provider/account.
719      */
720     @Override
cancelSync(Account account, String authority, ComponentName cname)721     public void cancelSync(Account account, String authority, ComponentName cname) {
722         cancelSyncAsUser(account, authority, cname, UserHandle.getCallingUserId());
723     }
724 
725     /**
726      * Clear all scheduled sync operations that match the uri and cancel the active sync
727      * if they match the authority and account, if they are present.
728      *
729      * <p> If the user id supplied is different to the calling user, the caller must hold the
730      * INTERACT_ACROSS_USERS_FULL permission.
731      *
732      * @param account filter the pending and active syncs to cancel using this account, or null.
733      * @param authority filter the pending and active syncs to cancel using this authority, or
734      * null.
735      * @param userId the user id for which to cancel sync operations.
736      * @param cname cancel syncs running on this service, or null for provider/account.
737      */
738     @Override
cancelSyncAsUser(Account account, String authority, ComponentName cname, int userId)739     public void cancelSyncAsUser(Account account, String authority, ComponentName cname,
740                                  int userId) {
741         if (authority != null && authority.length() == 0) {
742             throw new IllegalArgumentException("Authority must be non-empty");
743         }
744         enforceCrossUserPermission(userId,
745                 "no permission to modify the sync settings for user " + userId);
746         // This makes it so that future permission checks will be in the context of this
747         // process rather than the caller's process. We will restore this before returning.
748         final long identityToken = clearCallingIdentity();
749         if (cname != null) {
750             Slog.e(TAG, "cname not null.");
751             return;
752         }
753         try {
754             SyncManager syncManager = getSyncManager();
755             if (syncManager != null) {
756                 SyncStorageEngine.EndPoint info;
757                 info = new SyncStorageEngine.EndPoint(account, authority, userId);
758                 syncManager.clearScheduledSyncOperations(info);
759                 syncManager.cancelActiveSync(info, null /* all syncs for this adapter */, "API");
760             }
761         } finally {
762             restoreCallingIdentity(identityToken);
763         }
764     }
765 
766     @Override
cancelRequest(SyncRequest request)767     public void cancelRequest(SyncRequest request) {
768         SyncManager syncManager = getSyncManager();
769         if (syncManager == null) return;
770         int userId = UserHandle.getCallingUserId();
771         final int callingUid = Binder.getCallingUid();
772 
773         if (request.isPeriodic()) {
774             mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
775                     "no permission to write the sync settings");
776         }
777 
778         Bundle extras = new Bundle(request.getBundle());
779         validateExtras(callingUid, extras);
780 
781         final long identityToken = clearCallingIdentity();
782         try {
783             SyncStorageEngine.EndPoint info;
784 
785             Account account = request.getAccount();
786             String provider = request.getProvider();
787             info = new SyncStorageEngine.EndPoint(account, provider, userId);
788             if (request.isPeriodic()) {
789                 // Remove periodic sync.
790                 getSyncManager().removePeriodicSync(info, extras,
791                         "cancelRequest() by uid=" + callingUid);
792             }
793             // Cancel active syncs and clear pending syncs from the queue.
794             syncManager.cancelScheduledSyncOperation(info, extras);
795             syncManager.cancelActiveSync(info, extras, "API");
796         } finally {
797             restoreCallingIdentity(identityToken);
798         }
799     }
800 
801     /**
802      * Get information about the SyncAdapters that are known to the system.
803      * @return an array of SyncAdapters that have registered with the system
804      */
805     @Override
getSyncAdapterTypes()806     public SyncAdapterType[] getSyncAdapterTypes() {
807         return getSyncAdapterTypesAsUser(UserHandle.getCallingUserId());
808     }
809 
810     /**
811      * Get information about the SyncAdapters that are known to the system for a particular user.
812      *
813      * <p> If the user id supplied is different to the calling user, the caller must hold the
814      * INTERACT_ACROSS_USERS_FULL permission.
815      *
816      * @return an array of SyncAdapters that have registered with the system
817      */
818     @Override
getSyncAdapterTypesAsUser(int userId)819     public SyncAdapterType[] getSyncAdapterTypesAsUser(int userId) {
820         enforceCrossUserPermission(userId,
821                 "no permission to read sync settings for user " + userId);
822         final int callingUid = Binder.getCallingUid();
823         // This makes it so that future permission checks will be in the context of this
824         // process rather than the caller's process. We will restore this before returning.
825         final long identityToken = clearCallingIdentity();
826         try {
827             SyncManager syncManager = getSyncManager();
828             return syncManager.getSyncAdapterTypes(callingUid, userId);
829         } finally {
830             restoreCallingIdentity(identityToken);
831         }
832     }
833 
834     @Override
getSyncAdapterPackagesForAuthorityAsUser(String authority, int userId)835     public String[] getSyncAdapterPackagesForAuthorityAsUser(String authority, int userId) {
836         enforceCrossUserPermission(userId,
837                 "no permission to read sync settings for user " + userId);
838         final int callingUid = Binder.getCallingUid();
839         // This makes it so that future permission checks will be in the context of this
840         // process rather than the caller's process. We will restore this before returning.
841         final long identityToken = clearCallingIdentity();
842         try {
843             SyncManager syncManager = getSyncManager();
844             return syncManager.getSyncAdapterPackagesForAuthorityAsUser(authority, callingUid,
845                     userId);
846         } finally {
847             restoreCallingIdentity(identityToken);
848         }
849     }
850 
851     @Override
getSyncAdapterPackageAsUser(@onNull String accountType, @NonNull String authority, @UserIdInt int userId)852     public String getSyncAdapterPackageAsUser(@NonNull String accountType,
853             @NonNull String authority, @UserIdInt int userId) {
854         enforceCrossUserPermission(userId,
855                 "no permission to read sync settings for user " + userId);
856         final int callingUid = Binder.getCallingUid();
857         final long identityToken = clearCallingIdentity();
858         try {
859             return getSyncManager().getSyncAdapterPackageAsUser(accountType, authority,
860                     callingUid, userId);
861         } finally {
862             restoreCallingIdentity(identityToken);
863         }
864     }
865 
866     @Override
getSyncAutomatically(Account account, String providerName)867     public boolean getSyncAutomatically(Account account, String providerName) {
868         return getSyncAutomaticallyAsUser(account, providerName, UserHandle.getCallingUserId());
869     }
870 
871     /**
872      * If the user id supplied is different to the calling user, the caller must hold the
873      * INTERACT_ACROSS_USERS_FULL permission.
874      */
875     @Override
getSyncAutomaticallyAsUser(Account account, String providerName, int userId)876     public boolean getSyncAutomaticallyAsUser(Account account, String providerName, int userId) {
877         enforceCrossUserPermission(userId,
878                 "no permission to read the sync settings for user " + userId);
879         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
880                 "no permission to read the sync settings");
881         if (!hasAccountAccess(true, account, Binder.getCallingUid())) {
882             return false;
883         }
884 
885         final long identityToken = clearCallingIdentity();
886         try {
887             SyncManager syncManager = getSyncManager();
888             if (syncManager != null) {
889                 return syncManager.getSyncStorageEngine()
890                         .getSyncAutomatically(account, userId, providerName);
891             }
892         } finally {
893             restoreCallingIdentity(identityToken);
894         }
895         return false;
896     }
897 
898     @Override
setSyncAutomatically(Account account, String providerName, boolean sync)899     public void setSyncAutomatically(Account account, String providerName, boolean sync) {
900         setSyncAutomaticallyAsUser(account, providerName, sync, UserHandle.getCallingUserId());
901     }
902 
903     @Override
setSyncAutomaticallyAsUser(Account account, String providerName, boolean sync, int userId)904     public void setSyncAutomaticallyAsUser(Account account, String providerName, boolean sync,
905                                            int userId) {
906         if (TextUtils.isEmpty(providerName)) {
907             throw new IllegalArgumentException("Authority must be non-empty");
908         }
909         mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
910                 "no permission to write the sync settings");
911         enforceCrossUserPermission(userId,
912                 "no permission to modify the sync settings for user " + userId);
913 
914         final int callingUid = Binder.getCallingUid();
915         final int callingPid = Binder.getCallingPid();
916         if (!hasAccountAccess(true, account, callingUid)) {
917             return;
918         }
919 
920         final int syncExemptionFlag = getSyncExemptionForCaller(callingUid);
921 
922         final long identityToken = clearCallingIdentity();
923         try {
924             SyncManager syncManager = getSyncManager();
925             if (syncManager != null) {
926                 syncManager.getSyncStorageEngine().setSyncAutomatically(account, userId,
927                         providerName, sync, syncExemptionFlag, callingUid, callingPid);
928             }
929         } finally {
930             restoreCallingIdentity(identityToken);
931         }
932     }
933 
934     /** Old API. Schedule periodic sync with default flexMillis time. */
935     @Override
addPeriodicSync(Account account, String authority, Bundle extras, long pollFrequency)936     public void addPeriodicSync(Account account, String authority, Bundle extras,
937                                 long pollFrequency) {
938         Bundle.setDefusable(extras, true);
939         if (account == null) {
940             throw new IllegalArgumentException("Account must not be null");
941         }
942         if (TextUtils.isEmpty(authority)) {
943             throw new IllegalArgumentException("Authority must not be empty.");
944         }
945         mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
946                 "no permission to write the sync settings");
947 
948         final int callingUid = Binder.getCallingUid();
949         if (!hasAccountAccess(true, account, callingUid)) {
950             return;
951         }
952         validateExtras(callingUid, extras);
953 
954         int userId = UserHandle.getCallingUserId();
955 
956         pollFrequency = clampPeriod(pollFrequency);
957         long defaultFlex = SyncStorageEngine.calculateDefaultFlexTime(pollFrequency);
958 
959         final long identityToken = clearCallingIdentity();
960         try {
961             SyncStorageEngine.EndPoint info =
962                     new SyncStorageEngine.EndPoint(account, authority, userId);
963             getSyncManager().updateOrAddPeriodicSync(info, pollFrequency,
964                     defaultFlex, extras);
965         } finally {
966             restoreCallingIdentity(identityToken);
967         }
968     }
969 
970     @Override
removePeriodicSync(Account account, String authority, Bundle extras)971     public void removePeriodicSync(Account account, String authority, Bundle extras) {
972         Bundle.setDefusable(extras, true);
973         if (account == null) {
974             throw new IllegalArgumentException("Account must not be null");
975         }
976         if (TextUtils.isEmpty(authority)) {
977             throw new IllegalArgumentException("Authority must not be empty");
978         }
979         mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
980                 "no permission to write the sync settings");
981 
982         final int callingUid = Binder.getCallingUid();
983         if (!hasAccountAccess(true, account, callingUid)) {
984             return;
985         }
986         validateExtras(callingUid, extras);
987 
988         int userId = UserHandle.getCallingUserId();
989         final long identityToken = clearCallingIdentity();
990         try {
991             getSyncManager()
992                     .removePeriodicSync(
993                             new SyncStorageEngine.EndPoint(account, authority, userId),
994                             extras, "removePeriodicSync() by uid=" + callingUid);
995         } finally {
996             restoreCallingIdentity(identityToken);
997         }
998     }
999 
1000     @Override
getPeriodicSyncs(Account account, String providerName, ComponentName cname)1001     public List<PeriodicSync> getPeriodicSyncs(Account account, String providerName,
1002                                                ComponentName cname) {
1003         if (account == null) {
1004             throw new IllegalArgumentException("Account must not be null");
1005         }
1006         if (TextUtils.isEmpty(providerName)) {
1007             throw new IllegalArgumentException("Authority must not be empty");
1008         }
1009         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
1010                 "no permission to read the sync settings");
1011         if (!hasAccountAccess(true, account, Binder.getCallingUid())) {
1012             return new ArrayList<>(); // return a new empty list for consistent behavior
1013         }
1014 
1015         int userId = UserHandle.getCallingUserId();
1016         final long identityToken = clearCallingIdentity();
1017         try {
1018             return getSyncManager().getPeriodicSyncs(
1019                     new SyncStorageEngine.EndPoint(account, providerName, userId));
1020         } finally {
1021             restoreCallingIdentity(identityToken);
1022         }
1023     }
1024 
1025     @Override
getIsSyncable(Account account, String providerName)1026     public int getIsSyncable(Account account, String providerName) {
1027         return getIsSyncableAsUser(account, providerName, UserHandle.getCallingUserId());
1028     }
1029 
1030     /**
1031      * If the user id supplied is different to the calling user, the caller must hold the
1032      * INTERACT_ACROSS_USERS_FULL permission.
1033      */
1034     @Override
getIsSyncableAsUser(Account account, String providerName, int userId)1035     public int getIsSyncableAsUser(Account account, String providerName, int userId) {
1036         enforceCrossUserPermission(userId,
1037                 "no permission to read the sync settings for user " + userId);
1038         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
1039                 "no permission to read the sync settings");
1040         if (!hasAccountAccess(true, account, Binder.getCallingUid())) {
1041             return SyncStorageEngine.AuthorityInfo.NOT_SYNCABLE; // to keep behavior consistent
1042         }
1043 
1044         final long identityToken = clearCallingIdentity();
1045         try {
1046             SyncManager syncManager = getSyncManager();
1047             if (syncManager != null) {
1048                 return syncManager.computeSyncable(
1049                         account, userId, providerName, false);
1050             }
1051         } finally {
1052             restoreCallingIdentity(identityToken);
1053         }
1054         return -1;
1055     }
1056 
1057     @Override
setIsSyncable(Account account, String providerName, int syncable)1058     public void setIsSyncable(Account account, String providerName, int syncable) {
1059         setIsSyncableAsUser(account, providerName, syncable, UserHandle.getCallingUserId());
1060     }
1061 
1062     /**
1063      * @hide
1064      */
1065     @Override
setIsSyncableAsUser(Account account, String providerName, int syncable, int userId)1066     public void setIsSyncableAsUser(Account account, String providerName, int syncable,
1067             int userId) {
1068         if (TextUtils.isEmpty(providerName)) {
1069             throw new IllegalArgumentException("Authority must not be empty");
1070         }
1071         enforceCrossUserPermission(userId,
1072                 "no permission to set the sync settings for user " + userId);
1073         mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
1074                 "no permission to write the sync settings");
1075 
1076         syncable = normalizeSyncable(syncable);
1077         final int callingUid = Binder.getCallingUid();
1078         final int callingPid = Binder.getCallingPid();
1079         if (!hasAccountAccess(true, account, callingUid)) {
1080             return;
1081         }
1082 
1083         final long identityToken = clearCallingIdentity();
1084         try {
1085             SyncManager syncManager = getSyncManager();
1086             if (syncManager != null) {
1087                 syncManager.getSyncStorageEngine().setIsSyncable(
1088                         account, userId, providerName, syncable, callingUid, callingPid);
1089             }
1090         } finally {
1091             restoreCallingIdentity(identityToken);
1092         }
1093     }
1094 
1095     @Override
getMasterSyncAutomatically()1096     public boolean getMasterSyncAutomatically() {
1097         return getMasterSyncAutomaticallyAsUser(UserHandle.getCallingUserId());
1098     }
1099 
1100     /**
1101      * If the user id supplied is different to the calling user, the caller must hold the
1102      * INTERACT_ACROSS_USERS_FULL permission.
1103      */
1104     @Override
getMasterSyncAutomaticallyAsUser(int userId)1105     public boolean getMasterSyncAutomaticallyAsUser(int userId) {
1106         enforceCrossUserPermission(userId,
1107                 "no permission to read the sync settings for user " + userId);
1108         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
1109                 "no permission to read the sync settings");
1110 
1111         final long identityToken = clearCallingIdentity();
1112         try {
1113             SyncManager syncManager = getSyncManager();
1114             if (syncManager != null) {
1115                 return syncManager.getSyncStorageEngine().getMasterSyncAutomatically(userId);
1116             }
1117         } finally {
1118             restoreCallingIdentity(identityToken);
1119         }
1120         return false;
1121     }
1122 
1123     @Override
setMasterSyncAutomatically(boolean flag)1124     public void setMasterSyncAutomatically(boolean flag) {
1125         setMasterSyncAutomaticallyAsUser(flag, UserHandle.getCallingUserId());
1126     }
1127 
1128     @Override
setMasterSyncAutomaticallyAsUser(boolean flag, int userId)1129     public void setMasterSyncAutomaticallyAsUser(boolean flag, int userId) {
1130         enforceCrossUserPermission(userId,
1131                 "no permission to set the sync status for user " + userId);
1132         mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
1133                 "no permission to write the sync settings");
1134 
1135         final int callingUid = Binder.getCallingUid();
1136         final int callingPid = Binder.getCallingPid();
1137 
1138         final long identityToken = clearCallingIdentity();
1139         try {
1140             SyncManager syncManager = getSyncManager();
1141             if (syncManager != null) {
1142                 syncManager.getSyncStorageEngine().setMasterSyncAutomatically(flag, userId,
1143                         getSyncExemptionForCaller(callingUid), callingUid, callingPid);
1144             }
1145         } finally {
1146             restoreCallingIdentity(identityToken);
1147         }
1148     }
1149 
1150     @Override
isSyncActive(Account account, String authority, ComponentName cname)1151     public boolean isSyncActive(Account account, String authority, ComponentName cname) {
1152         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
1153                 "no permission to read the sync stats");
1154         if (!hasAccountAccess(true, account, Binder.getCallingUid())) {
1155             return false;
1156         }
1157 
1158         int userId = UserHandle.getCallingUserId();
1159         final long identityToken = clearCallingIdentity();
1160         try {
1161             SyncManager syncManager = getSyncManager();
1162             if (syncManager == null) {
1163                 return false;
1164             }
1165             return syncManager.getSyncStorageEngine().isSyncActive(
1166                     new SyncStorageEngine.EndPoint(account, authority, userId));
1167         } finally {
1168             restoreCallingIdentity(identityToken);
1169         }
1170     }
1171 
1172     @Override
getCurrentSyncs()1173     public List<SyncInfo> getCurrentSyncs() {
1174         return getCurrentSyncsAsUser(UserHandle.getCallingUserId());
1175     }
1176 
1177     /**
1178      * If the user id supplied is different to the calling user, the caller must hold the
1179      * INTERACT_ACROSS_USERS_FULL permission.
1180      */
1181     @Override
getCurrentSyncsAsUser(int userId)1182     public List<SyncInfo> getCurrentSyncsAsUser(int userId) {
1183         enforceCrossUserPermission(userId,
1184                 "no permission to read the sync settings for user " + userId);
1185         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
1186                 "no permission to read the sync stats");
1187 
1188         final boolean canAccessAccounts =
1189             mContext.checkCallingOrSelfPermission(Manifest.permission.GET_ACCOUNTS)
1190                 == PackageManager.PERMISSION_GRANTED;
1191         final long identityToken = clearCallingIdentity();
1192         try {
1193             return getSyncManager().getSyncStorageEngine()
1194                 .getCurrentSyncsCopy(userId, canAccessAccounts);
1195         } finally {
1196             restoreCallingIdentity(identityToken);
1197         }
1198     }
1199 
1200     @Override
getSyncStatus(Account account, String authority, ComponentName cname)1201     public SyncStatusInfo getSyncStatus(Account account, String authority, ComponentName cname) {
1202         return getSyncStatusAsUser(account, authority, cname, UserHandle.getCallingUserId());
1203     }
1204 
1205     /**
1206      * If the user id supplied is different to the calling user, the caller must hold the
1207      * INTERACT_ACROSS_USERS_FULL permission.
1208      */
1209     @Override
getSyncStatusAsUser(Account account, String authority, ComponentName cname, int userId)1210     public SyncStatusInfo getSyncStatusAsUser(Account account, String authority,
1211                                               ComponentName cname, int userId) {
1212         if (TextUtils.isEmpty(authority)) {
1213             throw new IllegalArgumentException("Authority must not be empty");
1214         }
1215 
1216         enforceCrossUserPermission(userId,
1217                 "no permission to read the sync stats for user " + userId);
1218         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
1219                 "no permission to read the sync stats");
1220         if (!hasAccountAccess(true, account, Binder.getCallingUid())) {
1221             return null;
1222         }
1223 
1224         final long identityToken = clearCallingIdentity();
1225         try {
1226             SyncManager syncManager = getSyncManager();
1227             if (syncManager == null) {
1228                 return null;
1229             }
1230             SyncStorageEngine.EndPoint info;
1231             if (!(account == null || authority == null)) {
1232                 info = new SyncStorageEngine.EndPoint(account, authority, userId);
1233             } else {
1234                 throw new IllegalArgumentException("Must call sync status with valid authority");
1235             }
1236             return syncManager.getSyncStorageEngine().getStatusByAuthority(info);
1237         } finally {
1238             restoreCallingIdentity(identityToken);
1239         }
1240     }
1241 
1242     @Override
isSyncPending(Account account, String authority, ComponentName cname)1243     public boolean isSyncPending(Account account, String authority, ComponentName cname) {
1244         return isSyncPendingAsUser(account, authority, cname, UserHandle.getCallingUserId());
1245     }
1246 
1247     @Override
isSyncPendingAsUser(Account account, String authority, ComponentName cname, int userId)1248     public boolean isSyncPendingAsUser(Account account, String authority, ComponentName cname,
1249                                        int userId) {
1250         mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
1251                 "no permission to read the sync stats");
1252         enforceCrossUserPermission(userId,
1253                 "no permission to retrieve the sync settings for user " + userId);
1254         if (!hasAccountAccess(true, account, Binder.getCallingUid())) {
1255             return false;
1256         }
1257 
1258         final long identityToken = clearCallingIdentity();
1259         SyncManager syncManager = getSyncManager();
1260         if (syncManager == null) return false;
1261 
1262         try {
1263             SyncStorageEngine.EndPoint info;
1264             if (!(account == null || authority == null)) {
1265                 info = new SyncStorageEngine.EndPoint(account, authority, userId);
1266             } else {
1267                 throw new IllegalArgumentException("Invalid authority specified");
1268             }
1269             return syncManager.getSyncStorageEngine().isSyncPending(info);
1270         } finally {
1271             restoreCallingIdentity(identityToken);
1272         }
1273     }
1274 
1275     @Override
addStatusChangeListener(int mask, ISyncStatusObserver callback)1276     public void addStatusChangeListener(int mask, ISyncStatusObserver callback) {
1277         final int callingUid = Binder.getCallingUid();
1278         final long identityToken = clearCallingIdentity();
1279         try {
1280             SyncManager syncManager = getSyncManager();
1281             if (syncManager != null && callback != null) {
1282                 syncManager.getSyncStorageEngine().addStatusChangeListener(
1283                         mask, callingUid, callback);
1284             }
1285         } finally {
1286             restoreCallingIdentity(identityToken);
1287         }
1288     }
1289 
1290     @Override
removeStatusChangeListener(ISyncStatusObserver callback)1291     public void removeStatusChangeListener(ISyncStatusObserver callback) {
1292         final long identityToken = clearCallingIdentity();
1293         try {
1294             SyncManager syncManager = getSyncManager();
1295             if (syncManager != null && callback != null) {
1296                 syncManager.getSyncStorageEngine().removeStatusChangeListener(callback);
1297             }
1298         } finally {
1299             restoreCallingIdentity(identityToken);
1300         }
1301     }
1302 
getProviderPackageName(Uri uri, int userId)1303     private @Nullable String getProviderPackageName(Uri uri, int userId) {
1304         final ProviderInfo pi = mContext.getPackageManager().resolveContentProviderAsUser(
1305                 uri.getAuthority(), 0, userId);
1306         return (pi != null) ? pi.packageName : null;
1307     }
1308 
1309     @GuardedBy("mCache")
findOrCreateCacheLocked(int userId, String providerPackageName)1310     private ArrayMap<Pair<String, Uri>, Bundle> findOrCreateCacheLocked(int userId,
1311             String providerPackageName) {
1312         ArrayMap<String, ArrayMap<Pair<String, Uri>, Bundle>> userCache = mCache.get(userId);
1313         if (userCache == null) {
1314             userCache = new ArrayMap<>();
1315             mCache.put(userId, userCache);
1316         }
1317         ArrayMap<Pair<String, Uri>, Bundle> packageCache = userCache.get(providerPackageName);
1318         if (packageCache == null) {
1319             packageCache = new ArrayMap<>();
1320             userCache.put(providerPackageName, packageCache);
1321         }
1322         return packageCache;
1323     }
1324 
1325     @GuardedBy("mCache")
invalidateCacheLocked(int userId, String providerPackageName, Uri uri)1326     private void invalidateCacheLocked(int userId, String providerPackageName, Uri uri) {
1327         ArrayMap<String, ArrayMap<Pair<String, Uri>, Bundle>> userCache = mCache.get(userId);
1328         if (userCache == null) return;
1329 
1330         ArrayMap<Pair<String, Uri>, Bundle> packageCache = userCache.get(providerPackageName);
1331         if (packageCache == null) return;
1332 
1333         if (uri != null) {
1334             for (int i = 0; i < packageCache.size();) {
1335                 final Pair<String, Uri> key = packageCache.keyAt(i);
1336                 if (key.second != null && key.second.toString().startsWith(uri.toString())) {
1337                     if (DEBUG) Slog.d(TAG, "Invalidating cache for key " + key);
1338                     packageCache.removeAt(i);
1339                 } else {
1340                     i++;
1341                 }
1342             }
1343         } else {
1344             if (DEBUG) Slog.d(TAG, "Invalidating cache for package " + providerPackageName);
1345             packageCache.clear();
1346         }
1347     }
1348 
1349     @Override
1350     @RequiresPermission(android.Manifest.permission.CACHE_CONTENT)
putCache(String packageName, Uri key, Bundle value, int userId)1351     public void putCache(String packageName, Uri key, Bundle value, int userId) {
1352         Bundle.setDefusable(value, true);
1353         enforceNonFullCrossUserPermission(userId, TAG);
1354         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CACHE_CONTENT, TAG);
1355         mContext.getSystemService(AppOpsManager.class).checkPackage(Binder.getCallingUid(),
1356                 packageName);
1357 
1358         final String providerPackageName = getProviderPackageName(key, userId);
1359         final Pair<String, Uri> fullKey = Pair.create(packageName, key);
1360 
1361         synchronized (mCache) {
1362             final ArrayMap<Pair<String, Uri>, Bundle> cache = findOrCreateCacheLocked(userId,
1363                     providerPackageName);
1364             if (value != null) {
1365                 cache.put(fullKey, value);
1366             } else {
1367                 cache.remove(fullKey);
1368             }
1369         }
1370     }
1371 
1372     @Override
1373     @RequiresPermission(android.Manifest.permission.CACHE_CONTENT)
getCache(String packageName, Uri key, int userId)1374     public Bundle getCache(String packageName, Uri key, int userId) {
1375         enforceNonFullCrossUserPermission(userId, TAG);
1376         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CACHE_CONTENT, TAG);
1377         mContext.getSystemService(AppOpsManager.class).checkPackage(Binder.getCallingUid(),
1378                 packageName);
1379 
1380         final String providerPackageName = getProviderPackageName(key, userId);
1381         final Pair<String, Uri> fullKey = Pair.create(packageName, key);
1382 
1383         synchronized (mCache) {
1384             final ArrayMap<Pair<String, Uri>, Bundle> cache = findOrCreateCacheLocked(userId,
1385                     providerPackageName);
1386             return cache.get(fullKey);
1387         }
1388     }
1389 
handleIncomingUser(Uri uri, int pid, int uid, int modeFlags, boolean allowNonFull, int userId)1390     private int handleIncomingUser(Uri uri, int pid, int uid, int modeFlags, boolean allowNonFull,
1391             int userId) {
1392         if (userId == UserHandle.USER_CURRENT) {
1393             userId = ActivityManager.getCurrentUser();
1394         }
1395 
1396         if (userId == UserHandle.USER_ALL) {
1397             mContext.enforceCallingOrSelfPermission(
1398                     Manifest.permission.INTERACT_ACROSS_USERS_FULL, "No access to " + uri);
1399         } else if (userId < 0) {
1400             throw new IllegalArgumentException("Invalid user: " + userId);
1401         } else if (userId != UserHandle.getCallingUserId()) {
1402             if (checkUriPermission(uri, pid, uid, modeFlags,
1403                     userId) != PackageManager.PERMISSION_GRANTED) {
1404                 boolean allow = false;
1405                 if (mContext.checkCallingOrSelfPermission(
1406                         Manifest.permission.INTERACT_ACROSS_USERS_FULL)
1407                                 == PackageManager.PERMISSION_GRANTED) {
1408                     allow = true;
1409                 } else if (allowNonFull && mContext.checkCallingOrSelfPermission(
1410                         Manifest.permission.INTERACT_ACROSS_USERS)
1411                                 == PackageManager.PERMISSION_GRANTED) {
1412                     allow = true;
1413                 }
1414                 if (!allow) {
1415                     final String permissions = allowNonFull
1416                             ? (Manifest.permission.INTERACT_ACROSS_USERS_FULL + " or " +
1417                                     Manifest.permission.INTERACT_ACROSS_USERS)
1418                             : Manifest.permission.INTERACT_ACROSS_USERS_FULL;
1419                     throw new SecurityException("No access to " + uri + ": neither user " + uid
1420                             + " nor current process has " + permissions);
1421                 }
1422             }
1423         }
1424 
1425         return userId;
1426     }
1427 
1428     /**
1429      * Checks if the request is from the system or an app that has INTERACT_ACROSS_USERS_FULL
1430      * permission, if the userHandle is not for the caller.
1431      *
1432      * @param userHandle the user handle of the user we want to act on behalf of.
1433      * @param message the message to log on security exception.
1434      */
enforceCrossUserPermission(int userHandle, String message)1435     private void enforceCrossUserPermission(int userHandle, String message) {
1436         final int callingUser = UserHandle.getCallingUserId();
1437         if (callingUser != userHandle) {
1438             mContext.enforceCallingOrSelfPermission(
1439                     Manifest.permission.INTERACT_ACROSS_USERS_FULL, message);
1440         }
1441     }
1442 
1443     /**
1444      * Checks if the request is from the system or an app that has {@code INTERACT_ACROSS_USERS} or
1445      * {@code INTERACT_ACROSS_USERS_FULL} permission, if the {@code userHandle} is not for the
1446      * caller.
1447      *
1448      * @param userHandle the user handle of the user we want to act on behalf of.
1449      * @param message the message to log on security exception.
1450      */
enforceNonFullCrossUserPermission(int userHandle, String message)1451     private void enforceNonFullCrossUserPermission(int userHandle, String message) {
1452         final int callingUser = UserHandle.getCallingUserId();
1453         if (callingUser == userHandle) {
1454             return;
1455         }
1456 
1457         int interactAcrossUsersState = mContext.checkCallingOrSelfPermission(
1458                 Manifest.permission.INTERACT_ACROSS_USERS);
1459         if (interactAcrossUsersState == PERMISSION_GRANTED) {
1460             return;
1461         }
1462 
1463         mContext.enforceCallingOrSelfPermission(
1464                 Manifest.permission.INTERACT_ACROSS_USERS_FULL, message);
1465     }
1466 
1467     /**
1468      * Checks to see if the given account is accessible by the provided uid.
1469      *
1470      * @param checkCompatFlag whether to check if the ACCOUNT_ACCESS_CHECK_CHANGE_ID flag is enabled
1471      * @param account the account trying to be accessed
1472      * @param uid the uid trying to access the account
1473      * @return {@code true} if the account is accessible by the given uid, {@code false} otherwise
1474      */
hasAccountAccess(boolean checkCompatFlag, Account account, int uid)1475     private boolean hasAccountAccess(boolean checkCompatFlag, Account account, int uid) {
1476         if (account == null) {
1477             // If the account is null, it means to check for all accounts hence skip the check here.
1478             return true;
1479         }
1480         if (checkCompatFlag
1481                 && !CompatChanges.isChangeEnabled(ACCOUNT_ACCESS_CHECK_CHANGE_ID, uid)) {
1482             return true;
1483         }
1484 
1485         final long identityToken = clearCallingIdentity();
1486         try {
1487             return mAccountManagerInternal.hasAccountAccess(account, uid);
1488         } finally {
1489             restoreCallingIdentity(identityToken);
1490         }
1491     }
1492 
normalizeSyncable(int syncable)1493     private static int normalizeSyncable(int syncable) {
1494         if (syncable > 0) {
1495             return SyncStorageEngine.AuthorityInfo.SYNCABLE;
1496         } else if (syncable == 0) {
1497             return SyncStorageEngine.AuthorityInfo.NOT_SYNCABLE;
1498         }
1499         return SyncStorageEngine.AuthorityInfo.UNDEFINED;
1500     }
1501 
validateExtras(int callingUid, Bundle extras)1502     private void validateExtras(int callingUid, Bundle extras) {
1503         if (extras.containsKey(ContentResolver.SYNC_VIRTUAL_EXTRAS_EXEMPTION_FLAG)) {
1504             switch (callingUid) {
1505                 case Process.ROOT_UID:
1506                 case Process.SHELL_UID:
1507                 case Process.SYSTEM_UID:
1508                     break; // Okay
1509                 default:
1510                     final String msg = "Invalid extras specified.";
1511                     Log.w(TAG, msg + " requestsync -f/-F needs to run on 'adb shell'");
1512                     throw new SecurityException(msg);
1513             }
1514         }
1515     }
1516 
1517     @SyncExemption
getSyncExemptionForCaller(int callingUid)1518     private int getSyncExemptionForCaller(int callingUid) {
1519         return getSyncExemptionAndCleanUpExtrasForCaller(callingUid, null);
1520     }
1521 
1522     @SyncExemption
getSyncExemptionAndCleanUpExtrasForCaller(int callingUid, Bundle extras)1523     private int getSyncExemptionAndCleanUpExtrasForCaller(int callingUid, Bundle extras) {
1524         if (extras != null) {
1525             final int exemption =
1526                     extras.getInt(ContentResolver.SYNC_VIRTUAL_EXTRAS_EXEMPTION_FLAG, -1);
1527 
1528             // Need to remove the virtual extra.
1529             extras.remove(ContentResolver.SYNC_VIRTUAL_EXTRAS_EXEMPTION_FLAG);
1530             if (exemption != -1) {
1531                 return exemption;
1532             }
1533         }
1534         final ActivityManagerInternal ami =
1535                 LocalServices.getService(ActivityManagerInternal.class);
1536         if (ami == null) {
1537             return ContentResolver.SYNC_EXEMPTION_NONE;
1538         }
1539         final int procState = ami.getUidProcessState(callingUid);
1540         final boolean isUidActive = ami.isUidActive(callingUid);
1541 
1542         // Providers bound by a TOP app will get PROCESS_STATE_BOUND_TOP, so include those as well
1543         if (procState <= ActivityManager.PROCESS_STATE_TOP
1544                 || procState == ActivityManager.PROCESS_STATE_BOUND_TOP) {
1545             return ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP;
1546         }
1547         if (procState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND || isUidActive) {
1548             FrameworkStatsLog.write(FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED,
1549                     callingUid, getProcStateForStatsd(procState), isUidActive,
1550                     getRestrictionLevelForStatsd(ami.getRestrictionLevel(callingUid)));
1551             return ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET;
1552         }
1553         return ContentResolver.SYNC_EXEMPTION_NONE;
1554     }
1555 
getProcStateForStatsd(int procState)1556     private int getProcStateForStatsd(int procState) {
1557         switch (procState) {
1558             case ActivityManager.PROCESS_STATE_UNKNOWN:
1559                 return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__UNKNOWN;
1560             case ActivityManager.PROCESS_STATE_PERSISTENT:
1561                 return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__PERSISTENT;
1562             case ActivityManager.PROCESS_STATE_PERSISTENT_UI:
1563                 return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__PERSISTENT_UI;
1564             case ActivityManager.PROCESS_STATE_TOP:
1565                 return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__TOP;
1566             case ActivityManager.PROCESS_STATE_BOUND_TOP:
1567                 return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__BOUND_TOP;
1568             case ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE:
1569                 return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__FOREGROUND_SERVICE;
1570             case ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE:
1571                 return FrameworkStatsLog
1572                         .SYNC_EXEMPTION_OCCURRED__PROC_STATE__BOUND_FOREGROUND_SERVICE;
1573             case ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND:
1574                 return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__IMPORTANT_FOREGROUND;
1575             case ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND:
1576                 return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__IMPORTANT_BACKGROUND;
1577             case ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND:
1578                 return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__TRANSIENT_BACKGROUND;
1579             case ActivityManager.PROCESS_STATE_BACKUP:
1580                 return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__BACKUP;
1581             case ActivityManager.PROCESS_STATE_SERVICE:
1582                 return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__SERVICE;
1583             case ActivityManager.PROCESS_STATE_RECEIVER:
1584                 return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__RECEIVER;
1585             case ActivityManager.PROCESS_STATE_TOP_SLEEPING:
1586                 return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__TOP_SLEEPING;
1587             case ActivityManager.PROCESS_STATE_HEAVY_WEIGHT:
1588                 return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__HEAVY_WEIGHT;
1589             case ActivityManager.PROCESS_STATE_LAST_ACTIVITY:
1590                 return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__LAST_ACTIVITY;
1591             case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
1592                 return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__CACHED_ACTIVITY;
1593             case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
1594                 return FrameworkStatsLog
1595                         .SYNC_EXEMPTION_OCCURRED__PROC_STATE__CACHED_ACTIVITY_CLIENT;
1596             case ActivityManager.PROCESS_STATE_CACHED_RECENT:
1597                 return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__CACHED_RECENT;
1598             case ActivityManager.PROCESS_STATE_CACHED_EMPTY:
1599                 return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__CACHED_EMPTY;
1600             default:
1601                 return FrameworkStatsLog.SYNC_EXEMPTION_OCCURRED__PROC_STATE__UNKNOWN;
1602         }
1603     }
1604 
getRestrictionLevelForStatsd(@estrictionLevel int level)1605     private int getRestrictionLevelForStatsd(@RestrictionLevel int level) {
1606         switch (level) {
1607             case ActivityManager.RESTRICTION_LEVEL_UNKNOWN:
1608                 return AppBackgroundRestrictionsInfo.LEVEL_UNKNOWN;
1609             case ActivityManager.RESTRICTION_LEVEL_UNRESTRICTED:
1610                 return AppBackgroundRestrictionsInfo.LEVEL_UNRESTRICTED;
1611             case ActivityManager.RESTRICTION_LEVEL_EXEMPTED:
1612                 return AppBackgroundRestrictionsInfo.LEVEL_EXEMPTED;
1613             case ActivityManager.RESTRICTION_LEVEL_ADAPTIVE_BUCKET:
1614                 return AppBackgroundRestrictionsInfo.LEVEL_ADAPTIVE_BUCKET;
1615             case ActivityManager.RESTRICTION_LEVEL_RESTRICTED_BUCKET:
1616                 return AppBackgroundRestrictionsInfo.LEVEL_RESTRICTED_BUCKET;
1617             case ActivityManager.RESTRICTION_LEVEL_BACKGROUND_RESTRICTED:
1618                 return AppBackgroundRestrictionsInfo.LEVEL_BACKGROUND_RESTRICTED;
1619             case ActivityManager.RESTRICTION_LEVEL_HIBERNATION:
1620                 return AppBackgroundRestrictionsInfo.LEVEL_HIBERNATION;
1621             default:
1622                 return AppBackgroundRestrictionsInfo.LEVEL_UNKNOWN;
1623         }
1624     }
1625 
1626     /** {@hide} */
1627     @VisibleForTesting
1628     public static final class ObserverNode {
1629         private class ObserverEntry implements IBinder.DeathRecipient {
1630             public final IContentObserver observer;
1631             public final int uid;
1632             public final int pid;
1633             public final boolean notifyForDescendants;
1634             private final int userHandle;
1635             private final Object observersLock;
1636 
ObserverEntry(IContentObserver o, boolean n, Object observersLock, int _uid, int _pid, int _userHandle, Uri uri)1637             public ObserverEntry(IContentObserver o, boolean n, Object observersLock,
1638                                  int _uid, int _pid, int _userHandle, Uri uri) {
1639                 this.observersLock = observersLock;
1640                 observer = o;
1641                 uid = _uid;
1642                 pid = _pid;
1643                 userHandle = _userHandle;
1644                 notifyForDescendants = n;
1645 
1646                 final int entries = sObserverDeathDispatcher.linkToDeath(observer, this);
1647                 if (entries == -1) {
1648                     binderDied();
1649                 } else if (entries == TOO_MANY_OBSERVERS_THRESHOLD) {
1650                     boolean alreadyDetected;
1651 
1652                     synchronized (sObserverLeakDetectedUid) {
1653                         alreadyDetected = sObserverLeakDetectedUid.contains(uid);
1654                         if (!alreadyDetected) {
1655                             sObserverLeakDetectedUid.add(uid);
1656                         }
1657                     }
1658                     if (!alreadyDetected) {
1659                         String caller = null;
1660                         try {
1661                             caller = ArrayUtils.firstOrNull(AppGlobals.getPackageManager()
1662                                     .getPackagesForUid(uid));
1663                         } catch (RemoteException ignore) {
1664                         }
1665                         Slog.wtf(TAG, "Observer registered too many times. Leak? cpid=" + pid
1666                                 + " cuid=" + uid
1667                                 + " cpkg=" + caller
1668                                 + " url=" + uri);
1669                     }
1670                 }
1671 
1672             }
1673 
1674             @Override
binderDied()1675             public void binderDied() {
1676                 synchronized (observersLock) {
1677                     removeObserverLocked(observer);
1678                 }
1679             }
1680 
dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args, String name, String prefix, SparseIntArray pidCounts)1681             public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
1682                                    String name, String prefix, SparseIntArray pidCounts) {
1683                 pidCounts.put(pid, pidCounts.get(pid)+1);
1684                 pw.print(prefix); pw.print(name); pw.print(": pid=");
1685                 pw.print(pid); pw.print(" uid=");
1686                 pw.print(uid); pw.print(" user=");
1687                 pw.print(userHandle); pw.print(" target=");
1688                 pw.println(Integer.toHexString(System.identityHashCode(
1689                         observer != null ? observer.asBinder() : null)));
1690             }
1691         }
1692 
1693         private String mName;
1694         private ArrayList<ObserverNode> mChildren = new ArrayList<ObserverNode>();
1695         private ArrayList<ObserverEntry> mObservers = new ArrayList<ObserverEntry>();
1696 
ObserverNode(String name)1697         public ObserverNode(String name) {
1698             mName = name;
1699         }
1700 
dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args, String name, String prefix, int[] counts, SparseIntArray pidCounts)1701         public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
1702                                String name, String prefix, int[] counts, SparseIntArray pidCounts) {
1703             String innerName = null;
1704             if (mObservers.size() > 0) {
1705                 if ("".equals(name)) {
1706                     innerName = mName;
1707                 } else {
1708                     innerName = name + "/" + mName;
1709                 }
1710                 for (int i=0; i<mObservers.size(); i++) {
1711                     counts[1]++;
1712                     mObservers.get(i).dumpLocked(fd, pw, args, innerName, prefix,
1713                             pidCounts);
1714                 }
1715             }
1716             if (mChildren.size() > 0) {
1717                 if (innerName == null) {
1718                     if ("".equals(name)) {
1719                         innerName = mName;
1720                     } else {
1721                         innerName = name + "/" + mName;
1722                     }
1723                 }
1724                 for (int i=0; i<mChildren.size(); i++) {
1725                     counts[0]++;
1726                     mChildren.get(i).dumpLocked(fd, pw, args, innerName, prefix,
1727                             counts, pidCounts);
1728                 }
1729             }
1730         }
1731 
getUriSegment(Uri uri, int index)1732         public static String getUriSegment(Uri uri, int index) {
1733             if (uri != null) {
1734                 if (index == 0) {
1735                     return uri.getAuthority();
1736                 } else {
1737                     return uri.getPathSegments().get(index - 1);
1738                 }
1739             } else {
1740                 return null;
1741             }
1742         }
1743 
countUriSegments(Uri uri)1744         public static int countUriSegments(Uri uri) {
1745             if (uri == null) {
1746                 return 0;
1747             }
1748             return uri.getPathSegments().size() + 1;
1749         }
1750 
1751         // Invariant:  userHandle is either a hard user number or is USER_ALL
addObserverLocked(Uri uri, IContentObserver observer, boolean notifyForDescendants, Object observersLock, int uid, int pid, int userHandle)1752         public void addObserverLocked(Uri uri, IContentObserver observer,
1753                                       boolean notifyForDescendants, Object observersLock,
1754                                       int uid, int pid, int userHandle) {
1755             addObserverLocked(uri, 0, observer, notifyForDescendants, observersLock,
1756                     uid, pid, userHandle);
1757         }
1758 
addObserverLocked(Uri uri, int index, IContentObserver observer, boolean notifyForDescendants, Object observersLock, int uid, int pid, int userHandle)1759         private void addObserverLocked(Uri uri, int index, IContentObserver observer,
1760                                        boolean notifyForDescendants, Object observersLock,
1761                                        int uid, int pid, int userHandle) {
1762             // If this is the leaf node add the observer
1763             if (index == countUriSegments(uri)) {
1764                 mObservers.add(new ObserverEntry(observer, notifyForDescendants, observersLock,
1765                         uid, pid, userHandle, uri));
1766                 return;
1767             }
1768 
1769             // Look to see if the proper child already exists
1770             String segment = getUriSegment(uri, index);
1771             if (segment == null) {
1772                 throw new IllegalArgumentException("Invalid Uri (" + uri + ") used for observer");
1773             }
1774             int N = mChildren.size();
1775             for (int i = 0; i < N; i++) {
1776                 ObserverNode node = mChildren.get(i);
1777                 if (node.mName.equals(segment)) {
1778                     node.addObserverLocked(uri, index + 1, observer, notifyForDescendants,
1779                             observersLock, uid, pid, userHandle);
1780                     return;
1781                 }
1782             }
1783 
1784             // No child found, create one
1785             ObserverNode node = new ObserverNode(segment);
1786             mChildren.add(node);
1787             node.addObserverLocked(uri, index + 1, observer, notifyForDescendants,
1788                     observersLock, uid, pid, userHandle);
1789         }
1790 
removeObserverLocked(IContentObserver observer)1791         public boolean removeObserverLocked(IContentObserver observer) {
1792             int size = mChildren.size();
1793             for (int i = 0; i < size; i++) {
1794                 boolean empty = mChildren.get(i).removeObserverLocked(observer);
1795                 if (empty) {
1796                     mChildren.remove(i);
1797                     i--;
1798                     size--;
1799                 }
1800             }
1801 
1802             IBinder observerBinder = observer.asBinder();
1803             size = mObservers.size();
1804             for (int i = 0; i < size; i++) {
1805                 ObserverEntry entry = mObservers.get(i);
1806                 if (entry.observer.asBinder() == observerBinder) {
1807                     mObservers.remove(i);
1808                     // We no longer need to listen for death notifications. Remove it.
1809                     sObserverDeathDispatcher.unlinkToDeath(observer, entry);
1810                     break;
1811                 }
1812             }
1813 
1814             if (mChildren.size() == 0 && mObservers.size() == 0) {
1815                 return true;
1816             }
1817             return false;
1818         }
1819 
collectMyObserversLocked(Uri uri, boolean leaf, IContentObserver observer, boolean observerWantsSelfNotifications, int flags, int targetUserHandle, ObserverCollector collector)1820         private void collectMyObserversLocked(Uri uri, boolean leaf, IContentObserver observer,
1821                                               boolean observerWantsSelfNotifications, int flags,
1822                                               int targetUserHandle, ObserverCollector collector) {
1823             int N = mObservers.size();
1824             IBinder observerBinder = observer == null ? null : observer.asBinder();
1825             for (int i = 0; i < N; i++) {
1826                 ObserverEntry entry = mObservers.get(i);
1827 
1828                 // Don't notify the observer if it sent the notification and isn't interested
1829                 // in self notifications
1830                 boolean selfChange = (entry.observer.asBinder() == observerBinder);
1831                 if (selfChange && !observerWantsSelfNotifications) {
1832                     continue;
1833                 }
1834 
1835                 // Does this observer match the target user?
1836                 if (targetUserHandle == UserHandle.USER_ALL
1837                         || entry.userHandle == UserHandle.USER_ALL
1838                         || targetUserHandle == entry.userHandle) {
1839                     // Make sure the observer is interested in the notification
1840                     if (leaf) {
1841                         // If we are at the leaf: we always report, unless the sender has asked
1842                         // to skip observers that are notifying for descendants (since they will
1843                         // be sending another more specific URI for them).
1844                         if ((flags&ContentResolver.NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS) != 0
1845                                 && entry.notifyForDescendants) {
1846                             if (DEBUG) Slog.d(TAG, "Skipping " + entry.observer
1847                                     + ": skip notify for descendants");
1848                             continue;
1849                         }
1850                     } else {
1851                         // If we are not at the leaf: we report if the observer says it wants
1852                         // to be notified for all descendants.
1853                         if (!entry.notifyForDescendants) {
1854                             if (DEBUG) Slog.d(TAG, "Skipping " + entry.observer
1855                                     + ": not monitor descendants");
1856                             continue;
1857                         }
1858                     }
1859                     if (DEBUG) Slog.d(TAG, "Reporting to " + entry.observer + ": leaf=" + leaf
1860                             + " flags=" + Integer.toHexString(flags)
1861                             + " desc=" + entry.notifyForDescendants);
1862                     collector.collect(entry.observer, entry.uid, selfChange, uri, flags,
1863                             targetUserHandle);
1864                 }
1865             }
1866         }
1867 
1868         @VisibleForTesting
collectObserversLocked(Uri uri, int index, IContentObserver observer, boolean observerWantsSelfNotifications, int flags, int targetUserHandle, ObserverCollector collector)1869         public void collectObserversLocked(Uri uri, int index,
1870                 IContentObserver observer, boolean observerWantsSelfNotifications, int flags,
1871                 int targetUserHandle, ObserverCollector collector) {
1872             collectObserversLocked(uri, countUriSegments(uri), index, observer,
1873                     observerWantsSelfNotifications, flags, targetUserHandle, collector);
1874         }
1875 
1876         /**
1877          * targetUserHandle is either a hard user handle or is USER_ALL
1878          */
collectObserversLocked(Uri uri, int segmentCount, int index, IContentObserver observer, boolean observerWantsSelfNotifications, int flags, int targetUserHandle, ObserverCollector collector)1879         public void collectObserversLocked(Uri uri, int segmentCount, int index,
1880                 IContentObserver observer, boolean observerWantsSelfNotifications, int flags,
1881                 int targetUserHandle, ObserverCollector collector) {
1882             String segment = null;
1883             if (index >= segmentCount) {
1884                 // This is the leaf node, notify all observers
1885                 if (DEBUG) Slog.d(TAG, "Collecting leaf observers @ #" + index + ", node " + mName);
1886                 collectMyObserversLocked(uri, true, observer, observerWantsSelfNotifications,
1887                         flags, targetUserHandle, collector);
1888             } else if (index < segmentCount){
1889                 segment = getUriSegment(uri, index);
1890                 if (DEBUG) Slog.d(TAG, "Collecting non-leaf observers @ #" + index + " / "
1891                         + segment);
1892                 // Notify any observers at this level who are interested in descendants
1893                 collectMyObserversLocked(uri, false, observer, observerWantsSelfNotifications,
1894                         flags, targetUserHandle, collector);
1895             }
1896 
1897             int N = mChildren.size();
1898             for (int i = 0; i < N; i++) {
1899                 ObserverNode node = mChildren.get(i);
1900                 if (segment == null || node.mName.equals(segment)) {
1901                     // We found the child,
1902                     node.collectObserversLocked(uri, segmentCount, index + 1, observer,
1903                             observerWantsSelfNotifications, flags, targetUserHandle, collector);
1904                     if (segment != null) {
1905                         break;
1906                     }
1907                 }
1908             }
1909         }
1910     }
1911 
enforceShell(String method)1912     private void enforceShell(String method) {
1913         final int callingUid = Binder.getCallingUid();
1914         if (callingUid != Process.SHELL_UID && callingUid != Process.ROOT_UID) {
1915             throw new SecurityException("Non-shell user attempted to call " + method);
1916         }
1917     }
1918 
1919     @Override
resetTodayStats()1920     public void resetTodayStats() {
1921         enforceShell("resetTodayStats");
1922 
1923         if (mSyncManager != null) {
1924             final long token = Binder.clearCallingIdentity();
1925             try {
1926                 mSyncManager.resetTodayStats();
1927             } finally {
1928                 Binder.restoreCallingIdentity(token);
1929             }
1930         }
1931     }
1932 
1933     @Override
onDbCorruption(String tag, String message, String stacktrace)1934     public void onDbCorruption(String tag, String message, String stacktrace) {
1935         Slog.e(tag, message);
1936         Slog.e(tag, "at " + stacktrace);
1937 
1938         // TODO: Figure out a better way to report it. b/117886381
1939         Slog.wtf(tag, message);
1940     }
1941 
1942     @Override
onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver)1943     public void onShellCommand(FileDescriptor in, FileDescriptor out,
1944             FileDescriptor err, String[] args, ShellCallback callback,
1945             ResultReceiver resultReceiver) {
1946         (new ContentShellCommand(this)).exec(this, in, out, err, args, callback, resultReceiver);
1947     }
1948 }
1949