blob: 03d8f395e36e2a26ead7eb7c7f540b6caabeebe1 [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;
Makoto Onuki75ad2492018-03-28 14:42:42 -070029import android.content.ContentResolver.SyncExemption;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080030import android.content.Context;
31import android.content.IContentService;
Jeff Sharkey7732e1e2016-03-30 17:14:23 -060032import android.content.ISyncStatusObserver;
Benjamin Franzadea1912015-06-19 16:03:38 +010033import android.content.Intent;
Jeff Sharkey87314082016-03-11 17:25:11 -070034import android.content.IntentFilter;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080035import android.content.PeriodicSync;
36import android.content.SyncAdapterType;
37import android.content.SyncInfo;
Matthew Williamsfa774182013-06-18 15:44:11 -070038import android.content.SyncRequest;
Jeff Sharkey7a96c392012-11-15 14:01:46 -080039import android.content.SyncStatusInfo;
Benjamin Franzadea1912015-06-19 16:03:38 +010040import android.content.pm.PackageManager;
Svetoslav0010b702015-06-30 18:05:26 -070041import android.content.pm.PackageManagerInternal;
Jeff Sharkey87314082016-03-11 17:25:11 -070042import android.content.pm.ProviderInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.database.IContentObserver;
44import android.database.sqlite.SQLiteException;
45import android.net.Uri;
Dianne Hackborn1b64e0d2011-07-17 15:23:59 -070046import android.os.Binder;
Jeff Sharkey912e80d2017-02-24 11:00:55 -070047import android.os.Build;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.os.Bundle;
Jeff Sharkeya3ebfec2016-04-04 08:58:04 -060049import android.os.FactoryTest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050import android.os.IBinder;
Dianne Hackborn231cc602009-04-27 17:10:36 -070051import android.os.Parcel;
Makoto Onuki61283ec2018-01-31 17:22:36 -080052import android.os.Process;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053import android.os.RemoteException;
Makoto Onuki94986212018-04-11 16:24:46 -070054import android.os.ResultReceiver;
55import android.os.ShellCallback;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070056import android.os.UserHandle;
Matthew Williams632515b2013-10-10 15:51:00 -070057import android.text.TextUtils;
Jeff Sharkey87314082016-03-11 17:25:11 -070058import android.util.ArrayMap;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059import android.util.Log;
Jeff Sharkey87314082016-03-11 17:25:11 -070060import android.util.Pair;
Jeff Sharkey60094592013-03-21 18:14:24 -070061import android.util.Slog;
Jeff Sharkey87314082016-03-11 17:25:11 -070062import android.util.SparseArray;
Dianne Hackborn1b64e0d2011-07-17 15:23:59 -070063import android.util.SparseIntArray;
Jeff Sharkey87314082016-03-11 17:25:11 -070064
65import com.android.internal.annotations.GuardedBy;
Makoto Onukia9dca242017-06-21 17:06:49 -070066import com.android.internal.util.ArrayUtils;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060067import com.android.internal.util.DumpUtils;
Jeff Sharkey87314082016-03-11 17:25:11 -070068import com.android.internal.util.IndentingPrintWriter;
Svetoslav0010b702015-06-30 18:05:26 -070069import com.android.server.LocalServices;
Jeff Sharkeya3ebfec2016-04-04 08:58:04 -060070import com.android.server.SystemService;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071
72import java.io.FileDescriptor;
73import java.io.PrintWriter;
74import java.util.ArrayList;
Dianne Hackborn1b64e0d2011-07-17 15:23:59 -070075import java.util.Collections;
76import java.util.Comparator;
Fred Quintanac5d1c6d2010-01-27 12:17:49 -080077import java.util.List;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080078
79/**
80 * {@hide}
81 */
Dianne Hackborn231cc602009-04-27 17:10:36 -070082public final class ContentService extends IContentService.Stub {
Dianne Hackborn141f11c2016-04-05 15:46:12 -070083 static final String TAG = "ContentService";
Makoto Onuki5c01be62018-04-09 08:59:01 -070084 static final boolean DEBUG = false;
Jeff Sharkey87314082016-03-11 17:25:11 -070085
Jeff Sharkeya3ebfec2016-04-04 08:58:04 -060086 public static class Lifecycle extends SystemService {
Jeff Sharkey1cab76a2016-04-12 18:23:31 -060087 private ContentService mService;
Jeff Sharkeya3ebfec2016-04-04 08:58:04 -060088
89 public Lifecycle(Context context) {
90 super(context);
91 }
92
93 @Override
94 public void onStart() {
95 final boolean factoryTest = (FactoryTest
96 .getMode() == FactoryTest.FACTORY_TEST_LOW_LEVEL);
Jeff Sharkey1cab76a2016-04-12 18:23:31 -060097 mService = new ContentService(getContext(), factoryTest);
98 publishBinderService(ContentResolver.CONTENT_SERVICE_NAME, mService);
99 }
100
101 @Override
102 public void onBootPhase(int phase) {
Makoto Onukiaad2b512018-02-07 09:31:46 -0800103 mService.onBootPhase(phase);
Jeff Sharkeya3ebfec2016-04-04 08:58:04 -0600104 }
105
Makoto Onukife224e02017-06-29 14:11:14 -0700106
107 @Override
108 public void onStartUser(int userHandle) {
109 mService.onStartUser(userHandle);
110 }
111
112 @Override
113 public void onUnlockUser(int userHandle) {
114 mService.onUnlockUser(userHandle);
115 }
116
117 @Override
118 public void onStopUser(int userHandle) {
119 mService.onStopUser(userHandle);
120 }
121
Jeff Sharkeya3ebfec2016-04-04 08:58:04 -0600122 @Override
123 public void onCleanupUser(int userHandle) {
Jeff Sharkey1cab76a2016-04-12 18:23:31 -0600124 synchronized (mService.mCache) {
125 mService.mCache.remove(userHandle);
Jeff Sharkeya3ebfec2016-04-04 08:58:04 -0600126 }
127 }
128 }
129
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800130 private Context mContext;
131 private boolean mFactoryTest;
Jeff Sharkey87314082016-03-11 17:25:11 -0700132
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133 private final ObserverNode mRootNode = new ObserverNode("");
Jeff Sharkey87314082016-03-11 17:25:11 -0700134
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800135 private SyncManager mSyncManager = null;
136 private final Object mSyncManagerLock = new Object();
137
Jeff Sharkey87314082016-03-11 17:25:11 -0700138 /**
139 * Map from userId to providerPackageName to [clientPackageName, uri] to
140 * value. This structure is carefully optimized to keep invalidation logic
141 * as cheap as possible.
142 */
143 @GuardedBy("mCache")
144 private final SparseArray<ArrayMap<String, ArrayMap<Pair<String, Uri>, Bundle>>>
145 mCache = new SparseArray<>();
146
147 private BroadcastReceiver mCacheReceiver = new BroadcastReceiver() {
148 @Override
149 public void onReceive(Context context, Intent intent) {
Jeff Sharkeya3ebfec2016-04-04 08:58:04 -0600150 synchronized (mCache) {
151 if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
152 mCache.clear();
153 } else {
154 final Uri data = intent.getData();
155 if (data != null) {
156 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
157 UserHandle.USER_NULL);
158 final String packageName = data.getSchemeSpecificPart();
159 invalidateCacheLocked(userId, packageName, null);
160 }
161 }
Jeff Sharkey87314082016-03-11 17:25:11 -0700162 }
163 }
164 };
165
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800166 private SyncManager getSyncManager() {
167 synchronized(mSyncManagerLock) {
168 try {
169 // Try to create the SyncManager, return null if it fails (e.g. the disk is full).
170 if (mSyncManager == null) mSyncManager = new SyncManager(mContext, mFactoryTest);
171 } catch (SQLiteException e) {
172 Log.e(TAG, "Can't create SyncManager", e);
173 }
174 return mSyncManager;
175 }
176 }
177
Makoto Onukife224e02017-06-29 14:11:14 -0700178 void onStartUser(int userHandle) {
179 if (mSyncManager != null) mSyncManager.onStartUser(userHandle);
180 }
181
182 void onUnlockUser(int userHandle) {
183 if (mSyncManager != null) mSyncManager.onUnlockUser(userHandle);
184 }
185
186 void onStopUser(int userHandle) {
187 if (mSyncManager != null) mSyncManager.onStopUser(userHandle);
188 }
189
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800190 @Override
Jeff Sharkey87314082016-03-11 17:25:11 -0700191 protected synchronized void dump(FileDescriptor fd, PrintWriter pw_, String[] args) {
Jeff Sharkey6df866a2017-03-31 14:08:23 -0600192 if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw_)) return;
Jeff Sharkey87314082016-03-11 17:25:11 -0700193 final IndentingPrintWriter pw = new IndentingPrintWriter(pw_, " ");
194
Makoto Onukia9dca242017-06-21 17:06:49 -0700195 final boolean dumpAll = ArrayUtils.contains(args, "-a");
196
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800197 // This makes it so that future permission checks will be in the context of this
198 // process rather than the caller's process. We will restore this before returning.
Jeff Sharkey87314082016-03-11 17:25:11 -0700199 final long identityToken = clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800200 try {
201 if (mSyncManager == null) {
202 pw.println("No SyncManager created! (Disk full?)");
203 } else {
Makoto Onukia9dca242017-06-21 17:06:49 -0700204 mSyncManager.dump(fd, pw, dumpAll);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800205 }
Dianne Hackborn1b64e0d2011-07-17 15:23:59 -0700206 pw.println();
207 pw.println("Observer tree:");
208 synchronized (mRootNode) {
209 int[] counts = new int[2];
210 final SparseIntArray pidCounts = new SparseIntArray();
211 mRootNode.dumpLocked(fd, pw, args, "", " ", counts, pidCounts);
212 pw.println();
213 ArrayList<Integer> sorted = new ArrayList<Integer>();
214 for (int i=0; i<pidCounts.size(); i++) {
215 sorted.add(pidCounts.keyAt(i));
216 }
217 Collections.sort(sorted, new Comparator<Integer>() {
218 @Override
219 public int compare(Integer lhs, Integer rhs) {
220 int lc = pidCounts.get(lhs);
221 int rc = pidCounts.get(rhs);
222 if (lc < rc) {
223 return 1;
224 } else if (lc > rc) {
225 return -1;
226 }
227 return 0;
228 }
229
230 });
231 for (int i=0; i<sorted.size(); i++) {
232 int pid = sorted.get(i);
233 pw.print(" pid "); pw.print(pid); pw.print(": ");
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000234 pw.print(pidCounts.get(pid)); pw.println(" observers");
Dianne Hackborn1b64e0d2011-07-17 15:23:59 -0700235 }
236 pw.println();
237 pw.print(" Total number of nodes: "); pw.println(counts[0]);
238 pw.print(" Total number of observers: "); pw.println(counts[1]);
239 }
Jeff Sharkey87314082016-03-11 17:25:11 -0700240
241 synchronized (mCache) {
242 pw.println();
243 pw.println("Cached content:");
244 pw.increaseIndent();
245 for (int i = 0; i < mCache.size(); i++) {
246 pw.println("User " + mCache.keyAt(i) + ":");
247 pw.increaseIndent();
248 pw.println(mCache.valueAt(i));
249 pw.decreaseIndent();
250 }
251 pw.decreaseIndent();
252 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800253 } finally {
254 restoreCallingIdentity(identityToken);
255 }
256 }
257
Dianne Hackborn231cc602009-04-27 17:10:36 -0700258 @Override
259 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
260 throws RemoteException {
261 try {
262 return super.onTransact(code, data, reply, flags);
263 } catch (RuntimeException e) {
264 // The content service only throws security exceptions, so let's
265 // log all others.
266 if (!(e instanceof SecurityException)) {
Dianne Hackborn164371f2013-10-01 19:10:13 -0700267 Slog.wtf(TAG, "Content Service Crash", e);
Dianne Hackborn231cc602009-04-27 17:10:36 -0700268 }
269 throw e;
270 }
271 }
272
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800273 /*package*/ ContentService(Context context, boolean factoryTest) {
274 mContext = context;
275 mFactoryTest = factoryTest;
Svetoslav0010b702015-06-30 18:05:26 -0700276
277 // Let the package manager query for the sync adapters for a given authority
Svet Ganov52153f42015-08-11 08:59:12 -0700278 // as we grant default permissions to sync adapters for specific authorities.
Svetoslav0010b702015-06-30 18:05:26 -0700279 PackageManagerInternal packageManagerInternal = LocalServices.getService(
280 PackageManagerInternal.class);
281 packageManagerInternal.setSyncAdapterPackagesprovider(
282 new PackageManagerInternal.SyncAdapterPackagesProvider() {
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000283 @Override
284 public String[] getPackages(String authority, int userId) {
285 return getSyncAdapterPackagesForAuthorityAsUser(authority, userId);
286 }
287 });
Jeff Sharkey87314082016-03-11 17:25:11 -0700288
289 final IntentFilter packageFilter = new IntentFilter();
290 packageFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
291 packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
292 packageFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
293 packageFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED);
294 packageFilter.addDataScheme("package");
295 mContext.registerReceiverAsUser(mCacheReceiver, UserHandle.ALL,
296 packageFilter, null, null);
Jeff Sharkeya3ebfec2016-04-04 08:58:04 -0600297
298 final IntentFilter localeFilter = new IntentFilter();
299 localeFilter.addAction(Intent.ACTION_LOCALE_CHANGED);
300 mContext.registerReceiverAsUser(mCacheReceiver, UserHandle.ALL,
301 localeFilter, null, null);
Kenny Root26ff6622012-07-30 12:58:03 -0700302 }
303
Makoto Onukiaad2b512018-02-07 09:31:46 -0800304 void onBootPhase(int phase) {
305 switch (phase) {
Makoto Onukid0c50dd2018-02-16 09:52:50 -0800306 case SystemService.PHASE_ACTIVITY_MANAGER_READY:
Makoto Onukiaad2b512018-02-07 09:31:46 -0800307 getSyncManager();
308 break;
309 }
310 if (mSyncManager != null) {
311 mSyncManager.onBootPhase(phase);
312 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800313 }
314
Christopher Tate16aa9732012-09-17 16:23:44 -0700315 /**
316 * Register a content observer tied to a specific user's view of the provider.
317 * @param userHandle the user whose view of the provider is to be observed. May be
318 * the calling user without requiring any permission, otherwise the caller needs to
Benjamin Franzadea1912015-06-19 16:03:38 +0100319 * hold the INTERACT_ACROSS_USERS_FULL permission or hold a read uri grant to the uri.
320 * Pseudousers USER_ALL and USER_CURRENT are properly handled; all other pseudousers
321 * are forbidden.
Christopher Tate16aa9732012-09-17 16:23:44 -0700322 */
323 @Override
324 public void registerContentObserver(Uri uri, boolean notifyForDescendants,
Jeff Sharkey912e80d2017-02-24 11:00:55 -0700325 IContentObserver observer, int userHandle, int targetSdkVersion) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800326 if (observer == null || uri == null) {
327 throw new IllegalArgumentException("You must pass a valid uri and observer");
328 }
Christopher Tate16aa9732012-09-17 16:23:44 -0700329
Benjamin Franzadea1912015-06-19 16:03:38 +0100330 final int uid = Binder.getCallingUid();
331 final int pid = Binder.getCallingPid();
Christopher Tate16aa9732012-09-17 16:23:44 -0700332
Jeff Sharkey923e0b82016-11-16 17:22:48 -0700333 userHandle = handleIncomingUser(uri, pid, uid,
Sudheer Shankab4e2ddd2017-02-03 15:15:57 -0800334 Intent.FLAG_GRANT_READ_URI_PERMISSION, true, userHandle);
Jeff Sharkey923e0b82016-11-16 17:22:48 -0700335
336 final String msg = LocalServices.getService(ActivityManagerInternal.class)
337 .checkContentProviderAccess(uri.getAuthority(), userHandle);
338 if (msg != null) {
Jeff Sharkey912e80d2017-02-24 11:00:55 -0700339 if (targetSdkVersion >= Build.VERSION_CODES.O) {
340 throw new SecurityException(msg);
341 } else {
342 if (msg.startsWith("Failed to find provider")) {
343 // Sigh, we need to quietly let apps targeting older API
344 // levels notify on non-existent providers.
345 } else {
346 Log.w(TAG, "Ignoring content changes for " + uri + " from " + uid + ": " + msg);
347 return;
348 }
349 }
Christopher Tate16aa9732012-09-17 16:23:44 -0700350 }
351
352 synchronized (mRootNode) {
353 mRootNode.addObserverLocked(uri, observer, notifyForDescendants, mRootNode,
Benjamin Franzadea1912015-06-19 16:03:38 +0100354 uid, pid, userHandle);
Christopher Tate16aa9732012-09-17 16:23:44 -0700355 if (false) Log.v(TAG, "Registered observer " + observer + " at " + uri +
356 " with notifyForDescendants " + notifyForDescendants);
357 }
358 }
359
360 public void registerContentObserver(Uri uri, boolean notifyForDescendants,
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000361 IContentObserver observer) {
Christopher Tate16aa9732012-09-17 16:23:44 -0700362 registerContentObserver(uri, notifyForDescendants, observer,
Jeff Sharkey912e80d2017-02-24 11:00:55 -0700363 UserHandle.getCallingUserId(), Build.VERSION_CODES.CUR_DEVELOPMENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800364 }
365
Jeff Sharkeya04c7a72016-03-18 12:20:36 -0600366 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800367 public void unregisterContentObserver(IContentObserver observer) {
368 if (observer == null) {
369 throw new IllegalArgumentException("You must pass a valid observer");
370 }
371 synchronized (mRootNode) {
Fred Quintana002ffad52010-03-02 11:18:16 -0800372 mRootNode.removeObserverLocked(observer);
Joe Onorato43a17652011-04-06 19:22:23 -0700373 if (false) Log.v(TAG, "Unregistered observer " + observer);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800374 }
375 }
376
Christopher Tate16aa9732012-09-17 16:23:44 -0700377 /**
378 * Notify observers of a particular user's view of the provider.
379 * @param userHandle the user whose view of the provider is to be notified. May be
380 * the calling user without requiring any permission, otherwise the caller needs to
Benjamin Franzadea1912015-06-19 16:03:38 +0100381 * hold the INTERACT_ACROSS_USERS_FULL permission or hold a write uri grant to the uri.
382 * Pseudousers USER_ALL and USER_CURRENT are properly interpreted; no other pseudousers are
383 * allowed.
Christopher Tate16aa9732012-09-17 16:23:44 -0700384 */
385 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800386 public void notifyChange(Uri uri, IContentObserver observer,
Jeff Sharkey912e80d2017-02-24 11:00:55 -0700387 boolean observerWantsSelfNotifications, int flags, int userHandle,
388 int targetSdkVersion) {
Dianne Hackborn141f11c2016-04-05 15:46:12 -0700389 if (DEBUG) Slog.d(TAG, "Notifying update of " + uri + " for user " + userHandle
390 + " from observer " + observer + ", flags " + Integer.toHexString(flags));
Amith Yamasani04e0d262012-02-14 11:50:53 -0800391
Dianne Hackborne7617772016-04-27 17:03:52 -0700392 if (uri == null) {
393 throw new NullPointerException("Uri must not be null");
394 }
395
Benjamin Franzadea1912015-06-19 16:03:38 +0100396 final int uid = Binder.getCallingUid();
397 final int pid = Binder.getCallingPid();
Christopher Tate16aa9732012-09-17 16:23:44 -0700398 final int callingUserHandle = UserHandle.getCallingUserId();
Christopher Tate16aa9732012-09-17 16:23:44 -0700399
Jeff Sharkey923e0b82016-11-16 17:22:48 -0700400 userHandle = handleIncomingUser(uri, pid, uid,
Sudheer Shankab4e2ddd2017-02-03 15:15:57 -0800401 Intent.FLAG_GRANT_WRITE_URI_PERMISSION, true, userHandle);
Jeff Sharkey923e0b82016-11-16 17:22:48 -0700402
403 final String msg = LocalServices.getService(ActivityManagerInternal.class)
404 .checkContentProviderAccess(uri.getAuthority(), userHandle);
405 if (msg != null) {
Jeff Sharkey912e80d2017-02-24 11:00:55 -0700406 if (targetSdkVersion >= Build.VERSION_CODES.O) {
407 throw new SecurityException(msg);
408 } else {
409 if (msg.startsWith("Failed to find provider")) {
410 // Sigh, we need to quietly let apps targeting older API
411 // levels notify on non-existent providers.
412 } else {
413 Log.w(TAG, "Ignoring notify for " + uri + " from " + uid + ": " + msg);
414 return;
415 }
416 }
Christopher Tate16aa9732012-09-17 16:23:44 -0700417 }
418
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800419 // This makes it so that future permission checks will be in the context of this
420 // process rather than the caller's process. We will restore this before returning.
421 long identityToken = clearCallingIdentity();
422 try {
423 ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>();
424 synchronized (mRootNode) {
Fred Quintana002ffad52010-03-02 11:18:16 -0800425 mRootNode.collectObserversLocked(uri, 0, observer, observerWantsSelfNotifications,
Dianne Hackborn141f11c2016-04-05 15:46:12 -0700426 flags, userHandle, calls);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800427 }
428 final int numCalls = calls.size();
429 for (int i=0; i<numCalls; i++) {
430 ObserverCall oc = calls.get(i);
431 try {
Svet Ganov3138a992016-06-15 16:57:32 -0700432 oc.mObserver.onChange(oc.mSelfChange, uri, userHandle);
Dianne Hackborn141f11c2016-04-05 15:46:12 -0700433 if (DEBUG) Slog.d(TAG, "Notified " + oc.mObserver + " of " + "update at "
Svet Ganov3138a992016-06-15 16:57:32 -0700434 + uri);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800435 } catch (RemoteException ex) {
436 synchronized (mRootNode) {
437 Log.w(TAG, "Found dead observer, removing");
438 IBinder binder = oc.mObserver.asBinder();
439 final ArrayList<ObserverNode.ObserverEntry> list
440 = oc.mNode.mObservers;
441 int numList = list.size();
442 for (int j=0; j<numList; j++) {
443 ObserverNode.ObserverEntry oe = list.get(j);
444 if (oe.observer.asBinder() == binder) {
445 list.remove(j);
446 j--;
447 numList--;
448 }
449 }
450 }
451 }
452 }
Dianne Hackborn141f11c2016-04-05 15:46:12 -0700453 if ((flags&ContentResolver.NOTIFY_SYNC_TO_NETWORK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800454 SyncManager syncManager = getSyncManager();
Fred Quintanaac9385e2009-06-22 18:00:59 -0700455 if (syncManager != null) {
Alon Albert57286f92012-10-09 14:21:38 -0700456 syncManager.scheduleLocalSync(null /* all accounts */, callingUserHandle, uid,
Makoto Onuki75ad2492018-03-28 14:42:42 -0700457 uri.getAuthority(), getSyncExemptionForCaller(uid));
Fred Quintanaac9385e2009-06-22 18:00:59 -0700458 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800459 }
Jeff Sharkey87314082016-03-11 17:25:11 -0700460
461 synchronized (mCache) {
462 final String providerPackageName = getProviderPackageName(uri);
463 invalidateCacheLocked(userHandle, providerPackageName, uri);
464 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800465 } finally {
466 restoreCallingIdentity(identityToken);
467 }
468 }
469
Nicolas Prevot051f3b72016-05-18 18:44:00 +0100470 private int checkUriPermission(Uri uri, int pid, int uid, int modeFlags, int userHandle) {
471 try {
Sudheer Shankadc589ac2016-11-10 15:30:17 -0800472 return ActivityManager.getService().checkUriPermission(
Nicolas Prevot051f3b72016-05-18 18:44:00 +0100473 uri, pid, uid, modeFlags, userHandle, null);
474 } catch (RemoteException e) {
475 return PackageManager.PERMISSION_DENIED;
476 }
477 }
478
Christopher Tate16aa9732012-09-17 16:23:44 -0700479 public void notifyChange(Uri uri, IContentObserver observer,
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000480 boolean observerWantsSelfNotifications, boolean syncToNetwork) {
Dianne Hackborn141f11c2016-04-05 15:46:12 -0700481 notifyChange(uri, observer, observerWantsSelfNotifications,
482 syncToNetwork ? ContentResolver.NOTIFY_SYNC_TO_NETWORK : 0,
Jeff Sharkey912e80d2017-02-24 11:00:55 -0700483 UserHandle.getCallingUserId(), Build.VERSION_CODES.CUR_DEVELOPMENT);
Christopher Tate16aa9732012-09-17 16:23:44 -0700484 }
485
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800486 /**
487 * Hide this class since it is not part of api,
488 * but current unittest framework requires it to be public
489 * @hide
490 *
491 */
492 public static final class ObserverCall {
493 final ObserverNode mNode;
494 final IContentObserver mObserver;
Jeff Brown86de0592012-01-23 13:01:18 -0800495 final boolean mSelfChange;
Nicolas Prevot051f3b72016-05-18 18:44:00 +0100496 final int mObserverUserId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800497
Nicolas Prevot051f3b72016-05-18 18:44:00 +0100498 ObserverCall(ObserverNode node, IContentObserver observer, boolean selfChange, int observerUserId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800499 mNode = node;
500 mObserver = observer;
Jeff Brown86de0592012-01-23 13:01:18 -0800501 mSelfChange = selfChange;
Nicolas Prevot051f3b72016-05-18 18:44:00 +0100502 mObserverUserId = observerUserId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800503 }
504 }
505
Jeff Sharkeya04c7a72016-03-18 12:20:36 -0600506 @Override
Fred Quintanaac9385e2009-06-22 18:00:59 -0700507 public void requestSync(Account account, String authority, Bundle extras) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -0600508 Bundle.setDefusable(extras, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800509 ContentResolver.validateSyncExtrasBundle(extras);
Dianne Hackbornf02b60a2012-08-16 10:48:27 -0700510 int userId = UserHandle.getCallingUserId();
Alon Albert57286f92012-10-09 14:21:38 -0700511 int uId = Binder.getCallingUid();
Amith Yamasani04e0d262012-02-14 11:50:53 -0800512
Makoto Onuki61283ec2018-01-31 17:22:36 -0800513 validateExtras(uId, extras);
Makoto Onuki75ad2492018-03-28 14:42:42 -0700514 final int syncExemption = getSyncExemptionAndCleanUpExtrasForCaller(uId, extras);
Makoto Onuki61283ec2018-01-31 17:22:36 -0800515
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800516 // This makes it so that future permission checks will be in the context of this
517 // process rather than the caller's process. We will restore this before returning.
518 long identityToken = clearCallingIdentity();
519 try {
520 SyncManager syncManager = getSyncManager();
Fred Quintanaac9385e2009-06-22 18:00:59 -0700521 if (syncManager != null) {
Matthew Williamsfa774182013-06-18 15:44:11 -0700522 syncManager.scheduleSync(account, userId, uId, authority, extras,
Makoto Onuki61283ec2018-01-31 17:22:36 -0800523 SyncStorageEngine.AuthorityInfo.UNDEFINED,
Makoto Onuki75ad2492018-03-28 14:42:42 -0700524 syncExemption);
Fred Quintanaac9385e2009-06-22 18:00:59 -0700525 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800526 } finally {
527 restoreCallingIdentity(identityToken);
528 }
529 }
530
531 /**
Matthew Williamsfa774182013-06-18 15:44:11 -0700532 * Request a sync with a generic {@link android.content.SyncRequest} object. This will be
533 * either:
534 * periodic OR one-off sync.
535 * and
536 * anonymous OR provider sync.
537 * Depending on the request, we enqueue to suit in the SyncManager.
Matthew Williams632515b2013-10-10 15:51:00 -0700538 * @param request The request object. Validation of this object is done by its builder.
Matthew Williamsfa774182013-06-18 15:44:11 -0700539 */
Jeff Sharkeya04c7a72016-03-18 12:20:36 -0600540 @Override
Matthew Williamsfa774182013-06-18 15:44:11 -0700541 public void sync(SyncRequest request) {
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +0100542 syncAsUser(request, UserHandle.getCallingUserId());
543 }
544
Shreyas Basarge3b840e32016-06-14 15:32:02 +0100545 private long clampPeriod(long period) {
546 long minPeriod = JobInfo.getMinPeriodMillis() / 1000;
547 if (period < minPeriod) {
548 Slog.w(TAG, "Requested poll frequency of " + period
549 + " seconds being rounded up to " + minPeriod + "s.");
550 period = minPeriod;
551 }
552 return period;
553 }
554
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +0100555 /**
556 * If the user id supplied is different to the calling user, the caller must hold the
557 * INTERACT_ACROSS_USERS_FULL permission.
558 */
Jeff Sharkeya04c7a72016-03-18 12:20:36 -0600559 @Override
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +0100560 public void syncAsUser(SyncRequest request, int userId) {
561 enforceCrossUserPermission(userId, "no permission to request sync as user: " + userId);
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700562 int callerUid = Binder.getCallingUid();
Makoto Onuki61283ec2018-01-31 17:22:36 -0800563
564 final Bundle extras = request.getBundle();
565
566 validateExtras(callerUid, extras);
Makoto Onuki75ad2492018-03-28 14:42:42 -0700567 final int syncExemption = getSyncExemptionAndCleanUpExtrasForCaller(callerUid, extras);
Makoto Onuki61283ec2018-01-31 17:22:36 -0800568
Matthew Williamsfa774182013-06-18 15:44:11 -0700569 // This makes it so that future permission checks will be in the context of this
570 // process rather than the caller's process. We will restore this before returning.
571 long identityToken = clearCallingIdentity();
572 try {
573 SyncManager syncManager = getSyncManager();
Matthew Williamsd08d6682013-10-14 10:39:41 -0700574 if (syncManager == null) {
575 return;
576 }
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700577 long flextime = request.getSyncFlexTime();
578 long runAtTime = request.getSyncRunTime();
579 if (request.isPeriodic()) {
580 mContext.enforceCallingOrSelfPermission(
581 Manifest.permission.WRITE_SYNC_SETTINGS,
582 "no permission to write the sync settings");
583 SyncStorageEngine.EndPoint info;
Matthew Williams5a9decd2014-06-04 09:25:11 -0700584 info = new SyncStorageEngine.EndPoint(
585 request.getAccount(), request.getProvider(), userId);
Shreyas Basarge3b840e32016-06-14 15:32:02 +0100586
587 runAtTime = clampPeriod(runAtTime);
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700588 // Schedule periodic sync.
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000589 getSyncManager().updateOrAddPeriodicSync(info, runAtTime,
590 flextime, extras);
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700591 } else {
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700592 syncManager.scheduleSync(
593 request.getAccount(), userId, callerUid, request.getProvider(), extras,
Makoto Onuki61283ec2018-01-31 17:22:36 -0800594 SyncStorageEngine.AuthorityInfo.UNDEFINED,
Makoto Onuki75ad2492018-03-28 14:42:42 -0700595 syncExemption);
Matthew Williamsfa774182013-06-18 15:44:11 -0700596 }
597 } finally {
598 restoreCallingIdentity(identityToken);
599 }
600 }
601
602 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800603 * Clear all scheduled sync operations that match the uri and cancel the active sync
Fred Quintanaac9385e2009-06-22 18:00:59 -0700604 * if they match the authority and account, if they are present.
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700605 *
606 * @param account filter the pending and active syncs to cancel using this account, or null.
607 * @param authority filter the pending and active syncs to cancel using this authority, or
608 * null.
609 * @param cname cancel syncs running on this service, or null for provider/account.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800610 */
Matthew Williamsfa774182013-06-18 15:44:11 -0700611 @Override
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700612 public void cancelSync(Account account, String authority, ComponentName cname) {
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +0100613 cancelSyncAsUser(account, authority, cname, UserHandle.getCallingUserId());
614 }
615
616 /**
617 * Clear all scheduled sync operations that match the uri and cancel the active sync
618 * if they match the authority and account, if they are present.
619 *
620 * <p> If the user id supplied is different to the calling user, the caller must hold the
621 * INTERACT_ACROSS_USERS_FULL permission.
622 *
623 * @param account filter the pending and active syncs to cancel using this account, or null.
624 * @param authority filter the pending and active syncs to cancel using this authority, or
625 * null.
626 * @param userId the user id for which to cancel sync operations.
627 * @param cname cancel syncs running on this service, or null for provider/account.
628 */
629 @Override
630 public void cancelSyncAsUser(Account account, String authority, ComponentName cname,
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000631 int userId) {
Matthew Williams632515b2013-10-10 15:51:00 -0700632 if (authority != null && authority.length() == 0) {
633 throw new IllegalArgumentException("Authority must be non-empty");
634 }
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +0100635 enforceCrossUserPermission(userId,
636 "no permission to modify the sync settings for user " + userId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800637 // This makes it so that future permission checks will be in the context of this
638 // process rather than the caller's process. We will restore this before returning.
639 long identityToken = clearCallingIdentity();
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000640 if (cname != null) {
641 Slog.e(TAG, "cname not null.");
642 return;
643 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800644 try {
645 SyncManager syncManager = getSyncManager();
646 if (syncManager != null) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700647 SyncStorageEngine.EndPoint info;
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000648 info = new SyncStorageEngine.EndPoint(account, authority, userId);
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700649 syncManager.clearScheduledSyncOperations(info);
Makoto Onukia9dca242017-06-21 17:06:49 -0700650 syncManager.cancelActiveSync(info, null /* all syncs for this adapter */, "API");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800651 }
652 } finally {
653 restoreCallingIdentity(identityToken);
654 }
655 }
656
Jeff Sharkeya04c7a72016-03-18 12:20:36 -0600657 @Override
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700658 public void cancelRequest(SyncRequest request) {
659 SyncManager syncManager = getSyncManager();
660 if (syncManager == null) return;
661 int userId = UserHandle.getCallingUserId();
Makoto Onukidd4b14f2017-08-17 14:03:48 -0700662 final int callingUid = Binder.getCallingUid();
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700663
Makoto Onukid51101c2017-12-11 14:57:43 -0800664 if (request.isPeriodic()) {
665 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
666 "no permission to write the sync settings");
667 }
668
Makoto Onuki61283ec2018-01-31 17:22:36 -0800669 Bundle extras = new Bundle(request.getBundle());
670 validateExtras(callingUid, extras);
671
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700672 long identityToken = clearCallingIdentity();
673 try {
674 SyncStorageEngine.EndPoint info;
Makoto Onuki61283ec2018-01-31 17:22:36 -0800675
Matthew Williams5a9decd2014-06-04 09:25:11 -0700676 Account account = request.getAccount();
677 String provider = request.getProvider();
678 info = new SyncStorageEngine.EndPoint(account, provider, userId);
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700679 if (request.isPeriodic()) {
680 // Remove periodic sync.
Makoto Onukidd4b14f2017-08-17 14:03:48 -0700681 getSyncManager().removePeriodicSync(info, extras,
682 "cancelRequest() by uid=" + callingUid);
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700683 }
684 // Cancel active syncs and clear pending syncs from the queue.
685 syncManager.cancelScheduledSyncOperation(info, extras);
Makoto Onukia9dca242017-06-21 17:06:49 -0700686 syncManager.cancelActiveSync(info, extras, "API");
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700687 } finally {
688 restoreCallingIdentity(identityToken);
689 }
690 }
691
Fred Quintanaac9385e2009-06-22 18:00:59 -0700692 /**
693 * Get information about the SyncAdapters that are known to the system.
694 * @return an array of SyncAdapters that have registered with the system
695 */
Matthew Williamsfa774182013-06-18 15:44:11 -0700696 @Override
Fred Quintanaac9385e2009-06-22 18:00:59 -0700697 public SyncAdapterType[] getSyncAdapterTypes() {
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +0100698 return getSyncAdapterTypesAsUser(UserHandle.getCallingUserId());
699 }
700
701 /**
702 * Get information about the SyncAdapters that are known to the system for a particular user.
703 *
704 * <p> If the user id supplied is different to the calling user, the caller must hold the
705 * INTERACT_ACROSS_USERS_FULL permission.
706 *
707 * @return an array of SyncAdapters that have registered with the system
708 */
709 @Override
710 public SyncAdapterType[] getSyncAdapterTypesAsUser(int userId) {
711 enforceCrossUserPermission(userId,
712 "no permission to read sync settings for user " + userId);
Fred Quintanaac9385e2009-06-22 18:00:59 -0700713 // This makes it so that future permission checks will be in the context of this
714 // process rather than the caller's process. We will restore this before returning.
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700715 final long identityToken = clearCallingIdentity();
Fred Quintanaac9385e2009-06-22 18:00:59 -0700716 try {
717 SyncManager syncManager = getSyncManager();
Jeff Sharkey6ab72d72012-10-08 16:44:37 -0700718 return syncManager.getSyncAdapterTypes(userId);
Fred Quintanaac9385e2009-06-22 18:00:59 -0700719 } finally {
720 restoreCallingIdentity(identityToken);
721 }
722 }
Costin Manolacheb7520982009-09-02 18:03:05 -0700723
Matthew Williamsfa774182013-06-18 15:44:11 -0700724 @Override
Amith Yamasani37a40c22015-06-17 13:25:42 -0700725 public String[] getSyncAdapterPackagesForAuthorityAsUser(String authority, int userId) {
726 enforceCrossUserPermission(userId,
727 "no permission to read sync settings for user " + userId);
728 // This makes it so that future permission checks will be in the context of this
729 // process rather than the caller's process. We will restore this before returning.
730 final long identityToken = clearCallingIdentity();
731 try {
732 SyncManager syncManager = getSyncManager();
733 return syncManager.getSyncAdapterPackagesForAuthorityAsUser(authority, userId);
734 } finally {
735 restoreCallingIdentity(identityToken);
736 }
737 }
738
739 @Override
Fred Quintanaac9385e2009-06-22 18:00:59 -0700740 public boolean getSyncAutomatically(Account account, String providerName) {
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +0100741 return getSyncAutomaticallyAsUser(account, providerName, UserHandle.getCallingUserId());
742 }
743
744 /**
745 * If the user id supplied is different to the calling user, the caller must hold the
746 * INTERACT_ACROSS_USERS_FULL permission.
747 */
748 @Override
749 public boolean getSyncAutomaticallyAsUser(Account account, String providerName, int userId) {
750 enforceCrossUserPermission(userId,
751 "no permission to read the sync settings for user " + userId);
Dianne Hackborn231cc602009-04-27 17:10:36 -0700752 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
753 "no permission to read the sync settings");
Amith Yamasani04e0d262012-02-14 11:50:53 -0800754
Dianne Hackborn231cc602009-04-27 17:10:36 -0700755 long identityToken = clearCallingIdentity();
756 try {
757 SyncManager syncManager = getSyncManager();
758 if (syncManager != null) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700759 return syncManager.getSyncStorageEngine()
760 .getSyncAutomatically(account, userId, providerName);
Dianne Hackborn231cc602009-04-27 17:10:36 -0700761 }
762 } finally {
763 restoreCallingIdentity(identityToken);
764 }
765 return false;
766 }
767
Matthew Williamsfa774182013-06-18 15:44:11 -0700768 @Override
Fred Quintanaac9385e2009-06-22 18:00:59 -0700769 public void setSyncAutomatically(Account account, String providerName, boolean sync) {
Alexandra Gherghinacb228072014-07-01 15:14:11 +0100770 setSyncAutomaticallyAsUser(account, providerName, sync, UserHandle.getCallingUserId());
771 }
772
773 @Override
774 public void setSyncAutomaticallyAsUser(Account account, String providerName, boolean sync,
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000775 int userId) {
Matthew Williams632515b2013-10-10 15:51:00 -0700776 if (TextUtils.isEmpty(providerName)) {
777 throw new IllegalArgumentException("Authority must be non-empty");
778 }
Dianne Hackborn231cc602009-04-27 17:10:36 -0700779 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
780 "no permission to write the sync settings");
Alexandra Gherghinacb228072014-07-01 15:14:11 +0100781 enforceCrossUserPermission(userId,
782 "no permission to modify the sync settings for user " + userId);
Makoto Onuki75ad2492018-03-28 14:42:42 -0700783 final int callingUid = Binder.getCallingUid();
784 final int syncExemptionFlag = getSyncExemptionForCaller(callingUid);
Amith Yamasani04e0d262012-02-14 11:50:53 -0800785
Dianne Hackborn231cc602009-04-27 17:10:36 -0700786 long identityToken = clearCallingIdentity();
787 try {
788 SyncManager syncManager = getSyncManager();
789 if (syncManager != null) {
Alexandra Gherghinacb228072014-07-01 15:14:11 +0100790 syncManager.getSyncStorageEngine().setSyncAutomatically(account, userId,
Makoto Onukid4764302018-03-30 17:32:57 -0700791 providerName, sync, syncExemptionFlag, callingUid);
Dianne Hackborn231cc602009-04-27 17:10:36 -0700792 }
793 } finally {
794 restoreCallingIdentity(identityToken);
795 }
796 }
797
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000798 /** Old API. Schedule periodic sync with default flexMillis time. */
Matthew Williamsfa774182013-06-18 15:44:11 -0700799 @Override
Fred Quintanac5d1c6d2010-01-27 12:17:49 -0800800 public void addPeriodicSync(Account account, String authority, Bundle extras,
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000801 long pollFrequency) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -0600802 Bundle.setDefusable(extras, true);
Matthew Williams632515b2013-10-10 15:51:00 -0700803 if (account == null) {
804 throw new IllegalArgumentException("Account must not be null");
805 }
806 if (TextUtils.isEmpty(authority)) {
807 throw new IllegalArgumentException("Authority must not be empty.");
808 }
Fred Quintanac5d1c6d2010-01-27 12:17:49 -0800809 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
810 "no permission to write the sync settings");
Amith Yamasani04e0d262012-02-14 11:50:53 -0800811
Makoto Onuki61283ec2018-01-31 17:22:36 -0800812 validateExtras(Binder.getCallingUid(), extras);
813
Matthew Williams632515b2013-10-10 15:51:00 -0700814 int userId = UserHandle.getCallingUserId();
Shreyas Basarge3b840e32016-06-14 15:32:02 +0100815
816 pollFrequency = clampPeriod(pollFrequency);
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700817 long defaultFlex = SyncStorageEngine.calculateDefaultFlexTime(pollFrequency);
Jeff Sharkey60094592013-03-21 18:14:24 -0700818
Fred Quintanac5d1c6d2010-01-27 12:17:49 -0800819 long identityToken = clearCallingIdentity();
820 try {
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700821 SyncStorageEngine.EndPoint info =
822 new SyncStorageEngine.EndPoint(account, authority, userId);
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000823 getSyncManager().updateOrAddPeriodicSync(info, pollFrequency,
824 defaultFlex, extras);
Fred Quintanac5d1c6d2010-01-27 12:17:49 -0800825 } finally {
826 restoreCallingIdentity(identityToken);
827 }
828 }
829
Jeff Sharkeya04c7a72016-03-18 12:20:36 -0600830 @Override
Fred Quintanac5d1c6d2010-01-27 12:17:49 -0800831 public void removePeriodicSync(Account account, String authority, Bundle extras) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -0600832 Bundle.setDefusable(extras, true);
Matthew Williams632515b2013-10-10 15:51:00 -0700833 if (account == null) {
834 throw new IllegalArgumentException("Account must not be null");
835 }
836 if (TextUtils.isEmpty(authority)) {
837 throw new IllegalArgumentException("Authority must not be empty");
838 }
Fred Quintanac5d1c6d2010-01-27 12:17:49 -0800839 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
840 "no permission to write the sync settings");
Amith Yamasani04e0d262012-02-14 11:50:53 -0800841
Makoto Onuki61283ec2018-01-31 17:22:36 -0800842 validateExtras(Binder.getCallingUid(), extras);
843
Makoto Onukidd4b14f2017-08-17 14:03:48 -0700844 final int callingUid = Binder.getCallingUid();
845
Matthew Williams632515b2013-10-10 15:51:00 -0700846 int userId = UserHandle.getCallingUserId();
Fred Quintanac5d1c6d2010-01-27 12:17:49 -0800847 long identityToken = clearCallingIdentity();
848 try {
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000849 getSyncManager()
850 .removePeriodicSync(
851 new SyncStorageEngine.EndPoint(account, authority, userId),
Makoto Onukidd4b14f2017-08-17 14:03:48 -0700852 extras, "removePeriodicSync() by uid=" + callingUid);
Fred Quintanac5d1c6d2010-01-27 12:17:49 -0800853 } finally {
854 restoreCallingIdentity(identityToken);
855 }
856 }
857
Jeff Sharkeya04c7a72016-03-18 12:20:36 -0600858 @Override
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700859 public List<PeriodicSync> getPeriodicSyncs(Account account, String providerName,
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000860 ComponentName cname) {
Matthew Williams632515b2013-10-10 15:51:00 -0700861 if (account == null) {
862 throw new IllegalArgumentException("Account must not be null");
863 }
864 if (TextUtils.isEmpty(providerName)) {
865 throw new IllegalArgumentException("Authority must not be empty");
866 }
Fred Quintanac5d1c6d2010-01-27 12:17:49 -0800867 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
868 "no permission to read the sync settings");
Amith Yamasani04e0d262012-02-14 11:50:53 -0800869
Matthew Williams632515b2013-10-10 15:51:00 -0700870 int userId = UserHandle.getCallingUserId();
Fred Quintanac5d1c6d2010-01-27 12:17:49 -0800871 long identityToken = clearCallingIdentity();
872 try {
Shreyas Basarge8c834c02016-01-07 13:53:16 +0000873 return getSyncManager().getPeriodicSyncs(
Matthew Williams5a9decd2014-06-04 09:25:11 -0700874 new SyncStorageEngine.EndPoint(account, providerName, userId));
Fred Quintanac5d1c6d2010-01-27 12:17:49 -0800875 } finally {
876 restoreCallingIdentity(identityToken);
877 }
878 }
879
Jeff Sharkeya04c7a72016-03-18 12:20:36 -0600880 @Override
Fred Quintana5e787c42009-08-16 23:13:53 -0700881 public int getIsSyncable(Account account, String providerName) {
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +0100882 return getIsSyncableAsUser(account, providerName, UserHandle.getCallingUserId());
883 }
884
885 /**
886 * If the user id supplied is different to the calling user, the caller must hold the
887 * INTERACT_ACROSS_USERS_FULL permission.
888 */
Jeff Sharkeya04c7a72016-03-18 12:20:36 -0600889 @Override
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +0100890 public int getIsSyncableAsUser(Account account, String providerName, int userId) {
891 enforceCrossUserPermission(userId,
892 "no permission to read the sync settings for user " + userId);
Fred Quintana5e787c42009-08-16 23:13:53 -0700893 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
894 "no permission to read the sync settings");
Amith Yamasani04e0d262012-02-14 11:50:53 -0800895
Fred Quintana5e787c42009-08-16 23:13:53 -0700896 long identityToken = clearCallingIdentity();
897 try {
898 SyncManager syncManager = getSyncManager();
899 if (syncManager != null) {
Svetoslav Ganov5cb29732016-07-11 19:32:30 -0700900 return syncManager.computeSyncable(
Svet Ganov96b9c752016-10-17 19:29:58 -0700901 account, userId, providerName, false);
Fred Quintana5e787c42009-08-16 23:13:53 -0700902 }
903 } finally {
904 restoreCallingIdentity(identityToken);
905 }
906 return -1;
907 }
908
Jeff Sharkeya04c7a72016-03-18 12:20:36 -0600909 @Override
Fred Quintana5e787c42009-08-16 23:13:53 -0700910 public void setIsSyncable(Account account, String providerName, int syncable) {
Matthew Williams632515b2013-10-10 15:51:00 -0700911 if (TextUtils.isEmpty(providerName)) {
912 throw new IllegalArgumentException("Authority must not be empty");
913 }
Fred Quintana5e787c42009-08-16 23:13:53 -0700914 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
915 "no permission to write the sync settings");
Amith Yamasani04e0d262012-02-14 11:50:53 -0800916
Svet Ganov96b9c752016-10-17 19:29:58 -0700917 syncable = normalizeSyncable(syncable);
Makoto Onukid4764302018-03-30 17:32:57 -0700918 final int callingUid = Binder.getCallingUid();
Svet Ganov96b9c752016-10-17 19:29:58 -0700919
Matthew Williams632515b2013-10-10 15:51:00 -0700920 int userId = UserHandle.getCallingUserId();
Fred Quintana5e787c42009-08-16 23:13:53 -0700921 long identityToken = clearCallingIdentity();
922 try {
923 SyncManager syncManager = getSyncManager();
924 if (syncManager != null) {
925 syncManager.getSyncStorageEngine().setIsSyncable(
Makoto Onukid4764302018-03-30 17:32:57 -0700926 account, userId, providerName, syncable, callingUid);
Fred Quintana5e787c42009-08-16 23:13:53 -0700927 }
928 } finally {
929 restoreCallingIdentity(identityToken);
930 }
931 }
932
Matthew Williamsfa774182013-06-18 15:44:11 -0700933 @Override
Fred Quintanaac9385e2009-06-22 18:00:59 -0700934 public boolean getMasterSyncAutomatically() {
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +0100935 return getMasterSyncAutomaticallyAsUser(UserHandle.getCallingUserId());
936 }
937
938 /**
939 * If the user id supplied is different to the calling user, the caller must hold the
940 * INTERACT_ACROSS_USERS_FULL permission.
941 */
942 @Override
943 public boolean getMasterSyncAutomaticallyAsUser(int userId) {
944 enforceCrossUserPermission(userId,
945 "no permission to read the sync settings for user " + userId);
Dianne Hackborn231cc602009-04-27 17:10:36 -0700946 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_SETTINGS,
947 "no permission to read the sync settings");
Amith Yamasani04e0d262012-02-14 11:50:53 -0800948
Dianne Hackborn231cc602009-04-27 17:10:36 -0700949 long identityToken = clearCallingIdentity();
950 try {
951 SyncManager syncManager = getSyncManager();
952 if (syncManager != null) {
Amith Yamasani04e0d262012-02-14 11:50:53 -0800953 return syncManager.getSyncStorageEngine().getMasterSyncAutomatically(userId);
Dianne Hackborn231cc602009-04-27 17:10:36 -0700954 }
955 } finally {
956 restoreCallingIdentity(identityToken);
957 }
958 return false;
959 }
Costin Manolacheb7520982009-09-02 18:03:05 -0700960
Matthew Williamsfa774182013-06-18 15:44:11 -0700961 @Override
Fred Quintanaac9385e2009-06-22 18:00:59 -0700962 public void setMasterSyncAutomatically(boolean flag) {
Alexandra Gherghina0e9ac202014-07-15 23:11:48 +0100963 setMasterSyncAutomaticallyAsUser(flag, UserHandle.getCallingUserId());
964 }
965
966 @Override
967 public void setMasterSyncAutomaticallyAsUser(boolean flag, int userId) {
968 enforceCrossUserPermission(userId,
969 "no permission to set the sync status for user " + userId);
Dianne Hackborn231cc602009-04-27 17:10:36 -0700970 mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
971 "no permission to write the sync settings");
Amith Yamasani04e0d262012-02-14 11:50:53 -0800972
Makoto Onuki75ad2492018-03-28 14:42:42 -0700973 final int callingUid = Binder.getCallingUid();
974
Dianne Hackborn231cc602009-04-27 17:10:36 -0700975 long identityToken = clearCallingIdentity();
976 try {
977 SyncManager syncManager = getSyncManager();
978 if (syncManager != null) {
Makoto Onuki75ad2492018-03-28 14:42:42 -0700979 syncManager.getSyncStorageEngine().setMasterSyncAutomatically(flag, userId,
Makoto Onukid4764302018-03-30 17:32:57 -0700980 getSyncExemptionForCaller(callingUid), callingUid);
Dianne Hackborn231cc602009-04-27 17:10:36 -0700981 }
982 } finally {
983 restoreCallingIdentity(identityToken);
984 }
985 }
986
Jeff Sharkeya04c7a72016-03-18 12:20:36 -0600987 @Override
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700988 public boolean isSyncActive(Account account, String authority, ComponentName cname) {
Dianne Hackborn231cc602009-04-27 17:10:36 -0700989 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
990 "no permission to read the sync stats");
Dianne Hackbornf02b60a2012-08-16 10:48:27 -0700991 int userId = UserHandle.getCallingUserId();
Dianne Hackborn231cc602009-04-27 17:10:36 -0700992 long identityToken = clearCallingIdentity();
993 try {
994 SyncManager syncManager = getSyncManager();
Matthew Williams56dbf8f2013-07-26 12:56:39 -0700995 if (syncManager == null) {
996 return false;
997 }
Matthew Williams5a9decd2014-06-04 09:25:11 -0700998 return syncManager.getSyncStorageEngine().isSyncActive(
999 new SyncStorageEngine.EndPoint(account, authority, userId));
Dianne Hackborn231cc602009-04-27 17:10:36 -07001000 } finally {
1001 restoreCallingIdentity(identityToken);
1002 }
Dianne Hackborn231cc602009-04-27 17:10:36 -07001003 }
Costin Manolacheb7520982009-09-02 18:03:05 -07001004
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001005 @Override
Fred Quintanac6a69552010-09-27 17:05:04 -07001006 public List<SyncInfo> getCurrentSyncs() {
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +01001007 return getCurrentSyncsAsUser(UserHandle.getCallingUserId());
1008 }
1009
1010 /**
1011 * If the user id supplied is different to the calling user, the caller must hold the
1012 * INTERACT_ACROSS_USERS_FULL permission.
1013 */
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001014 @Override
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +01001015 public List<SyncInfo> getCurrentSyncsAsUser(int userId) {
1016 enforceCrossUserPermission(userId,
1017 "no permission to read the sync settings 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
Matthew Williamsf39549e2016-01-19 23:04:04 +00001021 final boolean canAccessAccounts =
1022 mContext.checkCallingOrSelfPermission(Manifest.permission.GET_ACCOUNTS)
1023 == PackageManager.PERMISSION_GRANTED;
Dianne Hackborn231cc602009-04-27 17:10:36 -07001024 long identityToken = clearCallingIdentity();
1025 try {
Matthew Williamsf39549e2016-01-19 23:04:04 +00001026 return getSyncManager().getSyncStorageEngine()
1027 .getCurrentSyncsCopy(userId, canAccessAccounts);
Dianne Hackborn231cc602009-04-27 17:10:36 -07001028 } finally {
1029 restoreCallingIdentity(identityToken);
1030 }
Dianne Hackborn231cc602009-04-27 17:10:36 -07001031 }
Costin Manolacheb7520982009-09-02 18:03:05 -07001032
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001033 @Override
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001034 public SyncStatusInfo getSyncStatus(Account account, String authority, ComponentName cname) {
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +01001035 return getSyncStatusAsUser(account, authority, cname, UserHandle.getCallingUserId());
1036 }
1037
1038 /**
1039 * If the user id supplied is different to the calling user, the caller must hold the
1040 * INTERACT_ACROSS_USERS_FULL permission.
1041 */
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001042 @Override
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +01001043 public SyncStatusInfo getSyncStatusAsUser(Account account, String authority,
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001044 ComponentName cname, int userId) {
Matthew Williams632515b2013-10-10 15:51:00 -07001045 if (TextUtils.isEmpty(authority)) {
1046 throw new IllegalArgumentException("Authority must not be empty");
1047 }
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +01001048
1049 enforceCrossUserPermission(userId,
1050 "no permission to read the sync stats for user " + userId);
Dianne Hackborn231cc602009-04-27 17:10:36 -07001051 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
1052 "no permission to read the sync stats");
Amith Yamasani04e0d262012-02-14 11:50:53 -08001053
Dianne Hackborn231cc602009-04-27 17:10:36 -07001054 long identityToken = clearCallingIdentity();
1055 try {
1056 SyncManager syncManager = getSyncManager();
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001057 if (syncManager == null) {
1058 return null;
Dianne Hackborn231cc602009-04-27 17:10:36 -07001059 }
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001060 SyncStorageEngine.EndPoint info;
Matthew Williams5a9decd2014-06-04 09:25:11 -07001061 if (!(account == null || authority == null)) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001062 info = new SyncStorageEngine.EndPoint(account, authority, userId);
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001063 } else {
1064 throw new IllegalArgumentException("Must call sync status with valid authority");
1065 }
1066 return syncManager.getSyncStorageEngine().getStatusByAuthority(info);
Dianne Hackborn231cc602009-04-27 17:10:36 -07001067 } finally {
1068 restoreCallingIdentity(identityToken);
1069 }
Dianne Hackborn231cc602009-04-27 17:10:36 -07001070 }
Costin Manolacheb7520982009-09-02 18:03:05 -07001071
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001072 @Override
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001073 public boolean isSyncPending(Account account, String authority, ComponentName cname) {
Alexandra Gherghinacb228072014-07-01 15:14:11 +01001074 return isSyncPendingAsUser(account, authority, cname, UserHandle.getCallingUserId());
1075 }
1076
1077 @Override
1078 public boolean isSyncPendingAsUser(Account account, String authority, ComponentName cname,
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001079 int userId) {
Dianne Hackborn231cc602009-04-27 17:10:36 -07001080 mContext.enforceCallingOrSelfPermission(Manifest.permission.READ_SYNC_STATS,
1081 "no permission to read the sync stats");
Alexandra Gherghinacb228072014-07-01 15:14:11 +01001082 enforceCrossUserPermission(userId,
1083 "no permission to retrieve the sync settings for user " + userId);
Torne (Richard Coles)4890b082013-08-12 10:26:57 +00001084 long identityToken = clearCallingIdentity();
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001085 SyncManager syncManager = getSyncManager();
1086 if (syncManager == null) return false;
1087
Dianne Hackborn231cc602009-04-27 17:10:36 -07001088 try {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001089 SyncStorageEngine.EndPoint info;
Matthew Williams5a9decd2014-06-04 09:25:11 -07001090 if (!(account == null || authority == null)) {
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001091 info = new SyncStorageEngine.EndPoint(account, authority, userId);
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001092 } else {
1093 throw new IllegalArgumentException("Invalid authority specified");
Dianne Hackborn231cc602009-04-27 17:10:36 -07001094 }
Matthew Williams56dbf8f2013-07-26 12:56:39 -07001095 return syncManager.getSyncStorageEngine().isSyncPending(info);
Dianne Hackborn231cc602009-04-27 17:10:36 -07001096 } finally {
1097 restoreCallingIdentity(identityToken);
1098 }
Dianne Hackborn231cc602009-04-27 17:10:36 -07001099 }
Costin Manolacheb7520982009-09-02 18:03:05 -07001100
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001101 @Override
Dianne Hackborn231cc602009-04-27 17:10:36 -07001102 public void addStatusChangeListener(int mask, ISyncStatusObserver callback) {
1103 long identityToken = clearCallingIdentity();
1104 try {
1105 SyncManager syncManager = getSyncManager();
Fred Quintana1b487ec2010-02-26 10:57:55 -08001106 if (syncManager != null && callback != null) {
Fred Quintanaac9385e2009-06-22 18:00:59 -07001107 syncManager.getSyncStorageEngine().addStatusChangeListener(mask, callback);
Dianne Hackborn231cc602009-04-27 17:10:36 -07001108 }
1109 } finally {
1110 restoreCallingIdentity(identityToken);
1111 }
1112 }
Costin Manolacheb7520982009-09-02 18:03:05 -07001113
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001114 @Override
Dianne Hackborn231cc602009-04-27 17:10:36 -07001115 public void removeStatusChangeListener(ISyncStatusObserver callback) {
1116 long identityToken = clearCallingIdentity();
1117 try {
1118 SyncManager syncManager = getSyncManager();
Fred Quintana1b487ec2010-02-26 10:57:55 -08001119 if (syncManager != null && callback != null) {
Fred Quintanaac9385e2009-06-22 18:00:59 -07001120 syncManager.getSyncStorageEngine().removeStatusChangeListener(callback);
Dianne Hackborn231cc602009-04-27 17:10:36 -07001121 }
1122 } finally {
1123 restoreCallingIdentity(identityToken);
1124 }
1125 }
Costin Manolacheb7520982009-09-02 18:03:05 -07001126
Jeff Sharkey87314082016-03-11 17:25:11 -07001127 private @Nullable String getProviderPackageName(Uri uri) {
1128 final ProviderInfo pi = mContext.getPackageManager()
1129 .resolveContentProvider(uri.getAuthority(), 0);
1130 return (pi != null) ? pi.packageName : null;
1131 }
1132
Andreas Gampea36dc622018-02-05 17:19:22 -08001133 @GuardedBy("mCache")
Jeff Sharkey87314082016-03-11 17:25:11 -07001134 private ArrayMap<Pair<String, Uri>, Bundle> findOrCreateCacheLocked(int userId,
1135 String providerPackageName) {
1136 ArrayMap<String, ArrayMap<Pair<String, Uri>, Bundle>> userCache = mCache.get(userId);
1137 if (userCache == null) {
1138 userCache = new ArrayMap<>();
1139 mCache.put(userId, userCache);
1140 }
1141 ArrayMap<Pair<String, Uri>, Bundle> packageCache = userCache.get(providerPackageName);
1142 if (packageCache == null) {
1143 packageCache = new ArrayMap<>();
1144 userCache.put(providerPackageName, packageCache);
1145 }
1146 return packageCache;
1147 }
1148
Andreas Gampea36dc622018-02-05 17:19:22 -08001149 @GuardedBy("mCache")
Jeff Sharkey87314082016-03-11 17:25:11 -07001150 private void invalidateCacheLocked(int userId, String providerPackageName, Uri uri) {
1151 ArrayMap<String, ArrayMap<Pair<String, Uri>, Bundle>> userCache = mCache.get(userId);
1152 if (userCache == null) return;
1153
1154 ArrayMap<Pair<String, Uri>, Bundle> packageCache = userCache.get(providerPackageName);
1155 if (packageCache == null) return;
1156
1157 if (uri != null) {
1158 for (int i = 0; i < packageCache.size();) {
Jeff Sharkey7732e1e2016-03-30 17:14:23 -06001159 final Pair<String, Uri> key = packageCache.keyAt(i);
1160 if (key.second != null && key.second.toString().startsWith(uri.toString())) {
Dianne Hackborn141f11c2016-04-05 15:46:12 -07001161 if (DEBUG) Slog.d(TAG, "Invalidating cache for key " + key);
Jeff Sharkey87314082016-03-11 17:25:11 -07001162 packageCache.removeAt(i);
1163 } else {
1164 i++;
1165 }
1166 }
1167 } else {
Dianne Hackborn141f11c2016-04-05 15:46:12 -07001168 if (DEBUG) Slog.d(TAG, "Invalidating cache for package " + providerPackageName);
Jeff Sharkey87314082016-03-11 17:25:11 -07001169 packageCache.clear();
1170 }
1171 }
1172
1173 @Override
1174 public void putCache(String packageName, Uri key, Bundle value, int userId) {
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001175 Bundle.setDefusable(value, true);
Jeff Sharkey87314082016-03-11 17:25:11 -07001176 enforceCrossUserPermission(userId, TAG);
1177 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CACHE_CONTENT, TAG);
1178 mContext.getSystemService(AppOpsManager.class).checkPackage(Binder.getCallingUid(),
1179 packageName);
1180
1181 final String providerPackageName = getProviderPackageName(key);
1182 final Pair<String, Uri> fullKey = Pair.create(packageName, key);
1183
1184 synchronized (mCache) {
1185 final ArrayMap<Pair<String, Uri>, Bundle> cache = findOrCreateCacheLocked(userId,
1186 providerPackageName);
1187 if (value != null) {
1188 cache.put(fullKey, value);
1189 } else {
1190 cache.remove(fullKey);
1191 }
1192 }
1193 }
1194
1195 @Override
1196 public Bundle getCache(String packageName, Uri key, int userId) {
1197 enforceCrossUserPermission(userId, TAG);
1198 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CACHE_CONTENT, TAG);
1199 mContext.getSystemService(AppOpsManager.class).checkPackage(Binder.getCallingUid(),
1200 packageName);
1201
1202 final String providerPackageName = getProviderPackageName(key);
1203 final Pair<String, Uri> fullKey = Pair.create(packageName, key);
1204
1205 synchronized (mCache) {
1206 final ArrayMap<Pair<String, Uri>, Bundle> cache = findOrCreateCacheLocked(userId,
1207 providerPackageName);
1208 return cache.get(fullKey);
1209 }
1210 }
1211
Sudheer Shankab4e2ddd2017-02-03 15:15:57 -08001212 private int handleIncomingUser(Uri uri, int pid, int uid, int modeFlags, boolean allowNonFull,
1213 int userId) {
Jeff Sharkey923e0b82016-11-16 17:22:48 -07001214 if (userId == UserHandle.USER_CURRENT) {
1215 userId = ActivityManager.getCurrentUser();
1216 }
1217
1218 if (userId == UserHandle.USER_ALL) {
1219 mContext.enforceCallingOrSelfPermission(
1220 Manifest.permission.INTERACT_ACROSS_USERS_FULL, TAG);
1221 } else if (userId < 0) {
1222 throw new IllegalArgumentException("Invalid user: " + userId);
1223 } else if (userId != UserHandle.getCallingUserId()) {
1224 if (checkUriPermission(uri, pid, uid, modeFlags,
1225 userId) != PackageManager.PERMISSION_GRANTED) {
Sudheer Shankab4e2ddd2017-02-03 15:15:57 -08001226 boolean allow = false;
1227 if (mContext.checkCallingOrSelfPermission(
1228 Manifest.permission.INTERACT_ACROSS_USERS_FULL)
1229 == PackageManager.PERMISSION_GRANTED) {
1230 allow = true;
1231 } else if (allowNonFull && mContext.checkCallingOrSelfPermission(
1232 Manifest.permission.INTERACT_ACROSS_USERS)
1233 == PackageManager.PERMISSION_GRANTED) {
1234 allow = true;
1235 }
1236 if (!allow) {
1237 final String permissions = allowNonFull
1238 ? (Manifest.permission.INTERACT_ACROSS_USERS_FULL + " or " +
1239 Manifest.permission.INTERACT_ACROSS_USERS)
1240 : Manifest.permission.INTERACT_ACROSS_USERS_FULL;
1241 throw new SecurityException(TAG + "Neither user " + uid
1242 + " nor current process has " + permissions);
1243 }
Jeff Sharkey923e0b82016-11-16 17:22:48 -07001244 }
1245 }
1246
1247 return userId;
1248 }
1249
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001250 /**
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +01001251 * Checks if the request is from the system or an app that has INTERACT_ACROSS_USERS_FULL
1252 * permission, if the userHandle is not for the caller.
1253 *
1254 * @param userHandle the user handle of the user we want to act on behalf of.
1255 * @param message the message to log on security exception.
1256 */
1257 private void enforceCrossUserPermission(int userHandle, String message) {
1258 final int callingUser = UserHandle.getCallingUserId();
1259 if (callingUser != userHandle) {
1260 mContext.enforceCallingOrSelfPermission(
1261 Manifest.permission.INTERACT_ACROSS_USERS_FULL, message);
1262 }
1263 }
1264
Svet Ganov96b9c752016-10-17 19:29:58 -07001265 private static int normalizeSyncable(int syncable) {
1266 if (syncable > 0) {
1267 return SyncStorageEngine.AuthorityInfo.SYNCABLE;
1268 } else if (syncable == 0) {
1269 return SyncStorageEngine.AuthorityInfo.NOT_SYNCABLE;
1270 }
1271 return SyncStorageEngine.AuthorityInfo.UNDEFINED;
1272 }
1273
Makoto Onuki61283ec2018-01-31 17:22:36 -08001274 private void validateExtras(int callingUid, Bundle extras) {
Makoto Onuki75ad2492018-03-28 14:42:42 -07001275 if (extras.containsKey(ContentResolver.SYNC_VIRTUAL_EXTRAS_EXEMPTION_FLAG)) {
Makoto Onuki61283ec2018-01-31 17:22:36 -08001276 switch (callingUid) {
1277 case Process.ROOT_UID:
1278 case Process.SHELL_UID:
1279 case Process.SYSTEM_UID:
1280 break; // Okay
1281 default:
Makoto Onuki37a3e862018-04-30 14:50:43 -07001282 final String msg = "Invalid extras specified.";
1283 Log.w(TAG, msg + " requestsync -f/-F needs to run on 'adb shell'");
1284 throw new SecurityException(msg);
Makoto Onuki61283ec2018-01-31 17:22:36 -08001285 }
1286 }
1287 }
1288
Makoto Onuki75ad2492018-03-28 14:42:42 -07001289 @SyncExemption
1290 private int getSyncExemptionForCaller(int callingUid) {
1291 return getSyncExemptionAndCleanUpExtrasForCaller(callingUid, null);
Makoto Onuki61283ec2018-01-31 17:22:36 -08001292 }
1293
Makoto Onuki75ad2492018-03-28 14:42:42 -07001294 @SyncExemption
1295 private int getSyncExemptionAndCleanUpExtrasForCaller(int callingUid, Bundle extras) {
1296 if (extras != null) {
1297 final int exemption =
1298 extras.getInt(ContentResolver.SYNC_VIRTUAL_EXTRAS_EXEMPTION_FLAG, -1);
1299
1300 // Need to remove the virtual extra.
1301 extras.remove(ContentResolver.SYNC_VIRTUAL_EXTRAS_EXEMPTION_FLAG);
1302 if (exemption != -1) {
1303 return exemption;
1304 }
Makoto Onuki61283ec2018-01-31 17:22:36 -08001305 }
1306 final ActivityManagerInternal ami =
1307 LocalServices.getService(ActivityManagerInternal.class);
Makoto Onuki75ad2492018-03-28 14:42:42 -07001308 final int procState = (ami != null)
1309 ? ami.getUidProcessState(callingUid)
1310 : ActivityManager.PROCESS_STATE_NONEXISTENT;
1311
1312 if (procState <= ActivityManager.PROCESS_STATE_TOP) {
1313 return ContentResolver.SYNC_EXEMPTION_ACTIVE_WITH_TEMP;
Makoto Onuki61283ec2018-01-31 17:22:36 -08001314 }
Makoto Onuki75ad2492018-03-28 14:42:42 -07001315 if (procState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
1316 return ContentResolver.SYNC_EXEMPTION_ACTIVE;
1317 }
1318 return ContentResolver.SYNC_EXEMPTION_NONE;
Makoto Onuki61283ec2018-01-31 17:22:36 -08001319 }
1320
Alexandra Gherghina0363c3e2014-06-23 13:34:59 +01001321 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001322 * Hide this class since it is not part of api,
1323 * but current unittest framework requires it to be public
1324 * @hide
1325 */
1326 public static final class ObserverNode {
1327 private class ObserverEntry implements IBinder.DeathRecipient {
Fred Quintana002ffad52010-03-02 11:18:16 -08001328 public final IContentObserver observer;
Dianne Hackborn1b64e0d2011-07-17 15:23:59 -07001329 public final int uid;
1330 public final int pid;
Christopher Tate16aa9732012-09-17 16:23:44 -07001331 public final boolean notifyForDescendants;
1332 private final int userHandle;
Fred Quintana002ffad52010-03-02 11:18:16 -08001333 private final Object observersLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001334
Dianne Hackborn1b64e0d2011-07-17 15:23:59 -07001335 public ObserverEntry(IContentObserver o, boolean n, Object observersLock,
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001336 int _uid, int _pid, int _userHandle) {
Fred Quintana002ffad52010-03-02 11:18:16 -08001337 this.observersLock = observersLock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001338 observer = o;
Dianne Hackborn1b64e0d2011-07-17 15:23:59 -07001339 uid = _uid;
1340 pid = _pid;
Christopher Tate16aa9732012-09-17 16:23:44 -07001341 userHandle = _userHandle;
1342 notifyForDescendants = n;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001343 try {
1344 observer.asBinder().linkToDeath(this, 0);
1345 } catch (RemoteException e) {
1346 binderDied();
1347 }
1348 }
1349
Jeff Sharkeya04c7a72016-03-18 12:20:36 -06001350 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001351 public void binderDied() {
Fred Quintana002ffad52010-03-02 11:18:16 -08001352 synchronized (observersLock) {
1353 removeObserverLocked(observer);
1354 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001355 }
Dianne Hackborn1b64e0d2011-07-17 15:23:59 -07001356
1357 public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001358 String name, String prefix, SparseIntArray pidCounts) {
Dianne Hackborn1b64e0d2011-07-17 15:23:59 -07001359 pidCounts.put(pid, pidCounts.get(pid)+1);
1360 pw.print(prefix); pw.print(name); pw.print(": pid=");
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001361 pw.print(pid); pw.print(" uid=");
1362 pw.print(uid); pw.print(" user=");
1363 pw.print(userHandle); pw.print(" target=");
1364 pw.println(Integer.toHexString(System.identityHashCode(
1365 observer != null ? observer.asBinder() : null)));
Dianne Hackborn1b64e0d2011-07-17 15:23:59 -07001366 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001367 }
1368
1369 public static final int INSERT_TYPE = 0;
1370 public static final int UPDATE_TYPE = 1;
1371 public static final int DELETE_TYPE = 2;
1372
1373 private String mName;
1374 private ArrayList<ObserverNode> mChildren = new ArrayList<ObserverNode>();
1375 private ArrayList<ObserverEntry> mObservers = new ArrayList<ObserverEntry>();
1376
1377 public ObserverNode(String name) {
1378 mName = name;
1379 }
1380
Dianne Hackborn1b64e0d2011-07-17 15:23:59 -07001381 public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001382 String name, String prefix, int[] counts, SparseIntArray pidCounts) {
Dianne Hackborn1b64e0d2011-07-17 15:23:59 -07001383 String innerName = null;
1384 if (mObservers.size() > 0) {
1385 if ("".equals(name)) {
1386 innerName = mName;
1387 } else {
1388 innerName = name + "/" + mName;
1389 }
1390 for (int i=0; i<mObservers.size(); i++) {
1391 counts[1]++;
1392 mObservers.get(i).dumpLocked(fd, pw, args, innerName, prefix,
1393 pidCounts);
1394 }
1395 }
1396 if (mChildren.size() > 0) {
1397 if (innerName == null) {
1398 if ("".equals(name)) {
1399 innerName = mName;
1400 } else {
1401 innerName = name + "/" + mName;
1402 }
1403 }
1404 for (int i=0; i<mChildren.size(); i++) {
1405 counts[0]++;
1406 mChildren.get(i).dumpLocked(fd, pw, args, innerName, prefix,
1407 counts, pidCounts);
1408 }
1409 }
1410 }
1411
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001412 private String getUriSegment(Uri uri, int index) {
1413 if (uri != null) {
1414 if (index == 0) {
1415 return uri.getAuthority();
1416 } else {
1417 return uri.getPathSegments().get(index - 1);
1418 }
1419 } else {
1420 return null;
1421 }
1422 }
1423
1424 private int countUriSegments(Uri uri) {
1425 if (uri == null) {
1426 return 0;
1427 }
1428 return uri.getPathSegments().size() + 1;
1429 }
1430
Christopher Tate16aa9732012-09-17 16:23:44 -07001431 // Invariant: userHandle is either a hard user number or is USER_ALL
Fred Quintana002ffad52010-03-02 11:18:16 -08001432 public void addObserverLocked(Uri uri, IContentObserver observer,
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001433 boolean notifyForDescendants, Object observersLock,
1434 int uid, int pid, int userHandle) {
Christopher Tate16aa9732012-09-17 16:23:44 -07001435 addObserverLocked(uri, 0, observer, notifyForDescendants, observersLock,
1436 uid, pid, userHandle);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001437 }
1438
Fred Quintana002ffad52010-03-02 11:18:16 -08001439 private void addObserverLocked(Uri uri, int index, IContentObserver observer,
Shreyas Basarge8c834c02016-01-07 13:53:16 +00001440 boolean notifyForDescendants, Object observersLock,
1441 int uid, int pid, int userHandle) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001442 // If this is the leaf node add the observer
1443 if (index == countUriSegments(uri)) {
Christopher Tate16aa9732012-09-17 16:23:44 -07001444 mObservers.add(new ObserverEntry(observer, notifyForDescendants, observersLock,
1445 uid, pid, userHandle));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001446 return;
1447 }
1448
1449 // Look to see if the proper child already exists
1450 String segment = getUriSegment(uri, index);
Anthony Newnamf5126642010-03-22 17:29:06 -05001451 if (segment == null) {
1452 throw new IllegalArgumentException("Invalid Uri (" + uri + ") used for observer");
1453 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001454 int N = mChildren.size();
1455 for (int i = 0; i < N; i++) {
1456 ObserverNode node = mChildren.get(i);
1457 if (node.mName.equals(segment)) {
Christopher Tate16aa9732012-09-17 16:23:44 -07001458 node.addObserverLocked(uri, index + 1, observer, notifyForDescendants,
1459 observersLock, uid, pid, userHandle);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001460 return;
1461 }
1462 }
1463
1464 // No child found, create one
1465 ObserverNode node = new ObserverNode(segment);
1466 mChildren.add(node);
Christopher Tate16aa9732012-09-17 16:23:44 -07001467 node.addObserverLocked(uri, index + 1, observer, notifyForDescendants,
1468 observersLock, uid, pid, userHandle);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001469 }
1470
Fred Quintana002ffad52010-03-02 11:18:16 -08001471 public boolean removeObserverLocked(IContentObserver observer) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001472 int size = mChildren.size();
1473 for (int i = 0; i < size; i++) {
Fred Quintana002ffad52010-03-02 11:18:16 -08001474 boolean empty = mChildren.get(i).removeObserverLocked(observer);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001475 if (empty) {
1476 mChildren.remove(i);
1477 i--;
1478 size--;
1479 }
1480 }
1481
1482 IBinder observerBinder = observer.asBinder();
1483 size = mObservers.size();
1484 for (int i = 0; i < size; i++) {
1485 ObserverEntry entry = mObservers.get(i);
1486 if (entry.observer.asBinder() == observerBinder) {
1487 mObservers.remove(i);
1488 // We no longer need to listen for death notifications. Remove it.
1489 observerBinder.unlinkToDeath(entry, 0);
1490 break;
1491 }
1492 }
1493
1494 if (mChildren.size() == 0 && mObservers.size() == 0) {
1495 return true;
1496 }
1497 return false;
1498 }
1499
Fred Quintana002ffad52010-03-02 11:18:16 -08001500 private void collectMyObserversLocked(boolean leaf, IContentObserver observer,
Dianne Hackborn141f11c2016-04-05 15:46:12 -07001501 boolean observerWantsSelfNotifications, int flags,
1502 int targetUserHandle, ArrayList<ObserverCall> calls) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001503 int N = mObservers.size();
1504 IBinder observerBinder = observer == null ? null : observer.asBinder();
1505 for (int i = 0; i < N; i++) {
1506 ObserverEntry entry = mObservers.get(i);
1507
Christopher Tate16aa9732012-09-17 16:23:44 -07001508 // Don't notify the observer if it sent the notification and isn't interested
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001509 // in self notifications
Jeff Brown86de0592012-01-23 13:01:18 -08001510 boolean selfChange = (entry.observer.asBinder() == observerBinder);
1511 if (selfChange && !observerWantsSelfNotifications) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001512 continue;
1513 }
1514
Christopher Tate16aa9732012-09-17 16:23:44 -07001515 // Does this observer match the target user?
1516 if (targetUserHandle == UserHandle.USER_ALL
1517 || entry.userHandle == UserHandle.USER_ALL
1518 || targetUserHandle == entry.userHandle) {
1519 // Make sure the observer is interested in the notification
Dianne Hackborn141f11c2016-04-05 15:46:12 -07001520 if (leaf) {
1521 // If we are at the leaf: we always report, unless the sender has asked
1522 // to skip observers that are notifying for descendants (since they will
1523 // be sending another more specific URI for them).
1524 if ((flags&ContentResolver.NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS) != 0
1525 && entry.notifyForDescendants) {
1526 if (DEBUG) Slog.d(TAG, "Skipping " + entry.observer
1527 + ": skip notify for descendants");
1528 continue;
1529 }
1530 } else {
1531 // If we are not at the leaf: we report if the observer says it wants
1532 // to be notified for all descendants.
1533 if (!entry.notifyForDescendants) {
1534 if (DEBUG) Slog.d(TAG, "Skipping " + entry.observer
1535 + ": not monitor descendants");
1536 continue;
1537 }
Christopher Tate16aa9732012-09-17 16:23:44 -07001538 }
Dianne Hackborn141f11c2016-04-05 15:46:12 -07001539 if (DEBUG) Slog.d(TAG, "Reporting to " + entry.observer + ": leaf=" + leaf
1540 + " flags=" + Integer.toHexString(flags)
1541 + " desc=" + entry.notifyForDescendants);
Nicolas Prevot051f3b72016-05-18 18:44:00 +01001542 calls.add(new ObserverCall(this, entry.observer, selfChange,
1543 UserHandle.getUserId(entry.uid)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001544 }
1545 }
1546 }
1547
Christopher Tate16aa9732012-09-17 16:23:44 -07001548 /**
1549 * targetUserHandle is either a hard user handle or is USER_ALL
1550 */
Fred Quintana002ffad52010-03-02 11:18:16 -08001551 public void collectObserversLocked(Uri uri, int index, IContentObserver observer,
Dianne Hackborn141f11c2016-04-05 15:46:12 -07001552 boolean observerWantsSelfNotifications, int flags,
1553 int targetUserHandle, ArrayList<ObserverCall> calls) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001554 String segment = null;
1555 int segmentCount = countUriSegments(uri);
1556 if (index >= segmentCount) {
1557 // This is the leaf node, notify all observers
Dianne Hackborn141f11c2016-04-05 15:46:12 -07001558 if (DEBUG) Slog.d(TAG, "Collecting leaf observers @ #" + index + ", node " + mName);
Christopher Tate16aa9732012-09-17 16:23:44 -07001559 collectMyObserversLocked(true, observer, observerWantsSelfNotifications,
Dianne Hackborn141f11c2016-04-05 15:46:12 -07001560 flags, targetUserHandle, calls);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001561 } else if (index < segmentCount){
1562 segment = getUriSegment(uri, index);
Dianne Hackborn141f11c2016-04-05 15:46:12 -07001563 if (DEBUG) Slog.d(TAG, "Collecting non-leaf observers @ #" + index + " / "
1564 + segment);
Christopher Tate16aa9732012-09-17 16:23:44 -07001565 // Notify any observers at this level who are interested in descendants
1566 collectMyObserversLocked(false, observer, observerWantsSelfNotifications,
Dianne Hackborn141f11c2016-04-05 15:46:12 -07001567 flags, targetUserHandle, calls);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001568 }
1569
1570 int N = mChildren.size();
1571 for (int i = 0; i < N; i++) {
1572 ObserverNode node = mChildren.get(i);
1573 if (segment == null || node.mName.equals(segment)) {
1574 // We found the child,
Dianne Hackborn141f11c2016-04-05 15:46:12 -07001575 node.collectObserversLocked(uri, index + 1, observer,
1576 observerWantsSelfNotifications, flags, targetUserHandle, calls);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001577 if (segment != null) {
1578 break;
1579 }
1580 }
1581 }
1582 }
1583 }
Makoto Onuki94986212018-04-11 16:24:46 -07001584
1585 private void enforceShell(String method) {
1586 final int callingUid = Binder.getCallingUid();
1587 if (callingUid != Process.SHELL_UID && callingUid != Process.ROOT_UID) {
1588 throw new SecurityException("Non-shell user attempted to call " + method);
1589 }
1590 }
1591
1592 @Override
1593 public void resetTodayStats() {
1594 enforceShell("resetTodayStats");
1595
1596 if (mSyncManager != null) {
1597 final long token = Binder.clearCallingIdentity();
1598 try {
1599 mSyncManager.resetTodayStats();
1600 } finally {
1601 Binder.restoreCallingIdentity(token);
1602 }
1603 }
1604 }
1605
1606 @Override
1607 public void onShellCommand(FileDescriptor in, FileDescriptor out,
1608 FileDescriptor err, String[] args, ShellCallback callback,
1609 ResultReceiver resultReceiver) {
1610 (new ContentShellCommand(this)).exec(this, in, out, err, args, callback, resultReceiver);
1611 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001612}