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