blob: ad74ff88e80faeaa5608ca2cffa4a834c715cf05 [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;
Christopher Tate16aa9732012-09-17 16:23:44 -070022import android.app.ActivityManager;
Jeff Sharkey923e0b82016-11-16 17:22:48 -070023import android.app.ActivityManagerInternal;
Jeff Sharkey87314082016-03-11 17:25:11 -070024import android.app.AppOpsManager;
Shreyas Basarge3b840e32016-06-14 15:32:02 +010025import android.app.job.JobInfo;
Jeff Sharkey87314082016-03-11 17:25:11 -070026import android.content.BroadcastReceiver;
Matthew Williamsfa774182013-06-18 15:44:11 -070027import android.content.ComponentName;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080028import android.content.ContentResolver;
29import android.content.Context;
30import android.content.IContentService;
Jeff Sharkey7732e1e2016-03-30 17:14:23 -060031import android.content.ISyncStatusObserver;
Benjamin Franzadea1912015-06-19 16:03:38 +010032import android.content.Intent;
Jeff Sharkey87314082016-03-11 17:25:11 -070033import android.content.IntentFilter;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080034import android.content.PeriodicSync;
35import android.content.SyncAdapterType;
36import android.content.SyncInfo;
Matthew Williamsfa774182013-06-18 15:44:11 -070037import android.content.SyncRequest;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080038import android.content.SyncStatusInfo;
Benjamin Franzadea1912015-06-19 16:03:38 +010039import android.content.pm.PackageManager;
Svetoslav0010b702015-06-30 18:05:26 -070040import android.content.pm.PackageManagerInternal;
Jeff Sharkey87314082016-03-11 17:25:11 -070041import android.content.pm.ProviderInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042import android.database.IContentObserver;
43import android.database.sqlite.SQLiteException;
44import android.net.Uri;
Dianne Hackborn1b64e0d2011-07-17 15:23:59 -070045import android.os.Binder;
Jeff Sharkey912e80d2017-02-24 11:00:55 -070046import android.os.Build;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047import android.os.Bundle;
Jeff Sharkeya3ebfec2016-04-04 08:58:04 -060048import android.os.FactoryTest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049import android.os.IBinder;
Dianne Hackborn231cc602009-04-27 17:10:36 -070050import android.os.Parcel;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import android.os.RemoteException;
Dan Morrille4d9a012013-03-28 18:10:43 -070052import android.os.SystemProperties;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070053import android.os.UserHandle;
Matthew Williams632515b2013-10-10 15:51:00 -070054import android.text.TextUtils;
Jeff Sharkey87314082016-03-11 17:25:11 -070055import android.util.ArrayMap;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056import android.util.Log;
Jeff Sharkey87314082016-03-11 17:25:11 -070057import android.util.Pair;
Jeff Sharkey60094592013-03-21 18:14:24 -070058import android.util.Slog;
Jeff Sharkey87314082016-03-11 17:25:11 -070059import android.util.SparseArray;
Dianne Hackborn1b64e0d2011-07-17 15:23:59 -070060import android.util.SparseIntArray;
Jeff Sharkey87314082016-03-11 17:25:11 -070061
62import com.android.internal.annotations.GuardedBy;
Makoto Onukia9dca242017-06-21 17:06:49 -070063import com.android.internal.util.ArrayUtils;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060064import com.android.internal.util.DumpUtils;
Jeff Sharkey87314082016-03-11 17:25:11 -070065import com.android.internal.util.IndentingPrintWriter;
Svetoslav0010b702015-06-30 18:05:26 -070066import com.android.server.LocalServices;
Jeff Sharkeya3ebfec2016-04-04 08:58:04 -060067import com.android.server.SystemService;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080068
69import java.io.FileDescriptor;
70import java.io.PrintWriter;
71import java.util.ArrayList;
Dianne Hackborn1b64e0d2011-07-17 15:23:59 -070072import java.util.Collections;
73import java.util.Comparator;
Fred Quintanac5d1c6d2010-01-27 12:17:49 -080074import java.util.List;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080075
76/**
77 * {@hide}
78 */
Dianne Hackborn231cc602009-04-27 17:10:36 -070079public final class ContentService extends IContentService.Stub {
Dianne Hackborn141f11c2016-04-05 15:46:12 -070080 static final String TAG = "ContentService";
81 static final boolean DEBUG = false;
Jeff Sharkey87314082016-03-11 17:25:11 -070082
Jeff Sharkeya3ebfec2016-04-04 08:58:04 -060083 public static class Lifecycle extends SystemService {
Jeff Sharkey1cab76a2016-04-12 18:23:31 -060084 private ContentService mService;
Jeff Sharkeya3ebfec2016-04-04 08:58:04 -060085
86 public Lifecycle(Context context) {
87 super(context);
88 }
89
90 @Override
91 public void onStart() {
92 final boolean factoryTest = (FactoryTest
93 .getMode() == FactoryTest.FACTORY_TEST_LOW_LEVEL);
Jeff Sharkey1cab76a2016-04-12 18:23:31 -060094 mService = new ContentService(getContext(), factoryTest);
95 publishBinderService(ContentResolver.CONTENT_SERVICE_NAME, mService);
96 }
97
98 @Override
99 public void onBootPhase(int phase) {
100 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
101 mService.systemReady();
102 }
Jeff Sharkeya3ebfec2016-04-04 08:58:04 -0600103 }
104
Makoto Onukife224e02017-06-29 14:11:14 -0700105
106 @Override
107 public void onStartUser(int userHandle) {
108 mService.onStartUser(userHandle);
109 }
110
111 @Override
112 public void onUnlockUser(int userHandle) {
113 mService.onUnlockUser(userHandle);
114 }
115
116 @Override
117 public void onStopUser(int userHandle) {
118 mService.onStopUser(userHandle);
119 }
120
Jeff Sharkeya3ebfec2016-04-04 08:58:04 -0600121 @Override
122 public void onCleanupUser(int userHandle) {
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600123 synchronized (mService.mCache) {
124 mService.mCache.remove(userHandle);
Jeff Sharkeya3ebfec2016-04-04 08:58:04 -0600125 }
126 }
127 }
128
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129 private Context mContext;
130 private boolean mFactoryTest;
Jeff Sharkey87314082016-03-11 17:25:11 -0700131
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800132 private final ObserverNode mRootNode = new ObserverNode("");
Jeff Sharkey87314082016-03-11 17:25:11 -0700133
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800134 private SyncManager mSyncManager = null;
135 private final Object mSyncManagerLock = new Object();
136
Jeff Sharkey87314082016-03-11 17:25:11 -0700137 /**
138 * Map from userId to providerPackageName to [clientPackageName, uri] to
139 * value. This structure is carefully optimized to keep invalidation logic
140 * as cheap as possible.
141 */
142 @GuardedBy("mCache")
143 private final SparseArray<ArrayMap<String, ArrayMap<Pair<String, Uri>, Bundle>>>
144 mCache = new SparseArray<>();
145
146 private BroadcastReceiver mCacheReceiver = new BroadcastReceiver() {
147 @Override
148 public void onReceive(Context context, Intent intent) {
Jeff Sharkeya3ebfec2016-04-04 08:58:04 -0600149 synchronized (mCache) {
150 if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
151 mCache.clear();
152 } else {
153 final Uri data = intent.getData();
154 if (data != null) {
155 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
156 UserHandle.USER_NULL);
157 final String packageName = data.getSchemeSpecificPart();
158 invalidateCacheLocked(userId, packageName, null);
159 }
160 }
Jeff Sharkey87314082016-03-11 17:25:11 -0700161 }
162 }
163 };
164
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800165 private SyncManager getSyncManager() {
Dan Morrille4d9a012013-03-28 18:10:43 -0700166 if (SystemProperties.getBoolean("config.disable_network", false)) {
167 return null;
168 }
169
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800170 synchronized(mSyncManagerLock) {
171 try {
172 // Try to create the SyncManager, return null if it fails (e.g. the disk is full).
173 if (mSyncManager == null) mSyncManager = new SyncManager(mContext, mFactoryTest);
174 } catch (SQLiteException e) {
175 Log.e(TAG, "Can't create SyncManager", e);
176 }
177 return mSyncManager;
178 }
179 }
180
Makoto Onukife224e02017-06-29 14:11:14 -0700181 void onStartUser(int userHandle) {
182 if (mSyncManager != null) mSyncManager.onStartUser(userHandle);
183 }
184
185 void onUnlockUser(int userHandle) {
186 if (mSyncManager != null) mSyncManager.onUnlockUser(userHandle);
187 }
188
189 void onStopUser(int userHandle) {
190 if (mSyncManager != null) mSyncManager.onStopUser(userHandle);
191 }
192
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800193 @Override
Jeff Sharkey87314082016-03-11 17:25:11 -0700194 protected synchronized void dump(FileDescriptor fd, PrintWriter pw_, String[] args) {
Jeff Sharkey6df866a2017-03-31 14:08:23 -0600195 if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw_)) return;
Jeff Sharkey87314082016-03-11 17:25:11 -0700196 final IndentingPrintWriter pw = new IndentingPrintWriter(pw_, " ");
197
Makoto Onukia9dca242017-06-21 17:06:49 -0700198 final boolean dumpAll = ArrayUtils.contains(args, "-a");
199
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800200 // This makes it so that future permission checks will be in the context of this
201 // process rather than the caller's process. We will restore this before returning.
Jeff Sharkey87314082016-03-11 17:25:11 -0700202 final long identityToken = clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800203 try {
204 if (mSyncManager == null) {
205 pw.println("No SyncManager created! (Disk full?)");
206 } else {
Makoto Onukia9dca242017-06-21 17:06:49 -0700207 mSyncManager.dump(fd, pw, dumpAll);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800208 }
Dianne Hackborn1b64e0d2011-07-17 15:23:59 -0700209 pw.println();
210 pw.println("Observer tree:");
211 synchronized (mRootNode) {
212 int[] counts = new int[2];
213 final SparseIntArray pidCounts = new SparseIntArray();
214 mRootNode.dumpLocked(fd, pw, args, "", " ", counts, pidCounts);
215 pw.println();
216 ArrayList<Integer> sorted = new ArrayList<Integer>();
217 for (int i=0; i<pidCounts.size(); i++) {
218 sorted.add(pidCounts.keyAt(i));
219 }
220 Collections.sort(sorted, new Comparator<Integer>() {
221 @Override
222 public int compare(Integer lhs, Integer rhs) {
223 int lc = pidCounts.get(lhs);
224 int rc = pidCounts.get(rhs);
225 if (lc < rc) {
226 return 1;
227 } else if (lc > rc) {
228 return -1;
229 }
230 return 0;
231 }
232
233 });
234 for (int i=0; i<sorted.size(); i++) {
235 int pid = sorted.get(i);
236 pw.print(" pid "); pw.print(pid); pw.print(": ");
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000237 pw.print(pidCounts.get(pid)); pw.println(" observers");
Dianne Hackborn1b64e0d2011-07-17 15:23:59 -0700238 }
239 pw.println();
240 pw.print(" Total number of nodes: "); pw.println(counts[0]);
241 pw.print(" Total number of observers: "); pw.println(counts[1]);
242 }
Jeff Sharkey87314082016-03-11 17:25:11 -0700243
244 synchronized (mCache) {
245 pw.println();
246 pw.println("Cached content:");
247 pw.increaseIndent();
248 for (int i = 0; i < mCache.size(); i++) {
249 pw.println("User " + mCache.keyAt(i) + ":");
250 pw.increaseIndent();
251 pw.println(mCache.valueAt(i));
252 pw.decreaseIndent();
253 }
254 pw.decreaseIndent();
255 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800256 } finally {
257 restoreCallingIdentity(identityToken);
258 }
259 }
260
Dianne Hackborn231cc602009-04-27 17:10:36 -0700261 @Override
262 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
263 throws RemoteException {
264 try {
265 return super.onTransact(code, data, reply, flags);
266 } catch (RuntimeException e) {
267 // The content service only throws security exceptions, so let's
268 // log all others.
269 if (!(e instanceof SecurityException)) {
Dianne Hackborn164371f2013-10-01 19:10:13 -0700270 Slog.wtf(TAG, "Content Service Crash", e);
Dianne Hackborn231cc602009-04-27 17:10:36 -0700271 }
272 throw e;
273 }
274 }
275
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800276 /*package*/ ContentService(Context context, boolean factoryTest) {
277 mContext = context;
278 mFactoryTest = factoryTest;
Svetoslav0010b702015-06-30 18:05:26 -0700279
280 // Let the package manager query for the sync adapters for a given authority
Svet Ganov52153f42015-08-11 08:59:12 -0700281 // as we grant default permissions to sync adapters for specific authorities.
Svetoslav0010b702015-06-30 18:05:26 -0700282 PackageManagerInternal packageManagerInternal = LocalServices.getService(
283 PackageManagerInternal.class);
284 packageManagerInternal.setSyncAdapterPackagesprovider(
285 new PackageManagerInternal.SyncAdapterPackagesProvider() {
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000286 @Override
287 public String[] getPackages(String authority, int userId) {
288 return getSyncAdapterPackagesForAuthorityAsUser(authority, userId);
289 }
290 });
Jeff Sharkey87314082016-03-11 17:25:11 -0700291
292 final IntentFilter packageFilter = new IntentFilter();
293 packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
294 packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
295 packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
296 packageFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED);
297 packageFilter.addDataScheme("package");
298 mContext.registerReceiverAsUser(mCacheReceiver, UserHandle.ALL,
299 packageFilter, null, null);
Jeff Sharkeya3ebfec2016-04-04 08:58:04 -0600300
301 final IntentFilter localeFilter = new IntentFilter();
302 localeFilter.addAction(Intent.ACTION_LOCALE_CHANGED);
303 mContext.registerReceiverAsUser(mCacheReceiver, UserHandle.ALL,
304 localeFilter, null, null);
Kenny Root26ff6622012-07-30 12:58:03 -0700305 }
306
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600307 void systemReady() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800308 getSyncManager();
309 }
310
Christopher Tate16aa9732012-09-17 16:23:44 -0700311 /**
312 * Register a content observer tied to a specific user's view of the provider.
313 * @param userHandle the user whose view of the provider is to be observed. May be
314 * the calling user without requiring any permission, otherwise the caller needs to
Benjamin Franzadea1912015-06-19 16:03:38 +0100315 * hold the INTERACT_ACROSS_USERS_FULL permission or hold a read uri grant to the uri.
316 * Pseudousers USER_ALL and USER_CURRENT are properly handled; all other pseudousers
317 * are forbidden.
Christopher Tate16aa9732012-09-17 16:23:44 -0700318 */
319 @Override
320 public void registerContentObserver(Uri uri, boolean notifyForDescendants,
Jeff Sharkey912e80d2017-02-24 11:00:55 -0700321 IContentObserver observer, int userHandle, int targetSdkVersion) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800322 if (observer == null || uri == null) {
323 throw new IllegalArgumentException("You must pass a valid uri and observer");
324 }
Christopher Tate16aa9732012-09-17 16:23:44 -0700325
Benjamin Franzadea1912015-06-19 16:03:38 +0100326 final int uid = Binder.getCallingUid();
327 final int pid = Binder.getCallingPid();
Christopher Tate16aa9732012-09-17 16:23:44 -0700328
Jeff Sharkey923e0b82016-11-16 17:22:48 -0700329 userHandle = handleIncomingUser(uri, pid, uid,
Sudheer Shankab4e2ddd2017-02-03 15:15:57 -0800330 Intent.FLAG_GRANT_READ_URI_PERMISSION, true, userHandle);
Jeff Sharkey923e0b82016-11-16 17:22:48 -0700331
332 final String msg = LocalServices.getService(ActivityManagerInternal.class)
333 .checkContentProviderAccess(uri.getAuthority(), userHandle);
334 if (msg != null) {
Jeff Sharkey912e80d2017-02-24 11:00:55 -0700335 if (targetSdkVersion >= Build.VERSION_CODES.O) {
336 throw new SecurityException(msg);
337 } else {
338 if (msg.startsWith("Failed to find provider")) {
339 // Sigh, we need to quietly let apps targeting older API
340 // levels notify on non-existent providers.
341 } else {
342 Log.w(TAG, "Ignoring content changes for " + uri + " from " + uid + ": " + msg);
343 return;
344 }
345 }
Christopher Tate16aa9732012-09-17 16:23:44 -0700346 }
347
348 synchronized (mRootNode) {
349 mRootNode.addObserverLocked(uri, observer, notifyForDescendants, mRootNode,
Benjamin Franzadea1912015-06-19 16:03:38 +0100350 uid, pid, userHandle);
Christopher Tate16aa9732012-09-17 16:23:44 -0700351 if (false) Log.v(TAG, "Registered observer " + observer + " at " + uri +
352 " with notifyForDescendants " + notifyForDescendants);
353 }
354 }
355
356 public void registerContentObserver(Uri uri, boolean notifyForDescendants,
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000357 IContentObserver observer) {
Christopher Tate16aa9732012-09-17 16:23:44 -0700358 registerContentObserver(uri, notifyForDescendants, observer,
Jeff Sharkey912e80d2017-02-24 11:00:55 -0700359 UserHandle.getCallingUserId(), Build.VERSION_CODES.CUR_DEVELOPMENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800360 }
361
Jeff Sharkeya04c7a72016-03-18 12:20:36 -0600362 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800363 public void unregisterContentObserver(IContentObserver observer) {
364 if (observer == null) {
365 throw new IllegalArgumentException("You must pass a valid observer");
366 }
367 synchronized (mRootNode) {
Fred Quintana002ffad52010-03-02 11:18:16 -0800368 mRootNode.removeObserverLocked(observer);
Joe Onorato43a17652011-04-06 19:22:23 -0700369 if (false) Log.v(TAG, "Unregistered observer " + observer);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800370 }
371 }
372
Christopher Tate16aa9732012-09-17 16:23:44 -0700373 /**
374 * Notify observers of a particular user's view of the provider.
375 * @param userHandle the user whose view of the provider is to be notified. May be
376 * the calling user without requiring any permission, otherwise the caller needs to
Benjamin Franzadea1912015-06-19 16:03:38 +0100377 * hold the INTERACT_ACROSS_USERS_FULL permission or hold a write uri grant to the uri.
378 * Pseudousers USER_ALL and USER_CURRENT are properly interpreted; no other pseudousers are
379 * allowed.
Christopher Tate16aa9732012-09-17 16:23:44 -0700380 */
381 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800382 public void notifyChange(Uri uri, IContentObserver observer,
Jeff Sharkey912e80d2017-02-24 11:00:55 -0700383 boolean observerWantsSelfNotifications, int flags, int userHandle,
384 int targetSdkVersion) {
Dianne Hackborn141f11c2016-04-05 15:46:12 -0700385 if (DEBUG) Slog.d(TAG, "Notifying update of " + uri + " for user " + userHandle
386 + " from observer " + observer + ", flags " + Integer.toHexString(flags));
Amith Yamasani04e0d262012-02-14 11:50:53 -0800387
Dianne Hackborne7617772016-04-27 17:03:52 -0700388 if (uri == null) {
389 throw new NullPointerException("Uri must not be null");
390 }
391
Benjamin Franzadea1912015-06-19 16:03:38 +0100392 final int uid = Binder.getCallingUid();
393 final int pid = Binder.getCallingPid();
Christopher Tate16aa9732012-09-17 16:23:44 -0700394 final int callingUserHandle = UserHandle.getCallingUserId();
Christopher Tate16aa9732012-09-17 16:23:44 -0700395
Jeff Sharkey923e0b82016-11-16 17:22:48 -0700396 userHandle = handleIncomingUser(uri, pid, uid,
Sudheer Shankab4e2ddd2017-02-03 15:15:57 -0800397 Intent.FLAG_GRANT_WRITE_URI_PERMISSION, true, userHandle);
Jeff Sharkey923e0b82016-11-16 17:22:48 -0700398
399 final String msg = LocalServices.getService(ActivityManagerInternal.class)
400 .checkContentProviderAccess(uri.getAuthority(), userHandle);
401 if (msg != null) {
Jeff Sharkey912e80d2017-02-24 11:00:55 -0700402 if (targetSdkVersion >= Build.VERSION_CODES.O) {
403 throw new SecurityException(msg);
404 } else {
405 if (msg.startsWith("Failed to find provider")) {
406 // Sigh, we need to quietly let apps targeting older API
407 // levels notify on non-existent providers.
408 } else {
409 Log.w(TAG, "Ignoring notify for " + uri + " from " + uid + ": " + msg);
410 return;
411 }
412 }
Christopher Tate16aa9732012-09-17 16:23:44 -0700413 }
414
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800415 // This makes it so that future permission checks will be in the context of this
416 // process rather than the caller's process. We will restore this before returning.
417 long identityToken = clearCallingIdentity();
418 try {
419 ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>();
420 synchronized (mRootNode) {
Fred Quintana002ffad52010-03-02 11:18:16 -0800421 mRootNode.collectObserversLocked(uri, 0, observer, observerWantsSelfNotifications,
Dianne Hackborn141f11c2016-04-05 15:46:12 -0700422 flags, userHandle, calls);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800423 }
424 final int numCalls = calls.size();
425 for (int i=0; i<numCalls; i++) {
426 ObserverCall oc = calls.get(i);
427 try {
Svet Ganov3138a992016-06-15 16:57:32 -0700428 oc.mObserver.onChange(oc.mSelfChange, uri, userHandle);
Dianne Hackborn141f11c2016-04-05 15:46:12 -0700429 if (DEBUG) Slog.d(TAG, "Notified " + oc.mObserver + " of " + "update at "
Svet Ganov3138a992016-06-15 16:57:32 -0700430 + uri);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800431 } catch (RemoteException ex) {
432 synchronized (mRootNode) {
433 Log.w(TAG, "Found dead observer, removing");
434 IBinder binder = oc.mObserver.asBinder();
435 final ArrayList<ObserverNode.ObserverEntry> list
436 = oc.mNode.mObservers;
437 int numList = list.size();
438 for (int j=0; j<numList; j++) {
439 ObserverNode.ObserverEntry oe = list.get(j);
440 if (oe.observer.asBinder() == binder) {
441 list.remove(j);
442 j--;
443 numList--;
444 }
445 }
446 }
447 }
448 }
Dianne Hackborn141f11c2016-04-05 15:46:12 -0700449 if ((flags&ContentResolver.NOTIFY_SYNC_TO_NETWORK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800450 SyncManager syncManager = getSyncManager();
Fred Quintanaac9385e2009-06-22 18:00:59 -0700451 if (syncManager != null) {
Alon Albert57286f92012-10-09 14:21:38 -0700452 syncManager.scheduleLocalSync(null /* all accounts */, callingUserHandle, uid,
Amith Yamasani04e0d262012-02-14 11:50:53 -0800453 uri.getAuthority());
Fred Quintanaac9385e2009-06-22 18:00:59 -0700454 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800455 }
Jeff Sharkey87314082016-03-11 17:25:11 -0700456
457 synchronized (mCache) {
458 final String providerPackageName = getProviderPackageName(uri);
459 invalidateCacheLocked(userHandle, providerPackageName, uri);
460 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800461 } finally {
462 restoreCallingIdentity(identityToken);
463 }
464 }
465
Nicolas Prevot051f3b72016-05-18 18:44:00 +0100466 private int checkUriPermission(Uri uri, int pid, int uid, int modeFlags, int userHandle) {
467 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -0800468 return ActivityManager.getService().checkUriPermission(
Nicolas Prevot051f3b72016-05-18 18:44:00 +0100469 uri, pid, uid, modeFlags, userHandle, null);
470 } catch (RemoteException e) {
471 return PackageManager.PERMISSION_DENIED;
472 }
473 }
474
Christopher Tate16aa9732012-09-17 16:23:44 -0700475 public void notifyChange(Uri uri, IContentObserver observer,
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000476 boolean observerWantsSelfNotifications, boolean syncToNetwork) {
Dianne Hackborn141f11c2016-04-05 15:46:12 -0700477 notifyChange(uri, observer, observerWantsSelfNotifications,
478 syncToNetwork ? ContentResolver.NOTIFY_SYNC_TO_NETWORK : 0,
Jeff Sharkey912e80d2017-02-24 11:00:55 -0700479 UserHandle.getCallingUserId(), Build.VERSION_CODES.CUR_DEVELOPMENT);
Christopher Tate16aa9732012-09-17 16:23:44 -0700480 }
481
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800482 /**
483 * Hide this class since it is not part of api,
484 * but current unittest framework requires it to be public
485 * @hide
486 *
487 */
488 public static final class ObserverCall {
489 final ObserverNode mNode;
490 final IContentObserver mObserver;
Jeff Brown86de0592012-01-23 13:01:18 -0800491 final boolean mSelfChange;
Nicolas Prevot051f3b72016-05-18 18:44:00 +0100492 final int mObserverUserId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800493
Nicolas Prevot051f3b72016-05-18 18:44:00 +0100494 ObserverCall(ObserverNode node, IContentObserver observer, boolean selfChange, int observerUserId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800495 mNode = node;
496 mObserver = observer;
Jeff Brown86de0592012-01-23 13:01:18 -0800497 mSelfChange = selfChange;
Nicolas Prevot051f3b72016-05-18 18:44:00 +0100498 mObserverUserId = observerUserId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800499 }
500 }
501
Jeff Sharkeya04c7a72016-03-18 12:20:36 -0600502 @Override
Fred Quintanaac9385e2009-06-22 18:00:59 -0700503 public void requestSync(Account account, String authority, Bundle extras) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -0600504 Bundle.setDefusable(extras, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800505 ContentResolver.validateSyncExtrasBundle(extras);
Dianne Hackbornf02b60a2012-08-16 10:48:27 -0700506 int userId = UserHandle.getCallingUserId();
Alon Albert57286f92012-10-09 14:21:38 -0700507 int uId = Binder.getCallingUid();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800508
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800509 // This makes it so that future permission checks will be in the context of this
510 // process rather than the caller's process. We will restore this before returning.
511 long identityToken = clearCallingIdentity();
512 try {
513 SyncManager syncManager = getSyncManager();
Fred Quintanaac9385e2009-06-22 18:00:59 -0700514 if (syncManager != null) {
Matthew Williamsfa774182013-06-18 15:44:11 -0700515 syncManager.scheduleSync(account, userId, uId, authority, extras,
Svet Ganov91d37f42016-09-03 19:36:26 -0700516 SyncStorageEngine.AuthorityInfo.UNDEFINED);
Fred Quintanaac9385e2009-06-22 18:00:59 -0700517 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800518 } finally {
519 restoreCallingIdentity(identityToken);
520 }
521 }
522
523 /**
Matthew Williamsfa774182013-06-18 15:44:11 -0700524 * Request a sync with a generic {@link android.content.SyncRequest} object. This will be
525 * either:
526 * periodic OR one-off sync.
527 * and
528 * anonymous OR provider sync.
529 * Depending on the request, we enqueue to suit in the SyncManager.
Matthew Williams632515b2013-10-10 15:51:00 -0700530 * @param request The request object. Validation of this object is done by its builder.
Matthew Williamsfa774182013-06-18 15:44:11 -0700531 */
Jeff Sharkeya04c7a72016-03-18 12:20:36 -0600532 @Override
Matthew Williamsfa774182013-06-18 15:44:11 -0700533 public void sync(SyncRequest request) {
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +0100534 syncAsUser(request, UserHandle.getCallingUserId());
535 }
536
Shreyas Basarge3b840e32016-06-14 15:32:02 +0100537 private long clampPeriod(long period) {
538 long minPeriod = JobInfo.getMinPeriodMillis() / 1000;
539 if (period < minPeriod) {
540 Slog.w(TAG, "Requested poll frequency of " + period
541 + " seconds being rounded up to " + minPeriod + "s.");
542 period = minPeriod;
543 }
544 return period;
545 }
546
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +0100547 /**
548 * If the user id supplied is different to the calling user, the caller must hold the
549 * INTERACT_ACROSS_USERS_FULL permission.
550 */
Jeff Sharkeya04c7a72016-03-18 12:20:36 -0600551 @Override
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +0100552 public void syncAsUser(SyncRequest request, int userId) {
553 enforceCrossUserPermission(userId, "no permission to request sync as user: " + userId);
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700554 int callerUid = Binder.getCallingUid();
Matthew Williamsfa774182013-06-18 15:44:11 -0700555 // This makes it so that future permission checks will be in the context of this
556 // process rather than the caller's process. We will restore this before returning.
557 long identityToken = clearCallingIdentity();
558 try {
559 SyncManager syncManager = getSyncManager();
Matthew Williamsd08d6682013-10-14 10:39:41 -0700560 if (syncManager == null) {
561 return;
562 }
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700563
Matthew Williamsd08d6682013-10-14 10:39:41 -0700564 Bundle extras = request.getBundle();
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700565 long flextime = request.getSyncFlexTime();
566 long runAtTime = request.getSyncRunTime();
567 if (request.isPeriodic()) {
568 mContext.enforceCallingOrSelfPermission(
569 Manifest.permission.WRITE_SYNC_SETTINGS,
570 "no permission to write the sync settings");
571 SyncStorageEngine.EndPoint info;
Matthew Williams5a9decd2014-06-04 09:25:11 -0700572 info = new SyncStorageEngine.EndPoint(
573 request.getAccount(), request.getProvider(), userId);
Shreyas Basarge3b840e32016-06-14 15:32:02 +0100574
575 runAtTime = clampPeriod(runAtTime);
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700576 // Schedule periodic sync.
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000577 getSyncManager().updateOrAddPeriodicSync(info, runAtTime,
578 flextime, extras);
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700579 } else {
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700580 syncManager.scheduleSync(
581 request.getAccount(), userId, callerUid, request.getProvider(), extras,
Svet Ganov91d37f42016-09-03 19:36:26 -0700582 SyncStorageEngine.AuthorityInfo.UNDEFINED);
Matthew Williamsfa774182013-06-18 15:44:11 -0700583 }
584 } finally {
585 restoreCallingIdentity(identityToken);
586 }
587 }
588
589 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800590 * Clear all scheduled sync operations that match the uri and cancel the active sync
Fred Quintanaac9385e2009-06-22 18:00:59 -0700591 * if they match the authority and account, if they are present.
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700592 *
593 * @param account filter the pending and active syncs to cancel using this account, or null.
594 * @param authority filter the pending and active syncs to cancel using this authority, or
595 * null.
596 * @param cname cancel syncs running on this service, or null for provider/account.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800597 */
Matthew Williamsfa774182013-06-18 15:44:11 -0700598 @Override
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700599 public void cancelSync(Account account, String authority, ComponentName cname) {
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +0100600 cancelSyncAsUser(account, authority, cname, UserHandle.getCallingUserId());
601 }
602
603 /**
604 * Clear all scheduled sync operations that match the uri and cancel the active sync
605 * if they match the authority and account, if they are present.
606 *
607 * <p> If the user id supplied is different to the calling user, the caller must hold the
608 * INTERACT_ACROSS_USERS_FULL permission.
609 *
610 * @param account filter the pending and active syncs to cancel using this account, or null.
611 * @param authority filter the pending and active syncs to cancel using this authority, or
612 * null.
613 * @param userId the user id for which to cancel sync operations.
614 * @param cname cancel syncs running on this service, or null for provider/account.
615 */
616 @Override
617 public void cancelSyncAsUser(Account account, String authority, ComponentName cname,
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000618 int userId) {
Matthew Williams632515b2013-10-10 15:51:00 -0700619 if (authority != null && authority.length() == 0) {
620 throw new IllegalArgumentException("Authority must be non-empty");
621 }
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +0100622 enforceCrossUserPermission(userId,
623 "no permission to modify the sync settings for user " + userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800624 // This makes it so that future permission checks will be in the context of this
625 // process rather than the caller's process. We will restore this before returning.
626 long identityToken = clearCallingIdentity();
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000627 if (cname != null) {
628 Slog.e(TAG, "cname not null.");
629 return;
630 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800631 try {
632 SyncManager syncManager = getSyncManager();
633 if (syncManager != null) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700634 SyncStorageEngine.EndPoint info;
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000635 info = new SyncStorageEngine.EndPoint(account, authority, userId);
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700636 syncManager.clearScheduledSyncOperations(info);
Makoto Onukia9dca242017-06-21 17:06:49 -0700637 syncManager.cancelActiveSync(info, null /* all syncs for this adapter */, "API");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800638 }
639 } finally {
640 restoreCallingIdentity(identityToken);
641 }
642 }
643
Jeff Sharkeya04c7a72016-03-18 12:20:36 -0600644 @Override
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700645 public void cancelRequest(SyncRequest request) {
646 SyncManager syncManager = getSyncManager();
647 if (syncManager == null) return;
648 int userId = UserHandle.getCallingUserId();
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700649
650 long identityToken = clearCallingIdentity();
651 try {
652 SyncStorageEngine.EndPoint info;
653 Bundle extras = new Bundle(request.getBundle());
Matthew Williams5a9decd2014-06-04 09:25:11 -0700654 Account account = request.getAccount();
655 String provider = request.getProvider();
656 info = new SyncStorageEngine.EndPoint(account, provider, userId);
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700657 if (request.isPeriodic()) {
658 // Remove periodic sync.
659 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
660 "no permission to write the sync settings");
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000661 getSyncManager().removePeriodicSync(info, extras);
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700662 }
663 // Cancel active syncs and clear pending syncs from the queue.
664 syncManager.cancelScheduledSyncOperation(info, extras);
Makoto Onukia9dca242017-06-21 17:06:49 -0700665 syncManager.cancelActiveSync(info, extras, "API");
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700666 } finally {
667 restoreCallingIdentity(identityToken);
668 }
669 }
670
Fred Quintanaac9385e2009-06-22 18:00:59 -0700671 /**
672 * Get information about the SyncAdapters that are known to the system.
673 * @return an array of SyncAdapters that have registered with the system
674 */
Matthew Williamsfa774182013-06-18 15:44:11 -0700675 @Override
Fred Quintanaac9385e2009-06-22 18:00:59 -0700676 public SyncAdapterType[] getSyncAdapterTypes() {
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +0100677 return getSyncAdapterTypesAsUser(UserHandle.getCallingUserId());
678 }
679
680 /**
681 * Get information about the SyncAdapters that are known to the system for a particular user.
682 *
683 * <p> If the user id supplied is different to the calling user, the caller must hold the
684 * INTERACT_ACROSS_USERS_FULL permission.
685 *
686 * @return an array of SyncAdapters that have registered with the system
687 */
688 @Override
689 public SyncAdapterType[] getSyncAdapterTypesAsUser(int userId) {
690 enforceCrossUserPermission(userId,
691 "no permission to read sync settings for user " + userId);
Fred Quintanaac9385e2009-06-22 18:00:59 -0700692 // This makes it so that future permission checks will be in the context of this
693 // process rather than the caller's process. We will restore this before returning.
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700694 final long identityToken = clearCallingIdentity();
Fred Quintanaac9385e2009-06-22 18:00:59 -0700695 try {
696 SyncManager syncManager = getSyncManager();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700697 return syncManager.getSyncAdapterTypes(userId);
Fred Quintanaac9385e2009-06-22 18:00:59 -0700698 } finally {
699 restoreCallingIdentity(identityToken);
700 }
701 }
Costin Manolacheb7520982009-09-02 18:03:05 -0700702
Matthew Williamsfa774182013-06-18 15:44:11 -0700703 @Override
Amith Yamasani37a40c22015-06-17 13:25:42 -0700704 public String[] getSyncAdapterPackagesForAuthorityAsUser(String authority, int userId) {
705 enforceCrossUserPermission(userId,
706 "no permission to read sync settings for user " + userId);
707 // This makes it so that future permission checks will be in the context of this
708 // process rather than the caller's process. We will restore this before returning.
709 final long identityToken = clearCallingIdentity();
710 try {
711 SyncManager syncManager = getSyncManager();
712 return syncManager.getSyncAdapterPackagesForAuthorityAsUser(authority, userId);
713 } finally {
714 restoreCallingIdentity(identityToken);
715 }
716 }
717
718 @Override
Fred Quintanaac9385e2009-06-22 18:00:59 -0700719 public boolean getSyncAutomatically(Account account, String providerName) {
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +0100720 return getSyncAutomaticallyAsUser(account, providerName, UserHandle.getCallingUserId());
721 }
722
723 /**
724 * If the user id supplied is different to the calling user, the caller must hold the
725 * INTERACT_ACROSS_USERS_FULL permission.
726 */
727 @Override
728 public boolean getSyncAutomaticallyAsUser(Account account, String providerName, int userId) {
729 enforceCrossUserPermission(userId,
730 "no permission to read the sync settings for user " + userId);
Dianne Hackborn231cc602009-04-27 17:10:36 -0700731 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
732 "no permission to read the sync settings");
Amith Yamasani04e0d262012-02-14 11:50:53 -0800733
Dianne Hackborn231cc602009-04-27 17:10:36 -0700734 long identityToken = clearCallingIdentity();
735 try {
736 SyncManager syncManager = getSyncManager();
737 if (syncManager != null) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700738 return syncManager.getSyncStorageEngine()
739 .getSyncAutomatically(account, userId, providerName);
Dianne Hackborn231cc602009-04-27 17:10:36 -0700740 }
741 } finally {
742 restoreCallingIdentity(identityToken);
743 }
744 return false;
745 }
746
Matthew Williamsfa774182013-06-18 15:44:11 -0700747 @Override
Fred Quintanaac9385e2009-06-22 18:00:59 -0700748 public void setSyncAutomatically(Account account, String providerName, boolean sync) {
Alexandra Gherghinacb228072014-07-01 15:14:11 +0100749 setSyncAutomaticallyAsUser(account, providerName, sync, UserHandle.getCallingUserId());
750 }
751
752 @Override
753 public void setSyncAutomaticallyAsUser(Account account, String providerName, boolean sync,
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000754 int userId) {
Matthew Williams632515b2013-10-10 15:51:00 -0700755 if (TextUtils.isEmpty(providerName)) {
756 throw new IllegalArgumentException("Authority must be non-empty");
757 }
Dianne Hackborn231cc602009-04-27 17:10:36 -0700758 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
759 "no permission to write the sync settings");
Alexandra Gherghinacb228072014-07-01 15:14:11 +0100760 enforceCrossUserPermission(userId,
761 "no permission to modify the sync settings for user " + userId);
Amith Yamasani04e0d262012-02-14 11:50:53 -0800762
Dianne Hackborn231cc602009-04-27 17:10:36 -0700763 long identityToken = clearCallingIdentity();
764 try {
765 SyncManager syncManager = getSyncManager();
766 if (syncManager != null) {
Alexandra Gherghinacb228072014-07-01 15:14:11 +0100767 syncManager.getSyncStorageEngine().setSyncAutomatically(account, userId,
768 providerName, sync);
Dianne Hackborn231cc602009-04-27 17:10:36 -0700769 }
770 } finally {
771 restoreCallingIdentity(identityToken);
772 }
773 }
774
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000775 /** Old API. Schedule periodic sync with default flexMillis time. */
Matthew Williamsfa774182013-06-18 15:44:11 -0700776 @Override
Fred Quintanac5d1c6d2010-01-27 12:17:49 -0800777 public void addPeriodicSync(Account account, String authority, Bundle extras,
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000778 long pollFrequency) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -0600779 Bundle.setDefusable(extras, true);
Matthew Williams632515b2013-10-10 15:51:00 -0700780 if (account == null) {
781 throw new IllegalArgumentException("Account must not be null");
782 }
783 if (TextUtils.isEmpty(authority)) {
784 throw new IllegalArgumentException("Authority must not be empty.");
785 }
Fred Quintanac5d1c6d2010-01-27 12:17:49 -0800786 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
787 "no permission to write the sync settings");
Amith Yamasani04e0d262012-02-14 11:50:53 -0800788
Matthew Williams632515b2013-10-10 15:51:00 -0700789 int userId = UserHandle.getCallingUserId();
Shreyas Basarge3b840e32016-06-14 15:32:02 +0100790
791 pollFrequency = clampPeriod(pollFrequency);
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700792 long defaultFlex = SyncStorageEngine.calculateDefaultFlexTime(pollFrequency);
Jeff Sharkey60094592013-03-21 18:14:24 -0700793
Fred Quintanac5d1c6d2010-01-27 12:17:49 -0800794 long identityToken = clearCallingIdentity();
795 try {
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700796 SyncStorageEngine.EndPoint info =
797 new SyncStorageEngine.EndPoint(account, authority, userId);
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000798 getSyncManager().updateOrAddPeriodicSync(info, pollFrequency,
799 defaultFlex, extras);
Fred Quintanac5d1c6d2010-01-27 12:17:49 -0800800 } finally {
801 restoreCallingIdentity(identityToken);
802 }
803 }
804
Jeff Sharkeya04c7a72016-03-18 12:20:36 -0600805 @Override
Fred Quintanac5d1c6d2010-01-27 12:17:49 -0800806 public void removePeriodicSync(Account account, String authority, Bundle extras) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -0600807 Bundle.setDefusable(extras, true);
Matthew Williams632515b2013-10-10 15:51:00 -0700808 if (account == null) {
809 throw new IllegalArgumentException("Account must not be null");
810 }
811 if (TextUtils.isEmpty(authority)) {
812 throw new IllegalArgumentException("Authority must not be empty");
813 }
Fred Quintanac5d1c6d2010-01-27 12:17:49 -0800814 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
815 "no permission to write the sync settings");
Amith Yamasani04e0d262012-02-14 11:50:53 -0800816
Matthew Williams632515b2013-10-10 15:51:00 -0700817 int userId = UserHandle.getCallingUserId();
Fred Quintanac5d1c6d2010-01-27 12:17:49 -0800818 long identityToken = clearCallingIdentity();
819 try {
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000820 getSyncManager()
821 .removePeriodicSync(
822 new SyncStorageEngine.EndPoint(account, authority, userId),
823 extras);
Fred Quintanac5d1c6d2010-01-27 12:17:49 -0800824 } finally {
825 restoreCallingIdentity(identityToken);
826 }
827 }
828
Jeff Sharkeya04c7a72016-03-18 12:20:36 -0600829 @Override
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700830 public List<PeriodicSync> getPeriodicSyncs(Account account, String providerName,
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000831 ComponentName cname) {
Matthew Williams632515b2013-10-10 15:51:00 -0700832 if (account == null) {
833 throw new IllegalArgumentException("Account must not be null");
834 }
835 if (TextUtils.isEmpty(providerName)) {
836 throw new IllegalArgumentException("Authority must not be empty");
837 }
Fred Quintanac5d1c6d2010-01-27 12:17:49 -0800838 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
839 "no permission to read the sync settings");
Amith Yamasani04e0d262012-02-14 11:50:53 -0800840
Matthew Williams632515b2013-10-10 15:51:00 -0700841 int userId = UserHandle.getCallingUserId();
Fred Quintanac5d1c6d2010-01-27 12:17:49 -0800842 long identityToken = clearCallingIdentity();
843 try {
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000844 return getSyncManager().getPeriodicSyncs(
Matthew Williams5a9decd2014-06-04 09:25:11 -0700845 new SyncStorageEngine.EndPoint(account, providerName, userId));
Fred Quintanac5d1c6d2010-01-27 12:17:49 -0800846 } finally {
847 restoreCallingIdentity(identityToken);
848 }
849 }
850
Jeff Sharkeya04c7a72016-03-18 12:20:36 -0600851 @Override
Fred Quintana5e787c42009-08-16 23:13:53 -0700852 public int getIsSyncable(Account account, String providerName) {
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +0100853 return getIsSyncableAsUser(account, providerName, UserHandle.getCallingUserId());
854 }
855
856 /**
857 * If the user id supplied is different to the calling user, the caller must hold the
858 * INTERACT_ACROSS_USERS_FULL permission.
859 */
Jeff Sharkeya04c7a72016-03-18 12:20:36 -0600860 @Override
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +0100861 public int getIsSyncableAsUser(Account account, String providerName, int userId) {
862 enforceCrossUserPermission(userId,
863 "no permission to read the sync settings for user " + userId);
Fred Quintana5e787c42009-08-16 23:13:53 -0700864 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
865 "no permission to read the sync settings");
Amith Yamasani04e0d262012-02-14 11:50:53 -0800866
Fred Quintana5e787c42009-08-16 23:13:53 -0700867 long identityToken = clearCallingIdentity();
868 try {
869 SyncManager syncManager = getSyncManager();
870 if (syncManager != null) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700871 return syncManager.computeSyncable(
Svet Ganov96b9c752016-10-17 19:29:58 -0700872 account, userId, providerName, false);
Fred Quintana5e787c42009-08-16 23:13:53 -0700873 }
874 } finally {
875 restoreCallingIdentity(identityToken);
876 }
877 return -1;
878 }
879
Jeff Sharkeya04c7a72016-03-18 12:20:36 -0600880 @Override
Fred Quintana5e787c42009-08-16 23:13:53 -0700881 public void setIsSyncable(Account account, String providerName, int syncable) {
Matthew Williams632515b2013-10-10 15:51:00 -0700882 if (TextUtils.isEmpty(providerName)) {
883 throw new IllegalArgumentException("Authority must not be empty");
884 }
Fred Quintana5e787c42009-08-16 23:13:53 -0700885 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
886 "no permission to write the sync settings");
Amith Yamasani04e0d262012-02-14 11:50:53 -0800887
Svet Ganov96b9c752016-10-17 19:29:58 -0700888 syncable = normalizeSyncable(syncable);
889
Matthew Williams632515b2013-10-10 15:51:00 -0700890 int userId = UserHandle.getCallingUserId();
Fred Quintana5e787c42009-08-16 23:13:53 -0700891 long identityToken = clearCallingIdentity();
892 try {
893 SyncManager syncManager = getSyncManager();
894 if (syncManager != null) {
895 syncManager.getSyncStorageEngine().setIsSyncable(
Amith Yamasani04e0d262012-02-14 11:50:53 -0800896 account, userId, providerName, syncable);
Fred Quintana5e787c42009-08-16 23:13:53 -0700897 }
898 } finally {
899 restoreCallingIdentity(identityToken);
900 }
901 }
902
Matthew Williamsfa774182013-06-18 15:44:11 -0700903 @Override
Fred Quintanaac9385e2009-06-22 18:00:59 -0700904 public boolean getMasterSyncAutomatically() {
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +0100905 return getMasterSyncAutomaticallyAsUser(UserHandle.getCallingUserId());
906 }
907
908 /**
909 * If the user id supplied is different to the calling user, the caller must hold the
910 * INTERACT_ACROSS_USERS_FULL permission.
911 */
912 @Override
913 public boolean getMasterSyncAutomaticallyAsUser(int userId) {
914 enforceCrossUserPermission(userId,
915 "no permission to read the sync settings for user " + userId);
Dianne Hackborn231cc602009-04-27 17:10:36 -0700916 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
917 "no permission to read the sync settings");
Amith Yamasani04e0d262012-02-14 11:50:53 -0800918
Dianne Hackborn231cc602009-04-27 17:10:36 -0700919 long identityToken = clearCallingIdentity();
920 try {
921 SyncManager syncManager = getSyncManager();
922 if (syncManager != null) {
Amith Yamasani04e0d262012-02-14 11:50:53 -0800923 return syncManager.getSyncStorageEngine().getMasterSyncAutomatically(userId);
Dianne Hackborn231cc602009-04-27 17:10:36 -0700924 }
925 } finally {
926 restoreCallingIdentity(identityToken);
927 }
928 return false;
929 }
Costin Manolacheb7520982009-09-02 18:03:05 -0700930
Matthew Williamsfa774182013-06-18 15:44:11 -0700931 @Override
Fred Quintanaac9385e2009-06-22 18:00:59 -0700932 public void setMasterSyncAutomatically(boolean flag) {
Alexandra Gherghina0e9ac202014-07-15 23:11:48 +0100933 setMasterSyncAutomaticallyAsUser(flag, UserHandle.getCallingUserId());
934 }
935
936 @Override
937 public void setMasterSyncAutomaticallyAsUser(boolean flag, int userId) {
938 enforceCrossUserPermission(userId,
939 "no permission to set the sync status for user " + userId);
Dianne Hackborn231cc602009-04-27 17:10:36 -0700940 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
941 "no permission to write the sync settings");
Amith Yamasani04e0d262012-02-14 11:50:53 -0800942
Dianne Hackborn231cc602009-04-27 17:10:36 -0700943 long identityToken = clearCallingIdentity();
944 try {
945 SyncManager syncManager = getSyncManager();
946 if (syncManager != null) {
Amith Yamasani04e0d262012-02-14 11:50:53 -0800947 syncManager.getSyncStorageEngine().setMasterSyncAutomatically(flag, userId);
Dianne Hackborn231cc602009-04-27 17:10:36 -0700948 }
949 } finally {
950 restoreCallingIdentity(identityToken);
951 }
952 }
953
Jeff Sharkeya04c7a72016-03-18 12:20:36 -0600954 @Override
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700955 public boolean isSyncActive(Account account, String authority, ComponentName cname) {
Dianne Hackborn231cc602009-04-27 17:10:36 -0700956 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
957 "no permission to read the sync stats");
Dianne Hackbornf02b60a2012-08-16 10:48:27 -0700958 int userId = UserHandle.getCallingUserId();
Dianne Hackborn231cc602009-04-27 17:10:36 -0700959 long identityToken = clearCallingIdentity();
960 try {
961 SyncManager syncManager = getSyncManager();
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700962 if (syncManager == null) {
963 return false;
964 }
Matthew Williams5a9decd2014-06-04 09:25:11 -0700965 return syncManager.getSyncStorageEngine().isSyncActive(
966 new SyncStorageEngine.EndPoint(account, authority, userId));
Dianne Hackborn231cc602009-04-27 17:10:36 -0700967 } finally {
968 restoreCallingIdentity(identityToken);
969 }
Dianne Hackborn231cc602009-04-27 17:10:36 -0700970 }
Costin Manolacheb7520982009-09-02 18:03:05 -0700971
Jeff Sharkeya04c7a72016-03-18 12:20:36 -0600972 @Override
Fred Quintanac6a69552010-09-27 17:05:04 -0700973 public List<SyncInfo> getCurrentSyncs() {
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +0100974 return getCurrentSyncsAsUser(UserHandle.getCallingUserId());
975 }
976
977 /**
978 * If the user id supplied is different to the calling user, the caller must hold the
979 * INTERACT_ACROSS_USERS_FULL permission.
980 */
Jeff Sharkeya04c7a72016-03-18 12:20:36 -0600981 @Override
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +0100982 public List<SyncInfo> getCurrentSyncsAsUser(int userId) {
983 enforceCrossUserPermission(userId,
984 "no permission to read the sync settings for user " + userId);
Dianne Hackborn231cc602009-04-27 17:10:36 -0700985 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
986 "no permission to read the sync stats");
Amith Yamasani04e0d262012-02-14 11:50:53 -0800987
Matthew Williamsf39549e2016-01-19 23:04:04 +0000988 final boolean canAccessAccounts =
989 mContext.checkCallingOrSelfPermission(Manifest.permission.GET_ACCOUNTS)
990 == PackageManager.PERMISSION_GRANTED;
Dianne Hackborn231cc602009-04-27 17:10:36 -0700991 long identityToken = clearCallingIdentity();
992 try {
Matthew Williamsf39549e2016-01-19 23:04:04 +0000993 return getSyncManager().getSyncStorageEngine()
994 .getCurrentSyncsCopy(userId, canAccessAccounts);
Dianne Hackborn231cc602009-04-27 17:10:36 -0700995 } finally {
996 restoreCallingIdentity(identityToken);
997 }
Dianne Hackborn231cc602009-04-27 17:10:36 -0700998 }
Costin Manolacheb7520982009-09-02 18:03:05 -0700999
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001000 @Override
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001001 public SyncStatusInfo getSyncStatus(Account account, String authority, ComponentName cname) {
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +01001002 return getSyncStatusAsUser(account, authority, cname, UserHandle.getCallingUserId());
1003 }
1004
1005 /**
1006 * If the user id supplied is different to the calling user, the caller must hold the
1007 * INTERACT_ACROSS_USERS_FULL permission.
1008 */
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001009 @Override
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +01001010 public SyncStatusInfo getSyncStatusAsUser(Account account, String authority,
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001011 ComponentName cname, int userId) {
Matthew Williams632515b2013-10-10 15:51:00 -07001012 if (TextUtils.isEmpty(authority)) {
1013 throw new IllegalArgumentException("Authority must not be empty");
1014 }
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +01001015
1016 enforceCrossUserPermission(userId,
1017 "no permission to read the sync stats for user " + userId);
Dianne Hackborn231cc602009-04-27 17:10:36 -07001018 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
1019 "no permission to read the sync stats");
Amith Yamasani04e0d262012-02-14 11:50:53 -08001020
Dianne Hackborn231cc602009-04-27 17:10:36 -07001021 long identityToken = clearCallingIdentity();
1022 try {
1023 SyncManager syncManager = getSyncManager();
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001024 if (syncManager == null) {
1025 return null;
Dianne Hackborn231cc602009-04-27 17:10:36 -07001026 }
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001027 SyncStorageEngine.EndPoint info;
Matthew Williams5a9decd2014-06-04 09:25:11 -07001028 if (!(account == null || authority == null)) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001029 info = new SyncStorageEngine.EndPoint(account, authority, userId);
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001030 } else {
1031 throw new IllegalArgumentException("Must call sync status with valid authority");
1032 }
1033 return syncManager.getSyncStorageEngine().getStatusByAuthority(info);
Dianne Hackborn231cc602009-04-27 17:10:36 -07001034 } finally {
1035 restoreCallingIdentity(identityToken);
1036 }
Dianne Hackborn231cc602009-04-27 17:10:36 -07001037 }
Costin Manolacheb7520982009-09-02 18:03:05 -07001038
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001039 @Override
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001040 public boolean isSyncPending(Account account, String authority, ComponentName cname) {
Alexandra Gherghinacb228072014-07-01 15:14:11 +01001041 return isSyncPendingAsUser(account, authority, cname, UserHandle.getCallingUserId());
1042 }
1043
1044 @Override
1045 public boolean isSyncPendingAsUser(Account account, String authority, ComponentName cname,
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001046 int userId) {
Dianne Hackborn231cc602009-04-27 17:10:36 -07001047 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
1048 "no permission to read the sync stats");
Alexandra Gherghinacb228072014-07-01 15:14:11 +01001049 enforceCrossUserPermission(userId,
1050 "no permission to retrieve the sync settings for user " + userId);
Torne (Richard Coles)4890b082013-08-12 10:26:57 +00001051 long identityToken = clearCallingIdentity();
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001052 SyncManager syncManager = getSyncManager();
1053 if (syncManager == null) return false;
1054
Dianne Hackborn231cc602009-04-27 17:10:36 -07001055 try {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001056 SyncStorageEngine.EndPoint info;
Matthew Williams5a9decd2014-06-04 09:25:11 -07001057 if (!(account == null || authority == null)) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001058 info = new SyncStorageEngine.EndPoint(account, authority, userId);
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001059 } else {
1060 throw new IllegalArgumentException("Invalid authority specified");
Dianne Hackborn231cc602009-04-27 17:10:36 -07001061 }
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001062 return syncManager.getSyncStorageEngine().isSyncPending(info);
Dianne Hackborn231cc602009-04-27 17:10:36 -07001063 } finally {
1064 restoreCallingIdentity(identityToken);
1065 }
Dianne Hackborn231cc602009-04-27 17:10:36 -07001066 }
Costin Manolacheb7520982009-09-02 18:03:05 -07001067
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001068 @Override
Dianne Hackborn231cc602009-04-27 17:10:36 -07001069 public void addStatusChangeListener(int mask, ISyncStatusObserver callback) {
1070 long identityToken = clearCallingIdentity();
1071 try {
1072 SyncManager syncManager = getSyncManager();
Fred Quintana1b487ec2010-02-26 10:57:55 -08001073 if (syncManager != null && callback != null) {
Fred Quintanaac9385e2009-06-22 18:00:59 -07001074 syncManager.getSyncStorageEngine().addStatusChangeListener(mask, callback);
Dianne Hackborn231cc602009-04-27 17:10:36 -07001075 }
1076 } finally {
1077 restoreCallingIdentity(identityToken);
1078 }
1079 }
Costin Manolacheb7520982009-09-02 18:03:05 -07001080
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001081 @Override
Dianne Hackborn231cc602009-04-27 17:10:36 -07001082 public void removeStatusChangeListener(ISyncStatusObserver callback) {
1083 long identityToken = clearCallingIdentity();
1084 try {
1085 SyncManager syncManager = getSyncManager();
Fred Quintana1b487ec2010-02-26 10:57:55 -08001086 if (syncManager != null && callback != null) {
Fred Quintanaac9385e2009-06-22 18:00:59 -07001087 syncManager.getSyncStorageEngine().removeStatusChangeListener(callback);
Dianne Hackborn231cc602009-04-27 17:10:36 -07001088 }
1089 } finally {
1090 restoreCallingIdentity(identityToken);
1091 }
1092 }
Costin Manolacheb7520982009-09-02 18:03:05 -07001093
Jeff Sharkey87314082016-03-11 17:25:11 -07001094 private @Nullable String getProviderPackageName(Uri uri) {
1095 final ProviderInfo pi = mContext.getPackageManager()
1096 .resolveContentProvider(uri.getAuthority(), 0);
1097 return (pi != null) ? pi.packageName : null;
1098 }
1099
1100 private ArrayMap<Pair<String, Uri>, Bundle> findOrCreateCacheLocked(int userId,
1101 String providerPackageName) {
1102 ArrayMap<String, ArrayMap<Pair<String, Uri>, Bundle>> userCache = mCache.get(userId);
1103 if (userCache == null) {
1104 userCache = new ArrayMap<>();
1105 mCache.put(userId, userCache);
1106 }
1107 ArrayMap<Pair<String, Uri>, Bundle> packageCache = userCache.get(providerPackageName);
1108 if (packageCache == null) {
1109 packageCache = new ArrayMap<>();
1110 userCache.put(providerPackageName, packageCache);
1111 }
1112 return packageCache;
1113 }
1114
1115 private void invalidateCacheLocked(int userId, String providerPackageName, Uri uri) {
1116 ArrayMap<String, ArrayMap<Pair<String, Uri>, Bundle>> userCache = mCache.get(userId);
1117 if (userCache == null) return;
1118
1119 ArrayMap<Pair<String, Uri>, Bundle> packageCache = userCache.get(providerPackageName);
1120 if (packageCache == null) return;
1121
1122 if (uri != null) {
1123 for (int i = 0; i < packageCache.size();) {
Jeff Sharkey7732e1e2016-03-30 17:14:23 -06001124 final Pair<String, Uri> key = packageCache.keyAt(i);
1125 if (key.second != null && key.second.toString().startsWith(uri.toString())) {
Dianne Hackborn141f11c2016-04-05 15:46:12 -07001126 if (DEBUG) Slog.d(TAG, "Invalidating cache for key " + key);
Jeff Sharkey87314082016-03-11 17:25:11 -07001127 packageCache.removeAt(i);
1128 } else {
1129 i++;
1130 }
1131 }
1132 } else {
Dianne Hackborn141f11c2016-04-05 15:46:12 -07001133 if (DEBUG) Slog.d(TAG, "Invalidating cache for package " + providerPackageName);
Jeff Sharkey87314082016-03-11 17:25:11 -07001134 packageCache.clear();
1135 }
1136 }
1137
1138 @Override
1139 public void putCache(String packageName, Uri key, Bundle value, int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001140 Bundle.setDefusable(value, true);
Jeff Sharkey87314082016-03-11 17:25:11 -07001141 enforceCrossUserPermission(userId, TAG);
1142 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CACHE_CONTENT, TAG);
1143 mContext.getSystemService(AppOpsManager.class).checkPackage(Binder.getCallingUid(),
1144 packageName);
1145
1146 final String providerPackageName = getProviderPackageName(key);
1147 final Pair<String, Uri> fullKey = Pair.create(packageName, key);
1148
1149 synchronized (mCache) {
1150 final ArrayMap<Pair<String, Uri>, Bundle> cache = findOrCreateCacheLocked(userId,
1151 providerPackageName);
1152 if (value != null) {
1153 cache.put(fullKey, value);
1154 } else {
1155 cache.remove(fullKey);
1156 }
1157 }
1158 }
1159
1160 @Override
1161 public Bundle getCache(String packageName, Uri key, int userId) {
1162 enforceCrossUserPermission(userId, TAG);
1163 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CACHE_CONTENT, TAG);
1164 mContext.getSystemService(AppOpsManager.class).checkPackage(Binder.getCallingUid(),
1165 packageName);
1166
1167 final String providerPackageName = getProviderPackageName(key);
1168 final Pair<String, Uri> fullKey = Pair.create(packageName, key);
1169
1170 synchronized (mCache) {
1171 final ArrayMap<Pair<String, Uri>, Bundle> cache = findOrCreateCacheLocked(userId,
1172 providerPackageName);
1173 return cache.get(fullKey);
1174 }
1175 }
1176
Sudheer Shankab4e2ddd2017-02-03 15:15:57 -08001177 private int handleIncomingUser(Uri uri, int pid, int uid, int modeFlags, boolean allowNonFull,
1178 int userId) {
Jeff Sharkey923e0b82016-11-16 17:22:48 -07001179 if (userId == UserHandle.USER_CURRENT) {
1180 userId = ActivityManager.getCurrentUser();
1181 }
1182
1183 if (userId == UserHandle.USER_ALL) {
1184 mContext.enforceCallingOrSelfPermission(
1185 Manifest.permission.INTERACT_ACROSS_USERS_FULL, TAG);
1186 } else if (userId < 0) {
1187 throw new IllegalArgumentException("Invalid user: " + userId);
1188 } else if (userId != UserHandle.getCallingUserId()) {
1189 if (checkUriPermission(uri, pid, uid, modeFlags,
1190 userId) != PackageManager.PERMISSION_GRANTED) {
Sudheer Shankab4e2ddd2017-02-03 15:15:57 -08001191 boolean allow = false;
1192 if (mContext.checkCallingOrSelfPermission(
1193 Manifest.permission.INTERACT_ACROSS_USERS_FULL)
1194 == PackageManager.PERMISSION_GRANTED) {
1195 allow = true;
1196 } else if (allowNonFull && mContext.checkCallingOrSelfPermission(
1197 Manifest.permission.INTERACT_ACROSS_USERS)
1198 == PackageManager.PERMISSION_GRANTED) {
1199 allow = true;
1200 }
1201 if (!allow) {
1202 final String permissions = allowNonFull
1203 ? (Manifest.permission.INTERACT_ACROSS_USERS_FULL + " or " +
1204 Manifest.permission.INTERACT_ACROSS_USERS)
1205 : Manifest.permission.INTERACT_ACROSS_USERS_FULL;
1206 throw new SecurityException(TAG + "Neither user " + uid
1207 + " nor current process has " + permissions);
1208 }
Jeff Sharkey923e0b82016-11-16 17:22:48 -07001209 }
1210 }
1211
1212 return userId;
1213 }
1214
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001215 /**
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +01001216 * Checks if the request is from the system or an app that has INTERACT_ACROSS_USERS_FULL
1217 * permission, if the userHandle is not for the caller.
1218 *
1219 * @param userHandle the user handle of the user we want to act on behalf of.
1220 * @param message the message to log on security exception.
1221 */
1222 private void enforceCrossUserPermission(int userHandle, String message) {
1223 final int callingUser = UserHandle.getCallingUserId();
1224 if (callingUser != userHandle) {
1225 mContext.enforceCallingOrSelfPermission(
1226 Manifest.permission.INTERACT_ACROSS_USERS_FULL, message);
1227 }
1228 }
1229
Svet Ganov96b9c752016-10-17 19:29:58 -07001230 private static int normalizeSyncable(int syncable) {
1231 if (syncable > 0) {
1232 return SyncStorageEngine.AuthorityInfo.SYNCABLE;
1233 } else if (syncable == 0) {
1234 return SyncStorageEngine.AuthorityInfo.NOT_SYNCABLE;
1235 }
1236 return SyncStorageEngine.AuthorityInfo.UNDEFINED;
1237 }
1238
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +01001239 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001240 * Hide this class since it is not part of api,
1241 * but current unittest framework requires it to be public
1242 * @hide
1243 */
1244 public static final class ObserverNode {
1245 private class ObserverEntry implements IBinder.DeathRecipient {
Fred Quintana002ffad52010-03-02 11:18:16 -08001246 public final IContentObserver observer;
Dianne Hackborn1b64e0d2011-07-17 15:23:59 -07001247 public final int uid;
1248 public final int pid;
Christopher Tate16aa9732012-09-17 16:23:44 -07001249 public final boolean notifyForDescendants;
1250 private final int userHandle;
Fred Quintana002ffad52010-03-02 11:18:16 -08001251 private final Object observersLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001252
Dianne Hackborn1b64e0d2011-07-17 15:23:59 -07001253 public ObserverEntry(IContentObserver o, boolean n, Object observersLock,
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001254 int _uid, int _pid, int _userHandle) {
Fred Quintana002ffad52010-03-02 11:18:16 -08001255 this.observersLock = observersLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001256 observer = o;
Dianne Hackborn1b64e0d2011-07-17 15:23:59 -07001257 uid = _uid;
1258 pid = _pid;
Christopher Tate16aa9732012-09-17 16:23:44 -07001259 userHandle = _userHandle;
1260 notifyForDescendants = n;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001261 try {
1262 observer.asBinder().linkToDeath(this, 0);
1263 } catch (RemoteException e) {
1264 binderDied();
1265 }
1266 }
1267
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001268 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001269 public void binderDied() {
Fred Quintana002ffad52010-03-02 11:18:16 -08001270 synchronized (observersLock) {
1271 removeObserverLocked(observer);
1272 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001273 }
Dianne Hackborn1b64e0d2011-07-17 15:23:59 -07001274
1275 public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001276 String name, String prefix, SparseIntArray pidCounts) {
Dianne Hackborn1b64e0d2011-07-17 15:23:59 -07001277 pidCounts.put(pid, pidCounts.get(pid)+1);
1278 pw.print(prefix); pw.print(name); pw.print(": pid=");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001279 pw.print(pid); pw.print(" uid=");
1280 pw.print(uid); pw.print(" user=");
1281 pw.print(userHandle); pw.print(" target=");
1282 pw.println(Integer.toHexString(System.identityHashCode(
1283 observer != null ? observer.asBinder() : null)));
Dianne Hackborn1b64e0d2011-07-17 15:23:59 -07001284 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001285 }
1286
1287 public static final int INSERT_TYPE = 0;
1288 public static final int UPDATE_TYPE = 1;
1289 public static final int DELETE_TYPE = 2;
1290
1291 private String mName;
1292 private ArrayList<ObserverNode> mChildren = new ArrayList<ObserverNode>();
1293 private ArrayList<ObserverEntry> mObservers = new ArrayList<ObserverEntry>();
1294
1295 public ObserverNode(String name) {
1296 mName = name;
1297 }
1298
Dianne Hackborn1b64e0d2011-07-17 15:23:59 -07001299 public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001300 String name, String prefix, int[] counts, SparseIntArray pidCounts) {
Dianne Hackborn1b64e0d2011-07-17 15:23:59 -07001301 String innerName = null;
1302 if (mObservers.size() > 0) {
1303 if ("".equals(name)) {
1304 innerName = mName;
1305 } else {
1306 innerName = name + "/" + mName;
1307 }
1308 for (int i=0; i<mObservers.size(); i++) {
1309 counts[1]++;
1310 mObservers.get(i).dumpLocked(fd, pw, args, innerName, prefix,
1311 pidCounts);
1312 }
1313 }
1314 if (mChildren.size() > 0) {
1315 if (innerName == null) {
1316 if ("".equals(name)) {
1317 innerName = mName;
1318 } else {
1319 innerName = name + "/" + mName;
1320 }
1321 }
1322 for (int i=0; i<mChildren.size(); i++) {
1323 counts[0]++;
1324 mChildren.get(i).dumpLocked(fd, pw, args, innerName, prefix,
1325 counts, pidCounts);
1326 }
1327 }
1328 }
1329
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001330 private String getUriSegment(Uri uri, int index) {
1331 if (uri != null) {
1332 if (index == 0) {
1333 return uri.getAuthority();
1334 } else {
1335 return uri.getPathSegments().get(index - 1);
1336 }
1337 } else {
1338 return null;
1339 }
1340 }
1341
1342 private int countUriSegments(Uri uri) {
1343 if (uri == null) {
1344 return 0;
1345 }
1346 return uri.getPathSegments().size() + 1;
1347 }
1348
Christopher Tate16aa9732012-09-17 16:23:44 -07001349 // Invariant: userHandle is either a hard user number or is USER_ALL
Fred Quintana002ffad52010-03-02 11:18:16 -08001350 public void addObserverLocked(Uri uri, IContentObserver observer,
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001351 boolean notifyForDescendants, Object observersLock,
1352 int uid, int pid, int userHandle) {
Christopher Tate16aa9732012-09-17 16:23:44 -07001353 addObserverLocked(uri, 0, observer, notifyForDescendants, observersLock,
1354 uid, pid, userHandle);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001355 }
1356
Fred Quintana002ffad52010-03-02 11:18:16 -08001357 private void addObserverLocked(Uri uri, int index, IContentObserver observer,
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001358 boolean notifyForDescendants, Object observersLock,
1359 int uid, int pid, int userHandle) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001360 // If this is the leaf node add the observer
1361 if (index == countUriSegments(uri)) {
Christopher Tate16aa9732012-09-17 16:23:44 -07001362 mObservers.add(new ObserverEntry(observer, notifyForDescendants, observersLock,
1363 uid, pid, userHandle));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001364 return;
1365 }
1366
1367 // Look to see if the proper child already exists
1368 String segment = getUriSegment(uri, index);
Anthony Newnamf5126642010-03-22 17:29:06 -05001369 if (segment == null) {
1370 throw new IllegalArgumentException("Invalid Uri (" + uri + ") used for observer");
1371 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001372 int N = mChildren.size();
1373 for (int i = 0; i < N; i++) {
1374 ObserverNode node = mChildren.get(i);
1375 if (node.mName.equals(segment)) {
Christopher Tate16aa9732012-09-17 16:23:44 -07001376 node.addObserverLocked(uri, index + 1, observer, notifyForDescendants,
1377 observersLock, uid, pid, userHandle);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001378 return;
1379 }
1380 }
1381
1382 // No child found, create one
1383 ObserverNode node = new ObserverNode(segment);
1384 mChildren.add(node);
Christopher Tate16aa9732012-09-17 16:23:44 -07001385 node.addObserverLocked(uri, index + 1, observer, notifyForDescendants,
1386 observersLock, uid, pid, userHandle);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001387 }
1388
Fred Quintana002ffad52010-03-02 11:18:16 -08001389 public boolean removeObserverLocked(IContentObserver observer) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001390 int size = mChildren.size();
1391 for (int i = 0; i < size; i++) {
Fred Quintana002ffad52010-03-02 11:18:16 -08001392 boolean empty = mChildren.get(i).removeObserverLocked(observer);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001393 if (empty) {
1394 mChildren.remove(i);
1395 i--;
1396 size--;
1397 }
1398 }
1399
1400 IBinder observerBinder = observer.asBinder();
1401 size = mObservers.size();
1402 for (int i = 0; i < size; i++) {
1403 ObserverEntry entry = mObservers.get(i);
1404 if (entry.observer.asBinder() == observerBinder) {
1405 mObservers.remove(i);
1406 // We no longer need to listen for death notifications. Remove it.
1407 observerBinder.unlinkToDeath(entry, 0);
1408 break;
1409 }
1410 }
1411
1412 if (mChildren.size() == 0 && mObservers.size() == 0) {
1413 return true;
1414 }
1415 return false;
1416 }
1417
Fred Quintana002ffad52010-03-02 11:18:16 -08001418 private void collectMyObserversLocked(boolean leaf, IContentObserver observer,
Dianne Hackborn141f11c2016-04-05 15:46:12 -07001419 boolean observerWantsSelfNotifications, int flags,
1420 int targetUserHandle, ArrayList<ObserverCall> calls) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001421 int N = mObservers.size();
1422 IBinder observerBinder = observer == null ? null : observer.asBinder();
1423 for (int i = 0; i < N; i++) {
1424 ObserverEntry entry = mObservers.get(i);
1425
Christopher Tate16aa9732012-09-17 16:23:44 -07001426 // Don't notify the observer if it sent the notification and isn't interested
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001427 // in self notifications
Jeff Brown86de0592012-01-23 13:01:18 -08001428 boolean selfChange = (entry.observer.asBinder() == observerBinder);
1429 if (selfChange && !observerWantsSelfNotifications) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001430 continue;
1431 }
1432
Christopher Tate16aa9732012-09-17 16:23:44 -07001433 // Does this observer match the target user?
1434 if (targetUserHandle == UserHandle.USER_ALL
1435 || entry.userHandle == UserHandle.USER_ALL
1436 || targetUserHandle == entry.userHandle) {
1437 // Make sure the observer is interested in the notification
Dianne Hackborn141f11c2016-04-05 15:46:12 -07001438 if (leaf) {
1439 // If we are at the leaf: we always report, unless the sender has asked
1440 // to skip observers that are notifying for descendants (since they will
1441 // be sending another more specific URI for them).
1442 if ((flags&ContentResolver.NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS) != 0
1443 && entry.notifyForDescendants) {
1444 if (DEBUG) Slog.d(TAG, "Skipping " + entry.observer
1445 + ": skip notify for descendants");
1446 continue;
1447 }
1448 } else {
1449 // If we are not at the leaf: we report if the observer says it wants
1450 // to be notified for all descendants.
1451 if (!entry.notifyForDescendants) {
1452 if (DEBUG) Slog.d(TAG, "Skipping " + entry.observer
1453 + ": not monitor descendants");
1454 continue;
1455 }
Christopher Tate16aa9732012-09-17 16:23:44 -07001456 }
Dianne Hackborn141f11c2016-04-05 15:46:12 -07001457 if (DEBUG) Slog.d(TAG, "Reporting to " + entry.observer + ": leaf=" + leaf
1458 + " flags=" + Integer.toHexString(flags)
1459 + " desc=" + entry.notifyForDescendants);
Nicolas Prevot051f3b72016-05-18 18:44:00 +01001460 calls.add(new ObserverCall(this, entry.observer, selfChange,
1461 UserHandle.getUserId(entry.uid)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001462 }
1463 }
1464 }
1465
Christopher Tate16aa9732012-09-17 16:23:44 -07001466 /**
1467 * targetUserHandle is either a hard user handle or is USER_ALL
1468 */
Fred Quintana002ffad52010-03-02 11:18:16 -08001469 public void collectObserversLocked(Uri uri, int index, IContentObserver observer,
Dianne Hackborn141f11c2016-04-05 15:46:12 -07001470 boolean observerWantsSelfNotifications, int flags,
1471 int targetUserHandle, ArrayList<ObserverCall> calls) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001472 String segment = null;
1473 int segmentCount = countUriSegments(uri);
1474 if (index >= segmentCount) {
1475 // This is the leaf node, notify all observers
Dianne Hackborn141f11c2016-04-05 15:46:12 -07001476 if (DEBUG) Slog.d(TAG, "Collecting leaf observers @ #" + index + ", node " + mName);
Christopher Tate16aa9732012-09-17 16:23:44 -07001477 collectMyObserversLocked(true, observer, observerWantsSelfNotifications,
Dianne Hackborn141f11c2016-04-05 15:46:12 -07001478 flags, targetUserHandle, calls);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001479 } else if (index < segmentCount){
1480 segment = getUriSegment(uri, index);
Dianne Hackborn141f11c2016-04-05 15:46:12 -07001481 if (DEBUG) Slog.d(TAG, "Collecting non-leaf observers @ #" + index + " / "
1482 + segment);
Christopher Tate16aa9732012-09-17 16:23:44 -07001483 // Notify any observers at this level who are interested in descendants
1484 collectMyObserversLocked(false, observer, observerWantsSelfNotifications,
Dianne Hackborn141f11c2016-04-05 15:46:12 -07001485 flags, targetUserHandle, calls);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001486 }
1487
1488 int N = mChildren.size();
1489 for (int i = 0; i < N; i++) {
1490 ObserverNode node = mChildren.get(i);
1491 if (segment == null || node.mName.equals(segment)) {
1492 // We found the child,
Dianne Hackborn141f11c2016-04-05 15:46:12 -07001493 node.collectObserversLocked(uri, index + 1, observer,
1494 observerWantsSelfNotifications, flags, targetUserHandle, calls);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001495 if (segment != null) {
1496 break;
1497 }
1498 }
1499 }
1500 }
1501 }
1502}