blob: a9cdafd9aeaa415df8ff1acc75eb4aee3f93136d [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 Monk74f5e362017-12-06 08:56:33 -050039import android.content.Context;
40import android.content.Intent;
Jason Monk68ff6aa2018-01-31 15:51:52 -050041import android.content.IntentFilter;
Jason Monkbf3eedc2018-04-05 20:56:42 -040042import android.content.pm.PackageManager;
Jason Monk74f5e362017-12-06 08:56:33 -050043import android.content.pm.PackageManagerInternal;
44import android.content.pm.ResolveInfo;
Jason Monk74f5e362017-12-06 08:56:33 -050045import android.net.Uri;
46import android.os.Binder;
47import android.os.Handler;
Jason Monke8f8be72018-01-21 10:10:35 -050048import android.os.IBinder;
Jason Monk74f5e362017-12-06 08:56:33 -050049import android.os.Looper;
50import android.os.Process;
51import android.os.RemoteException;
Jason Monk3a1d2e972018-01-29 16:58:11 -050052import android.os.UserHandle;
Jason Monk74f5e362017-12-06 08:56:33 -050053import android.util.ArrayMap;
Jason Monkddb8a962018-01-30 13:27:33 -050054import android.util.Slog;
55import android.util.Xml.Encoding;
Jason Monk74f5e362017-12-06 08:56:33 -050056
57import com.android.internal.annotations.GuardedBy;
58import com.android.internal.annotations.VisibleForTesting;
59import com.android.internal.app.AssistUtils;
60import com.android.internal.util.Preconditions;
61import com.android.server.LocalServices;
62import com.android.server.ServiceThread;
Jason Monk8f5f7ff2017-10-17 14:12:42 -040063import com.android.server.SystemService;
64
Jason Monkddb8a962018-01-30 13:27:33 -050065import org.xmlpull.v1.XmlPullParser;
66import org.xmlpull.v1.XmlPullParserException;
67import org.xmlpull.v1.XmlPullParserFactory;
68import org.xmlpull.v1.XmlSerializer;
69
Jason Monkb715b042018-02-01 15:00:05 -050070import java.io.ByteArrayInputStream;
71import java.io.ByteArrayOutputStream;
Jason Monkddb8a962018-01-30 13:27:33 -050072import java.io.IOException;
Jason Monk74f5e362017-12-06 08:56:33 -050073import java.util.ArrayList;
74import java.util.List;
75import java.util.Objects;
76
Jason Monk8f5f7ff2017-10-17 14:12:42 -040077public class SliceManagerService extends ISliceManager.Stub {
78
Jason Monk74f5e362017-12-06 08:56:33 -050079 private static final String TAG = "SliceManagerService";
80 private final Object mLock = new Object();
Jason Monk8f5f7ff2017-10-17 14:12:42 -040081
Jason Monk74f5e362017-12-06 08:56:33 -050082 private final Context mContext;
83 private final PackageManagerInternal mPackageManagerInternal;
84 private final AppOpsManager mAppOps;
85 private final AssistUtils mAssistUtils;
86
87 @GuardedBy("mLock")
88 private final ArrayMap<Uri, PinnedSliceState> mPinnedSlicesByUri = new ArrayMap<>();
89 private final Handler mHandler;
Jason Monkbf3eedc2018-04-05 20:56:42 -040090
91 private final SlicePermissionManager mPermissions;
Jason Monk1918ef72018-03-14 09:20:39 -040092 private final UsageStatsManagerInternal mAppUsageStats;
Jason Monk74f5e362017-12-06 08:56:33 -050093
94 public SliceManagerService(Context context) {
95 this(context, createHandler().getLooper());
Jason Monk8f5f7ff2017-10-17 14:12:42 -040096 }
97
Jason Monk74f5e362017-12-06 08:56:33 -050098 @VisibleForTesting
99 SliceManagerService(Context context, Looper looper) {
100 mContext = context;
101 mPackageManagerInternal = Preconditions.checkNotNull(
102 LocalServices.getService(PackageManagerInternal.class));
103 mAppOps = context.getSystemService(AppOpsManager.class);
104 mAssistUtils = new AssistUtils(context);
105 mHandler = new Handler(looper);
106
Jason Monk1918ef72018-03-14 09:20:39 -0400107 mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
Jason Monkddb8a962018-01-30 13:27:33 -0500108
Jason Monkbf3eedc2018-04-05 20:56:42 -0400109 mPermissions = new SlicePermissionManager(mContext, looper);
Jason Monk68ff6aa2018-01-31 15:51:52 -0500110
111 IntentFilter filter = new IntentFilter();
112 filter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED);
113 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
114 filter.addDataScheme("package");
115 mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
Jason Monk74f5e362017-12-06 08:56:33 -0500116 }
117
118 /// ----- Lifecycle stuff -----
Jason Monk8f5f7ff2017-10-17 14:12:42 -0400119 private void systemReady() {
120 }
121
Jason Monk74f5e362017-12-06 08:56:33 -0500122 private void onUnlockUser(int userId) {
123 }
124
125 private void onStopUser(int userId) {
126 synchronized (mLock) {
127 mPinnedSlicesByUri.values().removeIf(s -> getUserIdFromUri(s.getUri()) == userId);
128 }
129 }
130
131 /// ----- ISliceManager stuff -----
132 @Override
Jason Monkf88d25e2018-03-06 20:13:24 -0500133 public Uri[] getPinnedSlices(String pkg) {
134 verifyCaller(pkg);
Jason Monk199286b2018-04-12 19:47:50 -0400135 int callingUser = Binder.getCallingUserHandle().getIdentifier();
Jason Monkf88d25e2018-03-06 20:13:24 -0500136 ArrayList<Uri> ret = new ArrayList<>();
137 synchronized (mLock) {
138 for (PinnedSliceState state : mPinnedSlicesByUri.values()) {
139 if (Objects.equals(pkg, state.getPkg())) {
Jason Monk199286b2018-04-12 19:47:50 -0400140 Uri uri = state.getUri();
141 int userId = ContentProvider.getUserIdFromUri(uri, callingUser);
142 if (userId == callingUser) {
143 ret.add(ContentProvider.getUriWithoutUserId(uri));
144 }
Jason Monkf88d25e2018-03-06 20:13:24 -0500145 }
146 }
147 }
148 return ret.toArray(new Uri[ret.size()]);
149 }
150
151 @Override
Jason Monk42e03f82018-03-30 11:26:56 -0400152 public void pinSlice(String pkg, Uri uri, SliceSpec[] specs, IBinder token)
153 throws RemoteException {
Jason Monk74f5e362017-12-06 08:56:33 -0500154 verifyCaller(pkg);
Jason Monk38df2802018-02-22 19:28:12 -0500155 enforceAccess(pkg, uri);
Jason Monk1918ef72018-03-14 09:20:39 -0400156 int user = Binder.getCallingUserHandle().getIdentifier();
157 uri = maybeAddUserId(uri, user);
Jason Monkf88d25e2018-03-06 20:13:24 -0500158 getOrCreatePinnedSlice(uri, pkg).pin(pkg, specs, token);
Jason Monk1918ef72018-03-14 09:20:39 -0400159
160 Uri finalUri = uri;
161 mHandler.post(() -> {
162 String slicePkg = getProviderPkg(finalUri, user);
163 if (slicePkg != null && !Objects.equals(pkg, slicePkg)) {
164 mAppUsageStats.reportEvent(slicePkg, user,
165 isAssistant(pkg, user) || isDefaultHomeApp(pkg, user)
166 ? SLICE_PINNED_PRIV : SLICE_PINNED);
167 }
168 });
Jason Monk74f5e362017-12-06 08:56:33 -0500169 }
170
171 @Override
Jason Monk38df2802018-02-22 19:28:12 -0500172 public void unpinSlice(String pkg, Uri uri, IBinder token) throws RemoteException {
Jason Monk74f5e362017-12-06 08:56:33 -0500173 verifyCaller(pkg);
Jason Monk38df2802018-02-22 19:28:12 -0500174 enforceAccess(pkg, uri);
Jason Monk74f5e362017-12-06 08:56:33 -0500175 uri = maybeAddUserId(uri, Binder.getCallingUserHandle().getIdentifier());
Jason Monk38df2802018-02-22 19:28:12 -0500176 if (getPinnedSlice(uri).unpin(pkg, token)) {
Jason Monk74f5e362017-12-06 08:56:33 -0500177 removePinnedSlice(uri);
178 }
179 }
180
181 @Override
182 public boolean hasSliceAccess(String pkg) throws RemoteException {
183 verifyCaller(pkg);
184 return hasFullSliceAccess(pkg, Binder.getCallingUserHandle().getIdentifier());
185 }
186
187 @Override
188 public SliceSpec[] getPinnedSpecs(Uri uri, String pkg) throws RemoteException {
189 verifyCaller(pkg);
190 enforceAccess(pkg, uri);
191 return getPinnedSlice(uri).getSpecs();
192 }
193
Jason Monke8f8be72018-01-21 10:10:35 -0500194 @Override
Jason Monkbf3eedc2018-04-05 20:56:42 -0400195 public void grantSlicePermission(String pkg, String toPkg, Uri uri) throws RemoteException {
196 verifyCaller(pkg);
197 int user = Binder.getCallingUserHandle().getIdentifier();
198 enforceOwner(pkg, uri, user);
199 mPermissions.grantSliceAccess(toPkg, user, pkg, user, uri);
200 }
201
202 @Override
203 public void revokeSlicePermission(String pkg, String toPkg, Uri uri) throws RemoteException {
204 verifyCaller(pkg);
205 int user = Binder.getCallingUserHandle().getIdentifier();
206 enforceOwner(pkg, uri, user);
207 mPermissions.revokeSliceAccess(toPkg, user, pkg, user, uri);
208 }
209
210 @Override
Jason Monk42e03f82018-03-30 11:26:56 -0400211 public int checkSlicePermission(Uri uri, String pkg, int pid, int uid,
Jason Monkbf3eedc2018-04-05 20:56:42 -0400212 String[] autoGrantPermissions) {
213 int userId = UserHandle.getUserId(uid);
214 if (pkg == null) {
215 for (String p : mContext.getPackageManager().getPackagesForUid(uid)) {
216 if (checkSlicePermission(uri, p, pid, uid, autoGrantPermissions)
217 == PERMISSION_GRANTED) {
218 return PERMISSION_GRANTED;
219 }
220 }
221 return PERMISSION_DENIED;
222 }
223 if (hasFullSliceAccess(pkg, userId)) {
224 return PackageManager.PERMISSION_GRANTED;
225 }
226 if (mPermissions.hasPermission(pkg, userId, uri)) {
227 return PackageManager.PERMISSION_GRANTED;
228 }
229 if (autoGrantPermissions != null) {
230 // Need to own the Uri to call in with permissions to grant.
231 enforceOwner(pkg, uri, userId);
232 for (String perm : autoGrantPermissions) {
233 if (mContext.checkPermission(perm, pid, uid) == PERMISSION_GRANTED) {
234 int providerUser = ContentProvider.getUserIdFromUri(uri, userId);
235 String providerPkg = getProviderPkg(uri, providerUser);
236 mPermissions.grantSliceAccess(pkg, userId, providerPkg, providerUser, uri);
237 return PackageManager.PERMISSION_GRANTED;
238 }
239 }
240 }
241 // Fallback to allowing uri permissions through.
Jason Monke8f8be72018-01-21 10:10:35 -0500242 if (mContext.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
Jason Monk3a1d2e972018-01-29 16:58:11 -0500243 == PERMISSION_GRANTED) {
Jason Monkbf3eedc2018-04-05 20:56:42 -0400244 return PackageManager.PERMISSION_GRANTED;
Jason Monke8f8be72018-01-21 10:10:35 -0500245 }
Jason Monkbf3eedc2018-04-05 20:56:42 -0400246 return PackageManager.PERMISSION_DENIED;
Jason Monke8f8be72018-01-21 10:10:35 -0500247 }
248
249 @Override
250 public void grantPermissionFromUser(Uri uri, String pkg, String callingPkg, boolean allSlices) {
251 verifyCaller(callingPkg);
252 getContext().enforceCallingOrSelfPermission(permission.MANAGE_SLICE_PERMISSIONS,
253 "Slice granting requires MANAGE_SLICE_PERMISSIONS");
Jason Monkbf3eedc2018-04-05 20:56:42 -0400254 int userId = Binder.getCallingUserHandle().getIdentifier();
Jason Monke8f8be72018-01-21 10:10:35 -0500255 if (allSlices) {
Jason Monkbf3eedc2018-04-05 20:56:42 -0400256 mPermissions.grantFullAccess(pkg, userId);
Jason Monke8f8be72018-01-21 10:10:35 -0500257 } else {
Jason Monkbf3eedc2018-04-05 20:56:42 -0400258 // When granting, grant to all slices in the provider.
259 Uri grantUri = uri.buildUpon()
260 .path("")
261 .build();
262 int providerUser = ContentProvider.getUserIdFromUri(grantUri, userId);
263 String providerPkg = getProviderPkg(grantUri, providerUser);
264 mPermissions.grantSliceAccess(pkg, userId, providerPkg, providerUser, grantUri);
Jason Monkddb8a962018-01-30 13:27:33 -0500265 }
266 long ident = Binder.clearCallingIdentity();
267 try {
268 mContext.getContentResolver().notifyChange(uri, null);
269 } finally {
270 Binder.restoreCallingIdentity(ident);
Jason Monke8f8be72018-01-21 10:10:35 -0500271 }
272 }
273
Jason Monkb715b042018-02-01 15:00:05 -0500274 // Backup/restore interface
275 @Override
276 public byte[] getBackupPayload(int user) {
277 if (Binder.getCallingUid() != SYSTEM_UID) {
278 throw new SecurityException("Caller must be system");
279 }
280 //TODO: http://b/22388012
281 if (user != UserHandle.USER_SYSTEM) {
282 Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
283 return null;
284 }
Jason Monkbf3eedc2018-04-05 20:56:42 -0400285 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
286 try {
287 XmlSerializer out = XmlPullParserFactory.newInstance().newSerializer();
288 out.setOutput(baos, Encoding.UTF_8.name());
289
290 mPermissions.writeBackup(out);
291
292 out.flush();
293 return baos.toByteArray();
294 } catch (IOException | XmlPullParserException e) {
295 Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
Jason Monkb715b042018-02-01 15:00:05 -0500296 }
297 return null;
298 }
299
300 @Override
301 public void applyRestore(byte[] payload, int user) {
302 if (Binder.getCallingUid() != SYSTEM_UID) {
303 throw new SecurityException("Caller must be system");
304 }
305 if (payload == null) {
306 Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
307 return;
308 }
309 //TODO: http://b/22388012
310 if (user != UserHandle.USER_SYSTEM) {
311 Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
312 return;
313 }
Jason Monkbf3eedc2018-04-05 20:56:42 -0400314 final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
315 try {
316 XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
317 parser.setInput(bais, Encoding.UTF_8.name());
318 mPermissions.readRestore(parser);
319 } catch (NumberFormatException | XmlPullParserException | IOException e) {
320 Slog.w(TAG, "applyRestore: error reading payload", e);
Jason Monkb715b042018-02-01 15:00:05 -0500321 }
322 }
323
Jason Monk74f5e362017-12-06 08:56:33 -0500324 /// ----- internal code -----
Jason Monkbf3eedc2018-04-05 20:56:42 -0400325 private void enforceOwner(String pkg, Uri uri, int user) {
326 if (!Objects.equals(getProviderPkg(uri, user), pkg) || pkg == null) {
327 throw new SecurityException("Caller must own " + uri);
Jason Monk68ff6aa2018-01-31 15:51:52 -0500328 }
Jason Monk68ff6aa2018-01-31 15:51:52 -0500329 }
330
Jason Monk9e3b8642018-01-21 20:54:00 -0500331 protected void removePinnedSlice(Uri uri) {
Jason Monk74f5e362017-12-06 08:56:33 -0500332 synchronized (mLock) {
333 mPinnedSlicesByUri.remove(uri).destroy();
334 }
335 }
336
337 private PinnedSliceState getPinnedSlice(Uri uri) {
338 synchronized (mLock) {
339 PinnedSliceState manager = mPinnedSlicesByUri.get(uri);
340 if (manager == null) {
341 throw new IllegalStateException(String.format("Slice %s not pinned",
342 uri.toString()));
343 }
344 return manager;
345 }
346 }
347
Jason Monkf88d25e2018-03-06 20:13:24 -0500348 private PinnedSliceState getOrCreatePinnedSlice(Uri uri, String pkg) {
Jason Monk74f5e362017-12-06 08:56:33 -0500349 synchronized (mLock) {
350 PinnedSliceState manager = mPinnedSlicesByUri.get(uri);
351 if (manager == null) {
Jason Monkf88d25e2018-03-06 20:13:24 -0500352 manager = createPinnedSlice(uri, pkg);
Jason Monk74f5e362017-12-06 08:56:33 -0500353 mPinnedSlicesByUri.put(uri, manager);
354 }
355 return manager;
356 }
357 }
358
359 @VisibleForTesting
Jason Monkf88d25e2018-03-06 20:13:24 -0500360 protected PinnedSliceState createPinnedSlice(Uri uri, String pkg) {
361 return new PinnedSliceState(this, uri, pkg);
Jason Monk74f5e362017-12-06 08:56:33 -0500362 }
363
364 public Object getLock() {
365 return mLock;
366 }
367
368 public Context getContext() {
369 return mContext;
370 }
371
372 public Handler getHandler() {
373 return mHandler;
374 }
375
Jason Monk3a1d2e972018-01-29 16:58:11 -0500376 protected int checkAccess(String pkg, Uri uri, int uid, int pid) {
Jason Monkbf3eedc2018-04-05 20:56:42 -0400377 return checkSlicePermission(uri, pkg, uid, pid, null);
Jason Monk3a1d2e972018-01-29 16:58:11 -0500378 }
379
Jason Monk1918ef72018-03-14 09:20:39 -0400380 private String getProviderPkg(Uri uri, int user) {
381 long ident = Binder.clearCallingIdentity();
382 try {
383 IBinder token = new Binder();
384 IActivityManager activityManager = ActivityManager.getService();
385 ContentProviderHolder holder = null;
386 String providerName = getUriWithoutUserId(uri).getAuthority();
387 try {
388 try {
389 holder = activityManager.getContentProviderExternal(
390 providerName, getUserIdFromUri(uri, user), token);
391 if (holder != null && holder.info != null) {
392 return holder.info.packageName;
393 } else {
394 return null;
395 }
396 } finally {
397 if (holder != null && holder.provider != null) {
398 activityManager.removeContentProviderExternal(providerName, token);
399 }
400 }
401 } catch (RemoteException e) {
402 // Can't happen.
403 throw e.rethrowAsRuntimeException();
404 }
405 } finally {
406 // I know, the double finally seems ugly, but seems safest for the identity.
407 Binder.restoreCallingIdentity(ident);
408 }
409 }
410
Jason Monk3a1d2e972018-01-29 16:58:11 -0500411 private void enforceCrossUser(String pkg, Uri uri) {
412 int user = Binder.getCallingUserHandle().getIdentifier();
Jason Monk74f5e362017-12-06 08:56:33 -0500413 if (getUserIdFromUri(uri, user) != user) {
414 getContext().enforceCallingOrSelfPermission(permission.INTERACT_ACROSS_USERS_FULL,
415 "Slice interaction across users requires INTERACT_ACROSS_USERS_FULL");
416 }
417 }
418
Jason Monk3a1d2e972018-01-29 16:58:11 -0500419 private void enforceAccess(String pkg, Uri uri) throws RemoteException {
420 if (checkAccess(pkg, uri, Binder.getCallingUid(), Binder.getCallingPid())
421 != PERMISSION_GRANTED) {
Jason Monkbf3eedc2018-04-05 20:56:42 -0400422 int userId = ContentProvider.getUserIdFromUri(uri,
423 Binder.getCallingUserHandle().getIdentifier());
424 if (!Objects.equals(pkg, getProviderPkg(uri, userId))) {
425 throw new SecurityException("Access to slice " + uri + " is required");
426 }
Jason Monk74f5e362017-12-06 08:56:33 -0500427 }
Jason Monk3a1d2e972018-01-29 16:58:11 -0500428 enforceCrossUser(pkg, uri);
Jason Monk74f5e362017-12-06 08:56:33 -0500429 }
430
431 private void verifyCaller(String pkg) {
432 mAppOps.checkPackage(Binder.getCallingUid(), pkg);
433 }
434
435 private boolean hasFullSliceAccess(String pkg, int userId) {
Jason Monke8f8be72018-01-21 10:10:35 -0500436 long ident = Binder.clearCallingIdentity();
437 try {
438 boolean ret = isDefaultHomeApp(pkg, userId) || isAssistant(pkg, userId)
439 || isGrantedFullAccess(pkg, userId);
440 return ret;
441 } finally {
442 Binder.restoreCallingIdentity(ident);
443 }
Jason Monk74f5e362017-12-06 08:56:33 -0500444 }
445
446 private boolean isAssistant(String pkg, int userId) {
447 final ComponentName cn = mAssistUtils.getAssistComponentForUser(userId);
448 if (cn == null) {
449 return false;
450 }
451 return cn.getPackageName().equals(pkg);
452 }
453
Jason Monk74f5e362017-12-06 08:56:33 -0500454 private boolean isDefaultHomeApp(String pkg, int userId) {
455 String defaultHome = getDefaultHome(userId);
Jason Monke8f8be72018-01-21 10:10:35 -0500456
457 return pkg != null && Objects.equals(pkg, defaultHome);
Jason Monk74f5e362017-12-06 08:56:33 -0500458 }
459
460 // Based on getDefaultHome in ShortcutService.
461 // TODO: Unify if possible
462 @VisibleForTesting
Jason Monk74848ae2018-01-21 17:11:57 -0500463 protected String getDefaultHome(int userId) {
Jason Monk74f5e362017-12-06 08:56:33 -0500464 final long token = Binder.clearCallingIdentity();
465 try {
466 final List<ResolveInfo> allHomeCandidates = new ArrayList<>();
467
468 // Default launcher from package manager.
469 final ComponentName defaultLauncher = mPackageManagerInternal
470 .getHomeActivitiesAsUser(allHomeCandidates, userId);
471
472 ComponentName detected = null;
473 if (defaultLauncher != null) {
474 detected = defaultLauncher;
475 }
476
477 if (detected == null) {
478 // If we reach here, that means it's the first check since the user was created,
479 // and there's already multiple launchers and there's no default set.
480 // Find the system one with the highest priority.
481 // (We need to check the priority too because of FallbackHome in Settings.)
482 // If there's no system launcher yet, then no one can access slices, until
483 // the user explicitly sets one.
484 final int size = allHomeCandidates.size();
485
486 int lastPriority = Integer.MIN_VALUE;
487 for (int i = 0; i < size; i++) {
488 final ResolveInfo ri = allHomeCandidates.get(i);
489 if (!ri.activityInfo.applicationInfo.isSystemApp()) {
490 continue;
491 }
492 if (ri.priority < lastPriority) {
493 continue;
494 }
495 detected = ri.activityInfo.getComponentName();
496 lastPriority = ri.priority;
497 }
498 }
Jason Monke8f8be72018-01-21 10:10:35 -0500499 return detected != null ? detected.getPackageName() : null;
Jason Monk74f5e362017-12-06 08:56:33 -0500500 } finally {
501 Binder.restoreCallingIdentity(token);
502 }
503 }
504
505 private boolean isGrantedFullAccess(String pkg, int userId) {
Jason Monkbf3eedc2018-04-05 20:56:42 -0400506 return mPermissions.hasFullAccess(pkg, userId);
Jason Monk74f5e362017-12-06 08:56:33 -0500507 }
508
509 private static ServiceThread createHandler() {
510 ServiceThread handlerThread = new ServiceThread(TAG,
511 Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
512 handlerThread.start();
513 return handlerThread;
Jason Monk8f5f7ff2017-10-17 14:12:42 -0400514 }
515
Jason Monk68ff6aa2018-01-31 15:51:52 -0500516 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
517 @Override
518 public void onReceive(Context context, Intent intent) {
519 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
520 if (userId == UserHandle.USER_NULL) {
521 Slog.w(TAG, "Intent broadcast does not contain user handle: " + intent);
522 return;
523 }
524 Uri data = intent.getData();
525 String pkg = data != null ? data.getSchemeSpecificPart() : null;
526 if (pkg == null) {
527 Slog.w(TAG, "Intent broadcast does not contain package name: " + intent);
528 return;
529 }
530 switch (intent.getAction()) {
531 case Intent.ACTION_PACKAGE_REMOVED:
532 final boolean replacing =
533 intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
534 if (!replacing) {
Jason Monkbf3eedc2018-04-05 20:56:42 -0400535 mPermissions.removePkg(pkg, userId);
Jason Monk68ff6aa2018-01-31 15:51:52 -0500536 }
537 break;
538 case Intent.ACTION_PACKAGE_DATA_CLEARED:
Jason Monkbf3eedc2018-04-05 20:56:42 -0400539 mPermissions.removePkg(pkg, userId);
Jason Monk68ff6aa2018-01-31 15:51:52 -0500540 break;
541 }
542 }
543 };
544
Jason Monk8f5f7ff2017-10-17 14:12:42 -0400545 public static class Lifecycle extends SystemService {
546 private SliceManagerService mService;
547
548 public Lifecycle(Context context) {
549 super(context);
550 }
551
552 @Override
553 public void onStart() {
554 mService = new SliceManagerService(getContext());
555 publishBinderService(Context.SLICE_SERVICE, mService);
556 }
557
558 @Override
559 public void onBootPhase(int phase) {
560 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
561 mService.systemReady();
562 }
563 }
564
565 @Override
566 public void onUnlockUser(int userHandle) {
567 mService.onUnlockUser(userHandle);
568 }
Jason Monk74f5e362017-12-06 08:56:33 -0500569
570 @Override
571 public void onStopUser(int userHandle) {
572 mService.onStopUser(userHandle);
573 }
Jason Monk8f5f7ff2017-10-17 14:12:42 -0400574 }
Jason Monke8f8be72018-01-21 10:10:35 -0500575
576 private class SliceGrant {
577 private final Uri mUri;
578 private final String mPkg;
Jason Monkddb8a962018-01-30 13:27:33 -0500579 private final int mUserId;
Jason Monke8f8be72018-01-21 10:10:35 -0500580
Jason Monkddb8a962018-01-30 13:27:33 -0500581 public SliceGrant(Uri uri, String pkg, int userId) {
Jason Monke8f8be72018-01-21 10:10:35 -0500582 mUri = uri;
583 mPkg = pkg;
Jason Monkddb8a962018-01-30 13:27:33 -0500584 mUserId = userId;
Jason Monke8f8be72018-01-21 10:10:35 -0500585 }
586
587 @Override
588 public int hashCode() {
589 return mUri.hashCode() + mPkg.hashCode();
590 }
591
592 @Override
593 public boolean equals(Object obj) {
594 if (!(obj instanceof SliceGrant)) return false;
595 SliceGrant other = (SliceGrant) obj;
Jason Monkddb8a962018-01-30 13:27:33 -0500596 return Objects.equals(other.mUri, mUri) && Objects.equals(other.mPkg, mPkg)
597 && (other.mUserId == mUserId);
Jason Monke8f8be72018-01-21 10:10:35 -0500598 }
599 }
Jason Monk8f5f7ff2017-10-17 14:12:42 -0400600}