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