blob: 73775b4387b95451227be38f7969c523b0b9ea28 [file] [log] [blame]
Jason Monk8f5f7ff2017-10-17 14:12:42 -04001/*
2 * Copyright (C) 2017 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
17package com.android.server.slice;
18
Jason Monk1918ef72018-03-14 09:20:39 -040019import static android.app.usage.UsageEvents.Event.SLICE_PINNED;
20import static android.app.usage.UsageEvents.Event.SLICE_PINNED_PRIV;
Jason Monke8f8be72018-01-21 10:10:35 -050021import static android.content.ContentProvider.getUriWithoutUserId;
Jason Monk74f5e362017-12-06 08:56:33 -050022import static android.content.ContentProvider.getUserIdFromUri;
23import static android.content.ContentProvider.maybeAddUserId;
Jason Monk3a1d2e972018-01-29 16:58:11 -050024import static android.content.pm.PackageManager.PERMISSION_DENIED;
25import static android.content.pm.PackageManager.PERMISSION_GRANTED;
Jason Monkb715b042018-02-01 15:00:05 -050026import static android.os.Process.SYSTEM_UID;
Jason Monk8f5f7ff2017-10-17 14:12:42 -040027
Jason Monk74f5e362017-12-06 08:56:33 -050028import android.Manifest.permission;
Jason Monke8f8be72018-01-21 10:10:35 -050029import android.app.ActivityManager;
Jason Monk74f5e362017-12-06 08:56:33 -050030import android.app.AppOpsManager;
Jason Monke8f8be72018-01-21 10:10:35 -050031import android.app.ContentProviderHolder;
32import android.app.IActivityManager;
Jason Monk74f5e362017-12-06 08:56:33 -050033import android.app.slice.ISliceManager;
34import android.app.slice.SliceSpec;
Jason Monk1918ef72018-03-14 09:20:39 -040035import android.app.usage.UsageStatsManagerInternal;
Jason Monk68ff6aa2018-01-31 15:51:52 -050036import android.content.BroadcastReceiver;
Jason Monk74f5e362017-12-06 08:56:33 -050037import android.content.ComponentName;
Jason Monkbf3eedc2018-04-05 20:56:42 -040038import android.content.ContentProvider;
Jason Monk7f01f3b2018-05-15 15:46:26 -040039import android.content.ContentResolver;
Jason Monk74f5e362017-12-06 08:56:33 -050040import android.content.Context;
41import android.content.Intent;
Jason Monk68ff6aa2018-01-31 15:51:52 -050042import android.content.IntentFilter;
Jason Monkbf3eedc2018-04-05 20:56:42 -040043import android.content.pm.PackageManager;
Jason Monk74f5e362017-12-06 08:56:33 -050044import android.content.pm.PackageManagerInternal;
Jason Monk664af782018-07-03 11:21:57 -040045import android.content.pm.ProviderInfo;
Jason Monk74f5e362017-12-06 08:56:33 -050046import android.content.pm.ResolveInfo;
Jason Monk74f5e362017-12-06 08:56:33 -050047import android.net.Uri;
48import android.os.Binder;
49import android.os.Handler;
Jason Monke8f8be72018-01-21 10:10:35 -050050import android.os.IBinder;
Jason Monk74f5e362017-12-06 08:56:33 -050051import android.os.Looper;
52import android.os.Process;
53import android.os.RemoteException;
Jason Monk7f01f3b2018-05-15 15:46:26 -040054import android.os.ResultReceiver;
55import android.os.ShellCallback;
Jason Monk3a1d2e972018-01-29 16:58:11 -050056import android.os.UserHandle;
Jason Monk74f5e362017-12-06 08:56:33 -050057import android.util.ArrayMap;
Jason Monkddb8a962018-01-30 13:27:33 -050058import android.util.Slog;
Jason Monke009a8e2018-05-21 13:36:21 -040059import android.util.SparseArray;
Jason Monkddb8a962018-01-30 13:27:33 -050060import android.util.Xml.Encoding;
Jason Monk74f5e362017-12-06 08:56:33 -050061
62import com.android.internal.annotations.GuardedBy;
63import com.android.internal.annotations.VisibleForTesting;
64import com.android.internal.app.AssistUtils;
65import com.android.internal.util.Preconditions;
66import com.android.server.LocalServices;
67import com.android.server.ServiceThread;
Jason Monk8f5f7ff2017-10-17 14:12:42 -040068import com.android.server.SystemService;
69
Jason Monkddb8a962018-01-30 13:27:33 -050070import org.xmlpull.v1.XmlPullParser;
71import org.xmlpull.v1.XmlPullParserException;
72import org.xmlpull.v1.XmlPullParserFactory;
73import org.xmlpull.v1.XmlSerializer;
74
Jason Monkb715b042018-02-01 15:00:05 -050075import java.io.ByteArrayInputStream;
76import java.io.ByteArrayOutputStream;
Jason Monk7f01f3b2018-05-15 15:46:26 -040077import java.io.FileDescriptor;
Jason Monkddb8a962018-01-30 13:27:33 -050078import java.io.IOException;
Jason Monk74f5e362017-12-06 08:56:33 -050079import java.util.ArrayList;
80import java.util.List;
81import java.util.Objects;
Jason Monke009a8e2018-05-21 13:36:21 -040082import java.util.function.Supplier;
Jason Monk74f5e362017-12-06 08:56:33 -050083
Jason Monk8f5f7ff2017-10-17 14:12:42 -040084public class SliceManagerService extends ISliceManager.Stub {
85
Jason Monk74f5e362017-12-06 08:56:33 -050086 private static final String TAG = "SliceManagerService";
87 private final Object mLock = new Object();
Jason Monk8f5f7ff2017-10-17 14:12:42 -040088
Jason Monk74f5e362017-12-06 08:56:33 -050089 private final Context mContext;
90 private final PackageManagerInternal mPackageManagerInternal;
91 private final AppOpsManager mAppOps;
92 private final AssistUtils mAssistUtils;
93
94 @GuardedBy("mLock")
95 private final ArrayMap<Uri, PinnedSliceState> mPinnedSlicesByUri = new ArrayMap<>();
Jason Monke009a8e2018-05-21 13:36:21 -040096 @GuardedBy("mLock")
97 private final SparseArray<PackageMatchingCache> mAssistantLookup = new SparseArray<>();
98 @GuardedBy("mLock")
99 private final SparseArray<PackageMatchingCache> mHomeLookup = new SparseArray<>();
Jason Monk74f5e362017-12-06 08:56:33 -0500100 private final Handler mHandler;
Jason Monkbf3eedc2018-04-05 20:56:42 -0400101
102 private final SlicePermissionManager mPermissions;
Jason Monk1918ef72018-03-14 09:20:39 -0400103 private final UsageStatsManagerInternal mAppUsageStats;
Jason Monk74f5e362017-12-06 08:56:33 -0500104
105 public SliceManagerService(Context context) {
106 this(context, createHandler().getLooper());
Jason Monk8f5f7ff2017-10-17 14:12:42 -0400107 }
108
Jason Monk74f5e362017-12-06 08:56:33 -0500109 @VisibleForTesting
110 SliceManagerService(Context context, Looper looper) {
111 mContext = context;
112 mPackageManagerInternal = Preconditions.checkNotNull(
113 LocalServices.getService(PackageManagerInternal.class));
114 mAppOps = context.getSystemService(AppOpsManager.class);
115 mAssistUtils = new AssistUtils(context);
116 mHandler = new Handler(looper);
117
Jason Monk1918ef72018-03-14 09:20:39 -0400118 mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
Jason Monkddb8a962018-01-30 13:27:33 -0500119
Jason Monkbf3eedc2018-04-05 20:56:42 -0400120 mPermissions = new SlicePermissionManager(mContext, looper);
Jason Monk68ff6aa2018-01-31 15:51:52 -0500121
122 IntentFilter filter = new IntentFilter();
123 filter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED);
124 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
125 filter.addDataScheme("package");
126 mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
Jason Monk74f5e362017-12-06 08:56:33 -0500127 }
128
129 /// ----- Lifecycle stuff -----
Jason Monk8f5f7ff2017-10-17 14:12:42 -0400130 private void systemReady() {
131 }
132
Jason Monk74f5e362017-12-06 08:56:33 -0500133 private void onUnlockUser(int userId) {
134 }
135
136 private void onStopUser(int userId) {
137 synchronized (mLock) {
138 mPinnedSlicesByUri.values().removeIf(s -> getUserIdFromUri(s.getUri()) == userId);
139 }
140 }
141
142 /// ----- ISliceManager stuff -----
143 @Override
Jason Monkf88d25e2018-03-06 20:13:24 -0500144 public Uri[] getPinnedSlices(String pkg) {
145 verifyCaller(pkg);
Jason Monk199286b2018-04-12 19:47:50 -0400146 int callingUser = Binder.getCallingUserHandle().getIdentifier();
Jason Monkf88d25e2018-03-06 20:13:24 -0500147 ArrayList<Uri> ret = new ArrayList<>();
148 synchronized (mLock) {
149 for (PinnedSliceState state : mPinnedSlicesByUri.values()) {
150 if (Objects.equals(pkg, state.getPkg())) {
Jason Monk199286b2018-04-12 19:47:50 -0400151 Uri uri = state.getUri();
152 int userId = ContentProvider.getUserIdFromUri(uri, callingUser);
153 if (userId == callingUser) {
154 ret.add(ContentProvider.getUriWithoutUserId(uri));
155 }
Jason Monkf88d25e2018-03-06 20:13:24 -0500156 }
157 }
158 }
159 return ret.toArray(new Uri[ret.size()]);
160 }
161
162 @Override
Jason Monk42e03f82018-03-30 11:26:56 -0400163 public void pinSlice(String pkg, Uri uri, SliceSpec[] specs, IBinder token)
164 throws RemoteException {
Jason Monk74f5e362017-12-06 08:56:33 -0500165 verifyCaller(pkg);
Jason Monk38df2802018-02-22 19:28:12 -0500166 enforceAccess(pkg, uri);
Jason Monk1918ef72018-03-14 09:20:39 -0400167 int user = Binder.getCallingUserHandle().getIdentifier();
168 uri = maybeAddUserId(uri, user);
Jason Monk397f6d82018-04-24 17:01:11 -0400169 String slicePkg = getProviderPkg(uri, user);
170 getOrCreatePinnedSlice(uri, slicePkg).pin(pkg, specs, token);
Jason Monk1918ef72018-03-14 09:20:39 -0400171
Jason Monk1918ef72018-03-14 09:20:39 -0400172 mHandler.post(() -> {
Jason Monk1918ef72018-03-14 09:20:39 -0400173 if (slicePkg != null && !Objects.equals(pkg, slicePkg)) {
174 mAppUsageStats.reportEvent(slicePkg, user,
175 isAssistant(pkg, user) || isDefaultHomeApp(pkg, user)
176 ? SLICE_PINNED_PRIV : SLICE_PINNED);
177 }
178 });
Jason Monk74f5e362017-12-06 08:56:33 -0500179 }
180
181 @Override
Jason Monk38df2802018-02-22 19:28:12 -0500182 public void unpinSlice(String pkg, Uri uri, IBinder token) throws RemoteException {
Jason Monk74f5e362017-12-06 08:56:33 -0500183 verifyCaller(pkg);
Jason Monk38df2802018-02-22 19:28:12 -0500184 enforceAccess(pkg, uri);
Jason Monk74f5e362017-12-06 08:56:33 -0500185 uri = maybeAddUserId(uri, Binder.getCallingUserHandle().getIdentifier());
Jason Monk38df2802018-02-22 19:28:12 -0500186 if (getPinnedSlice(uri).unpin(pkg, token)) {
Jason Monk74f5e362017-12-06 08:56:33 -0500187 removePinnedSlice(uri);
188 }
189 }
190
191 @Override
192 public boolean hasSliceAccess(String pkg) throws RemoteException {
193 verifyCaller(pkg);
194 return hasFullSliceAccess(pkg, Binder.getCallingUserHandle().getIdentifier());
195 }
196
197 @Override
198 public SliceSpec[] getPinnedSpecs(Uri uri, String pkg) throws RemoteException {
199 verifyCaller(pkg);
200 enforceAccess(pkg, uri);
Jason Monk4f645cc2018-06-22 16:01:55 -0400201 uri = maybeAddUserId(uri, Binder.getCallingUserHandle().getIdentifier());
Jason Monk74f5e362017-12-06 08:56:33 -0500202 return getPinnedSlice(uri).getSpecs();
203 }
204
Jason Monke8f8be72018-01-21 10:10:35 -0500205 @Override
Jason Monkbf3eedc2018-04-05 20:56:42 -0400206 public void grantSlicePermission(String pkg, String toPkg, Uri uri) throws RemoteException {
207 verifyCaller(pkg);
208 int user = Binder.getCallingUserHandle().getIdentifier();
209 enforceOwner(pkg, uri, user);
210 mPermissions.grantSliceAccess(toPkg, user, pkg, user, uri);
211 }
212
213 @Override
214 public void revokeSlicePermission(String pkg, String toPkg, Uri uri) throws RemoteException {
215 verifyCaller(pkg);
216 int user = Binder.getCallingUserHandle().getIdentifier();
217 enforceOwner(pkg, uri, user);
218 mPermissions.revokeSliceAccess(toPkg, user, pkg, user, uri);
219 }
220
221 @Override
Jason Monkfe4885e2018-07-23 13:31:30 -0400222 public int checkSlicePermission(Uri uri, String callingPkg, String pkg, int pid, int uid,
Jason Monkbf3eedc2018-04-05 20:56:42 -0400223 String[] autoGrantPermissions) {
224 int userId = UserHandle.getUserId(uid);
225 if (pkg == null) {
226 for (String p : mContext.getPackageManager().getPackagesForUid(uid)) {
Jason Monkfe4885e2018-07-23 13:31:30 -0400227 if (checkSlicePermission(uri, callingPkg, p, pid, uid, autoGrantPermissions)
Jason Monkbf3eedc2018-04-05 20:56:42 -0400228 == PERMISSION_GRANTED) {
229 return PERMISSION_GRANTED;
230 }
231 }
232 return PERMISSION_DENIED;
233 }
234 if (hasFullSliceAccess(pkg, userId)) {
235 return PackageManager.PERMISSION_GRANTED;
236 }
237 if (mPermissions.hasPermission(pkg, userId, uri)) {
238 return PackageManager.PERMISSION_GRANTED;
239 }
Jason Monkfe4885e2018-07-23 13:31:30 -0400240 if (autoGrantPermissions != null && callingPkg != null) {
Jason Monkbf3eedc2018-04-05 20:56:42 -0400241 // Need to own the Uri to call in with permissions to grant.
Jason Monkfe4885e2018-07-23 13:31:30 -0400242 enforceOwner(callingPkg, uri, userId);
Jason Monkbf3eedc2018-04-05 20:56:42 -0400243 for (String perm : autoGrantPermissions) {
244 if (mContext.checkPermission(perm, pid, uid) == PERMISSION_GRANTED) {
245 int providerUser = ContentProvider.getUserIdFromUri(uri, userId);
246 String providerPkg = getProviderPkg(uri, providerUser);
247 mPermissions.grantSliceAccess(pkg, userId, providerPkg, providerUser, uri);
248 return PackageManager.PERMISSION_GRANTED;
249 }
250 }
251 }
252 // Fallback to allowing uri permissions through.
Jason Monke8f8be72018-01-21 10:10:35 -0500253 if (mContext.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
Jason Monk3a1d2e972018-01-29 16:58:11 -0500254 == PERMISSION_GRANTED) {
Jason Monkbf3eedc2018-04-05 20:56:42 -0400255 return PackageManager.PERMISSION_GRANTED;
Jason Monke8f8be72018-01-21 10:10:35 -0500256 }
Jason Monkbf3eedc2018-04-05 20:56:42 -0400257 return PackageManager.PERMISSION_DENIED;
Jason Monke8f8be72018-01-21 10:10:35 -0500258 }
259
260 @Override
261 public void grantPermissionFromUser(Uri uri, String pkg, String callingPkg, boolean allSlices) {
262 verifyCaller(callingPkg);
263 getContext().enforceCallingOrSelfPermission(permission.MANAGE_SLICE_PERMISSIONS,
264 "Slice granting requires MANAGE_SLICE_PERMISSIONS");
Jason Monkbf3eedc2018-04-05 20:56:42 -0400265 int userId = Binder.getCallingUserHandle().getIdentifier();
Jason Monke8f8be72018-01-21 10:10:35 -0500266 if (allSlices) {
Jason Monkbf3eedc2018-04-05 20:56:42 -0400267 mPermissions.grantFullAccess(pkg, userId);
Jason Monke8f8be72018-01-21 10:10:35 -0500268 } else {
Jason Monkbf3eedc2018-04-05 20:56:42 -0400269 // When granting, grant to all slices in the provider.
270 Uri grantUri = uri.buildUpon()
271 .path("")
272 .build();
273 int providerUser = ContentProvider.getUserIdFromUri(grantUri, userId);
274 String providerPkg = getProviderPkg(grantUri, providerUser);
275 mPermissions.grantSliceAccess(pkg, userId, providerPkg, providerUser, grantUri);
Jason Monkddb8a962018-01-30 13:27:33 -0500276 }
277 long ident = Binder.clearCallingIdentity();
278 try {
279 mContext.getContentResolver().notifyChange(uri, null);
280 } finally {
281 Binder.restoreCallingIdentity(ident);
Jason Monke8f8be72018-01-21 10:10:35 -0500282 }
283 }
284
Jason Monkb715b042018-02-01 15:00:05 -0500285 // Backup/restore interface
286 @Override
287 public byte[] getBackupPayload(int user) {
288 if (Binder.getCallingUid() != SYSTEM_UID) {
289 throw new SecurityException("Caller must be system");
290 }
291 //TODO: http://b/22388012
292 if (user != UserHandle.USER_SYSTEM) {
293 Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
294 return null;
295 }
Jason Monkbf3eedc2018-04-05 20:56:42 -0400296 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
297 try {
298 XmlSerializer out = XmlPullParserFactory.newInstance().newSerializer();
299 out.setOutput(baos, Encoding.UTF_8.name());
300
301 mPermissions.writeBackup(out);
302
303 out.flush();
304 return baos.toByteArray();
305 } catch (IOException | XmlPullParserException e) {
306 Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
Jason Monkb715b042018-02-01 15:00:05 -0500307 }
308 return null;
309 }
310
311 @Override
312 public void applyRestore(byte[] payload, int user) {
313 if (Binder.getCallingUid() != SYSTEM_UID) {
314 throw new SecurityException("Caller must be system");
315 }
316 if (payload == null) {
317 Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
318 return;
319 }
320 //TODO: http://b/22388012
321 if (user != UserHandle.USER_SYSTEM) {
322 Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
323 return;
324 }
Jason Monkbf3eedc2018-04-05 20:56:42 -0400325 final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
326 try {
327 XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
328 parser.setInput(bais, Encoding.UTF_8.name());
329 mPermissions.readRestore(parser);
330 } catch (NumberFormatException | XmlPullParserException | IOException e) {
331 Slog.w(TAG, "applyRestore: error reading payload", e);
Jason Monkb715b042018-02-01 15:00:05 -0500332 }
333 }
334
Jason Monk7f01f3b2018-05-15 15:46:26 -0400335 @Override
336 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
337 String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
338 new SliceShellCommand(this).exec(this, in, out, err, args, callback, resultReceiver);
339 }
340
Jason Monk74f5e362017-12-06 08:56:33 -0500341 /// ----- internal code -----
Jason Monkbf3eedc2018-04-05 20:56:42 -0400342 private void enforceOwner(String pkg, Uri uri, int user) {
343 if (!Objects.equals(getProviderPkg(uri, user), pkg) || pkg == null) {
344 throw new SecurityException("Caller must own " + uri);
Jason Monk68ff6aa2018-01-31 15:51:52 -0500345 }
Jason Monk68ff6aa2018-01-31 15:51:52 -0500346 }
347
Jason Monk9e3b8642018-01-21 20:54:00 -0500348 protected void removePinnedSlice(Uri uri) {
Jason Monk74f5e362017-12-06 08:56:33 -0500349 synchronized (mLock) {
350 mPinnedSlicesByUri.remove(uri).destroy();
351 }
352 }
353
354 private PinnedSliceState getPinnedSlice(Uri uri) {
355 synchronized (mLock) {
356 PinnedSliceState manager = mPinnedSlicesByUri.get(uri);
357 if (manager == null) {
358 throw new IllegalStateException(String.format("Slice %s not pinned",
359 uri.toString()));
360 }
361 return manager;
362 }
363 }
364
Jason Monkf88d25e2018-03-06 20:13:24 -0500365 private PinnedSliceState getOrCreatePinnedSlice(Uri uri, String pkg) {
Jason Monk74f5e362017-12-06 08:56:33 -0500366 synchronized (mLock) {
367 PinnedSliceState manager = mPinnedSlicesByUri.get(uri);
368 if (manager == null) {
Jason Monkf88d25e2018-03-06 20:13:24 -0500369 manager = createPinnedSlice(uri, pkg);
Jason Monk74f5e362017-12-06 08:56:33 -0500370 mPinnedSlicesByUri.put(uri, manager);
371 }
372 return manager;
373 }
374 }
375
376 @VisibleForTesting
Jason Monkf88d25e2018-03-06 20:13:24 -0500377 protected PinnedSliceState createPinnedSlice(Uri uri, String pkg) {
378 return new PinnedSliceState(this, uri, pkg);
Jason Monk74f5e362017-12-06 08:56:33 -0500379 }
380
381 public Object getLock() {
382 return mLock;
383 }
384
385 public Context getContext() {
386 return mContext;
387 }
388
389 public Handler getHandler() {
390 return mHandler;
391 }
392
Jason Monk3a1d2e972018-01-29 16:58:11 -0500393 protected int checkAccess(String pkg, Uri uri, int uid, int pid) {
Jason Monkfe4885e2018-07-23 13:31:30 -0400394 return checkSlicePermission(uri, null, pkg, uid, pid, null);
Jason Monk3a1d2e972018-01-29 16:58:11 -0500395 }
396
Jason Monk1918ef72018-03-14 09:20:39 -0400397 private String getProviderPkg(Uri uri, int user) {
398 long ident = Binder.clearCallingIdentity();
399 try {
Jason Monk1918ef72018-03-14 09:20:39 -0400400 String providerName = getUriWithoutUserId(uri).getAuthority();
Jason Monk664af782018-07-03 11:21:57 -0400401 ProviderInfo provider = mContext.getPackageManager().resolveContentProviderAsUser(
402 providerName, 0, getUserIdFromUri(uri, user));
403 return provider.packageName;
Jason Monk1918ef72018-03-14 09:20:39 -0400404 } finally {
Jason Monk1918ef72018-03-14 09:20:39 -0400405 Binder.restoreCallingIdentity(ident);
406 }
407 }
408
Jason Monk3a1d2e972018-01-29 16:58:11 -0500409 private void enforceCrossUser(String pkg, Uri uri) {
410 int user = Binder.getCallingUserHandle().getIdentifier();
Jason Monk74f5e362017-12-06 08:56:33 -0500411 if (getUserIdFromUri(uri, user) != user) {
412 getContext().enforceCallingOrSelfPermission(permission.INTERACT_ACROSS_USERS_FULL,
413 "Slice interaction across users requires INTERACT_ACROSS_USERS_FULL");
414 }
415 }
416
Jason Monk3a1d2e972018-01-29 16:58:11 -0500417 private void enforceAccess(String pkg, Uri uri) throws RemoteException {
418 if (checkAccess(pkg, uri, Binder.getCallingUid(), Binder.getCallingPid())
419 != PERMISSION_GRANTED) {
Jason Monkbf3eedc2018-04-05 20:56:42 -0400420 int userId = ContentProvider.getUserIdFromUri(uri,
421 Binder.getCallingUserHandle().getIdentifier());
422 if (!Objects.equals(pkg, getProviderPkg(uri, userId))) {
423 throw new SecurityException("Access to slice " + uri + " is required");
424 }
Jason Monk74f5e362017-12-06 08:56:33 -0500425 }
Jason Monk3a1d2e972018-01-29 16:58:11 -0500426 enforceCrossUser(pkg, uri);
Jason Monk74f5e362017-12-06 08:56:33 -0500427 }
428
429 private void verifyCaller(String pkg) {
430 mAppOps.checkPackage(Binder.getCallingUid(), pkg);
431 }
432
433 private boolean hasFullSliceAccess(String pkg, int userId) {
Jason Monke8f8be72018-01-21 10:10:35 -0500434 long ident = Binder.clearCallingIdentity();
435 try {
436 boolean ret = isDefaultHomeApp(pkg, userId) || isAssistant(pkg, userId)
437 || isGrantedFullAccess(pkg, userId);
438 return ret;
439 } finally {
440 Binder.restoreCallingIdentity(ident);
441 }
Jason Monk74f5e362017-12-06 08:56:33 -0500442 }
443
444 private boolean isAssistant(String pkg, int userId) {
Jason Monke009a8e2018-05-21 13:36:21 -0400445 return getAssistantMatcher(userId).matches(pkg);
Jason Monk74f5e362017-12-06 08:56:33 -0500446 }
447
Jason Monk74f5e362017-12-06 08:56:33 -0500448 private boolean isDefaultHomeApp(String pkg, int userId) {
Jason Monke009a8e2018-05-21 13:36:21 -0400449 return getHomeMatcher(userId).matches(pkg);
450 }
Jason Monke8f8be72018-01-21 10:10:35 -0500451
Jason Monke009a8e2018-05-21 13:36:21 -0400452 private PackageMatchingCache getAssistantMatcher(int userId) {
453 PackageMatchingCache matcher = mAssistantLookup.get(userId);
454 if (matcher == null) {
455 matcher = new PackageMatchingCache(() -> getAssistant(userId));
456 mAssistantLookup.put(userId, matcher);
457 }
458 return matcher;
459 }
460
461 private PackageMatchingCache getHomeMatcher(int userId) {
462 PackageMatchingCache matcher = mHomeLookup.get(userId);
463 if (matcher == null) {
464 matcher = new PackageMatchingCache(() -> getDefaultHome(userId));
465 mHomeLookup.put(userId, matcher);
466 }
467 return matcher;
468 }
469
470 private String getAssistant(int userId) {
471 final ComponentName cn = mAssistUtils.getAssistComponentForUser(userId);
472 if (cn == null) {
473 return null;
474 }
475 return cn.getPackageName();
Jason Monk74f5e362017-12-06 08:56:33 -0500476 }
477
478 // Based on getDefaultHome in ShortcutService.
479 // TODO: Unify if possible
480 @VisibleForTesting
Jason Monk74848ae2018-01-21 17:11:57 -0500481 protected String getDefaultHome(int userId) {
Jason Monk74f5e362017-12-06 08:56:33 -0500482 final long token = Binder.clearCallingIdentity();
483 try {
484 final List<ResolveInfo> allHomeCandidates = new ArrayList<>();
485
486 // Default launcher from package manager.
487 final ComponentName defaultLauncher = mPackageManagerInternal
488 .getHomeActivitiesAsUser(allHomeCandidates, userId);
489
490 ComponentName detected = null;
491 if (defaultLauncher != null) {
492 detected = defaultLauncher;
493 }
494
495 if (detected == null) {
496 // If we reach here, that means it's the first check since the user was created,
497 // and there's already multiple launchers and there's no default set.
498 // Find the system one with the highest priority.
499 // (We need to check the priority too because of FallbackHome in Settings.)
500 // If there's no system launcher yet, then no one can access slices, until
501 // the user explicitly sets one.
502 final int size = allHomeCandidates.size();
503
504 int lastPriority = Integer.MIN_VALUE;
505 for (int i = 0; i < size; i++) {
506 final ResolveInfo ri = allHomeCandidates.get(i);
507 if (!ri.activityInfo.applicationInfo.isSystemApp()) {
508 continue;
509 }
510 if (ri.priority < lastPriority) {
511 continue;
512 }
513 detected = ri.activityInfo.getComponentName();
514 lastPriority = ri.priority;
515 }
516 }
Jason Monke8f8be72018-01-21 10:10:35 -0500517 return detected != null ? detected.getPackageName() : null;
Jason Monk74f5e362017-12-06 08:56:33 -0500518 } finally {
519 Binder.restoreCallingIdentity(token);
520 }
521 }
522
523 private boolean isGrantedFullAccess(String pkg, int userId) {
Jason Monkbf3eedc2018-04-05 20:56:42 -0400524 return mPermissions.hasFullAccess(pkg, userId);
Jason Monk74f5e362017-12-06 08:56:33 -0500525 }
526
527 private static ServiceThread createHandler() {
528 ServiceThread handlerThread = new ServiceThread(TAG,
529 Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
530 handlerThread.start();
531 return handlerThread;
Jason Monk8f5f7ff2017-10-17 14:12:42 -0400532 }
533
Jason Monk68ff6aa2018-01-31 15:51:52 -0500534 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
535 @Override
536 public void onReceive(Context context, Intent intent) {
537 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
538 if (userId == UserHandle.USER_NULL) {
539 Slog.w(TAG, "Intent broadcast does not contain user handle: " + intent);
540 return;
541 }
542 Uri data = intent.getData();
543 String pkg = data != null ? data.getSchemeSpecificPart() : null;
544 if (pkg == null) {
545 Slog.w(TAG, "Intent broadcast does not contain package name: " + intent);
546 return;
547 }
548 switch (intent.getAction()) {
549 case Intent.ACTION_PACKAGE_REMOVED:
550 final boolean replacing =
551 intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
552 if (!replacing) {
Jason Monkbf3eedc2018-04-05 20:56:42 -0400553 mPermissions.removePkg(pkg, userId);
Jason Monk68ff6aa2018-01-31 15:51:52 -0500554 }
555 break;
556 case Intent.ACTION_PACKAGE_DATA_CLEARED:
Jason Monkbf3eedc2018-04-05 20:56:42 -0400557 mPermissions.removePkg(pkg, userId);
Jason Monk68ff6aa2018-01-31 15:51:52 -0500558 break;
559 }
560 }
561 };
562
Jason Monk7f01f3b2018-05-15 15:46:26 -0400563 public String[] getAllPackagesGranted(String authority) {
564 String pkg = getProviderPkg(new Uri.Builder()
565 .scheme(ContentResolver.SCHEME_CONTENT)
566 .authority(authority)
567 .build(), 0);
568 return mPermissions.getAllPackagesGranted(pkg);
569 }
570
Jason Monke009a8e2018-05-21 13:36:21 -0400571 /**
572 * Holder that caches a package that has access to a slice.
573 */
574 static class PackageMatchingCache {
575
576 private final Supplier<String> mPkgSource;
577 private String mCurrentPkg;
578
579 public PackageMatchingCache(Supplier<String> pkgSource) {
580 mPkgSource = pkgSource;
581 }
582
583 public boolean matches(String pkgCandidate) {
584 if (pkgCandidate == null) return false;
585
586 if (Objects.equals(pkgCandidate, mCurrentPkg)) {
587 return true;
588 }
589 // Failed on cached value, try updating.
590 mCurrentPkg = mPkgSource.get();
591 return Objects.equals(pkgCandidate, mCurrentPkg);
592 }
593 }
594
Jason Monk8f5f7ff2017-10-17 14:12:42 -0400595 public static class Lifecycle extends SystemService {
596 private SliceManagerService mService;
597
598 public Lifecycle(Context context) {
599 super(context);
600 }
601
602 @Override
603 public void onStart() {
604 mService = new SliceManagerService(getContext());
605 publishBinderService(Context.SLICE_SERVICE, mService);
606 }
607
608 @Override
609 public void onBootPhase(int phase) {
610 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
611 mService.systemReady();
612 }
613 }
614
615 @Override
616 public void onUnlockUser(int userHandle) {
617 mService.onUnlockUser(userHandle);
618 }
Jason Monk74f5e362017-12-06 08:56:33 -0500619
620 @Override
621 public void onStopUser(int userHandle) {
622 mService.onStopUser(userHandle);
623 }
Jason Monk8f5f7ff2017-10-17 14:12:42 -0400624 }
Jason Monke8f8be72018-01-21 10:10:35 -0500625
626 private class SliceGrant {
627 private final Uri mUri;
628 private final String mPkg;
Jason Monkddb8a962018-01-30 13:27:33 -0500629 private final int mUserId;
Jason Monke8f8be72018-01-21 10:10:35 -0500630
Jason Monkddb8a962018-01-30 13:27:33 -0500631 public SliceGrant(Uri uri, String pkg, int userId) {
Jason Monke8f8be72018-01-21 10:10:35 -0500632 mUri = uri;
633 mPkg = pkg;
Jason Monkddb8a962018-01-30 13:27:33 -0500634 mUserId = userId;
Jason Monke8f8be72018-01-21 10:10:35 -0500635 }
636
637 @Override
638 public int hashCode() {
639 return mUri.hashCode() + mPkg.hashCode();
640 }
641
642 @Override
643 public boolean equals(Object obj) {
644 if (!(obj instanceof SliceGrant)) return false;
645 SliceGrant other = (SliceGrant) obj;
Jason Monkddb8a962018-01-30 13:27:33 -0500646 return Objects.equals(other.mUri, mUri) && Objects.equals(other.mPkg, mPkg)
647 && (other.mUserId == mUserId);
Jason Monke8f8be72018-01-21 10:10:35 -0500648 }
649 }
Jason Monk8f5f7ff2017-10-17 14:12:42 -0400650}