blob: 7824a0ac319410e0d03cd44187c4f27082b47257 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
Jeff Sharkey7a96c392012-11-15 14:01:46 -080017package com.android.server.content;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080018
Jeff Sharkey7a96c392012-11-15 14:01:46 -080019import android.Manifest;
Dianne Hackborn7a135592009-05-06 00:28:37 -070020import android.accounts.Account;
Jeff Sharkey87314082016-03-11 17:25:11 -070021import android.annotation.Nullable;
Ivan Chianga46ade32019-02-25 11:30:34 +080022import android.annotation.RequiresPermission;
Christopher Tate16aa9732012-09-17 16:23:44 -070023import android.app.ActivityManager;
Jeff Sharkey923e0b82016-11-16 17:22:48 -070024import android.app.ActivityManagerInternal;
Makoto Onukiad1291e2019-05-30 11:36:55 -070025import android.app.AppGlobals;
Jeff Sharkey87314082016-03-11 17:25:11 -070026import android.app.AppOpsManager;
Shreyas Basarge3b840e32016-06-14 15:32:02 +010027import android.app.job.JobInfo;
Jeff Sharkey87314082016-03-11 17:25:11 -070028import android.content.BroadcastReceiver;
Matthew Williamsfa774182013-06-18 15:44:11 -070029import android.content.ComponentName;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080030import android.content.ContentResolver;
Makoto Onuki75ad2492018-03-28 14:42:42 -070031import android.content.ContentResolver.SyncExemption;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080032import android.content.Context;
33import android.content.IContentService;
Jeff Sharkey7732e1e2016-03-30 17:14:23 -060034import android.content.ISyncStatusObserver;
Benjamin Franzadea1912015-06-19 16:03:38 +010035import android.content.Intent;
Jeff Sharkey87314082016-03-11 17:25:11 -070036import android.content.IntentFilter;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080037import android.content.PeriodicSync;
38import android.content.SyncAdapterType;
39import android.content.SyncInfo;
Matthew Williamsfa774182013-06-18 15:44:11 -070040import android.content.SyncRequest;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080041import android.content.SyncStatusInfo;
Benjamin Franzadea1912015-06-19 16:03:38 +010042import android.content.pm.PackageManager;
Svetoslav0010b702015-06-30 18:05:26 -070043import android.content.pm.PackageManagerInternal;
Jeff Sharkey87314082016-03-11 17:25:11 -070044import android.content.pm.ProviderInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045import android.database.IContentObserver;
46import android.database.sqlite.SQLiteException;
47import android.net.Uri;
Dianne Hackborn1b64e0d2011-07-17 15:23:59 -070048import android.os.Binder;
Jeff Sharkey912e80d2017-02-24 11:00:55 -070049import android.os.Build;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050import android.os.Bundle;
Jeff Sharkeya3ebfec2016-04-04 08:58:04 -060051import android.os.FactoryTest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052import android.os.IBinder;
Makoto Onuki61283ec2018-01-31 17:22:36 -080053import android.os.Process;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054import android.os.RemoteException;
Makoto Onuki94986212018-04-11 16:24:46 -070055import android.os.ResultReceiver;
56import android.os.ShellCallback;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070057import android.os.UserHandle;
Matthew Williams632515b2013-10-10 15:51:00 -070058import android.text.TextUtils;
Jeff Sharkey87314082016-03-11 17:25:11 -070059import android.util.ArrayMap;
Makoto Onukiad1291e2019-05-30 11:36:55 -070060import android.util.ArraySet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061import android.util.Log;
Jeff Sharkey87314082016-03-11 17:25:11 -070062import android.util.Pair;
Jeff Sharkey60094592013-03-21 18:14:24 -070063import android.util.Slog;
Jeff Sharkey87314082016-03-11 17:25:11 -070064import android.util.SparseArray;
Dianne Hackborn1b64e0d2011-07-17 15:23:59 -070065import android.util.SparseIntArray;
Jeff Sharkey87314082016-03-11 17:25:11 -070066
67import com.android.internal.annotations.GuardedBy;
Makoto Onukiad1291e2019-05-30 11:36:55 -070068import com.android.internal.os.BinderDeathDispatcher;
Makoto Onukia9dca242017-06-21 17:06:49 -070069import com.android.internal.util.ArrayUtils;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060070import com.android.internal.util.DumpUtils;
Jeff Sharkey87314082016-03-11 17:25:11 -070071import com.android.internal.util.IndentingPrintWriter;
Svetoslav0010b702015-06-30 18:05:26 -070072import com.android.server.LocalServices;
Jeff Sharkeya3ebfec2016-04-04 08:58:04 -060073import com.android.server.SystemService;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080074
75import java.io.FileDescriptor;
76import java.io.PrintWriter;
77import java.util.ArrayList;
Dianne Hackborn1b64e0d2011-07-17 15:23:59 -070078import java.util.Collections;
79import java.util.Comparator;
Fred Quintanac5d1c6d2010-01-27 12:17:49 -080080import java.util.List;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081
82/**
83 * {@hide}
84 */
Dianne Hackborn231cc602009-04-27 17:10:36 -070085public final class ContentService extends IContentService.Stub {
Dianne Hackborn141f11c2016-04-05 15:46:12 -070086 static final String TAG = "ContentService";
Makoto Onuki5c01be62018-04-09 08:59:01 -070087 static final boolean DEBUG = false;
Jeff Sharkey87314082016-03-11 17:25:11 -070088
Makoto Onukiad1291e2019-05-30 11:36:55 -070089 /** Do a WTF if a single observer is registered more than this times. */
90 private static final int TOO_MANY_OBSERVERS_THRESHOLD = 1000;
91
Jeff Sharkeya3ebfec2016-04-04 08:58:04 -060092 public static class Lifecycle extends SystemService {
Jeff Sharkey1cab76a2016-04-12 18:23:31 -060093 private ContentService mService;
Jeff Sharkeya3ebfec2016-04-04 08:58:04 -060094
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);
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600103 mService = new ContentService(getContext(), factoryTest);
104 publishBinderService(ContentResolver.CONTENT_SERVICE_NAME, mService);
105 }
106
107 @Override
108 public void onBootPhase(int phase) {
Makoto Onukiaad2b512018-02-07 09:31:46 -0800109 mService.onBootPhase(phase);
Jeff Sharkeya3ebfec2016-04-04 08:58:04 -0600110 }
111
Makoto Onukife224e02017-06-29 14:11:14 -0700112
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
Jeff Sharkeya3ebfec2016-04-04 08:58:04 -0600128 @Override
129 public void onCleanupUser(int userHandle) {
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600130 synchronized (mService.mCache) {
131 mService.mCache.remove(userHandle);
Jeff Sharkeya3ebfec2016-04-04 08:58:04 -0600132 }
133 }
134 }
135
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800136 private Context mContext;
137 private boolean mFactoryTest;
Jeff Sharkey87314082016-03-11 17:25:11 -0700138
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800139 private final ObserverNode mRootNode = new ObserverNode("");
Jeff Sharkey87314082016-03-11 17:25:11 -0700140
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800141 private SyncManager mSyncManager = null;
142 private final Object mSyncManagerLock = new Object();
143
Makoto Onukiad1291e2019-05-30 11:36:55 -0700144 private static final BinderDeathDispatcher<IContentObserver> sObserverDeathDispatcher =
145 new BinderDeathDispatcher<>();
146
147 @GuardedBy("sObserverLeakDetectedUid")
148 private static final ArraySet<Integer> sObserverLeakDetectedUid = new ArraySet<>(0);
149
Jeff Sharkey87314082016-03-11 17:25:11 -0700150 /**
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) {
Jeff Sharkeya3ebfec2016-04-04 08:58:04 -0600162 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 }
Jeff Sharkey87314082016-03-11 17:25:11 -0700174 }
175 }
176 };
177
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800178 private SyncManager getSyncManager() {
179 synchronized(mSyncManagerLock) {
180 try {
Makoto Onuki056a9752018-05-08 15:21:56 -0700181 // Try to create the SyncManager, return null if it fails (which it shouldn't).
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800182 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
Makoto Onukife224e02017-06-29 14:11:14 -0700190 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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800202 @Override
Jeff Sharkey87314082016-03-11 17:25:11 -0700203 protected synchronized void dump(FileDescriptor fd, PrintWriter pw_, String[] args) {
Jeff Sharkey6df866a2017-03-31 14:08:23 -0600204 if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw_)) return;
Jeff Sharkey87314082016-03-11 17:25:11 -0700205 final IndentingPrintWriter pw = new IndentingPrintWriter(pw_, " ");
206
Makoto Onukia9dca242017-06-21 17:06:49 -0700207 final boolean dumpAll = ArrayUtils.contains(args, "-a");
208
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800209 // 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.
Jeff Sharkey87314082016-03-11 17:25:11 -0700211 final long identityToken = clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800212 try {
213 if (mSyncManager == null) {
Makoto Onuki056a9752018-05-08 15:21:56 -0700214 pw.println("SyncManager not available yet");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800215 } else {
Makoto Onukia9dca242017-06-21 17:06:49 -0700216 mSyncManager.dump(fd, pw, dumpAll);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800217 }
Dianne Hackborn1b64e0d2011-07-17 15:23:59 -0700218 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(": ");
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000246 pw.print(pidCounts.get(pid)); pw.println(" observers");
Dianne Hackborn1b64e0d2011-07-17 15:23:59 -0700247 }
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]);
Makoto Onukiad1291e2019-05-30 11:36:55 -0700251
252 sObserverDeathDispatcher.dump(pw, " ");
253 }
254 synchronized (sObserverLeakDetectedUid) {
255 pw.println();
256 pw.print("Observer leaking UIDs: ");
257 pw.println(sObserverLeakDetectedUid.toString());
Dianne Hackborn1b64e0d2011-07-17 15:23:59 -0700258 }
Jeff Sharkey87314082016-03-11 17:25:11 -0700259
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 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800272 } finally {
273 restoreCallingIdentity(identityToken);
274 }
275 }
276
277 /*package*/ ContentService(Context context, boolean factoryTest) {
278 mContext = context;
279 mFactoryTest = factoryTest;
Svetoslav0010b702015-06-30 18:05:26 -0700280
281 // Let the package manager query for the sync adapters for a given authority
Svet Ganov52153f42015-08-11 08:59:12 -0700282 // as we grant default permissions to sync adapters for specific authorities.
Svetoslav0010b702015-06-30 18:05:26 -0700283 PackageManagerInternal packageManagerInternal = LocalServices.getService(
284 PackageManagerInternal.class);
285 packageManagerInternal.setSyncAdapterPackagesprovider(
286 new PackageManagerInternal.SyncAdapterPackagesProvider() {
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000287 @Override
288 public String[] getPackages(String authority, int userId) {
289 return getSyncAdapterPackagesForAuthorityAsUser(authority, userId);
290 }
291 });
Jeff Sharkey87314082016-03-11 17:25:11 -0700292
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);
Jeff Sharkeya3ebfec2016-04-04 08:58:04 -0600301
302 final IntentFilter localeFilter = new IntentFilter();
303 localeFilter.addAction(Intent.ACTION_LOCALE_CHANGED);
304 mContext.registerReceiverAsUser(mCacheReceiver, UserHandle.ALL,
305 localeFilter, null, null);
Kenny Root26ff6622012-07-30 12:58:03 -0700306 }
307
Makoto Onukiaad2b512018-02-07 09:31:46 -0800308 void onBootPhase(int phase) {
309 switch (phase) {
Makoto Onukid0c50dd2018-02-16 09:52:50 -0800310 case SystemService.PHASE_ACTIVITY_MANAGER_READY:
Makoto Onukiaad2b512018-02-07 09:31:46 -0800311 getSyncManager();
312 break;
313 }
314 if (mSyncManager != null) {
315 mSyncManager.onBootPhase(phase);
316 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800317 }
318
Christopher Tate16aa9732012-09-17 16:23:44 -0700319 /**
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
Benjamin Franzadea1912015-06-19 16:03:38 +0100323 * 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.
Christopher Tate16aa9732012-09-17 16:23:44 -0700326 */
327 @Override
328 public void registerContentObserver(Uri uri, boolean notifyForDescendants,
Jeff Sharkey912e80d2017-02-24 11:00:55 -0700329 IContentObserver observer, int userHandle, int targetSdkVersion) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800330 if (observer == null || uri == null) {
331 throw new IllegalArgumentException("You must pass a valid uri and observer");
332 }
Christopher Tate16aa9732012-09-17 16:23:44 -0700333
Benjamin Franzadea1912015-06-19 16:03:38 +0100334 final int uid = Binder.getCallingUid();
335 final int pid = Binder.getCallingPid();
Christopher Tate16aa9732012-09-17 16:23:44 -0700336
Jeff Sharkey923e0b82016-11-16 17:22:48 -0700337 userHandle = handleIncomingUser(uri, pid, uid,
Sudheer Shankab4e2ddd2017-02-03 15:15:57 -0800338 Intent.FLAG_GRANT_READ_URI_PERMISSION, true, userHandle);
Jeff Sharkey923e0b82016-11-16 17:22:48 -0700339
340 final String msg = LocalServices.getService(ActivityManagerInternal.class)
341 .checkContentProviderAccess(uri.getAuthority(), userHandle);
342 if (msg != null) {
Jeff Sharkey912e80d2017-02-24 11:00:55 -0700343 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 }
Christopher Tate16aa9732012-09-17 16:23:44 -0700354 }
355
356 synchronized (mRootNode) {
357 mRootNode.addObserverLocked(uri, observer, notifyForDescendants, mRootNode,
Benjamin Franzadea1912015-06-19 16:03:38 +0100358 uid, pid, userHandle);
Christopher Tate16aa9732012-09-17 16:23:44 -0700359 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,
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000365 IContentObserver observer) {
Christopher Tate16aa9732012-09-17 16:23:44 -0700366 registerContentObserver(uri, notifyForDescendants, observer,
Jeff Sharkey912e80d2017-02-24 11:00:55 -0700367 UserHandle.getCallingUserId(), Build.VERSION_CODES.CUR_DEVELOPMENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800368 }
369
Jeff Sharkeya04c7a72016-03-18 12:20:36 -0600370 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800371 public void unregisterContentObserver(IContentObserver observer) {
372 if (observer == null) {
373 throw new IllegalArgumentException("You must pass a valid observer");
374 }
375 synchronized (mRootNode) {
Fred Quintana002ffad52010-03-02 11:18:16 -0800376 mRootNode.removeObserverLocked(observer);
Joe Onorato43a17652011-04-06 19:22:23 -0700377 if (false) Log.v(TAG, "Unregistered observer " + observer);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800378 }
379 }
380
Christopher Tate16aa9732012-09-17 16:23:44 -0700381 /**
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
Benjamin Franzadea1912015-06-19 16:03:38 +0100385 * 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.
Christopher Tate16aa9732012-09-17 16:23:44 -0700388 */
389 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800390 public void notifyChange(Uri uri, IContentObserver observer,
Jeff Sharkey912e80d2017-02-24 11:00:55 -0700391 boolean observerWantsSelfNotifications, int flags, int userHandle,
Makoto Onukie183a402018-08-29 11:46:41 -0700392 int targetSdkVersion, String callingPackage) {
Dianne Hackborn141f11c2016-04-05 15:46:12 -0700393 if (DEBUG) Slog.d(TAG, "Notifying update of " + uri + " for user " + userHandle
394 + " from observer " + observer + ", flags " + Integer.toHexString(flags));
Amith Yamasani04e0d262012-02-14 11:50:53 -0800395
Dianne Hackborne7617772016-04-27 17:03:52 -0700396 if (uri == null) {
397 throw new NullPointerException("Uri must not be null");
398 }
399
Makoto Onukie183a402018-08-29 11:46:41 -0700400 final int callingUid = Binder.getCallingUid();
401 final int callingPid = Binder.getCallingPid();
Christopher Tate16aa9732012-09-17 16:23:44 -0700402 final int callingUserHandle = UserHandle.getCallingUserId();
Christopher Tate16aa9732012-09-17 16:23:44 -0700403
Makoto Onukie183a402018-08-29 11:46:41 -0700404 userHandle = handleIncomingUser(uri, callingPid, callingUid,
Sudheer Shankab4e2ddd2017-02-03 15:15:57 -0800405 Intent.FLAG_GRANT_WRITE_URI_PERMISSION, true, userHandle);
Jeff Sharkey923e0b82016-11-16 17:22:48 -0700406
407 final String msg = LocalServices.getService(ActivityManagerInternal.class)
408 .checkContentProviderAccess(uri.getAuthority(), userHandle);
409 if (msg != null) {
Jeff Sharkey912e80d2017-02-24 11:00:55 -0700410 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 {
Makoto Onukie183a402018-08-29 11:46:41 -0700417 Log.w(TAG, "Ignoring notify for " + uri + " from " + callingUid + ": " + msg);
Jeff Sharkey912e80d2017-02-24 11:00:55 -0700418 return;
419 }
420 }
Christopher Tate16aa9732012-09-17 16:23:44 -0700421 }
422
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800423 // 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) {
Fred Quintana002ffad52010-03-02 11:18:16 -0800429 mRootNode.collectObserversLocked(uri, 0, observer, observerWantsSelfNotifications,
Dianne Hackborn141f11c2016-04-05 15:46:12 -0700430 flags, userHandle, calls);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800431 }
432 final int numCalls = calls.size();
433 for (int i=0; i<numCalls; i++) {
434 ObserverCall oc = calls.get(i);
435 try {
Svet Ganov3138a992016-06-15 16:57:32 -0700436 oc.mObserver.onChange(oc.mSelfChange, uri, userHandle);
Dianne Hackborn141f11c2016-04-05 15:46:12 -0700437 if (DEBUG) Slog.d(TAG, "Notified " + oc.mObserver + " of " + "update at "
Svet Ganov3138a992016-06-15 16:57:32 -0700438 + uri);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800439 } 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 }
Dianne Hackborn141f11c2016-04-05 15:46:12 -0700457 if ((flags&ContentResolver.NOTIFY_SYNC_TO_NETWORK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800458 SyncManager syncManager = getSyncManager();
Fred Quintanaac9385e2009-06-22 18:00:59 -0700459 if (syncManager != null) {
Makoto Onukie183a402018-08-29 11:46:41 -0700460 syncManager.scheduleLocalSync(null /* all accounts */, callingUserHandle,
461 callingUid,
462 uri.getAuthority(), getSyncExemptionForCaller(callingUid),
463 callingUid, callingPid, callingPackage);
Fred Quintanaac9385e2009-06-22 18:00:59 -0700464 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800465 }
Jeff Sharkey87314082016-03-11 17:25:11 -0700466
467 synchronized (mCache) {
468 final String providerPackageName = getProviderPackageName(uri);
469 invalidateCacheLocked(userHandle, providerPackageName, uri);
470 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800471 } finally {
472 restoreCallingIdentity(identityToken);
473 }
474 }
475
Nicolas Prevot051f3b72016-05-18 18:44:00 +0100476 private int checkUriPermission(Uri uri, int pid, int uid, int modeFlags, int userHandle) {
477 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -0800478 return ActivityManager.getService().checkUriPermission(
Nicolas Prevot051f3b72016-05-18 18:44:00 +0100479 uri, pid, uid, modeFlags, userHandle, null);
480 } catch (RemoteException e) {
481 return PackageManager.PERMISSION_DENIED;
482 }
483 }
484
Christopher Tate16aa9732012-09-17 16:23:44 -0700485 public void notifyChange(Uri uri, IContentObserver observer,
Makoto Onukie183a402018-08-29 11:46:41 -0700486 boolean observerWantsSelfNotifications, boolean syncToNetwork,
487 String callingPackage) {
Dianne Hackborn141f11c2016-04-05 15:46:12 -0700488 notifyChange(uri, observer, observerWantsSelfNotifications,
489 syncToNetwork ? ContentResolver.NOTIFY_SYNC_TO_NETWORK : 0,
Makoto Onukie183a402018-08-29 11:46:41 -0700490 UserHandle.getCallingUserId(), Build.VERSION_CODES.CUR_DEVELOPMENT, callingPackage);
Christopher Tate16aa9732012-09-17 16:23:44 -0700491 }
492
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800493 /**
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;
Jeff Brown86de0592012-01-23 13:01:18 -0800502 final boolean mSelfChange;
Nicolas Prevot051f3b72016-05-18 18:44:00 +0100503 final int mObserverUserId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800504
Nicolas Prevot051f3b72016-05-18 18:44:00 +0100505 ObserverCall(ObserverNode node, IContentObserver observer, boolean selfChange, int observerUserId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800506 mNode = node;
507 mObserver = observer;
Jeff Brown86de0592012-01-23 13:01:18 -0800508 mSelfChange = selfChange;
Nicolas Prevot051f3b72016-05-18 18:44:00 +0100509 mObserverUserId = observerUserId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800510 }
511 }
512
Jeff Sharkeya04c7a72016-03-18 12:20:36 -0600513 @Override
Makoto Onukie183a402018-08-29 11:46:41 -0700514 public void requestSync(Account account, String authority, Bundle extras,
515 String callingPackage) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -0600516 Bundle.setDefusable(extras, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800517 ContentResolver.validateSyncExtrasBundle(extras);
Dianne Hackbornf02b60a2012-08-16 10:48:27 -0700518 int userId = UserHandle.getCallingUserId();
Makoto Onukie183a402018-08-29 11:46:41 -0700519 final int callingUid = Binder.getCallingUid();
520 final int callingPid = Binder.getCallingPid();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800521
Makoto Onukie183a402018-08-29 11:46:41 -0700522 validateExtras(callingUid, extras);
523 final int syncExemption = getSyncExemptionAndCleanUpExtrasForCaller(callingUid, extras);
Makoto Onuki61283ec2018-01-31 17:22:36 -0800524
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800525 // 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();
Fred Quintanaac9385e2009-06-22 18:00:59 -0700530 if (syncManager != null) {
Makoto Onukie183a402018-08-29 11:46:41 -0700531 syncManager.scheduleSync(account, userId, callingUid, authority, extras,
Makoto Onuki61283ec2018-01-31 17:22:36 -0800532 SyncStorageEngine.AuthorityInfo.UNDEFINED,
Makoto Onukie183a402018-08-29 11:46:41 -0700533 syncExemption, callingUid, callingPid, callingPackage);
Fred Quintanaac9385e2009-06-22 18:00:59 -0700534 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800535 } finally {
536 restoreCallingIdentity(identityToken);
537 }
538 }
539
540 /**
Matthew Williamsfa774182013-06-18 15:44:11 -0700541 * 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.
Matthew Williams632515b2013-10-10 15:51:00 -0700547 * @param request The request object. Validation of this object is done by its builder.
Matthew Williamsfa774182013-06-18 15:44:11 -0700548 */
Jeff Sharkeya04c7a72016-03-18 12:20:36 -0600549 @Override
Makoto Onukie183a402018-08-29 11:46:41 -0700550 public void sync(SyncRequest request, String callingPackage) {
551 syncAsUser(request, UserHandle.getCallingUserId(), callingPackage);
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +0100552 }
553
Shreyas Basarge3b840e32016-06-14 15:32:02 +0100554 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
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +0100564 /**
565 * If the user id supplied is different to the calling user, the caller must hold the
566 * INTERACT_ACROSS_USERS_FULL permission.
567 */
Jeff Sharkeya04c7a72016-03-18 12:20:36 -0600568 @Override
Makoto Onukie183a402018-08-29 11:46:41 -0700569 public void syncAsUser(SyncRequest request, int userId, String callingPackage) {
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +0100570 enforceCrossUserPermission(userId, "no permission to request sync as user: " + userId);
Makoto Onukie183a402018-08-29 11:46:41 -0700571 final int callingUid = Binder.getCallingUid();
572 final int callingPid = Binder.getCallingPid();
Makoto Onuki61283ec2018-01-31 17:22:36 -0800573
574 final Bundle extras = request.getBundle();
575
Makoto Onukie183a402018-08-29 11:46:41 -0700576 validateExtras(callingUid, extras);
577 final int syncExemption = getSyncExemptionAndCleanUpExtrasForCaller(callingUid, extras);
Makoto Onuki61283ec2018-01-31 17:22:36 -0800578
Matthew Williamsfa774182013-06-18 15:44:11 -0700579 // 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();
Matthew Williamsd08d6682013-10-14 10:39:41 -0700584 if (syncManager == null) {
585 return;
586 }
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700587 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;
Matthew Williams5a9decd2014-06-04 09:25:11 -0700594 info = new SyncStorageEngine.EndPoint(
595 request.getAccount(), request.getProvider(), userId);
Shreyas Basarge3b840e32016-06-14 15:32:02 +0100596
597 runAtTime = clampPeriod(runAtTime);
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700598 // Schedule periodic sync.
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000599 getSyncManager().updateOrAddPeriodicSync(info, runAtTime,
600 flextime, extras);
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700601 } else {
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700602 syncManager.scheduleSync(
Makoto Onukie183a402018-08-29 11:46:41 -0700603 request.getAccount(), userId, callingUid, request.getProvider(), extras,
Makoto Onuki61283ec2018-01-31 17:22:36 -0800604 SyncStorageEngine.AuthorityInfo.UNDEFINED,
Makoto Onukie183a402018-08-29 11:46:41 -0700605 syncExemption, callingUid, callingPid, callingPackage);
Matthew Williamsfa774182013-06-18 15:44:11 -0700606 }
607 } finally {
608 restoreCallingIdentity(identityToken);
609 }
610 }
611
612 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800613 * Clear all scheduled sync operations that match the uri and cancel the active sync
Fred Quintanaac9385e2009-06-22 18:00:59 -0700614 * if they match the authority and account, if they are present.
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700615 *
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.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800620 */
Matthew Williamsfa774182013-06-18 15:44:11 -0700621 @Override
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700622 public void cancelSync(Account account, String authority, ComponentName cname) {
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +0100623 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,
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000641 int userId) {
Matthew Williams632515b2013-10-10 15:51:00 -0700642 if (authority != null && authority.length() == 0) {
643 throw new IllegalArgumentException("Authority must be non-empty");
644 }
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +0100645 enforceCrossUserPermission(userId,
646 "no permission to modify the sync settings for user " + userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800647 // 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();
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000650 if (cname != null) {
651 Slog.e(TAG, "cname not null.");
652 return;
653 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800654 try {
655 SyncManager syncManager = getSyncManager();
656 if (syncManager != null) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700657 SyncStorageEngine.EndPoint info;
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000658 info = new SyncStorageEngine.EndPoint(account, authority, userId);
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700659 syncManager.clearScheduledSyncOperations(info);
Makoto Onukia9dca242017-06-21 17:06:49 -0700660 syncManager.cancelActiveSync(info, null /* all syncs for this adapter */, "API");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800661 }
662 } finally {
663 restoreCallingIdentity(identityToken);
664 }
665 }
666
Jeff Sharkeya04c7a72016-03-18 12:20:36 -0600667 @Override
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700668 public void cancelRequest(SyncRequest request) {
669 SyncManager syncManager = getSyncManager();
670 if (syncManager == null) return;
671 int userId = UserHandle.getCallingUserId();
Makoto Onukidd4b14f2017-08-17 14:03:48 -0700672 final int callingUid = Binder.getCallingUid();
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700673
Makoto Onukid51101c2017-12-11 14:57:43 -0800674 if (request.isPeriodic()) {
675 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
676 "no permission to write the sync settings");
677 }
678
Makoto Onuki61283ec2018-01-31 17:22:36 -0800679 Bundle extras = new Bundle(request.getBundle());
680 validateExtras(callingUid, extras);
681
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700682 long identityToken = clearCallingIdentity();
683 try {
684 SyncStorageEngine.EndPoint info;
Makoto Onuki61283ec2018-01-31 17:22:36 -0800685
Matthew Williams5a9decd2014-06-04 09:25:11 -0700686 Account account = request.getAccount();
687 String provider = request.getProvider();
688 info = new SyncStorageEngine.EndPoint(account, provider, userId);
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700689 if (request.isPeriodic()) {
690 // Remove periodic sync.
Makoto Onukidd4b14f2017-08-17 14:03:48 -0700691 getSyncManager().removePeriodicSync(info, extras,
692 "cancelRequest() by uid=" + callingUid);
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700693 }
694 // Cancel active syncs and clear pending syncs from the queue.
695 syncManager.cancelScheduledSyncOperation(info, extras);
Makoto Onukia9dca242017-06-21 17:06:49 -0700696 syncManager.cancelActiveSync(info, extras, "API");
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700697 } finally {
698 restoreCallingIdentity(identityToken);
699 }
700 }
701
Fred Quintanaac9385e2009-06-22 18:00:59 -0700702 /**
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 */
Matthew Williamsfa774182013-06-18 15:44:11 -0700706 @Override
Fred Quintanaac9385e2009-06-22 18:00:59 -0700707 public SyncAdapterType[] getSyncAdapterTypes() {
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +0100708 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);
Fred Quintanaac9385e2009-06-22 18:00:59 -0700723 // 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.
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700725 final long identityToken = clearCallingIdentity();
Fred Quintanaac9385e2009-06-22 18:00:59 -0700726 try {
727 SyncManager syncManager = getSyncManager();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700728 return syncManager.getSyncAdapterTypes(userId);
Fred Quintanaac9385e2009-06-22 18:00:59 -0700729 } finally {
730 restoreCallingIdentity(identityToken);
731 }
732 }
Costin Manolacheb7520982009-09-02 18:03:05 -0700733
Matthew Williamsfa774182013-06-18 15:44:11 -0700734 @Override
Amith Yamasani37a40c22015-06-17 13:25:42 -0700735 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
Fred Quintanaac9385e2009-06-22 18:00:59 -0700750 public boolean getSyncAutomatically(Account account, String providerName) {
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +0100751 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);
Dianne Hackborn231cc602009-04-27 17:10:36 -0700762 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
763 "no permission to read the sync settings");
Amith Yamasani04e0d262012-02-14 11:50:53 -0800764
Dianne Hackborn231cc602009-04-27 17:10:36 -0700765 long identityToken = clearCallingIdentity();
766 try {
767 SyncManager syncManager = getSyncManager();
768 if (syncManager != null) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700769 return syncManager.getSyncStorageEngine()
770 .getSyncAutomatically(account, userId, providerName);
Dianne Hackborn231cc602009-04-27 17:10:36 -0700771 }
772 } finally {
773 restoreCallingIdentity(identityToken);
774 }
775 return false;
776 }
777
Matthew Williamsfa774182013-06-18 15:44:11 -0700778 @Override
Fred Quintanaac9385e2009-06-22 18:00:59 -0700779 public void setSyncAutomatically(Account account, String providerName, boolean sync) {
Alexandra Gherghinacb228072014-07-01 15:14:11 +0100780 setSyncAutomaticallyAsUser(account, providerName, sync, UserHandle.getCallingUserId());
781 }
782
783 @Override
784 public void setSyncAutomaticallyAsUser(Account account, String providerName, boolean sync,
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000785 int userId) {
Matthew Williams632515b2013-10-10 15:51:00 -0700786 if (TextUtils.isEmpty(providerName)) {
787 throw new IllegalArgumentException("Authority must be non-empty");
788 }
Dianne Hackborn231cc602009-04-27 17:10:36 -0700789 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
790 "no permission to write the sync settings");
Alexandra Gherghinacb228072014-07-01 15:14:11 +0100791 enforceCrossUserPermission(userId,
792 "no permission to modify the sync settings for user " + userId);
Makoto Onuki75ad2492018-03-28 14:42:42 -0700793 final int callingUid = Binder.getCallingUid();
Makoto Onukie183a402018-08-29 11:46:41 -0700794 final int callingPid = Binder.getCallingPid();
Makoto Onuki75ad2492018-03-28 14:42:42 -0700795 final int syncExemptionFlag = getSyncExemptionForCaller(callingUid);
Amith Yamasani04e0d262012-02-14 11:50:53 -0800796
Dianne Hackborn231cc602009-04-27 17:10:36 -0700797 long identityToken = clearCallingIdentity();
798 try {
799 SyncManager syncManager = getSyncManager();
800 if (syncManager != null) {
Alexandra Gherghinacb228072014-07-01 15:14:11 +0100801 syncManager.getSyncStorageEngine().setSyncAutomatically(account, userId,
Makoto Onukie183a402018-08-29 11:46:41 -0700802 providerName, sync, syncExemptionFlag, callingUid, callingPid);
Dianne Hackborn231cc602009-04-27 17:10:36 -0700803 }
804 } finally {
805 restoreCallingIdentity(identityToken);
806 }
807 }
808
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000809 /** Old API. Schedule periodic sync with default flexMillis time. */
Matthew Williamsfa774182013-06-18 15:44:11 -0700810 @Override
Fred Quintanac5d1c6d2010-01-27 12:17:49 -0800811 public void addPeriodicSync(Account account, String authority, Bundle extras,
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000812 long pollFrequency) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -0600813 Bundle.setDefusable(extras, true);
Matthew Williams632515b2013-10-10 15:51:00 -0700814 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 }
Fred Quintanac5d1c6d2010-01-27 12:17:49 -0800820 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
821 "no permission to write the sync settings");
Amith Yamasani04e0d262012-02-14 11:50:53 -0800822
Makoto Onuki61283ec2018-01-31 17:22:36 -0800823 validateExtras(Binder.getCallingUid(), extras);
824
Matthew Williams632515b2013-10-10 15:51:00 -0700825 int userId = UserHandle.getCallingUserId();
Shreyas Basarge3b840e32016-06-14 15:32:02 +0100826
827 pollFrequency = clampPeriod(pollFrequency);
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700828 long defaultFlex = SyncStorageEngine.calculateDefaultFlexTime(pollFrequency);
Jeff Sharkey60094592013-03-21 18:14:24 -0700829
Fred Quintanac5d1c6d2010-01-27 12:17:49 -0800830 long identityToken = clearCallingIdentity();
831 try {
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700832 SyncStorageEngine.EndPoint info =
833 new SyncStorageEngine.EndPoint(account, authority, userId);
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000834 getSyncManager().updateOrAddPeriodicSync(info, pollFrequency,
835 defaultFlex, extras);
Fred Quintanac5d1c6d2010-01-27 12:17:49 -0800836 } finally {
837 restoreCallingIdentity(identityToken);
838 }
839 }
840
Jeff Sharkeya04c7a72016-03-18 12:20:36 -0600841 @Override
Fred Quintanac5d1c6d2010-01-27 12:17:49 -0800842 public void removePeriodicSync(Account account, String authority, Bundle extras) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -0600843 Bundle.setDefusable(extras, true);
Matthew Williams632515b2013-10-10 15:51:00 -0700844 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 }
Fred Quintanac5d1c6d2010-01-27 12:17:49 -0800850 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
851 "no permission to write the sync settings");
Amith Yamasani04e0d262012-02-14 11:50:53 -0800852
Makoto Onuki61283ec2018-01-31 17:22:36 -0800853 validateExtras(Binder.getCallingUid(), extras);
854
Makoto Onukidd4b14f2017-08-17 14:03:48 -0700855 final int callingUid = Binder.getCallingUid();
856
Matthew Williams632515b2013-10-10 15:51:00 -0700857 int userId = UserHandle.getCallingUserId();
Fred Quintanac5d1c6d2010-01-27 12:17:49 -0800858 long identityToken = clearCallingIdentity();
859 try {
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000860 getSyncManager()
861 .removePeriodicSync(
862 new SyncStorageEngine.EndPoint(account, authority, userId),
Makoto Onukidd4b14f2017-08-17 14:03:48 -0700863 extras, "removePeriodicSync() by uid=" + callingUid);
Fred Quintanac5d1c6d2010-01-27 12:17:49 -0800864 } finally {
865 restoreCallingIdentity(identityToken);
866 }
867 }
868
Jeff Sharkeya04c7a72016-03-18 12:20:36 -0600869 @Override
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700870 public List<PeriodicSync> getPeriodicSyncs(Account account, String providerName,
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000871 ComponentName cname) {
Matthew Williams632515b2013-10-10 15:51:00 -0700872 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 }
Fred Quintanac5d1c6d2010-01-27 12:17:49 -0800878 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
879 "no permission to read the sync settings");
Amith Yamasani04e0d262012-02-14 11:50:53 -0800880
Matthew Williams632515b2013-10-10 15:51:00 -0700881 int userId = UserHandle.getCallingUserId();
Fred Quintanac5d1c6d2010-01-27 12:17:49 -0800882 long identityToken = clearCallingIdentity();
883 try {
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000884 return getSyncManager().getPeriodicSyncs(
Matthew Williams5a9decd2014-06-04 09:25:11 -0700885 new SyncStorageEngine.EndPoint(account, providerName, userId));
Fred Quintanac5d1c6d2010-01-27 12:17:49 -0800886 } finally {
887 restoreCallingIdentity(identityToken);
888 }
889 }
890
Jeff Sharkeya04c7a72016-03-18 12:20:36 -0600891 @Override
Fred Quintana5e787c42009-08-16 23:13:53 -0700892 public int getIsSyncable(Account account, String providerName) {
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +0100893 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 */
Jeff Sharkeya04c7a72016-03-18 12:20:36 -0600900 @Override
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +0100901 public int getIsSyncableAsUser(Account account, String providerName, int userId) {
902 enforceCrossUserPermission(userId,
903 "no permission to read the sync settings for user " + userId);
Fred Quintana5e787c42009-08-16 23:13:53 -0700904 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
905 "no permission to read the sync settings");
Amith Yamasani04e0d262012-02-14 11:50:53 -0800906
Fred Quintana5e787c42009-08-16 23:13:53 -0700907 long identityToken = clearCallingIdentity();
908 try {
909 SyncManager syncManager = getSyncManager();
910 if (syncManager != null) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700911 return syncManager.computeSyncable(
Svet Ganov96b9c752016-10-17 19:29:58 -0700912 account, userId, providerName, false);
Fred Quintana5e787c42009-08-16 23:13:53 -0700913 }
914 } finally {
915 restoreCallingIdentity(identityToken);
916 }
917 return -1;
918 }
919
Jeff Sharkeya04c7a72016-03-18 12:20:36 -0600920 @Override
Fred Quintana5e787c42009-08-16 23:13:53 -0700921 public void setIsSyncable(Account account, String providerName, int syncable) {
Ruslan Tkhakokhov19513032019-02-05 11:06:21 +0000922 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) {
Matthew Williams632515b2013-10-10 15:51:00 -0700931 if (TextUtils.isEmpty(providerName)) {
932 throw new IllegalArgumentException("Authority must not be empty");
933 }
Ruslan Tkhakokhov19513032019-02-05 11:06:21 +0000934 enforceCrossUserPermission(userId,
935 "no permission to set the sync settings for user " + userId);
Fred Quintana5e787c42009-08-16 23:13:53 -0700936 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
937 "no permission to write the sync settings");
Amith Yamasani04e0d262012-02-14 11:50:53 -0800938
Svet Ganov96b9c752016-10-17 19:29:58 -0700939 syncable = normalizeSyncable(syncable);
Makoto Onukid4764302018-03-30 17:32:57 -0700940 final int callingUid = Binder.getCallingUid();
Makoto Onukie183a402018-08-29 11:46:41 -0700941 final int callingPid = Binder.getCallingPid();
Svet Ganov96b9c752016-10-17 19:29:58 -0700942
Fred Quintana5e787c42009-08-16 23:13:53 -0700943 long identityToken = clearCallingIdentity();
944 try {
945 SyncManager syncManager = getSyncManager();
946 if (syncManager != null) {
947 syncManager.getSyncStorageEngine().setIsSyncable(
Makoto Onukie183a402018-08-29 11:46:41 -0700948 account, userId, providerName, syncable, callingUid, callingPid);
Fred Quintana5e787c42009-08-16 23:13:53 -0700949 }
950 } finally {
951 restoreCallingIdentity(identityToken);
952 }
953 }
954
Matthew Williamsfa774182013-06-18 15:44:11 -0700955 @Override
Fred Quintanaac9385e2009-06-22 18:00:59 -0700956 public boolean getMasterSyncAutomatically() {
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +0100957 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);
Dianne Hackborn231cc602009-04-27 17:10:36 -0700968 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
969 "no permission to read the sync settings");
Amith Yamasani04e0d262012-02-14 11:50:53 -0800970
Dianne Hackborn231cc602009-04-27 17:10:36 -0700971 long identityToken = clearCallingIdentity();
972 try {
973 SyncManager syncManager = getSyncManager();
974 if (syncManager != null) {
Amith Yamasani04e0d262012-02-14 11:50:53 -0800975 return syncManager.getSyncStorageEngine().getMasterSyncAutomatically(userId);
Dianne Hackborn231cc602009-04-27 17:10:36 -0700976 }
977 } finally {
978 restoreCallingIdentity(identityToken);
979 }
980 return false;
981 }
Costin Manolacheb7520982009-09-02 18:03:05 -0700982
Matthew Williamsfa774182013-06-18 15:44:11 -0700983 @Override
Fred Quintanaac9385e2009-06-22 18:00:59 -0700984 public void setMasterSyncAutomatically(boolean flag) {
Alexandra Gherghina0e9ac202014-07-15 23:11:48 +0100985 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);
Dianne Hackborn231cc602009-04-27 17:10:36 -0700992 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
993 "no permission to write the sync settings");
Amith Yamasani04e0d262012-02-14 11:50:53 -0800994
Makoto Onuki75ad2492018-03-28 14:42:42 -0700995 final int callingUid = Binder.getCallingUid();
Makoto Onukie183a402018-08-29 11:46:41 -0700996 final int callingPid = Binder.getCallingPid();
Makoto Onuki75ad2492018-03-28 14:42:42 -0700997
Dianne Hackborn231cc602009-04-27 17:10:36 -0700998 long identityToken = clearCallingIdentity();
999 try {
1000 SyncManager syncManager = getSyncManager();
1001 if (syncManager != null) {
Makoto Onuki75ad2492018-03-28 14:42:42 -07001002 syncManager.getSyncStorageEngine().setMasterSyncAutomatically(flag, userId,
Makoto Onukie183a402018-08-29 11:46:41 -07001003 getSyncExemptionForCaller(callingUid), callingUid, callingPid);
Dianne Hackborn231cc602009-04-27 17:10:36 -07001004 }
1005 } finally {
1006 restoreCallingIdentity(identityToken);
1007 }
1008 }
1009
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001010 @Override
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001011 public boolean isSyncActive(Account account, String authority, ComponentName cname) {
Dianne Hackborn231cc602009-04-27 17:10:36 -07001012 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
1013 "no permission to read the sync stats");
Dianne Hackbornf02b60a2012-08-16 10:48:27 -07001014 int userId = UserHandle.getCallingUserId();
Dianne Hackborn231cc602009-04-27 17:10:36 -07001015 long identityToken = clearCallingIdentity();
1016 try {
1017 SyncManager syncManager = getSyncManager();
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001018 if (syncManager == null) {
1019 return false;
1020 }
Matthew Williams5a9decd2014-06-04 09:25:11 -07001021 return syncManager.getSyncStorageEngine().isSyncActive(
1022 new SyncStorageEngine.EndPoint(account, authority, userId));
Dianne Hackborn231cc602009-04-27 17:10:36 -07001023 } finally {
1024 restoreCallingIdentity(identityToken);
1025 }
Dianne Hackborn231cc602009-04-27 17:10:36 -07001026 }
Costin Manolacheb7520982009-09-02 18:03:05 -07001027
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001028 @Override
Fred Quintanac6a69552010-09-27 17:05:04 -07001029 public List<SyncInfo> getCurrentSyncs() {
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +01001030 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 */
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001037 @Override
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +01001038 public List<SyncInfo> getCurrentSyncsAsUser(int userId) {
1039 enforceCrossUserPermission(userId,
1040 "no permission to read the sync settings for user " + userId);
Dianne Hackborn231cc602009-04-27 17:10:36 -07001041 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
1042 "no permission to read the sync stats");
Amith Yamasani04e0d262012-02-14 11:50:53 -08001043
Matthew Williamsf39549e2016-01-19 23:04:04 +00001044 final boolean canAccessAccounts =
1045 mContext.checkCallingOrSelfPermission(Manifest.permission.GET_ACCOUNTS)
1046 == PackageManager.PERMISSION_GRANTED;
Dianne Hackborn231cc602009-04-27 17:10:36 -07001047 long identityToken = clearCallingIdentity();
1048 try {
Matthew Williamsf39549e2016-01-19 23:04:04 +00001049 return getSyncManager().getSyncStorageEngine()
1050 .getCurrentSyncsCopy(userId, canAccessAccounts);
Dianne Hackborn231cc602009-04-27 17:10:36 -07001051 } finally {
1052 restoreCallingIdentity(identityToken);
1053 }
Dianne Hackborn231cc602009-04-27 17:10:36 -07001054 }
Costin Manolacheb7520982009-09-02 18:03:05 -07001055
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001056 @Override
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001057 public SyncStatusInfo getSyncStatus(Account account, String authority, ComponentName cname) {
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +01001058 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 */
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001065 @Override
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +01001066 public SyncStatusInfo getSyncStatusAsUser(Account account, String authority,
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001067 ComponentName cname, int userId) {
Matthew Williams632515b2013-10-10 15:51:00 -07001068 if (TextUtils.isEmpty(authority)) {
1069 throw new IllegalArgumentException("Authority must not be empty");
1070 }
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +01001071
1072 enforceCrossUserPermission(userId,
1073 "no permission to read the sync stats for user " + userId);
Dianne Hackborn231cc602009-04-27 17:10:36 -07001074 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
1075 "no permission to read the sync stats");
Amith Yamasani04e0d262012-02-14 11:50:53 -08001076
Dianne Hackborn231cc602009-04-27 17:10:36 -07001077 long identityToken = clearCallingIdentity();
1078 try {
1079 SyncManager syncManager = getSyncManager();
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001080 if (syncManager == null) {
1081 return null;
Dianne Hackborn231cc602009-04-27 17:10:36 -07001082 }
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001083 SyncStorageEngine.EndPoint info;
Matthew Williams5a9decd2014-06-04 09:25:11 -07001084 if (!(account == null || authority == null)) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001085 info = new SyncStorageEngine.EndPoint(account, authority, userId);
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001086 } else {
1087 throw new IllegalArgumentException("Must call sync status with valid authority");
1088 }
1089 return syncManager.getSyncStorageEngine().getStatusByAuthority(info);
Dianne Hackborn231cc602009-04-27 17:10:36 -07001090 } finally {
1091 restoreCallingIdentity(identityToken);
1092 }
Dianne Hackborn231cc602009-04-27 17:10:36 -07001093 }
Costin Manolacheb7520982009-09-02 18:03:05 -07001094
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001095 @Override
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001096 public boolean isSyncPending(Account account, String authority, ComponentName cname) {
Alexandra Gherghinacb228072014-07-01 15:14:11 +01001097 return isSyncPendingAsUser(account, authority, cname, UserHandle.getCallingUserId());
1098 }
1099
1100 @Override
1101 public boolean isSyncPendingAsUser(Account account, String authority, ComponentName cname,
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001102 int userId) {
Dianne Hackborn231cc602009-04-27 17:10:36 -07001103 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
1104 "no permission to read the sync stats");
Alexandra Gherghinacb228072014-07-01 15:14:11 +01001105 enforceCrossUserPermission(userId,
1106 "no permission to retrieve the sync settings for user " + userId);
Torne (Richard Coles)4890b082013-08-12 10:26:57 +00001107 long identityToken = clearCallingIdentity();
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001108 SyncManager syncManager = getSyncManager();
1109 if (syncManager == null) return false;
1110
Dianne Hackborn231cc602009-04-27 17:10:36 -07001111 try {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001112 SyncStorageEngine.EndPoint info;
Matthew Williams5a9decd2014-06-04 09:25:11 -07001113 if (!(account == null || authority == null)) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001114 info = new SyncStorageEngine.EndPoint(account, authority, userId);
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001115 } else {
1116 throw new IllegalArgumentException("Invalid authority specified");
Dianne Hackborn231cc602009-04-27 17:10:36 -07001117 }
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001118 return syncManager.getSyncStorageEngine().isSyncPending(info);
Dianne Hackborn231cc602009-04-27 17:10:36 -07001119 } finally {
1120 restoreCallingIdentity(identityToken);
1121 }
Dianne Hackborn231cc602009-04-27 17:10:36 -07001122 }
Costin Manolacheb7520982009-09-02 18:03:05 -07001123
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001124 @Override
Dianne Hackborn231cc602009-04-27 17:10:36 -07001125 public void addStatusChangeListener(int mask, ISyncStatusObserver callback) {
Varun Shahfe009ec2019-04-29 14:26:45 -07001126 final int callingUid = Binder.getCallingUid();
Dianne Hackborn231cc602009-04-27 17:10:36 -07001127 long identityToken = clearCallingIdentity();
1128 try {
1129 SyncManager syncManager = getSyncManager();
Fred Quintana1b487ec2010-02-26 10:57:55 -08001130 if (syncManager != null && callback != null) {
Varun Shahfe009ec2019-04-29 14:26:45 -07001131 syncManager.getSyncStorageEngine().addStatusChangeListener(
1132 mask, UserHandle.getUserId(callingUid), callback);
Dianne Hackborn231cc602009-04-27 17:10:36 -07001133 }
1134 } finally {
1135 restoreCallingIdentity(identityToken);
1136 }
1137 }
Costin Manolacheb7520982009-09-02 18:03:05 -07001138
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001139 @Override
Dianne Hackborn231cc602009-04-27 17:10:36 -07001140 public void removeStatusChangeListener(ISyncStatusObserver callback) {
1141 long identityToken = clearCallingIdentity();
1142 try {
1143 SyncManager syncManager = getSyncManager();
Fred Quintana1b487ec2010-02-26 10:57:55 -08001144 if (syncManager != null && callback != null) {
Fred Quintanaac9385e2009-06-22 18:00:59 -07001145 syncManager.getSyncStorageEngine().removeStatusChangeListener(callback);
Dianne Hackborn231cc602009-04-27 17:10:36 -07001146 }
1147 } finally {
1148 restoreCallingIdentity(identityToken);
1149 }
1150 }
Costin Manolacheb7520982009-09-02 18:03:05 -07001151
Jeff Sharkey87314082016-03-11 17:25:11 -07001152 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
Andreas Gampea36dc622018-02-05 17:19:22 -08001158 @GuardedBy("mCache")
Jeff Sharkey87314082016-03-11 17:25:11 -07001159 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
Andreas Gampea36dc622018-02-05 17:19:22 -08001174 @GuardedBy("mCache")
Jeff Sharkey87314082016-03-11 17:25:11 -07001175 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();) {
Jeff Sharkey7732e1e2016-03-30 17:14:23 -06001184 final Pair<String, Uri> key = packageCache.keyAt(i);
1185 if (key.second != null && key.second.toString().startsWith(uri.toString())) {
Dianne Hackborn141f11c2016-04-05 15:46:12 -07001186 if (DEBUG) Slog.d(TAG, "Invalidating cache for key " + key);
Jeff Sharkey87314082016-03-11 17:25:11 -07001187 packageCache.removeAt(i);
1188 } else {
1189 i++;
1190 }
1191 }
1192 } else {
Dianne Hackborn141f11c2016-04-05 15:46:12 -07001193 if (DEBUG) Slog.d(TAG, "Invalidating cache for package " + providerPackageName);
Jeff Sharkey87314082016-03-11 17:25:11 -07001194 packageCache.clear();
1195 }
1196 }
1197
1198 @Override
Ivan Chianga46ade32019-02-25 11:30:34 +08001199 @RequiresPermission(android.Manifest.permission.CACHE_CONTENT)
Jeff Sharkey87314082016-03-11 17:25:11 -07001200 public void putCache(String packageName, Uri key, Bundle value, int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001201 Bundle.setDefusable(value, true);
Jeff Sharkey87314082016-03-11 17:25:11 -07001202 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
Ivan Chianga46ade32019-02-25 11:30:34 +08001222 @RequiresPermission(android.Manifest.permission.CACHE_CONTENT)
Jeff Sharkey87314082016-03-11 17:25:11 -07001223 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
Sudheer Shankab4e2ddd2017-02-03 15:15:57 -08001239 private int handleIncomingUser(Uri uri, int pid, int uid, int modeFlags, boolean allowNonFull,
1240 int userId) {
Jeff Sharkey923e0b82016-11-16 17:22:48 -07001241 if (userId == UserHandle.USER_CURRENT) {
1242 userId = ActivityManager.getCurrentUser();
1243 }
1244
1245 if (userId == UserHandle.USER_ALL) {
1246 mContext.enforceCallingOrSelfPermission(
Jeff Sharkey0cdf1f32018-09-27 11:24:42 -06001247 Manifest.permission.INTERACT_ACROSS_USERS_FULL, "No access to " + uri);
Jeff Sharkey923e0b82016-11-16 17:22:48 -07001248 } 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) {
Sudheer Shankab4e2ddd2017-02-03 15:15:57 -08001253 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;
Jeff Sharkey0cdf1f32018-09-27 11:24:42 -06001268 throw new SecurityException("No access to " + uri + ": neither user " + uid
Sudheer Shankab4e2ddd2017-02-03 15:15:57 -08001269 + " nor current process has " + permissions);
1270 }
Jeff Sharkey923e0b82016-11-16 17:22:48 -07001271 }
1272 }
1273
1274 return userId;
1275 }
1276
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001277 /**
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +01001278 * 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
Svet Ganov96b9c752016-10-17 19:29:58 -07001292 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
Makoto Onuki61283ec2018-01-31 17:22:36 -08001301 private void validateExtras(int callingUid, Bundle extras) {
Makoto Onuki75ad2492018-03-28 14:42:42 -07001302 if (extras.containsKey(ContentResolver.SYNC_VIRTUAL_EXTRAS_EXEMPTION_FLAG)) {
Makoto Onuki61283ec2018-01-31 17:22:36 -08001303 switch (callingUid) {
1304 case Process.ROOT_UID:
1305 case Process.SHELL_UID:
1306 case Process.SYSTEM_UID:
1307 break; // Okay
1308 default:
Makoto Onuki37a3e862018-04-30 14:50:43 -07001309 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);
Makoto Onuki61283ec2018-01-31 17:22:36 -08001312 }
1313 }
1314 }
1315
Makoto Onuki75ad2492018-03-28 14:42:42 -07001316 @SyncExemption
1317 private int getSyncExemptionForCaller(int callingUid) {
1318 return getSyncExemptionAndCleanUpExtrasForCaller(callingUid, null);
Makoto Onuki61283ec2018-01-31 17:22:36 -08001319 }
1320
Makoto Onuki75ad2492018-03-28 14:42:42 -07001321 @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 }
Makoto Onuki61283ec2018-01-31 17:22:36 -08001332 }
1333 final ActivityManagerInternal ami =
1334 LocalServices.getService(ActivityManagerInternal.class);
Makoto Onuki35e9a392018-08-27 15:59:20 -07001335 if (ami == null) {
1336 return ContentResolver.SYNC_EXEMPTION_NONE;
1337 }
1338 final int procState = ami.getUidProcessState(callingUid);
1339 final boolean isUidActive = ami.isUidActive(callingUid);
Makoto Onuki75ad2492018-03-28 14:42:42 -07001340
Amith Yamasanif235d0b2019-03-20 22:49:43 -07001341 // 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) {
Makoto Onukid5f25d22018-05-22 16:02:17 -07001344 return ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP;
Makoto Onuki61283ec2018-01-31 17:22:36 -08001345 }
Makoto Onuki35e9a392018-08-27 15:59:20 -07001346 if (procState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND || isUidActive) {
Makoto Onukid5f25d22018-05-22 16:02:17 -07001347 return ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET;
Makoto Onuki75ad2492018-03-28 14:42:42 -07001348 }
1349 return ContentResolver.SYNC_EXEMPTION_NONE;
Makoto Onuki61283ec2018-01-31 17:22:36 -08001350 }
1351
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +01001352 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001353 * 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 {
Fred Quintana002ffad52010-03-02 11:18:16 -08001359 public final IContentObserver observer;
Dianne Hackborn1b64e0d2011-07-17 15:23:59 -07001360 public final int uid;
1361 public final int pid;
Christopher Tate16aa9732012-09-17 16:23:44 -07001362 public final boolean notifyForDescendants;
1363 private final int userHandle;
Fred Quintana002ffad52010-03-02 11:18:16 -08001364 private final Object observersLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001365
Dianne Hackborn1b64e0d2011-07-17 15:23:59 -07001366 public ObserverEntry(IContentObserver o, boolean n, Object observersLock,
Makoto Onukiad1291e2019-05-30 11:36:55 -07001367 int _uid, int _pid, int _userHandle, Uri uri) {
Fred Quintana002ffad52010-03-02 11:18:16 -08001368 this.observersLock = observersLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001369 observer = o;
Dianne Hackborn1b64e0d2011-07-17 15:23:59 -07001370 uid = _uid;
1371 pid = _pid;
Christopher Tate16aa9732012-09-17 16:23:44 -07001372 userHandle = _userHandle;
1373 notifyForDescendants = n;
Makoto Onukiad1291e2019-05-30 11:36:55 -07001374
1375 final int entries = sObserverDeathDispatcher.linkToDeath(observer, this);
1376 if (entries == -1) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001377 binderDied();
Makoto Onukiad1291e2019-05-30 11:36:55 -07001378 } 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 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001399 }
Makoto Onukiad1291e2019-05-30 11:36:55 -07001400
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001401 }
1402
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001403 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001404 public void binderDied() {
Fred Quintana002ffad52010-03-02 11:18:16 -08001405 synchronized (observersLock) {
1406 removeObserverLocked(observer);
1407 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001408 }
Dianne Hackborn1b64e0d2011-07-17 15:23:59 -07001409
1410 public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001411 String name, String prefix, SparseIntArray pidCounts) {
Dianne Hackborn1b64e0d2011-07-17 15:23:59 -07001412 pidCounts.put(pid, pidCounts.get(pid)+1);
1413 pw.print(prefix); pw.print(name); pw.print(": pid=");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001414 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)));
Dianne Hackborn1b64e0d2011-07-17 15:23:59 -07001419 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001420 }
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
Dianne Hackborn1b64e0d2011-07-17 15:23:59 -07001434 public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001435 String name, String prefix, int[] counts, SparseIntArray pidCounts) {
Dianne Hackborn1b64e0d2011-07-17 15:23:59 -07001436 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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001465 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
Christopher Tate16aa9732012-09-17 16:23:44 -07001484 // Invariant: userHandle is either a hard user number or is USER_ALL
Fred Quintana002ffad52010-03-02 11:18:16 -08001485 public void addObserverLocked(Uri uri, IContentObserver observer,
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001486 boolean notifyForDescendants, Object observersLock,
1487 int uid, int pid, int userHandle) {
Christopher Tate16aa9732012-09-17 16:23:44 -07001488 addObserverLocked(uri, 0, observer, notifyForDescendants, observersLock,
1489 uid, pid, userHandle);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001490 }
1491
Fred Quintana002ffad52010-03-02 11:18:16 -08001492 private void addObserverLocked(Uri uri, int index, IContentObserver observer,
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001493 boolean notifyForDescendants, Object observersLock,
1494 int uid, int pid, int userHandle) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001495 // If this is the leaf node add the observer
1496 if (index == countUriSegments(uri)) {
Christopher Tate16aa9732012-09-17 16:23:44 -07001497 mObservers.add(new ObserverEntry(observer, notifyForDescendants, observersLock,
Makoto Onukiad1291e2019-05-30 11:36:55 -07001498 uid, pid, userHandle, uri));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001499 return;
1500 }
1501
1502 // Look to see if the proper child already exists
1503 String segment = getUriSegment(uri, index);
Anthony Newnamf5126642010-03-22 17:29:06 -05001504 if (segment == null) {
1505 throw new IllegalArgumentException("Invalid Uri (" + uri + ") used for observer");
1506 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001507 int N = mChildren.size();
1508 for (int i = 0; i < N; i++) {
1509 ObserverNode node = mChildren.get(i);
1510 if (node.mName.equals(segment)) {
Christopher Tate16aa9732012-09-17 16:23:44 -07001511 node.addObserverLocked(uri, index + 1, observer, notifyForDescendants,
1512 observersLock, uid, pid, userHandle);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001513 return;
1514 }
1515 }
1516
1517 // No child found, create one
1518 ObserverNode node = new ObserverNode(segment);
1519 mChildren.add(node);
Christopher Tate16aa9732012-09-17 16:23:44 -07001520 node.addObserverLocked(uri, index + 1, observer, notifyForDescendants,
1521 observersLock, uid, pid, userHandle);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001522 }
1523
Fred Quintana002ffad52010-03-02 11:18:16 -08001524 public boolean removeObserverLocked(IContentObserver observer) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001525 int size = mChildren.size();
1526 for (int i = 0; i < size; i++) {
Fred Quintana002ffad52010-03-02 11:18:16 -08001527 boolean empty = mChildren.get(i).removeObserverLocked(observer);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001528 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.
Makoto Onukiad1291e2019-05-30 11:36:55 -07001542 sObserverDeathDispatcher.unlinkToDeath(observer, entry);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001543 break;
1544 }
1545 }
1546
1547 if (mChildren.size() == 0 && mObservers.size() == 0) {
1548 return true;
1549 }
1550 return false;
1551 }
1552
Fred Quintana002ffad52010-03-02 11:18:16 -08001553 private void collectMyObserversLocked(boolean leaf, IContentObserver observer,
Dianne Hackborn141f11c2016-04-05 15:46:12 -07001554 boolean observerWantsSelfNotifications, int flags,
1555 int targetUserHandle, ArrayList<ObserverCall> calls) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001556 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
Christopher Tate16aa9732012-09-17 16:23:44 -07001561 // Don't notify the observer if it sent the notification and isn't interested
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001562 // in self notifications
Jeff Brown86de0592012-01-23 13:01:18 -08001563 boolean selfChange = (entry.observer.asBinder() == observerBinder);
1564 if (selfChange && !observerWantsSelfNotifications) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001565 continue;
1566 }
1567
Christopher Tate16aa9732012-09-17 16:23:44 -07001568 // 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
Dianne Hackborn141f11c2016-04-05 15:46:12 -07001573 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 }
Christopher Tate16aa9732012-09-17 16:23:44 -07001591 }
Dianne Hackborn141f11c2016-04-05 15:46:12 -07001592 if (DEBUG) Slog.d(TAG, "Reporting to " + entry.observer + ": leaf=" + leaf
1593 + " flags=" + Integer.toHexString(flags)
1594 + " desc=" + entry.notifyForDescendants);
Nicolas Prevot051f3b72016-05-18 18:44:00 +01001595 calls.add(new ObserverCall(this, entry.observer, selfChange,
1596 UserHandle.getUserId(entry.uid)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001597 }
1598 }
1599 }
1600
Christopher Tate16aa9732012-09-17 16:23:44 -07001601 /**
1602 * targetUserHandle is either a hard user handle or is USER_ALL
1603 */
Fred Quintana002ffad52010-03-02 11:18:16 -08001604 public void collectObserversLocked(Uri uri, int index, IContentObserver observer,
Dianne Hackborn141f11c2016-04-05 15:46:12 -07001605 boolean observerWantsSelfNotifications, int flags,
1606 int targetUserHandle, ArrayList<ObserverCall> calls) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001607 String segment = null;
1608 int segmentCount = countUriSegments(uri);
1609 if (index >= segmentCount) {
1610 // This is the leaf node, notify all observers
Dianne Hackborn141f11c2016-04-05 15:46:12 -07001611 if (DEBUG) Slog.d(TAG, "Collecting leaf observers @ #" + index + ", node " + mName);
Christopher Tate16aa9732012-09-17 16:23:44 -07001612 collectMyObserversLocked(true, observer, observerWantsSelfNotifications,
Dianne Hackborn141f11c2016-04-05 15:46:12 -07001613 flags, targetUserHandle, calls);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001614 } else if (index < segmentCount){
1615 segment = getUriSegment(uri, index);
Dianne Hackborn141f11c2016-04-05 15:46:12 -07001616 if (DEBUG) Slog.d(TAG, "Collecting non-leaf observers @ #" + index + " / "
1617 + segment);
Christopher Tate16aa9732012-09-17 16:23:44 -07001618 // Notify any observers at this level who are interested in descendants
1619 collectMyObserversLocked(false, observer, observerWantsSelfNotifications,
Dianne Hackborn141f11c2016-04-05 15:46:12 -07001620 flags, targetUserHandle, calls);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001621 }
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,
Dianne Hackborn141f11c2016-04-05 15:46:12 -07001628 node.collectObserversLocked(uri, index + 1, observer,
1629 observerWantsSelfNotifications, flags, targetUserHandle, calls);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001630 if (segment != null) {
1631 break;
1632 }
1633 }
1634 }
1635 }
1636 }
Makoto Onuki94986212018-04-11 16:24:46 -07001637
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
Makoto Onukiee93ad22018-10-18 16:24:13 -07001660 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
Makoto Onuki94986212018-04-11 16:24:46 -07001669 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 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001674}