blob: b7b96126fa2101fccc271ef9f31675b6601dbe51 [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;
Jason Monkddb8a962018-01-30 13:27:33 -050047import android.os.Environment;
Jason Monk74f5e362017-12-06 08:56:33 -050048import 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 Monk3a1d2e972018-01-29 16:58:11 -050053import android.os.UserHandle;
Jason Monk74f5e362017-12-06 08:56:33 -050054import android.util.ArrayMap;
Jason Monkddb8a962018-01-30 13:27:33 -050055import android.util.AtomicFile;
Jason Monkddb8a962018-01-30 13:27:33 -050056import android.util.Slog;
57import android.util.Xml.Encoding;
Jason Monk74f5e362017-12-06 08:56:33 -050058
59import com.android.internal.annotations.GuardedBy;
60import com.android.internal.annotations.VisibleForTesting;
61import com.android.internal.app.AssistUtils;
62import com.android.internal.util.Preconditions;
63import com.android.server.LocalServices;
64import com.android.server.ServiceThread;
Jason Monk8f5f7ff2017-10-17 14:12:42 -040065import com.android.server.SystemService;
66
Jason Monkddb8a962018-01-30 13:27:33 -050067import org.xmlpull.v1.XmlPullParser;
68import org.xmlpull.v1.XmlPullParserException;
69import org.xmlpull.v1.XmlPullParserFactory;
70import org.xmlpull.v1.XmlSerializer;
71
Jason Monkb715b042018-02-01 15:00:05 -050072import java.io.ByteArrayInputStream;
73import java.io.ByteArrayOutputStream;
Jason Monkddb8a962018-01-30 13:27:33 -050074import java.io.File;
Jason Monkddb8a962018-01-30 13:27:33 -050075import java.io.IOException;
76import java.io.InputStream;
Jason Monk74f5e362017-12-06 08:56:33 -050077import java.util.ArrayList;
78import java.util.List;
79import java.util.Objects;
80
Jason Monk8f5f7ff2017-10-17 14:12:42 -040081public class SliceManagerService extends ISliceManager.Stub {
82
Jason Monk74f5e362017-12-06 08:56:33 -050083 private static final String TAG = "SliceManagerService";
84 private final Object mLock = new Object();
Jason Monk8f5f7ff2017-10-17 14:12:42 -040085
Jason Monk74f5e362017-12-06 08:56:33 -050086 private final Context mContext;
87 private final PackageManagerInternal mPackageManagerInternal;
88 private final AppOpsManager mAppOps;
89 private final AssistUtils mAssistUtils;
90
91 @GuardedBy("mLock")
92 private final ArrayMap<Uri, PinnedSliceState> mPinnedSlicesByUri = new ArrayMap<>();
93 private final Handler mHandler;
Jason Monkbf3eedc2018-04-05 20:56:42 -040094
95 private final SlicePermissionManager mPermissions;
Jason Monk1918ef72018-03-14 09:20:39 -040096 private final UsageStatsManagerInternal mAppUsageStats;
Jason Monk74f5e362017-12-06 08:56:33 -050097
98 public SliceManagerService(Context context) {
99 this(context, createHandler().getLooper());
Jason Monk8f5f7ff2017-10-17 14:12:42 -0400100 }
101
Jason Monk74f5e362017-12-06 08:56:33 -0500102 @VisibleForTesting
103 SliceManagerService(Context context, Looper looper) {
104 mContext = context;
105 mPackageManagerInternal = Preconditions.checkNotNull(
106 LocalServices.getService(PackageManagerInternal.class));
107 mAppOps = context.getSystemService(AppOpsManager.class);
108 mAssistUtils = new AssistUtils(context);
109 mHandler = new Handler(looper);
110
Jason Monk1918ef72018-03-14 09:20:39 -0400111 mAppUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
Jason Monkddb8a962018-01-30 13:27:33 -0500112
Jason Monkbf3eedc2018-04-05 20:56:42 -0400113 mPermissions = new SlicePermissionManager(mContext, looper);
Jason Monk68ff6aa2018-01-31 15:51:52 -0500114
115 IntentFilter filter = new IntentFilter();
116 filter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED);
117 filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
118 filter.addDataScheme("package");
119 mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
Jason Monk74f5e362017-12-06 08:56:33 -0500120 }
121
122 /// ----- Lifecycle stuff -----
Jason Monk8f5f7ff2017-10-17 14:12:42 -0400123 private void systemReady() {
124 }
125
Jason Monk74f5e362017-12-06 08:56:33 -0500126 private void onUnlockUser(int userId) {
127 }
128
129 private void onStopUser(int userId) {
130 synchronized (mLock) {
131 mPinnedSlicesByUri.values().removeIf(s -> getUserIdFromUri(s.getUri()) == userId);
132 }
133 }
134
135 /// ----- ISliceManager stuff -----
136 @Override
Jason Monkf88d25e2018-03-06 20:13:24 -0500137 public Uri[] getPinnedSlices(String pkg) {
138 verifyCaller(pkg);
139 ArrayList<Uri> ret = new ArrayList<>();
140 synchronized (mLock) {
141 for (PinnedSliceState state : mPinnedSlicesByUri.values()) {
142 if (Objects.equals(pkg, state.getPkg())) {
143 ret.add(state.getUri());
144 }
145 }
146 }
147 return ret.toArray(new Uri[ret.size()]);
148 }
149
150 @Override
Jason Monk42e03f82018-03-30 11:26:56 -0400151 public void pinSlice(String pkg, Uri uri, SliceSpec[] specs, IBinder token)
152 throws RemoteException {
Jason Monk74f5e362017-12-06 08:56:33 -0500153 verifyCaller(pkg);
Jason Monk38df2802018-02-22 19:28:12 -0500154 enforceAccess(pkg, uri);
Jason Monk1918ef72018-03-14 09:20:39 -0400155 int user = Binder.getCallingUserHandle().getIdentifier();
156 uri = maybeAddUserId(uri, user);
Jason Monkf88d25e2018-03-06 20:13:24 -0500157 getOrCreatePinnedSlice(uri, pkg).pin(pkg, specs, token);
Jason Monk1918ef72018-03-14 09:20:39 -0400158
159 Uri finalUri = uri;
160 mHandler.post(() -> {
161 String slicePkg = getProviderPkg(finalUri, user);
162 if (slicePkg != null && !Objects.equals(pkg, slicePkg)) {
163 mAppUsageStats.reportEvent(slicePkg, user,
164 isAssistant(pkg, user) || isDefaultHomeApp(pkg, user)
165 ? SLICE_PINNED_PRIV : SLICE_PINNED);
166 }
167 });
Jason Monk74f5e362017-12-06 08:56:33 -0500168 }
169
170 @Override
Jason Monk38df2802018-02-22 19:28:12 -0500171 public void unpinSlice(String pkg, Uri uri, IBinder token) throws RemoteException {
Jason Monk74f5e362017-12-06 08:56:33 -0500172 verifyCaller(pkg);
Jason Monk38df2802018-02-22 19:28:12 -0500173 enforceAccess(pkg, uri);
Jason Monk74f5e362017-12-06 08:56:33 -0500174 uri = maybeAddUserId(uri, Binder.getCallingUserHandle().getIdentifier());
Jason Monk38df2802018-02-22 19:28:12 -0500175 if (getPinnedSlice(uri).unpin(pkg, token)) {
Jason Monk74f5e362017-12-06 08:56:33 -0500176 removePinnedSlice(uri);
177 }
178 }
179
180 @Override
181 public boolean hasSliceAccess(String pkg) throws RemoteException {
182 verifyCaller(pkg);
183 return hasFullSliceAccess(pkg, Binder.getCallingUserHandle().getIdentifier());
184 }
185
186 @Override
187 public SliceSpec[] getPinnedSpecs(Uri uri, String pkg) throws RemoteException {
188 verifyCaller(pkg);
189 enforceAccess(pkg, uri);
190 return getPinnedSlice(uri).getSpecs();
191 }
192
Jason Monke8f8be72018-01-21 10:10:35 -0500193 @Override
Jason Monkbf3eedc2018-04-05 20:56:42 -0400194 public void grantSlicePermission(String pkg, String toPkg, Uri uri) throws RemoteException {
195 verifyCaller(pkg);
196 int user = Binder.getCallingUserHandle().getIdentifier();
197 enforceOwner(pkg, uri, user);
198 mPermissions.grantSliceAccess(toPkg, user, pkg, user, uri);
199 }
200
201 @Override
202 public void revokeSlicePermission(String pkg, String toPkg, Uri uri) throws RemoteException {
203 verifyCaller(pkg);
204 int user = Binder.getCallingUserHandle().getIdentifier();
205 enforceOwner(pkg, uri, user);
206 mPermissions.revokeSliceAccess(toPkg, user, pkg, user, uri);
207 }
208
209 @Override
Jason Monk42e03f82018-03-30 11:26:56 -0400210 public int checkSlicePermission(Uri uri, String pkg, int pid, int uid,
Jason Monkbf3eedc2018-04-05 20:56:42 -0400211 String[] autoGrantPermissions) {
212 int userId = UserHandle.getUserId(uid);
213 if (pkg == null) {
214 for (String p : mContext.getPackageManager().getPackagesForUid(uid)) {
215 if (checkSlicePermission(uri, p, pid, uid, autoGrantPermissions)
216 == PERMISSION_GRANTED) {
217 return PERMISSION_GRANTED;
218 }
219 }
220 return PERMISSION_DENIED;
221 }
222 if (hasFullSliceAccess(pkg, userId)) {
223 return PackageManager.PERMISSION_GRANTED;
224 }
225 if (mPermissions.hasPermission(pkg, userId, uri)) {
226 return PackageManager.PERMISSION_GRANTED;
227 }
228 if (autoGrantPermissions != null) {
229 // Need to own the Uri to call in with permissions to grant.
230 enforceOwner(pkg, uri, userId);
231 for (String perm : autoGrantPermissions) {
232 if (mContext.checkPermission(perm, pid, uid) == PERMISSION_GRANTED) {
233 int providerUser = ContentProvider.getUserIdFromUri(uri, userId);
234 String providerPkg = getProviderPkg(uri, providerUser);
235 mPermissions.grantSliceAccess(pkg, userId, providerPkg, providerUser, uri);
236 return PackageManager.PERMISSION_GRANTED;
237 }
238 }
239 }
240 // Fallback to allowing uri permissions through.
Jason Monke8f8be72018-01-21 10:10:35 -0500241 if (mContext.checkUriPermission(uri, pid, uid, Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
Jason Monk3a1d2e972018-01-29 16:58:11 -0500242 == PERMISSION_GRANTED) {
Jason Monkbf3eedc2018-04-05 20:56:42 -0400243 return PackageManager.PERMISSION_GRANTED;
Jason Monke8f8be72018-01-21 10:10:35 -0500244 }
Jason Monkbf3eedc2018-04-05 20:56:42 -0400245 return PackageManager.PERMISSION_DENIED;
Jason Monke8f8be72018-01-21 10:10:35 -0500246 }
247
248 @Override
249 public void grantPermissionFromUser(Uri uri, String pkg, String callingPkg, boolean allSlices) {
250 verifyCaller(callingPkg);
251 getContext().enforceCallingOrSelfPermission(permission.MANAGE_SLICE_PERMISSIONS,
252 "Slice granting requires MANAGE_SLICE_PERMISSIONS");
Jason Monkbf3eedc2018-04-05 20:56:42 -0400253 int userId = Binder.getCallingUserHandle().getIdentifier();
Jason Monke8f8be72018-01-21 10:10:35 -0500254 if (allSlices) {
Jason Monkbf3eedc2018-04-05 20:56:42 -0400255 mPermissions.grantFullAccess(pkg, userId);
Jason Monke8f8be72018-01-21 10:10:35 -0500256 } else {
Jason Monkbf3eedc2018-04-05 20:56:42 -0400257 // When granting, grant to all slices in the provider.
258 Uri grantUri = uri.buildUpon()
259 .path("")
260 .build();
261 int providerUser = ContentProvider.getUserIdFromUri(grantUri, userId);
262 String providerPkg = getProviderPkg(grantUri, providerUser);
263 mPermissions.grantSliceAccess(pkg, userId, providerPkg, providerUser, grantUri);
Jason Monkddb8a962018-01-30 13:27:33 -0500264 }
265 long ident = Binder.clearCallingIdentity();
266 try {
267 mContext.getContentResolver().notifyChange(uri, null);
268 } finally {
269 Binder.restoreCallingIdentity(ident);
Jason Monke8f8be72018-01-21 10:10:35 -0500270 }
271 }
272
Jason Monkb715b042018-02-01 15:00:05 -0500273 // Backup/restore interface
274 @Override
275 public byte[] getBackupPayload(int user) {
276 if (Binder.getCallingUid() != SYSTEM_UID) {
277 throw new SecurityException("Caller must be system");
278 }
279 //TODO: http://b/22388012
280 if (user != UserHandle.USER_SYSTEM) {
281 Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
282 return null;
283 }
Jason Monkbf3eedc2018-04-05 20:56:42 -0400284 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
285 try {
286 XmlSerializer out = XmlPullParserFactory.newInstance().newSerializer();
287 out.setOutput(baos, Encoding.UTF_8.name());
288
289 mPermissions.writeBackup(out);
290
291 out.flush();
292 return baos.toByteArray();
293 } catch (IOException | XmlPullParserException e) {
294 Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
Jason Monkb715b042018-02-01 15:00:05 -0500295 }
296 return null;
297 }
298
299 @Override
300 public void applyRestore(byte[] payload, int user) {
301 if (Binder.getCallingUid() != SYSTEM_UID) {
302 throw new SecurityException("Caller must be system");
303 }
304 if (payload == null) {
305 Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
306 return;
307 }
308 //TODO: http://b/22388012
309 if (user != UserHandle.USER_SYSTEM) {
310 Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
311 return;
312 }
Jason Monkbf3eedc2018-04-05 20:56:42 -0400313 final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
314 try {
315 XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
316 parser.setInput(bais, Encoding.UTF_8.name());
317 mPermissions.readRestore(parser);
318 } catch (NumberFormatException | XmlPullParserException | IOException e) {
319 Slog.w(TAG, "applyRestore: error reading payload", e);
Jason Monkb715b042018-02-01 15:00:05 -0500320 }
321 }
322
Jason Monk74f5e362017-12-06 08:56:33 -0500323 /// ----- internal code -----
Jason Monkbf3eedc2018-04-05 20:56:42 -0400324 private void enforceOwner(String pkg, Uri uri, int user) {
325 if (!Objects.equals(getProviderPkg(uri, user), pkg) || pkg == null) {
326 throw new SecurityException("Caller must own " + uri);
Jason Monk68ff6aa2018-01-31 15:51:52 -0500327 }
Jason Monk68ff6aa2018-01-31 15:51:52 -0500328 }
329
Jason Monk9e3b8642018-01-21 20:54:00 -0500330 protected void removePinnedSlice(Uri uri) {
Jason Monk74f5e362017-12-06 08:56:33 -0500331 synchronized (mLock) {
332 mPinnedSlicesByUri.remove(uri).destroy();
333 }
334 }
335
336 private PinnedSliceState getPinnedSlice(Uri uri) {
337 synchronized (mLock) {
338 PinnedSliceState manager = mPinnedSlicesByUri.get(uri);
339 if (manager == null) {
340 throw new IllegalStateException(String.format("Slice %s not pinned",
341 uri.toString()));
342 }
343 return manager;
344 }
345 }
346
Jason Monkf88d25e2018-03-06 20:13:24 -0500347 private PinnedSliceState getOrCreatePinnedSlice(Uri uri, String pkg) {
Jason Monk74f5e362017-12-06 08:56:33 -0500348 synchronized (mLock) {
349 PinnedSliceState manager = mPinnedSlicesByUri.get(uri);
350 if (manager == null) {
Jason Monkf88d25e2018-03-06 20:13:24 -0500351 manager = createPinnedSlice(uri, pkg);
Jason Monk74f5e362017-12-06 08:56:33 -0500352 mPinnedSlicesByUri.put(uri, manager);
353 }
354 return manager;
355 }
356 }
357
358 @VisibleForTesting
Jason Monkf88d25e2018-03-06 20:13:24 -0500359 protected PinnedSliceState createPinnedSlice(Uri uri, String pkg) {
360 return new PinnedSliceState(this, uri, pkg);
Jason Monk74f5e362017-12-06 08:56:33 -0500361 }
362
363 public Object getLock() {
364 return mLock;
365 }
366
367 public Context getContext() {
368 return mContext;
369 }
370
371 public Handler getHandler() {
372 return mHandler;
373 }
374
Jason Monk3a1d2e972018-01-29 16:58:11 -0500375 protected int checkAccess(String pkg, Uri uri, int uid, int pid) {
Jason Monkbf3eedc2018-04-05 20:56:42 -0400376 return checkSlicePermission(uri, pkg, uid, pid, null);
Jason Monk3a1d2e972018-01-29 16:58:11 -0500377 }
378
Jason Monk1918ef72018-03-14 09:20:39 -0400379 private String getProviderPkg(Uri uri, int user) {
380 long ident = Binder.clearCallingIdentity();
381 try {
382 IBinder token = new Binder();
383 IActivityManager activityManager = ActivityManager.getService();
384 ContentProviderHolder holder = null;
385 String providerName = getUriWithoutUserId(uri).getAuthority();
386 try {
387 try {
388 holder = activityManager.getContentProviderExternal(
389 providerName, getUserIdFromUri(uri, user), token);
390 if (holder != null && holder.info != null) {
391 return holder.info.packageName;
392 } else {
393 return null;
394 }
395 } finally {
396 if (holder != null && holder.provider != null) {
397 activityManager.removeContentProviderExternal(providerName, token);
398 }
399 }
400 } catch (RemoteException e) {
401 // Can't happen.
402 throw e.rethrowAsRuntimeException();
403 }
404 } finally {
405 // I know, the double finally seems ugly, but seems safest for the identity.
406 Binder.restoreCallingIdentity(ident);
407 }
408 }
409
Jason Monk3a1d2e972018-01-29 16:58:11 -0500410 private void enforceCrossUser(String pkg, Uri uri) {
411 int user = Binder.getCallingUserHandle().getIdentifier();
Jason Monk74f5e362017-12-06 08:56:33 -0500412 if (getUserIdFromUri(uri, user) != user) {
413 getContext().enforceCallingOrSelfPermission(permission.INTERACT_ACROSS_USERS_FULL,
414 "Slice interaction across users requires INTERACT_ACROSS_USERS_FULL");
415 }
416 }
417
Jason Monk3a1d2e972018-01-29 16:58:11 -0500418 private void enforceAccess(String pkg, Uri uri) throws RemoteException {
419 if (checkAccess(pkg, uri, Binder.getCallingUid(), Binder.getCallingPid())
420 != PERMISSION_GRANTED) {
Jason Monkbf3eedc2018-04-05 20:56:42 -0400421 int userId = ContentProvider.getUserIdFromUri(uri,
422 Binder.getCallingUserHandle().getIdentifier());
423 if (!Objects.equals(pkg, getProviderPkg(uri, userId))) {
424 throw new SecurityException("Access to slice " + uri + " is required");
425 }
Jason Monk74f5e362017-12-06 08:56:33 -0500426 }
Jason Monk3a1d2e972018-01-29 16:58:11 -0500427 enforceCrossUser(pkg, uri);
Jason Monk74f5e362017-12-06 08:56:33 -0500428 }
429
430 private void verifyCaller(String pkg) {
431 mAppOps.checkPackage(Binder.getCallingUid(), pkg);
432 }
433
434 private boolean hasFullSliceAccess(String pkg, int userId) {
Jason Monke8f8be72018-01-21 10:10:35 -0500435 long ident = Binder.clearCallingIdentity();
436 try {
437 boolean ret = isDefaultHomeApp(pkg, userId) || isAssistant(pkg, userId)
438 || isGrantedFullAccess(pkg, userId);
439 return ret;
440 } finally {
441 Binder.restoreCallingIdentity(ident);
442 }
Jason Monk74f5e362017-12-06 08:56:33 -0500443 }
444
445 private boolean isAssistant(String pkg, int userId) {
446 final ComponentName cn = mAssistUtils.getAssistComponentForUser(userId);
447 if (cn == null) {
448 return false;
449 }
450 return cn.getPackageName().equals(pkg);
451 }
452
Jason Monk74f5e362017-12-06 08:56:33 -0500453 private boolean isDefaultHomeApp(String pkg, int userId) {
454 String defaultHome = getDefaultHome(userId);
Jason Monke8f8be72018-01-21 10:10:35 -0500455
456 return pkg != null && Objects.equals(pkg, defaultHome);
Jason Monk74f5e362017-12-06 08:56:33 -0500457 }
458
459 // Based on getDefaultHome in ShortcutService.
460 // TODO: Unify if possible
461 @VisibleForTesting
Jason Monk74848ae2018-01-21 17:11:57 -0500462 protected String getDefaultHome(int userId) {
Jason Monk74f5e362017-12-06 08:56:33 -0500463 final long token = Binder.clearCallingIdentity();
464 try {
465 final List<ResolveInfo> allHomeCandidates = new ArrayList<>();
466
467 // Default launcher from package manager.
468 final ComponentName defaultLauncher = mPackageManagerInternal
469 .getHomeActivitiesAsUser(allHomeCandidates, userId);
470
471 ComponentName detected = null;
472 if (defaultLauncher != null) {
473 detected = defaultLauncher;
474 }
475
476 if (detected == null) {
477 // If we reach here, that means it's the first check since the user was created,
478 // and there's already multiple launchers and there's no default set.
479 // Find the system one with the highest priority.
480 // (We need to check the priority too because of FallbackHome in Settings.)
481 // If there's no system launcher yet, then no one can access slices, until
482 // the user explicitly sets one.
483 final int size = allHomeCandidates.size();
484
485 int lastPriority = Integer.MIN_VALUE;
486 for (int i = 0; i < size; i++) {
487 final ResolveInfo ri = allHomeCandidates.get(i);
488 if (!ri.activityInfo.applicationInfo.isSystemApp()) {
489 continue;
490 }
491 if (ri.priority < lastPriority) {
492 continue;
493 }
494 detected = ri.activityInfo.getComponentName();
495 lastPriority = ri.priority;
496 }
497 }
Jason Monke8f8be72018-01-21 10:10:35 -0500498 return detected != null ? detected.getPackageName() : null;
Jason Monk74f5e362017-12-06 08:56:33 -0500499 } finally {
500 Binder.restoreCallingIdentity(token);
501 }
502 }
503
504 private boolean isGrantedFullAccess(String pkg, int userId) {
Jason Monkbf3eedc2018-04-05 20:56:42 -0400505 return mPermissions.hasFullAccess(pkg, userId);
Jason Monk74f5e362017-12-06 08:56:33 -0500506 }
507
508 private static ServiceThread createHandler() {
509 ServiceThread handlerThread = new ServiceThread(TAG,
510 Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
511 handlerThread.start();
512 return handlerThread;
Jason Monk8f5f7ff2017-10-17 14:12:42 -0400513 }
514
Jason Monk68ff6aa2018-01-31 15:51:52 -0500515 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
516 @Override
517 public void onReceive(Context context, Intent intent) {
518 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
519 if (userId == UserHandle.USER_NULL) {
520 Slog.w(TAG, "Intent broadcast does not contain user handle: " + intent);
521 return;
522 }
523 Uri data = intent.getData();
524 String pkg = data != null ? data.getSchemeSpecificPart() : null;
525 if (pkg == null) {
526 Slog.w(TAG, "Intent broadcast does not contain package name: " + intent);
527 return;
528 }
529 switch (intent.getAction()) {
530 case Intent.ACTION_PACKAGE_REMOVED:
531 final boolean replacing =
532 intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
533 if (!replacing) {
Jason Monkbf3eedc2018-04-05 20:56:42 -0400534 mPermissions.removePkg(pkg, userId);
Jason Monk68ff6aa2018-01-31 15:51:52 -0500535 }
536 break;
537 case Intent.ACTION_PACKAGE_DATA_CLEARED:
Jason Monkbf3eedc2018-04-05 20:56:42 -0400538 mPermissions.removePkg(pkg, userId);
Jason Monk68ff6aa2018-01-31 15:51:52 -0500539 break;
540 }
541 }
542 };
543
Jason Monk8f5f7ff2017-10-17 14:12:42 -0400544 public static class Lifecycle extends SystemService {
545 private SliceManagerService mService;
546
547 public Lifecycle(Context context) {
548 super(context);
549 }
550
551 @Override
552 public void onStart() {
553 mService = new SliceManagerService(getContext());
554 publishBinderService(Context.SLICE_SERVICE, mService);
555 }
556
557 @Override
558 public void onBootPhase(int phase) {
559 if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
560 mService.systemReady();
561 }
562 }
563
564 @Override
565 public void onUnlockUser(int userHandle) {
566 mService.onUnlockUser(userHandle);
567 }
Jason Monk74f5e362017-12-06 08:56:33 -0500568
569 @Override
570 public void onStopUser(int userHandle) {
571 mService.onStopUser(userHandle);
572 }
Jason Monk8f5f7ff2017-10-17 14:12:42 -0400573 }
Jason Monke8f8be72018-01-21 10:10:35 -0500574
575 private class SliceGrant {
576 private final Uri mUri;
577 private final String mPkg;
Jason Monkddb8a962018-01-30 13:27:33 -0500578 private final int mUserId;
Jason Monke8f8be72018-01-21 10:10:35 -0500579
Jason Monkddb8a962018-01-30 13:27:33 -0500580 public SliceGrant(Uri uri, String pkg, int userId) {
Jason Monke8f8be72018-01-21 10:10:35 -0500581 mUri = uri;
582 mPkg = pkg;
Jason Monkddb8a962018-01-30 13:27:33 -0500583 mUserId = userId;
Jason Monke8f8be72018-01-21 10:10:35 -0500584 }
585
586 @Override
587 public int hashCode() {
588 return mUri.hashCode() + mPkg.hashCode();
589 }
590
591 @Override
592 public boolean equals(Object obj) {
593 if (!(obj instanceof SliceGrant)) return false;
594 SliceGrant other = (SliceGrant) obj;
Jason Monkddb8a962018-01-30 13:27:33 -0500595 return Objects.equals(other.mUri, mUri) && Objects.equals(other.mPkg, mPkg)
596 && (other.mUserId == mUserId);
Jason Monke8f8be72018-01-21 10:10:35 -0500597 }
598 }
Jason Monk8f5f7ff2017-10-17 14:12:42 -0400599}