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