blob: c3b98417280263fb19ca12bc42de67a381a1d73d [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;
45import android.content.pm.ResolveInfo;
Jason Monk74f5e362017-12-06 08:56:33 -050046import android.net.Uri;
47import android.os.Binder;
48import android.os.Handler;
Jason Monke8f8be72018-01-21 10:10:35 -050049import android.os.IBinder;
Jason Monk74f5e362017-12-06 08:56:33 -050050import android.os.Looper;
51import android.os.Process;
52import android.os.RemoteException;
Jason Monk7f01f3b2018-05-15 15:46:26 -040053import android.os.ResultReceiver;
54import android.os.ShellCallback;
Jason Monk3a1d2e972018-01-29 16:58:11 -050055import android.os.UserHandle;
Jason Monk74f5e362017-12-06 08:56:33 -050056import android.util.ArrayMap;
Jason Monkddb8a962018-01-30 13:27:33 -050057import android.util.Slog;
Jason Monke009a8e2018-05-21 13:36:21 -040058import android.util.SparseArray;
Jason Monkddb8a962018-01-30 13:27:33 -050059import android.util.Xml.Encoding;
Jason Monk74f5e362017-12-06 08:56:33 -050060
61import com.android.internal.annotations.GuardedBy;
62import com.android.internal.annotations.VisibleForTesting;
63import com.android.internal.app.AssistUtils;
64import com.android.internal.util.Preconditions;
65import com.android.server.LocalServices;
66import com.android.server.ServiceThread;
Jason Monk8f5f7ff2017-10-17 14:12:42 -040067import com.android.server.SystemService;
68
Jason Monkddb8a962018-01-30 13:27:33 -050069import org.xmlpull.v1.XmlPullParser;
70import org.xmlpull.v1.XmlPullParserException;
71import org.xmlpull.v1.XmlPullParserFactory;
72import org.xmlpull.v1.XmlSerializer;
73
Jason Monkb715b042018-02-01 15:00:05 -050074import java.io.ByteArrayInputStream;
75import java.io.ByteArrayOutputStream;
Jason Monk7f01f3b2018-05-15 15:46:26 -040076import java.io.FileDescriptor;
Jason Monkddb8a962018-01-30 13:27:33 -050077import java.io.IOException;
Jason Monk74f5e362017-12-06 08:56:33 -050078import java.util.ArrayList;
79import java.util.List;
80import java.util.Objects;
Jason Monke009a8e2018-05-21 13:36:21 -040081import java.util.function.Supplier;
Jason Monk74f5e362017-12-06 08:56:33 -050082
Jason Monk8f5f7ff2017-10-17 14:12:42 -040083public class SliceManagerService extends ISliceManager.Stub {
84
Jason Monk74f5e362017-12-06 08:56:33 -050085 private static final String TAG = "SliceManagerService";
86 private final Object mLock = new Object();
Jason Monk8f5f7ff2017-10-17 14:12:42 -040087
Jason Monk74f5e362017-12-06 08:56:33 -050088 private final Context mContext;
89 private final PackageManagerInternal mPackageManagerInternal;
90 private final AppOpsManager mAppOps;
91 private final AssistUtils mAssistUtils;
92
93 @GuardedBy("mLock")
94 private final ArrayMap<Uri, PinnedSliceState> mPinnedSlicesByUri = new ArrayMap<>();
Jason Monke009a8e2018-05-21 13:36:21 -040095 @GuardedBy("mLock")
96 private final SparseArray<PackageMatchingCache> mAssistantLookup = new SparseArray<>();
97 @GuardedBy("mLock")
98 private final SparseArray<PackageMatchingCache> mHomeLookup = new SparseArray<>();
Jason Monk74f5e362017-12-06 08:56:33 -050099 private final Handler mHandler;
Jason Monkbf3eedc2018-04-05 20:56:42 -0400100
101 private final SlicePermissionManager mPermissions;
Jason Monk1918ef72018-03-14 09:20:39 -0400102 private final UsageStatsManagerInternal mAppUsageStats;
Jason Monk74f5e362017-12-06 08:56:33 -0500103
104 public SliceManagerService(Context context) {
105 this(context, createHandler().getLooper());
Jason Monk8f5f7ff2017-10-17 14:12:42 -0400106 }
107
Jason Monk74f5e362017-12-06 08:56:33 -0500108 @VisibleForTesting
109 SliceManagerService(Context context, Looper looper) {
110 mContext = context;
111 mPackageManagerInternal = Preconditions.checkNotNull(
112 LocalServices.getService(PackageManagerInternal.class));
113 mAppOps = context.getSystemService(AppOpsManager.class);
114 mAssistUtils = new AssistUtils(context);
115 mHandler = new Handler(looper);
116
Jason Monk1918ef72018-03-14 09:20:39 -0400117 mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
Jason Monkddb8a962018-01-30 13:27:33 -0500118
Jason Monkbf3eedc2018-04-05 20:56:42 -0400119 mPermissions = new SlicePermissionManager(mContext, looper);
Jason Monk68ff6aa2018-01-31 15:51:52 -0500120
121 IntentFilter filter = new IntentFilter();
122 filter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED);
123 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
124 filter.addDataScheme("package");
125 mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
Jason Monk74f5e362017-12-06 08:56:33 -0500126 }
127
128 /// ----- Lifecycle stuff -----
Jason Monk8f5f7ff2017-10-17 14:12:42 -0400129 private void systemReady() {
130 }
131
Jason Monk74f5e362017-12-06 08:56:33 -0500132 private void onUnlockUser(int userId) {
133 }
134
135 private void onStopUser(int userId) {
136 synchronized (mLock) {
137 mPinnedSlicesByUri.values().removeIf(s -> getUserIdFromUri(s.getUri()) == userId);
138 }
139 }
140
141 /// ----- ISliceManager stuff -----
142 @Override
Jason Monkf88d25e2018-03-06 20:13:24 -0500143 public Uri[] getPinnedSlices(String pkg) {
144 verifyCaller(pkg);
Jason Monk199286b2018-04-12 19:47:50 -0400145 int callingUser = Binder.getCallingUserHandle().getIdentifier();
Jason Monkf88d25e2018-03-06 20:13:24 -0500146 ArrayList<Uri> ret = new ArrayList<>();
147 synchronized (mLock) {
148 for (PinnedSliceState state : mPinnedSlicesByUri.values()) {
149 if (Objects.equals(pkg, state.getPkg())) {
Jason Monk199286b2018-04-12 19:47:50 -0400150 Uri uri = state.getUri();
151 int userId = ContentProvider.getUserIdFromUri(uri, callingUser);
152 if (userId == callingUser) {
153 ret.add(ContentProvider.getUriWithoutUserId(uri));
154 }
Jason Monkf88d25e2018-03-06 20:13:24 -0500155 }
156 }
157 }
158 return ret.toArray(new Uri[ret.size()]);
159 }
160
161 @Override
Jason Monk42e03f82018-03-30 11:26:56 -0400162 public void pinSlice(String pkg, Uri uri, SliceSpec[] specs, IBinder token)
163 throws RemoteException {
Jason Monk74f5e362017-12-06 08:56:33 -0500164 verifyCaller(pkg);
Jason Monk38df2802018-02-22 19:28:12 -0500165 enforceAccess(pkg, uri);
Jason Monk1918ef72018-03-14 09:20:39 -0400166 int user = Binder.getCallingUserHandle().getIdentifier();
167 uri = maybeAddUserId(uri, user);
Jason Monk397f6d82018-04-24 17:01:11 -0400168 String slicePkg = getProviderPkg(uri, user);
169 getOrCreatePinnedSlice(uri, slicePkg).pin(pkg, specs, token);
Jason Monk1918ef72018-03-14 09:20:39 -0400170
Jason Monk1918ef72018-03-14 09:20:39 -0400171 mHandler.post(() -> {
Jason Monk1918ef72018-03-14 09:20:39 -0400172 if (slicePkg != null && !Objects.equals(pkg, slicePkg)) {
173 mAppUsageStats.reportEvent(slicePkg, user,
174 isAssistant(pkg, user) || isDefaultHomeApp(pkg, user)
175 ? SLICE_PINNED_PRIV : SLICE_PINNED);
176 }
177 });
Jason Monk74f5e362017-12-06 08:56:33 -0500178 }
179
180 @Override
Jason Monk38df2802018-02-22 19:28:12 -0500181 public void unpinSlice(String pkg, Uri uri, IBinder token) throws RemoteException {
Jason Monk74f5e362017-12-06 08:56:33 -0500182 verifyCaller(pkg);
Jason Monk38df2802018-02-22 19:28:12 -0500183 enforceAccess(pkg, uri);
Jason Monk74f5e362017-12-06 08:56:33 -0500184 uri = maybeAddUserId(uri, Binder.getCallingUserHandle().getIdentifier());
Jason Monk38df2802018-02-22 19:28:12 -0500185 if (getPinnedSlice(uri).unpin(pkg, token)) {
Jason Monk74f5e362017-12-06 08:56:33 -0500186 removePinnedSlice(uri);
187 }
188 }
189
190 @Override
191 public boolean hasSliceAccess(String pkg) throws RemoteException {
192 verifyCaller(pkg);
193 return hasFullSliceAccess(pkg, Binder.getCallingUserHandle().getIdentifier());
194 }
195
196 @Override
197 public SliceSpec[] getPinnedSpecs(Uri uri, String pkg) throws RemoteException {
198 verifyCaller(pkg);
199 enforceAccess(pkg, uri);
200 return getPinnedSlice(uri).getSpecs();
201 }
202
Jason Monke8f8be72018-01-21 10:10:35 -0500203 @Override
Jason Monkbf3eedc2018-04-05 20:56:42 -0400204 public void grantSlicePermission(String pkg, String toPkg, Uri uri) throws RemoteException {
205 verifyCaller(pkg);
206 int user = Binder.getCallingUserHandle().getIdentifier();
207 enforceOwner(pkg, uri, user);
208 mPermissions.grantSliceAccess(toPkg, user, pkg, user, uri);
209 }
210
211 @Override
212 public void revokeSlicePermission(String pkg, String toPkg, Uri uri) throws RemoteException {
213 verifyCaller(pkg);
214 int user = Binder.getCallingUserHandle().getIdentifier();
215 enforceOwner(pkg, uri, user);
216 mPermissions.revokeSliceAccess(toPkg, user, pkg, user, uri);
217 }
218
219 @Override
Jason Monk42e03f82018-03-30 11:26:56 -0400220 public int checkSlicePermission(Uri uri, String pkg, int pid, int uid,
Jason Monkbf3eedc2018-04-05 20:56:42 -0400221 String[] autoGrantPermissions) {
222 int userId = UserHandle.getUserId(uid);
223 if (pkg == null) {
224 for (String p : mContext.getPackageManager().getPackagesForUid(uid)) {
225 if (checkSlicePermission(uri, p, pid, uid, autoGrantPermissions)
226 == PERMISSION_GRANTED) {
227 return PERMISSION_GRANTED;
228 }
229 }
230 return PERMISSION_DENIED;
231 }
232 if (hasFullSliceAccess(pkg, userId)) {
233 return PackageManager.PERMISSION_GRANTED;
234 }
235 if (mPermissions.hasPermission(pkg, userId, uri)) {
236 return PackageManager.PERMISSION_GRANTED;
237 }
238 if (autoGrantPermissions != null) {
239 // Need to own the Uri to call in with permissions to grant.
240 enforceOwner(pkg, uri, userId);
241 for (String perm : autoGrantPermissions) {
242 if (mContext.checkPermission(perm, pid, uid) == PERMISSION_GRANTED) {
243 int providerUser = ContentProvider.getUserIdFromUri(uri, userId);
244 String providerPkg = getProviderPkg(uri, providerUser);
245 mPermissions.grantSliceAccess(pkg, userId, providerPkg, providerUser, uri);
246 return PackageManager.PERMISSION_GRANTED;
247 }
248 }
249 }
250 // Fallback to allowing uri permissions through.
Jason Monke8f8be72018-01-21 10:10:35 -0500251 if (mContext.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
Jason Monk3a1d2e972018-01-29 16:58:11 -0500252 == PERMISSION_GRANTED) {
Jason Monkbf3eedc2018-04-05 20:56:42 -0400253 return PackageManager.PERMISSION_GRANTED;
Jason Monke8f8be72018-01-21 10:10:35 -0500254 }
Jason Monkbf3eedc2018-04-05 20:56:42 -0400255 return PackageManager.PERMISSION_DENIED;
Jason Monke8f8be72018-01-21 10:10:35 -0500256 }
257
258 @Override
259 public void grantPermissionFromUser(Uri uri, String pkg, String callingPkg, boolean allSlices) {
260 verifyCaller(callingPkg);
261 getContext().enforceCallingOrSelfPermission(permission.MANAGE_SLICE_PERMISSIONS,
262 "Slice granting requires MANAGE_SLICE_PERMISSIONS");
Jason Monkbf3eedc2018-04-05 20:56:42 -0400263 int userId = Binder.getCallingUserHandle().getIdentifier();
Jason Monke8f8be72018-01-21 10:10:35 -0500264 if (allSlices) {
Jason Monkbf3eedc2018-04-05 20:56:42 -0400265 mPermissions.grantFullAccess(pkg, userId);
Jason Monke8f8be72018-01-21 10:10:35 -0500266 } else {
Jason Monkbf3eedc2018-04-05 20:56:42 -0400267 // When granting, grant to all slices in the provider.
268 Uri grantUri = uri.buildUpon()
269 .path("")
270 .build();
271 int providerUser = ContentProvider.getUserIdFromUri(grantUri, userId);
272 String providerPkg = getProviderPkg(grantUri, providerUser);
273 mPermissions.grantSliceAccess(pkg, userId, providerPkg, providerUser, grantUri);
Jason Monkddb8a962018-01-30 13:27:33 -0500274 }
275 long ident = Binder.clearCallingIdentity();
276 try {
277 mContext.getContentResolver().notifyChange(uri, null);
278 } finally {
279 Binder.restoreCallingIdentity(ident);
Jason Monke8f8be72018-01-21 10:10:35 -0500280 }
281 }
282
Jason Monkb715b042018-02-01 15:00:05 -0500283 // Backup/restore interface
284 @Override
285 public byte[] getBackupPayload(int user) {
286 if (Binder.getCallingUid() != SYSTEM_UID) {
287 throw new SecurityException("Caller must be system");
288 }
289 //TODO: http://b/22388012
290 if (user != UserHandle.USER_SYSTEM) {
291 Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
292 return null;
293 }
Jason Monkbf3eedc2018-04-05 20:56:42 -0400294 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
295 try {
296 XmlSerializer out = XmlPullParserFactory.newInstance().newSerializer();
297 out.setOutput(baos, Encoding.UTF_8.name());
298
299 mPermissions.writeBackup(out);
300
301 out.flush();
302 return baos.toByteArray();
303 } catch (IOException | XmlPullParserException e) {
304 Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
Jason Monkb715b042018-02-01 15:00:05 -0500305 }
306 return null;
307 }
308
309 @Override
310 public void applyRestore(byte[] payload, int user) {
311 if (Binder.getCallingUid() != SYSTEM_UID) {
312 throw new SecurityException("Caller must be system");
313 }
314 if (payload == null) {
315 Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
316 return;
317 }
318 //TODO: http://b/22388012
319 if (user != UserHandle.USER_SYSTEM) {
320 Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
321 return;
322 }
Jason Monkbf3eedc2018-04-05 20:56:42 -0400323 final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
324 try {
325 XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
326 parser.setInput(bais, Encoding.UTF_8.name());
327 mPermissions.readRestore(parser);
328 } catch (NumberFormatException | XmlPullParserException | IOException e) {
329 Slog.w(TAG, "applyRestore: error reading payload", e);
Jason Monkb715b042018-02-01 15:00:05 -0500330 }
331 }
332
Jason Monk7f01f3b2018-05-15 15:46:26 -0400333 @Override
334 public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
335 String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
336 new SliceShellCommand(this).exec(this, in, out, err, args, callback, resultReceiver);
337 }
338
Jason Monk74f5e362017-12-06 08:56:33 -0500339 /// ----- internal code -----
Jason Monkbf3eedc2018-04-05 20:56:42 -0400340 private void enforceOwner(String pkg, Uri uri, int user) {
341 if (!Objects.equals(getProviderPkg(uri, user), pkg) || pkg == null) {
342 throw new SecurityException("Caller must own " + uri);
Jason Monk68ff6aa2018-01-31 15:51:52 -0500343 }
Jason Monk68ff6aa2018-01-31 15:51:52 -0500344 }
345
Jason Monk9e3b8642018-01-21 20:54:00 -0500346 protected void removePinnedSlice(Uri uri) {
Jason Monk74f5e362017-12-06 08:56:33 -0500347 synchronized (mLock) {
348 mPinnedSlicesByUri.remove(uri).destroy();
349 }
350 }
351
352 private PinnedSliceState getPinnedSlice(Uri uri) {
353 synchronized (mLock) {
354 PinnedSliceState manager = mPinnedSlicesByUri.get(uri);
355 if (manager == null) {
356 throw new IllegalStateException(String.format("Slice %s not pinned",
357 uri.toString()));
358 }
359 return manager;
360 }
361 }
362
Jason Monkf88d25e2018-03-06 20:13:24 -0500363 private PinnedSliceState getOrCreatePinnedSlice(Uri uri, String pkg) {
Jason Monk74f5e362017-12-06 08:56:33 -0500364 synchronized (mLock) {
365 PinnedSliceState manager = mPinnedSlicesByUri.get(uri);
366 if (manager == null) {
Jason Monkf88d25e2018-03-06 20:13:24 -0500367 manager = createPinnedSlice(uri, pkg);
Jason Monk74f5e362017-12-06 08:56:33 -0500368 mPinnedSlicesByUri.put(uri, manager);
369 }
370 return manager;
371 }
372 }
373
374 @VisibleForTesting
Jason Monkf88d25e2018-03-06 20:13:24 -0500375 protected PinnedSliceState createPinnedSlice(Uri uri, String pkg) {
376 return new PinnedSliceState(this, uri, pkg);
Jason Monk74f5e362017-12-06 08:56:33 -0500377 }
378
379 public Object getLock() {
380 return mLock;
381 }
382
383 public Context getContext() {
384 return mContext;
385 }
386
387 public Handler getHandler() {
388 return mHandler;
389 }
390
Jason Monk3a1d2e972018-01-29 16:58:11 -0500391 protected int checkAccess(String pkg, Uri uri, int uid, int pid) {
Jason Monkbf3eedc2018-04-05 20:56:42 -0400392 return checkSlicePermission(uri, pkg, uid, pid, null);
Jason Monk3a1d2e972018-01-29 16:58:11 -0500393 }
394
Jason Monk1918ef72018-03-14 09:20:39 -0400395 private String getProviderPkg(Uri uri, int user) {
396 long ident = Binder.clearCallingIdentity();
397 try {
398 IBinder token = new Binder();
399 IActivityManager activityManager = ActivityManager.getService();
400 ContentProviderHolder holder = null;
401 String providerName = getUriWithoutUserId(uri).getAuthority();
402 try {
403 try {
404 holder = activityManager.getContentProviderExternal(
405 providerName, getUserIdFromUri(uri, user), token);
406 if (holder != null && holder.info != null) {
407 return holder.info.packageName;
408 } else {
409 return null;
410 }
411 } finally {
412 if (holder != null && holder.provider != null) {
413 activityManager.removeContentProviderExternal(providerName, token);
414 }
415 }
416 } catch (RemoteException e) {
417 // Can't happen.
418 throw e.rethrowAsRuntimeException();
419 }
420 } finally {
421 // I know, the double finally seems ugly, but seems safest for the identity.
422 Binder.restoreCallingIdentity(ident);
423 }
424 }
425
Jason Monk3a1d2e972018-01-29 16:58:11 -0500426 private void enforceCrossUser(String pkg, Uri uri) {
427 int user = Binder.getCallingUserHandle().getIdentifier();
Jason Monk74f5e362017-12-06 08:56:33 -0500428 if (getUserIdFromUri(uri, user) != user) {
429 getContext().enforceCallingOrSelfPermission(permission.INTERACT_ACROSS_USERS_FULL,
430 "Slice interaction across users requires INTERACT_ACROSS_USERS_FULL");
431 }
432 }
433
Jason Monk3a1d2e972018-01-29 16:58:11 -0500434 private void enforceAccess(String pkg, Uri uri) throws RemoteException {
435 if (checkAccess(pkg, uri, Binder.getCallingUid(), Binder.getCallingPid())
436 != PERMISSION_GRANTED) {
Jason Monkbf3eedc2018-04-05 20:56:42 -0400437 int userId = ContentProvider.getUserIdFromUri(uri,
438 Binder.getCallingUserHandle().getIdentifier());
439 if (!Objects.equals(pkg, getProviderPkg(uri, userId))) {
440 throw new SecurityException("Access to slice " + uri + " is required");
441 }
Jason Monk74f5e362017-12-06 08:56:33 -0500442 }
Jason Monk3a1d2e972018-01-29 16:58:11 -0500443 enforceCrossUser(pkg, uri);
Jason Monk74f5e362017-12-06 08:56:33 -0500444 }
445
446 private void verifyCaller(String pkg) {
447 mAppOps.checkPackage(Binder.getCallingUid(), pkg);
448 }
449
450 private boolean hasFullSliceAccess(String pkg, int userId) {
Jason Monke8f8be72018-01-21 10:10:35 -0500451 long ident = Binder.clearCallingIdentity();
452 try {
453 boolean ret = isDefaultHomeApp(pkg, userId) || isAssistant(pkg, userId)
454 || isGrantedFullAccess(pkg, userId);
455 return ret;
456 } finally {
457 Binder.restoreCallingIdentity(ident);
458 }
Jason Monk74f5e362017-12-06 08:56:33 -0500459 }
460
461 private boolean isAssistant(String pkg, int userId) {
Jason Monke009a8e2018-05-21 13:36:21 -0400462 return getAssistantMatcher(userId).matches(pkg);
Jason Monk74f5e362017-12-06 08:56:33 -0500463 }
464
Jason Monk74f5e362017-12-06 08:56:33 -0500465 private boolean isDefaultHomeApp(String pkg, int userId) {
Jason Monke009a8e2018-05-21 13:36:21 -0400466 return getHomeMatcher(userId).matches(pkg);
467 }
Jason Monke8f8be72018-01-21 10:10:35 -0500468
Jason Monke009a8e2018-05-21 13:36:21 -0400469 private PackageMatchingCache getAssistantMatcher(int userId) {
470 PackageMatchingCache matcher = mAssistantLookup.get(userId);
471 if (matcher == null) {
472 matcher = new PackageMatchingCache(() -> getAssistant(userId));
473 mAssistantLookup.put(userId, matcher);
474 }
475 return matcher;
476 }
477
478 private PackageMatchingCache getHomeMatcher(int userId) {
479 PackageMatchingCache matcher = mHomeLookup.get(userId);
480 if (matcher == null) {
481 matcher = new PackageMatchingCache(() -> getDefaultHome(userId));
482 mHomeLookup.put(userId, matcher);
483 }
484 return matcher;
485 }
486
487 private String getAssistant(int userId) {
488 final ComponentName cn = mAssistUtils.getAssistComponentForUser(userId);
489 if (cn == null) {
490 return null;
491 }
492 return cn.getPackageName();
Jason Monk74f5e362017-12-06 08:56:33 -0500493 }
494
495 // Based on getDefaultHome in ShortcutService.
496 // TODO: Unify if possible
497 @VisibleForTesting
Jason Monk74848ae2018-01-21 17:11:57 -0500498 protected String getDefaultHome(int userId) {
Jason Monk74f5e362017-12-06 08:56:33 -0500499 final long token = Binder.clearCallingIdentity();
500 try {
501 final List<ResolveInfo> allHomeCandidates = new ArrayList<>();
502
503 // Default launcher from package manager.
504 final ComponentName defaultLauncher = mPackageManagerInternal
505 .getHomeActivitiesAsUser(allHomeCandidates, userId);
506
507 ComponentName detected = null;
508 if (defaultLauncher != null) {
509 detected = defaultLauncher;
510 }
511
512 if (detected == null) {
513 // If we reach here, that means it's the first check since the user was created,
514 // and there's already multiple launchers and there's no default set.
515 // Find the system one with the highest priority.
516 // (We need to check the priority too because of FallbackHome in Settings.)
517 // If there's no system launcher yet, then no one can access slices, until
518 // the user explicitly sets one.
519 final int size = allHomeCandidates.size();
520
521 int lastPriority = Integer.MIN_VALUE;
522 for (int i = 0; i < size; i++) {
523 final ResolveInfo ri = allHomeCandidates.get(i);
524 if (!ri.activityInfo.applicationInfo.isSystemApp()) {
525 continue;
526 }
527 if (ri.priority < lastPriority) {
528 continue;
529 }
530 detected = ri.activityInfo.getComponentName();
531 lastPriority = ri.priority;
532 }
533 }
Jason Monke8f8be72018-01-21 10:10:35 -0500534 return detected != null ? detected.getPackageName() : null;
Jason Monk74f5e362017-12-06 08:56:33 -0500535 } finally {
536 Binder.restoreCallingIdentity(token);
537 }
538 }
539
540 private boolean isGrantedFullAccess(String pkg, int userId) {
Jason Monkbf3eedc2018-04-05 20:56:42 -0400541 return mPermissions.hasFullAccess(pkg, userId);
Jason Monk74f5e362017-12-06 08:56:33 -0500542 }
543
544 private static ServiceThread createHandler() {
545 ServiceThread handlerThread = new ServiceThread(TAG,
546 Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
547 handlerThread.start();
548 return handlerThread;
Jason Monk8f5f7ff2017-10-17 14:12:42 -0400549 }
550
Jason Monk68ff6aa2018-01-31 15:51:52 -0500551 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
552 @Override
553 public void onReceive(Context context, Intent intent) {
554 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
555 if (userId == UserHandle.USER_NULL) {
556 Slog.w(TAG, "Intent broadcast does not contain user handle: " + intent);
557 return;
558 }
559 Uri data = intent.getData();
560 String pkg = data != null ? data.getSchemeSpecificPart() : null;
561 if (pkg == null) {
562 Slog.w(TAG, "Intent broadcast does not contain package name: " + intent);
563 return;
564 }
565 switch (intent.getAction()) {
566 case Intent.ACTION_PACKAGE_REMOVED:
567 final boolean replacing =
568 intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
569 if (!replacing) {
Jason Monkbf3eedc2018-04-05 20:56:42 -0400570 mPermissions.removePkg(pkg, userId);
Jason Monk68ff6aa2018-01-31 15:51:52 -0500571 }
572 break;
573 case Intent.ACTION_PACKAGE_DATA_CLEARED:
Jason Monkbf3eedc2018-04-05 20:56:42 -0400574 mPermissions.removePkg(pkg, userId);
Jason Monk68ff6aa2018-01-31 15:51:52 -0500575 break;
576 }
577 }
578 };
579
Jason Monk7f01f3b2018-05-15 15:46:26 -0400580 public String[] getAllPackagesGranted(String authority) {
581 String pkg = getProviderPkg(new Uri.Builder()
582 .scheme(ContentResolver.SCHEME_CONTENT)
583 .authority(authority)
584 .build(), 0);
585 return mPermissions.getAllPackagesGranted(pkg);
586 }
587
Jason Monke009a8e2018-05-21 13:36:21 -0400588 /**
589 * Holder that caches a package that has access to a slice.
590 */
591 static class PackageMatchingCache {
592
593 private final Supplier<String> mPkgSource;
594 private String mCurrentPkg;
595
596 public PackageMatchingCache(Supplier<String> pkgSource) {
597 mPkgSource = pkgSource;
598 }
599
600 public boolean matches(String pkgCandidate) {
601 if (pkgCandidate == null) return false;
602
603 if (Objects.equals(pkgCandidate, mCurrentPkg)) {
604 return true;
605 }
606 // Failed on cached value, try updating.
607 mCurrentPkg = mPkgSource.get();
608 return Objects.equals(pkgCandidate, mCurrentPkg);
609 }
610 }
611
Jason Monk8f5f7ff2017-10-17 14:12:42 -0400612 public static class Lifecycle extends SystemService {
613 private SliceManagerService mService;
614
615 public Lifecycle(Context context) {
616 super(context);
617 }
618
619 @Override
620 public void onStart() {
621 mService = new SliceManagerService(getContext());
622 publishBinderService(Context.SLICE_SERVICE, mService);
623 }
624
625 @Override
626 public void onBootPhase(int phase) {
627 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
628 mService.systemReady();
629 }
630 }
631
632 @Override
633 public void onUnlockUser(int userHandle) {
634 mService.onUnlockUser(userHandle);
635 }
Jason Monk74f5e362017-12-06 08:56:33 -0500636
637 @Override
638 public void onStopUser(int userHandle) {
639 mService.onStopUser(userHandle);
640 }
Jason Monk8f5f7ff2017-10-17 14:12:42 -0400641 }
Jason Monke8f8be72018-01-21 10:10:35 -0500642
643 private class SliceGrant {
644 private final Uri mUri;
645 private final String mPkg;
Jason Monkddb8a962018-01-30 13:27:33 -0500646 private final int mUserId;
Jason Monke8f8be72018-01-21 10:10:35 -0500647
Jason Monkddb8a962018-01-30 13:27:33 -0500648 public SliceGrant(Uri uri, String pkg, int userId) {
Jason Monke8f8be72018-01-21 10:10:35 -0500649 mUri = uri;
650 mPkg = pkg;
Jason Monkddb8a962018-01-30 13:27:33 -0500651 mUserId = userId;
Jason Monke8f8be72018-01-21 10:10:35 -0500652 }
653
654 @Override
655 public int hashCode() {
656 return mUri.hashCode() + mPkg.hashCode();
657 }
658
659 @Override
660 public boolean equals(Object obj) {
661 if (!(obj instanceof SliceGrant)) return false;
662 SliceGrant other = (SliceGrant) obj;
Jason Monkddb8a962018-01-30 13:27:33 -0500663 return Objects.equals(other.mUri, mUri) && Objects.equals(other.mPkg, mPkg)
664 && (other.mUserId == mUserId);
Jason Monke8f8be72018-01-21 10:10:35 -0500665 }
666 }
Jason Monk8f5f7ff2017-10-17 14:12:42 -0400667}