blob: cf09b8fc4c841327d6a634fdd40c7e6f6da9d7e0 [file] [log] [blame]
John Spurlock7340fc82014-04-24 18:50:12 -04001/**
2 * Copyright (c) 2014, 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.notification;
18
Felipe Lemea1b79bf2016-05-24 13:06:54 -070019import static android.content.Context.BIND_ALLOW_WHITELIST_MANAGEMENT;
20import static android.content.Context.BIND_AUTO_CREATE;
21import static android.content.Context.BIND_FOREGROUND_SERVICE;
Esteban Talavera9c6458d2017-03-30 17:59:50 +010022import static android.content.Context.DEVICE_POLICY_SERVICE;
Julia Reynoldsca8e5352018-09-18 13:39:26 -040023import static android.os.UserHandle.USER_ALL;
Felipe Lemea1b79bf2016-05-24 13:06:54 -070024
Ruben Brunke24b9a62016-02-16 21:38:24 -080025import android.annotation.NonNull;
John Spurlock7340fc82014-04-24 18:50:12 -040026import android.app.ActivityManager;
27import android.app.PendingIntent;
Esteban Talavera9c6458d2017-03-30 17:59:50 +010028import android.app.admin.DevicePolicyManager;
John Spurlock7340fc82014-04-24 18:50:12 -040029import android.content.ComponentName;
30import android.content.ContentResolver;
31import android.content.Context;
32import android.content.Intent;
33import android.content.ServiceConnection;
34import android.content.pm.ApplicationInfo;
Julia Reynoldsa75c7522017-03-21 17:34:25 -040035import android.content.pm.IPackageManager;
John Spurlock7340fc82014-04-24 18:50:12 -040036import android.content.pm.PackageManager;
37import android.content.pm.PackageManager.NameNotFoundException;
38import android.content.pm.ResolveInfo;
39import android.content.pm.ServiceInfo;
40import android.content.pm.UserInfo;
Esteban Talavera9c6458d2017-03-30 17:59:50 +010041import android.os.Binder;
John Spurlock7340fc82014-04-24 18:50:12 -040042import android.os.Build;
Ryan Lothian4a86a512017-12-04 11:56:58 -050043import android.os.Handler;
John Spurlock7340fc82014-04-24 18:50:12 -040044import android.os.IBinder;
45import android.os.IInterface;
Ryan Lothian4a86a512017-12-04 11:56:58 -050046import android.os.Looper;
John Spurlock7340fc82014-04-24 18:50:12 -040047import android.os.RemoteException;
48import android.os.UserHandle;
49import android.os.UserManager;
50import android.provider.Settings;
Kweku Adams93304b62017-09-20 17:03:00 -070051import android.service.notification.ManagedServiceInfoProto;
52import android.service.notification.ManagedServicesProto;
53import android.service.notification.ManagedServicesProto.ServiceProto;
John Spurlock7340fc82014-04-24 18:50:12 -040054import android.text.TextUtils;
Julia Reynoldsb852e562017-06-06 16:14:18 -040055import android.util.ArrayMap;
John Spurlock7340fc82014-04-24 18:50:12 -040056import android.util.ArraySet;
Julia Reynoldsca8e5352018-09-18 13:39:26 -040057import android.util.IntArray;
John Spurlock4db0d982014-08-13 09:19:03 -040058import android.util.Log;
Andrew Zeng190c0672018-06-28 15:15:05 -070059import android.util.Pair;
John Spurlock7340fc82014-04-24 18:50:12 -040060import android.util.Slog;
61import android.util.SparseArray;
Kweku Adams93304b62017-09-20 17:03:00 -070062import android.util.proto.ProtoOutputStream;
John Spurlock7340fc82014-04-24 18:50:12 -040063
Julia Reynoldsca8e5352018-09-18 13:39:26 -040064import com.android.internal.annotations.GuardedBy;
65import com.android.internal.annotations.VisibleForTesting;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -040066import com.android.internal.util.XmlUtils;
John Spurlock25e2d242014-06-27 13:58:23 -040067import com.android.server.notification.NotificationManagerService.DumpFilter;
68
Julia Reynoldsb852e562017-06-06 16:14:18 -040069import org.xmlpull.v1.XmlPullParser;
70import org.xmlpull.v1.XmlPullParserException;
71import org.xmlpull.v1.XmlSerializer;
72
73import java.io.IOException;
John Spurlock7340fc82014-04-24 18:50:12 -040074import java.io.PrintWriter;
75import java.util.ArrayList;
John Spurlocke77bb362014-04-26 10:24:59 -040076import java.util.Arrays;
Julia Reynolds9a86cc02016-02-10 15:38:15 -050077import java.util.HashSet;
John Spurlock7340fc82014-04-24 18:50:12 -040078import java.util.List;
Julia Reynoldsca8e5352018-09-18 13:39:26 -040079import java.util.Objects;
John Spurlock7340fc82014-04-24 18:50:12 -040080import java.util.Set;
Kristian Monsen05f34792018-04-09 10:27:16 +020081import java.util.function.Predicate;
John Spurlock7340fc82014-04-24 18:50:12 -040082
83/**
84 * Manages the lifecycle of application-provided services bound by system server.
85 *
86 * Services managed by this helper must have:
87 * - An associated system settings value with a list of enabled component names.
88 * - A well-known action for services to use in their intent-filter.
89 * - A system permission for services to require in order to ensure system has exclusive binding.
90 * - A settings page for user configuration of enabled services, and associated intent action.
91 * - A remote interface definition (aidl) provided by the service used for communication.
92 */
93abstract public class ManagedServices {
94 protected final String TAG = getClass().getSimpleName();
John Spurlock4db0d982014-08-13 09:19:03 -040095 protected final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
John Spurlock7340fc82014-04-24 18:50:12 -040096
Ryan Lothian4a86a512017-12-04 11:56:58 -050097 private static final int ON_BINDING_DIED_REBIND_DELAY_MS = 10000;
Julia Reynoldsc279b992015-10-30 08:23:51 -040098 protected static final String ENABLED_SERVICES_SEPARATOR = ":";
John Spurlock7340fc82014-04-24 18:50:12 -040099
Julia Reynoldsb852e562017-06-06 16:14:18 -0400100 /**
101 * List of components and apps that can have running {@link ManagedServices}.
102 */
103 static final String TAG_MANAGED_SERVICES = "service_listing";
104 static final String ATT_APPROVED_LIST = "approved";
105 static final String ATT_USER_ID = "user";
106 static final String ATT_IS_PRIMARY = "primary";
Julia Reynolds7380d872018-01-12 10:28:26 -0500107 static final String ATT_VERSION = "version";
108
109 static final int DB_VERSION = 1;
Julia Reynoldsb852e562017-06-06 16:14:18 -0400110
111 static final int APPROVAL_BY_PACKAGE = 0;
112 static final int APPROVAL_BY_COMPONENT = 1;
113
John Spurlockaf8d6c42014-05-07 17:49:08 -0400114 protected final Context mContext;
John Spurlocke77bb362014-04-26 10:24:59 -0400115 protected final Object mMutex;
John Spurlock7340fc82014-04-24 18:50:12 -0400116 private final UserProfiles mUserProfiles;
Julia Reynoldsa75c7522017-03-21 17:34:25 -0400117 private final IPackageManager mPm;
Julia Reynoldsd6d5a592018-04-02 11:03:32 -0400118 protected final UserManager mUm;
John Spurlock7340fc82014-04-24 18:50:12 -0400119 private final Config mConfig;
Ryan Lothian4a86a512017-12-04 11:56:58 -0500120 private final Handler mHandler = new Handler(Looper.getMainLooper());
John Spurlock7340fc82014-04-24 18:50:12 -0400121
122 // contains connections to all connected services, including app services
123 // and system services
Julia Reynoldsb852e562017-06-06 16:14:18 -0400124 private final ArrayList<ManagedServiceInfo> mServices = new ArrayList<>();
Andrew Zeng190c0672018-06-28 15:15:05 -0700125 /**
126 * The services that have been bound by us. If the service is also connected, it will also
127 * be in {@link #mServices}.
128 */
129 private final ArrayList<Pair<ComponentName, Integer>> mServicesBound = new ArrayList<>();
130 private final ArraySet<Pair<ComponentName, Integer>> mServicesRebinding = new ArraySet<>();
Ryan Lothian4a86a512017-12-04 11:56:58 -0500131
Chris Wrenab41eec2016-01-04 18:01:27 -0500132 // lists the component names of all enabled (and therefore potentially connected)
John Spurlock7340fc82014-04-24 18:50:12 -0400133 // app services for current profiles.
134 private ArraySet<ComponentName> mEnabledServicesForCurrentProfiles
Julia Reynoldsb852e562017-06-06 16:14:18 -0400135 = new ArraySet<>();
John Spurlock7340fc82014-04-24 18:50:12 -0400136 // Just the packages from mEnabledServicesForCurrentProfiles
Julia Reynoldsb852e562017-06-06 16:14:18 -0400137 private ArraySet<String> mEnabledServicesPackageNames = new ArraySet<>();
Chris Wrenab41eec2016-01-04 18:01:27 -0500138 // List of enabled packages that have nevertheless asked not to be run
139 private ArraySet<ComponentName> mSnoozingForCurrentProfiles = new ArraySet<>();
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200140
Julia Reynoldsb852e562017-06-06 16:14:18 -0400141 // List of approved packages or components (by user, then by primary/secondary) that are
142 // allowed to be bound as managed services. A package or component appearing in this list does
143 // not mean that we are currently bound to said package/component.
144 private ArrayMap<Integer, ArrayMap<Boolean, ArraySet<String>>> mApproved = new ArrayMap<>();
John Spurlock7340fc82014-04-24 18:50:12 -0400145
Julia Reynoldsb852e562017-06-06 16:14:18 -0400146 // True if approved services are stored in xml, not settings.
147 private boolean mUseXml;
Christopher Tate6597e342015-02-17 12:15:25 -0800148
Julia Reynoldsb852e562017-06-06 16:14:18 -0400149 // Whether managed services are approved individually or package wide
150 protected int mApprovalLevel;
151
152 public ManagedServices(Context context, Object mutex, UserProfiles userProfiles,
153 IPackageManager pm) {
John Spurlock7340fc82014-04-24 18:50:12 -0400154 mContext = context;
155 mMutex = mutex;
156 mUserProfiles = userProfiles;
Julia Reynoldsb852e562017-06-06 16:14:18 -0400157 mPm = pm;
John Spurlock7340fc82014-04-24 18:50:12 -0400158 mConfig = getConfig();
Julia Reynoldsb852e562017-06-06 16:14:18 -0400159 mApprovalLevel = APPROVAL_BY_COMPONENT;
Julia Reynolds45523002017-09-12 09:43:57 -0400160 mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
John Spurlock7340fc82014-04-24 18:50:12 -0400161 }
162
163 abstract protected Config getConfig();
164
165 private String getCaption() {
166 return mConfig.caption;
167 }
168
169 abstract protected IInterface asInterface(IBinder binder);
170
Chris Wren51017d02015-12-15 15:34:46 -0500171 abstract protected boolean checkType(IInterface service);
172
John Spurlock3b98b3f2014-05-01 09:08:48 -0400173 abstract protected void onServiceAdded(ManagedServiceInfo info);
John Spurlock7340fc82014-04-24 18:50:12 -0400174
Julia Reynolds73ed76b2017-04-04 17:04:38 -0400175 protected List<ManagedServiceInfo> getServices() {
176 synchronized (mMutex) {
177 List<ManagedServiceInfo> services = new ArrayList<>(mServices);
178 return services;
179 }
180 }
181
Amith Yamasanie5bfeee2018-09-05 18:52:35 -0700182 protected int getBindFlags() {
183 return BIND_AUTO_CREATE | BIND_FOREGROUND_SERVICE | BIND_ALLOW_WHITELIST_MANAGEMENT;
184 }
185
John Spurlocke77bb362014-04-26 10:24:59 -0400186 protected void onServiceRemovedLocked(ManagedServiceInfo removed) { }
187
John Spurlock7340fc82014-04-24 18:50:12 -0400188 private ManagedServiceInfo newServiceInfo(IInterface service,
Julia Reynoldsb852e562017-06-06 16:14:18 -0400189 ComponentName component, int userId, boolean isSystem, ServiceConnection connection,
John Spurlock7340fc82014-04-24 18:50:12 -0400190 int targetSdkVersion) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400191 return new ManagedServiceInfo(service, component, userId, isSystem, connection,
John Spurlock7340fc82014-04-24 18:50:12 -0400192 targetSdkVersion);
193 }
194
Julia Reynoldsb852e562017-06-06 16:14:18 -0400195 public void onBootPhaseAppsCanStart() {}
John Spurlock7340fc82014-04-24 18:50:12 -0400196
John Spurlock25e2d242014-06-27 13:58:23 -0400197 public void dump(PrintWriter pw, DumpFilter filter) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400198 pw.println(" Allowed " + getCaption() + "s:");
199 final int N = mApproved.size();
200 for (int i = 0 ; i < N; i++) {
201 final int userId = mApproved.keyAt(i);
202 final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
203 if (approvedByType != null) {
204 final int M = approvedByType.size();
205 for (int j = 0; j < M; j++) {
206 final boolean isPrimary = approvedByType.keyAt(j);
207 final ArraySet<String> approved = approvedByType.valueAt(j);
208 if (approvedByType != null && approvedByType.size() > 0) {
209 pw.println(" " + String.join(ENABLED_SERVICES_SEPARATOR, approved)
210 + " (user: " + userId + " isPrimary: " + isPrimary + ")");
211 }
212 }
213 }
214 }
215
John Spurlocke77bb362014-04-26 10:24:59 -0400216 pw.println(" All " + getCaption() + "s (" + mEnabledServicesForCurrentProfiles.size()
John Spurlock7340fc82014-04-24 18:50:12 -0400217 + ") enabled for current profiles:");
218 for (ComponentName cmpt : mEnabledServicesForCurrentProfiles) {
John Spurlock25e2d242014-06-27 13:58:23 -0400219 if (filter != null && !filter.matches(cmpt)) continue;
John Spurlocke77bb362014-04-26 10:24:59 -0400220 pw.println(" " + cmpt);
John Spurlock7340fc82014-04-24 18:50:12 -0400221 }
222
John Spurlocke77bb362014-04-26 10:24:59 -0400223 pw.println(" Live " + getCaption() + "s (" + mServices.size() + "):");
Julia Reynolds3ff1fd92018-08-29 09:57:11 -0400224 synchronized (mMutex) {
225 for (ManagedServiceInfo info : mServices) {
226 if (filter != null && !filter.matches(info.component)) continue;
227 pw.println(" " + info.component
228 + " (user " + info.userid + "): " + info.service
229 + (info.isSystem ? " SYSTEM" : "")
230 + (info.isGuest(this) ? " GUEST" : ""));
231 }
John Spurlock7340fc82014-04-24 18:50:12 -0400232 }
Chris Wrenab41eec2016-01-04 18:01:27 -0500233
234 pw.println(" Snoozed " + getCaption() + "s (" +
235 mSnoozingForCurrentProfiles.size() + "):");
236 for (ComponentName name : mSnoozingForCurrentProfiles) {
237 pw.println(" " + name.flattenToShortString());
238 }
John Spurlock7340fc82014-04-24 18:50:12 -0400239 }
240
Kweku Adams93304b62017-09-20 17:03:00 -0700241 public void dump(ProtoOutputStream proto, DumpFilter filter) {
242 proto.write(ManagedServicesProto.CAPTION, getCaption());
243 final int N = mApproved.size();
244 for (int i = 0 ; i < N; i++) {
245 final int userId = mApproved.keyAt(i);
246 final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
247 if (approvedByType != null) {
248 final int M = approvedByType.size();
249 for (int j = 0; j < M; j++) {
250 final boolean isPrimary = approvedByType.keyAt(j);
251 final ArraySet<String> approved = approvedByType.valueAt(j);
252 if (approvedByType != null && approvedByType.size() > 0) {
253 final long sToken = proto.start(ManagedServicesProto.APPROVED);
254 for (String s : approved) {
255 proto.write(ServiceProto.NAME, s);
256 }
257 proto.write(ServiceProto.USER_ID, userId);
258 proto.write(ServiceProto.IS_PRIMARY, isPrimary);
259 proto.end(sToken);
260 }
261 }
262 }
263 }
264
265 for (ComponentName cmpt : mEnabledServicesForCurrentProfiles) {
266 if (filter != null && !filter.matches(cmpt)) continue;
Kweku Adams85f2fbc2017-12-18 12:04:12 -0800267 cmpt.writeToProto(proto, ManagedServicesProto.ENABLED);
Kweku Adams93304b62017-09-20 17:03:00 -0700268 }
269
Julia Reynolds3ff1fd92018-08-29 09:57:11 -0400270 synchronized (mMutex) {
271 for (ManagedServiceInfo info : mServices) {
272 if (filter != null && !filter.matches(info.component)) continue;
273 info.writeToProto(proto, ManagedServicesProto.LIVE_SERVICES, this);
274 }
Kweku Adams93304b62017-09-20 17:03:00 -0700275 }
276
277 for (ComponentName name : mSnoozingForCurrentProfiles) {
Kweku Adams85f2fbc2017-12-18 12:04:12 -0800278 name.writeToProto(proto, ManagedServicesProto.SNOOZED);
Kweku Adams93304b62017-09-20 17:03:00 -0700279 }
280 }
281
Julia Reynoldsfa206a42017-08-14 13:22:23 -0400282 protected void onSettingRestored(String element, String value, int backupSdkInt, int userId) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400283 if (!mUseXml) {
284 Slog.d(TAG, "Restored managed service setting: " + element);
285 if (mConfig.secureSettingName.equals(element) ||
286 (mConfig.secondarySettingName != null
287 && mConfig.secondarySettingName.equals(element))) {
Julia Reynoldsfa206a42017-08-14 13:22:23 -0400288 if (backupSdkInt < Build.VERSION_CODES.O) {
289 // automatic system grants were added in O, so append the approved apps
290 // rather than wiping out the setting
291 String currentSetting =
292 getApproved(userId, mConfig.secureSettingName.equals(element));
293 if (!TextUtils.isEmpty(currentSetting)) {
294 if (!TextUtils.isEmpty(value)) {
295 value = value + ENABLED_SERVICES_SEPARATOR + currentSetting;
296 } else {
297 value = currentSetting;
298 }
299 }
300 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400301 Settings.Secure.putStringForUser(
302 mContext.getContentResolver(), element, value, userId);
303 loadAllowedComponentsFromSettings();
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400304 rebindServices(false, userId);
Christopher Tate6597e342015-02-17 12:15:25 -0800305 }
306 }
307 }
308
Annie Meng8b646fd2019-02-01 18:46:42 +0000309 public void writeXml(XmlSerializer out, boolean forBackup, int userId) throws IOException {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400310 out.startTag(null, getConfig().xmlTag);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400311
Julia Reynolds7380d872018-01-12 10:28:26 -0500312 out.attribute(null, ATT_VERSION, String.valueOf(DB_VERSION));
313
Julia Reynoldsb852e562017-06-06 16:14:18 -0400314 if (forBackup) {
Annie Meng8b646fd2019-02-01 18:46:42 +0000315 trimApprovedListsAccordingToInstalledServices(userId);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400316 }
317
318 final int N = mApproved.size();
319 for (int i = 0 ; i < N; i++) {
Annie Meng8b646fd2019-02-01 18:46:42 +0000320 final int approvedUserId = mApproved.keyAt(i);
321 if (forBackup && approvedUserId != userId) {
322 continue;
323 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400324 final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
325 if (approvedByType != null) {
326 final int M = approvedByType.size();
327 for (int j = 0; j < M; j++) {
328 final boolean isPrimary = approvedByType.keyAt(j);
329 final Set<String> approved = approvedByType.valueAt(j);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400330 if (approved != null) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400331 String allowedItems = String.join(ENABLED_SERVICES_SEPARATOR, approved);
332 out.startTag(null, TAG_MANAGED_SERVICES);
333 out.attribute(null, ATT_APPROVED_LIST, allowedItems);
Annie Meng8b646fd2019-02-01 18:46:42 +0000334 out.attribute(null, ATT_USER_ID, Integer.toString(approvedUserId));
Julia Reynoldsb852e562017-06-06 16:14:18 -0400335 out.attribute(null, ATT_IS_PRIMARY, Boolean.toString(isPrimary));
336 out.endTag(null, TAG_MANAGED_SERVICES);
337
338 if (!forBackup && isPrimary) {
339 // Also write values to settings, for observers who haven't migrated yet
340 Settings.Secure.putStringForUser(mContext.getContentResolver(),
Annie Meng8b646fd2019-02-01 18:46:42 +0000341 getConfig().secureSettingName, allowedItems, approvedUserId);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400342 }
343
344 }
345 }
346 }
347 }
348
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400349 out.endTag(null, getConfig().xmlTag);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400350 }
351
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400352 protected void migrateToXml() {
353 loadAllowedComponentsFromSettings();
354 }
355
Annie Meng8b646fd2019-02-01 18:46:42 +0000356 public void readXml(
357 XmlPullParser parser,
358 Predicate<String> allowedManagedServicePackages,
359 boolean forRestore,
360 int userId)
Julia Reynoldsb852e562017-06-06 16:14:18 -0400361 throws XmlPullParserException, IOException {
Julia Reynolds7380d872018-01-12 10:28:26 -0500362 // read grants
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400363 int type;
364 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
365 String tag = parser.getName();
366 if (type == XmlPullParser.END_TAG
367 && getConfig().xmlTag.equals(tag)) {
368 break;
369 }
370 if (type == XmlPullParser.START_TAG) {
371 if (TAG_MANAGED_SERVICES.equals(tag)) {
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -0400372 Slog.i(TAG, "Read " + mConfig.caption + " permissions from xml");
Julia Reynolds7380d872018-01-12 10:28:26 -0500373
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400374 final String approved = XmlUtils.readStringAttribute(parser, ATT_APPROVED_LIST);
Annie Meng8b646fd2019-02-01 18:46:42 +0000375 // Ignore parser's user id for restore.
376 final int resolvedUserId = forRestore
377 ? userId : XmlUtils.readIntAttribute(parser, ATT_USER_ID, 0);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400378 final boolean isPrimary =
379 XmlUtils.readBooleanAttribute(parser, ATT_IS_PRIMARY, true);
Kristian Monsen05f34792018-04-09 10:27:16 +0200380
381 if (allowedManagedServicePackages == null ||
382 allowedManagedServicePackages.test(getPackageName(approved))) {
Annie Meng8b646fd2019-02-01 18:46:42 +0000383 if (mUm.getUserInfo(resolvedUserId) != null) {
384 addApprovedList(approved, resolvedUserId, isPrimary);
Kristian Monsen05f34792018-04-09 10:27:16 +0200385 }
386 mUseXml = true;
Julia Reynolds45523002017-09-12 09:43:57 -0400387 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400388 }
389 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400390 }
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400391 rebindServices(false, USER_ALL);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400392 }
393
394 private void loadAllowedComponentsFromSettings() {
Julia Reynoldse0d711f2017-09-01 08:50:47 -0400395 for (UserInfo user : mUm.getUsers()) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400396 final ContentResolver cr = mContext.getContentResolver();
397 addApprovedList(Settings.Secure.getStringForUser(
398 cr,
399 getConfig().secureSettingName,
400 user.id), user.id, true);
401 if (!TextUtils.isEmpty(getConfig().secondarySettingName)) {
402 addApprovedList(Settings.Secure.getStringForUser(
403 cr,
404 getConfig().secondarySettingName,
405 user.id), user.id, false);
406 }
407 }
408 Slog.d(TAG, "Done loading approved values from settings");
409 }
410
Julia Reynolds7380d872018-01-12 10:28:26 -0500411 protected void addApprovedList(String approved, int userId, boolean isPrimary) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400412 if (TextUtils.isEmpty(approved)) {
413 approved = "";
414 }
415 ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId);
416 if (approvedByType == null) {
417 approvedByType = new ArrayMap<>();
418 mApproved.put(userId, approvedByType);
419 }
Artem Iglikovbec96172018-04-24 12:46:44 +0100420
421 ArraySet<String> approvedList = approvedByType.get(isPrimary);
422 if (approvedList == null) {
423 approvedList = new ArraySet<>();
424 approvedByType.put(isPrimary, approvedList);
425 }
426
Julia Reynoldsb852e562017-06-06 16:14:18 -0400427 String[] approvedArray = approved.split(ENABLED_SERVICES_SEPARATOR);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400428 for (String pkgOrComponent : approvedArray) {
429 String approvedItem = getApprovedValue(pkgOrComponent);
430 if (approvedItem != null) {
431 approvedList.add(approvedItem);
432 }
433 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400434 }
435
436 protected boolean isComponentEnabledForPackage(String pkg) {
John Spurlock80774932015-05-07 17:38:50 -0400437 return mEnabledServicesPackageNames.contains(pkg);
438 }
439
Julia Reynoldsb852e562017-06-06 16:14:18 -0400440 protected void setPackageOrComponentEnabled(String pkgOrComponent, int userId,
441 boolean isPrimary, boolean enabled) {
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -0400442 Slog.i(TAG,
443 (enabled ? " Allowing " : "Disallowing ") + mConfig.caption + " " + pkgOrComponent);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400444 ArrayMap<Boolean, ArraySet<String>> allowedByType = mApproved.get(userId);
445 if (allowedByType == null) {
446 allowedByType = new ArrayMap<>();
447 mApproved.put(userId, allowedByType);
448 }
449 ArraySet<String> approved = allowedByType.get(isPrimary);
450 if (approved == null) {
451 approved = new ArraySet<>();
452 allowedByType.put(isPrimary, approved);
453 }
454 String approvedItem = getApprovedValue(pkgOrComponent);
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200455
Julia Reynoldsb852e562017-06-06 16:14:18 -0400456 if (approvedItem != null) {
457 if (enabled) {
458 approved.add(approvedItem);
459 } else {
460 approved.remove(approvedItem);
John Spurlock7340fc82014-04-24 18:50:12 -0400461 }
462 }
463
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400464 rebindServices(false, userId);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400465 }
466
467 private String getApprovedValue(String pkgOrComponent) {
468 if (mApprovalLevel == APPROVAL_BY_COMPONENT) {
469 if(ComponentName.unflattenFromString(pkgOrComponent) != null) {
470 return pkgOrComponent;
John Spurlock7340fc82014-04-24 18:50:12 -0400471 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400472 return null;
473 } else {
474 return getPackageName(pkgOrComponent);
475 }
476 }
477
Julia Reynoldsfa206a42017-08-14 13:22:23 -0400478 protected String getApproved(int userId, boolean primary) {
479 final ArrayMap<Boolean, ArraySet<String>> allowedByType =
480 mApproved.getOrDefault(userId, new ArrayMap<>());
481 ArraySet<String> approved = allowedByType.getOrDefault(primary, new ArraySet<>());
482 return String.join(ENABLED_SERVICES_SEPARATOR, approved);
483 }
484
Julia Reynoldsb852e562017-06-06 16:14:18 -0400485 protected List<ComponentName> getAllowedComponents(int userId) {
486 final List<ComponentName> allowedComponents = new ArrayList<>();
487 final ArrayMap<Boolean, ArraySet<String>> allowedByType =
488 mApproved.getOrDefault(userId, new ArrayMap<>());
489 for (int i = 0; i < allowedByType.size(); i++) {
490 final ArraySet<String> allowed = allowedByType.valueAt(i);
Julia Reynolds2f496962018-04-16 13:17:01 -0400491 for (int j = 0; j < allowed.size(); j++) {
492 ComponentName cn = ComponentName.unflattenFromString(allowed.valueAt(j));
493 if (cn != null) {
494 allowedComponents.add(cn);
495 }
496 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400497 }
498 return allowedComponents;
499 }
500
501 protected List<String> getAllowedPackages(int userId) {
502 final List<String> allowedPackages = new ArrayList<>();
503 final ArrayMap<Boolean, ArraySet<String>> allowedByType =
504 mApproved.getOrDefault(userId, new ArrayMap<>());
505 for (int i = 0; i < allowedByType.size(); i++) {
506 final ArraySet<String> allowed = allowedByType.valueAt(i);
Julia Reynolds2f496962018-04-16 13:17:01 -0400507 for (int j = 0; j < allowed.size(); j++) {
508 String pkgName = getPackageName(allowed.valueAt(j));
509 if (!TextUtils.isEmpty(pkgName)) {
510 allowedPackages.add(pkgName);
511 }
512 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400513 }
514 return allowedPackages;
515 }
516
517 protected boolean isPackageOrComponentAllowed(String pkgOrComponent, int userId) {
518 ArrayMap<Boolean, ArraySet<String>> allowedByType =
519 mApproved.getOrDefault(userId, new ArrayMap<>());
520 for (int i = 0; i < allowedByType.size(); i++) {
521 ArraySet<String> allowed = allowedByType.valueAt(i);
522 if (allowed.contains(pkgOrComponent)) {
523 return true;
524 }
525 }
526 return false;
527 }
528
Julia Reynolds14590742018-07-30 09:25:35 -0400529 protected boolean isPackageAllowed(String pkg, int userId) {
530 if (pkg == null) {
531 return false;
532 }
533 ArrayMap<Boolean, ArraySet<String>> allowedByType =
534 mApproved.getOrDefault(userId, new ArrayMap<>());
535 for (int i = 0; i < allowedByType.size(); i++) {
536 ArraySet<String> allowed = allowedByType.valueAt(i);
537 for (String allowedEntry : allowed) {
538 ComponentName component = ComponentName.unflattenFromString(allowedEntry);
539 if (component != null) {
540 if (pkg.equals(component.getPackageName())) {
541 return true;
542 }
543 } else {
544 if (pkg.equals(allowedEntry)) {
545 return true;
546 }
547 }
548 }
549 }
550 return false;
551 }
552
Julia Reynoldsb852e562017-06-06 16:14:18 -0400553 public void onPackagesChanged(boolean removingPackage, String[] pkgList, int[] uidList) {
554 if (DEBUG) Slog.d(TAG, "onPackagesChanged removingPackage=" + removingPackage
555 + " pkgList=" + (pkgList == null ? null : Arrays.asList(pkgList))
556 + " mEnabledServicesPackageNames=" + mEnabledServicesPackageNames);
557
558 if (pkgList != null && (pkgList.length > 0)) {
559 boolean anyServicesInvolved = false;
560 // Remove notification settings for uninstalled package
Beverly42d01902019-01-03 12:47:57 -0500561 if (removingPackage && uidList != null) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400562 int size = Math.min(pkgList.length, uidList.length);
563 for (int i = 0; i < size; i++) {
564 final String pkg = pkgList[i];
565 final int userId = UserHandle.getUserId(uidList[i]);
566 anyServicesInvolved = removeUninstalledItemsFromApprovedLists(userId, pkg);
567 }
568 }
569 for (String pkgName : pkgList) {
570 if (mEnabledServicesPackageNames.contains(pkgName)) {
571 anyServicesInvolved = true;
572 }
Beverly42d01902019-01-03 12:47:57 -0500573 if (uidList != null && uidList.length > 0) {
574 for (int uid : uidList) {
575 if (isPackageAllowed(pkgName, UserHandle.getUserId(uid))) {
576 anyServicesInvolved = true;
577 }
Julia Reynolds14590742018-07-30 09:25:35 -0400578 }
579 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400580 }
581
582 if (anyServicesInvolved) {
583 // make sure we're still bound to any of our services who may have just upgraded
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400584 rebindServices(false, USER_ALL);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400585 }
John Spurlock7340fc82014-04-24 18:50:12 -0400586 }
587 }
588
Julia Reynolds5aa13a42017-08-24 09:10:23 -0400589 public void onUserRemoved(int user) {
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -0400590 Slog.i(TAG, "Removing approved services for removed user " + user);
Julia Reynolds5aa13a42017-08-24 09:10:23 -0400591 mApproved.remove(user);
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400592 rebindServices(true, user);
Julia Reynolds5aa13a42017-08-24 09:10:23 -0400593 }
594
John Spurlock1b8b22b2015-05-20 09:47:13 -0400595 public void onUserSwitched(int user) {
596 if (DEBUG) Slog.d(TAG, "onUserSwitched u=" + user);
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400597 rebindServices(true, user);
Christoph Studerb53dfd42014-09-12 14:45:59 +0200598 }
599
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -0500600 public void onUserUnlocked(int user) {
601 if (DEBUG) Slog.d(TAG, "onUserUnlocked u=" + user);
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400602 rebindServices(false, user);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -0500603 }
604
Julia Reynoldsb852e562017-06-06 16:14:18 -0400605 private ManagedServiceInfo getServiceFromTokenLocked(IInterface service) {
Chris Wrenab41eec2016-01-04 18:01:27 -0500606 if (service == null) {
607 return null;
608 }
John Spurlock7340fc82014-04-24 18:50:12 -0400609 final IBinder token = service.asBinder();
610 final int N = mServices.size();
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200611 for (int i = 0; i < N; i++) {
John Spurlock7340fc82014-04-24 18:50:12 -0400612 final ManagedServiceInfo info = mServices.get(i);
613 if (info.service.asBinder() == token) return info;
614 }
Chris Wrenab41eec2016-01-04 18:01:27 -0500615 return null;
616 }
617
Julia Reynolds503ed942017-10-04 16:04:56 -0400618 protected boolean isServiceTokenValidLocked(IInterface service) {
619 if (service == null) {
620 return false;
621 }
622 ManagedServiceInfo info = getServiceFromTokenLocked(service);
623 if (info != null) {
624 return true;
625 }
626 return false;
627 }
628
Julia Reynoldsb852e562017-06-06 16:14:18 -0400629 protected ManagedServiceInfo checkServiceTokenLocked(IInterface service) {
Chris Wrenab41eec2016-01-04 18:01:27 -0500630 checkNotNull(service);
631 ManagedServiceInfo info = getServiceFromTokenLocked(service);
632 if (info != null) {
633 return info;
634 }
John Spurlock7340fc82014-04-24 18:50:12 -0400635 throw new SecurityException("Disallowed call from unknown " + getCaption() + ": "
Julia Reynoldscb507b82017-09-07 13:53:40 -0400636 + service + " " + service.getClass());
John Spurlock7340fc82014-04-24 18:50:12 -0400637 }
638
Julia Reynolds70aaea72018-07-13 13:38:34 -0400639 public boolean isSameUser(IInterface service, int userId) {
640 checkNotNull(service);
Julia Reynolds3ff1fd92018-08-29 09:57:11 -0400641 synchronized (mMutex) {
642 ManagedServiceInfo info = getServiceFromTokenLocked(service);
643 if (info != null) {
644 return info.isSameUser(userId);
645 }
646 return false;
Julia Reynolds70aaea72018-07-13 13:38:34 -0400647 }
Julia Reynolds70aaea72018-07-13 13:38:34 -0400648 }
649
John Spurlock7340fc82014-04-24 18:50:12 -0400650 public void unregisterService(IInterface service, int userid) {
651 checkNotNull(service);
652 // no need to check permissions; if your service binder is in the list,
653 // that's proof that you had permission to add it in the first place
654 unregisterServiceImpl(service, userid);
655 }
656
657 public void registerService(IInterface service, ComponentName component, int userid) {
658 checkNotNull(service);
Christoph Studer3e144d32014-05-22 16:48:40 +0200659 ManagedServiceInfo info = registerServiceImpl(service, component, userid);
660 if (info != null) {
661 onServiceAdded(info);
662 }
John Spurlock7340fc82014-04-24 18:50:12 -0400663 }
664
Chris Wren51017d02015-12-15 15:34:46 -0500665 /**
666 * Add a service to our callbacks. The lifecycle of this service is managed externally,
Julia Reynoldsb852e562017-06-06 16:14:18 -0400667 * but unlike a system service, it should not be considered privileged.
Chris Wren51017d02015-12-15 15:34:46 -0500668 * */
Julia Reynoldsb852e562017-06-06 16:14:18 -0400669 protected void registerGuestService(ManagedServiceInfo guest) {
Chris Wren51017d02015-12-15 15:34:46 -0500670 checkNotNull(guest.service);
Ruben Brunke24b9a62016-02-16 21:38:24 -0800671 if (!checkType(guest.service)) {
672 throw new IllegalArgumentException();
673 }
Chris Wren51017d02015-12-15 15:34:46 -0500674 if (registerServiceImpl(guest) != null) {
675 onServiceAdded(guest);
Chris Wrenab41eec2016-01-04 18:01:27 -0500676 }
677 }
678
Julia Reynoldsb852e562017-06-06 16:14:18 -0400679 protected void setComponentState(ComponentName component, boolean enabled) {
Chris Wrenab41eec2016-01-04 18:01:27 -0500680 boolean previous = !mSnoozingForCurrentProfiles.contains(component);
681 if (previous == enabled) {
682 return;
683 }
684
685 if (enabled) {
686 mSnoozingForCurrentProfiles.remove(component);
687 } else {
688 mSnoozingForCurrentProfiles.add(component);
689 }
690
691 // State changed
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -0400692 Slog.d(TAG, ((enabled) ? "Enabling " : "Disabling ") + "component " +
693 component.flattenToShortString());
Chris Wrenab41eec2016-01-04 18:01:27 -0500694
Chris Wren0efdb882016-03-01 17:17:47 -0500695 synchronized (mMutex) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400696 final IntArray userIds = mUserProfiles.getCurrentProfileIds();
Chris Wren0efdb882016-03-01 17:17:47 -0500697
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400698 for (int i = 0; i < userIds.size(); i++) {
699 final int userId = userIds.get(i);
Chris Wren0efdb882016-03-01 17:17:47 -0500700 if (enabled) {
Beverly363da782018-10-09 16:05:15 -0400701 if (isPackageOrComponentAllowed(component.flattenToString(), userId)
Beverly2d783fc2018-09-07 13:38:21 -0400702 || isPackageOrComponentAllowed(component.getPackageName(), userId)) {
Julia Reynolds00fa8402018-07-25 08:57:58 -0400703 registerServiceLocked(component, userId);
704 } else {
705 Slog.d(TAG, component + " no longer has permission to be bound");
706 }
Chris Wren0efdb882016-03-01 17:17:47 -0500707 } else {
708 unregisterServiceLocked(component, userId);
709 }
Chris Wrenab41eec2016-01-04 18:01:27 -0500710 }
Chris Wren51017d02015-12-15 15:34:46 -0500711 }
712 }
713
Julia Reynoldsb852e562017-06-06 16:14:18 -0400714 private @NonNull ArraySet<ComponentName> loadComponentNamesFromValues(
715 ArraySet<String> approved, int userId) {
716 if (approved == null || approved.size() == 0)
Julia Reynolds6e839b02016-04-13 10:01:17 -0400717 return new ArraySet<>();
Julia Reynoldsb852e562017-06-06 16:14:18 -0400718 ArraySet<ComponentName> result = new ArraySet<>(approved.size());
719 for (int i = 0; i < approved.size(); i++) {
720 final String packageOrComponent = approved.valueAt(i);
721 if (!TextUtils.isEmpty(packageOrComponent)) {
722 ComponentName component = ComponentName.unflattenFromString(packageOrComponent);
723 if (component != null) {
724 result.add(component);
725 } else {
726 result.addAll(queryPackageForServices(packageOrComponent, userId));
727 }
Christopher Tate6597e342015-02-17 12:15:25 -0800728 }
729 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200730 return result;
731 }
John Spurlock7340fc82014-04-24 18:50:12 -0400732
Julia Reynoldsc279b992015-10-30 08:23:51 -0400733 protected Set<ComponentName> queryPackageForServices(String packageName, int userId) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400734 return queryPackageForServices(packageName, 0, userId);
735 }
736
737 protected Set<ComponentName> queryPackageForServices(String packageName, int extraFlags,
738 int userId) {
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200739 Set<ComponentName> installed = new ArraySet<>();
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200740 final PackageManager pm = mContext.getPackageManager();
Julia Reynoldsc279b992015-10-30 08:23:51 -0400741 Intent queryIntent = new Intent(mConfig.serviceInterface);
742 if (!TextUtils.isEmpty(packageName)) {
743 queryIntent.setPackage(packageName);
744 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200745 List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser(
Julia Reynoldsc279b992015-10-30 08:23:51 -0400746 queryIntent,
Julia Reynoldsb852e562017-06-06 16:14:18 -0400747 PackageManager.GET_SERVICES | PackageManager.GET_META_DATA | extraFlags,
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200748 userId);
749 if (DEBUG)
750 Slog.v(TAG, mConfig.serviceInterface + " services: " + installedServices);
Julia Reynolds50f05142015-10-30 17:03:59 -0400751 if (installedServices != null) {
752 for (int i = 0, count = installedServices.size(); i < count; i++) {
753 ResolveInfo resolveInfo = installedServices.get(i);
754 ServiceInfo info = resolveInfo.serviceInfo;
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200755
Julia Reynolds50f05142015-10-30 17:03:59 -0400756 ComponentName component = new ComponentName(info.packageName, info.name);
757 if (!mConfig.bindPermission.equals(info.permission)) {
758 Slog.w(TAG, "Skipping " + getCaption() + " service "
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800759 + info.packageName + "/" + info.name
760 + ": it does not require the permission "
761 + mConfig.bindPermission);
Julia Reynolds50f05142015-10-30 17:03:59 -0400762 continue;
763 }
764 installed.add(component);
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200765 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200766 }
Julia Reynoldsc279b992015-10-30 08:23:51 -0400767 return installed;
768 }
769
Julia Reynolds4c456dd2019-01-07 12:22:00 -0500770 protected Set<String> getAllowedPackages() {
771 final Set<String> allowedPackages = new ArraySet<>();
772 for (int k = 0; k < mApproved.size(); k++) {
773 ArrayMap<Boolean, ArraySet<String>> allowedByType = mApproved.valueAt(k);
774 for (int i = 0; i < allowedByType.size(); i++) {
775 final ArraySet<String> allowed = allowedByType.valueAt(i);
776 for (int j = 0; j < allowed.size(); j++) {
777 String pkgName = getPackageName(allowed.valueAt(j));
778 if (!TextUtils.isEmpty(pkgName)) {
779 allowedPackages.add(pkgName);
780 }
781 }
782 }
783 }
784 return allowedPackages;
785 }
786
Annie Meng8b646fd2019-02-01 18:46:42 +0000787 private void trimApprovedListsAccordingToInstalledServices(int userId) {
788 final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId);
789 if (approvedByType == null) {
790 return;
791 }
792 for (int i = 0; i < approvedByType.size(); i++) {
793 final ArraySet<String> approved = approvedByType.valueAt(i);
794 for (int j = approved.size() - 1; j >= 0; j--) {
795 final String approvedPackageOrComponent = approved.valueAt(j);
796 if (!isValidEntry(approvedPackageOrComponent, userId)){
797 approved.removeAt(j);
798 Slog.v(TAG, "Removing " + approvedPackageOrComponent
799 + " from approved list; no matching services found");
800 } else {
801 if (DEBUG) {
802 Slog.v(TAG, "Keeping " + approvedPackageOrComponent
803 + " on approved list; matching services found");
Julia Reynoldsb852e562017-06-06 16:14:18 -0400804 }
John Spurlock7340fc82014-04-24 18:50:12 -0400805 }
John Spurlock7340fc82014-04-24 18:50:12 -0400806 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400807 }
808 }
John Spurlock7340fc82014-04-24 18:50:12 -0400809
Julia Reynoldsb852e562017-06-06 16:14:18 -0400810 private boolean removeUninstalledItemsFromApprovedLists(int uninstalledUserId, String pkg) {
811 boolean removed = false;
812 final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(uninstalledUserId);
813 if (approvedByType != null) {
814 int M = approvedByType.size();
815 for (int j = 0; j < M; j++) {
816 final ArraySet<String> approved = approvedByType.valueAt(j);
817 int O = approved.size();
818 for (int k = O - 1; k >= 0; k--) {
819 final String packageOrComponent = approved.valueAt(k);
820 final String packageName = getPackageName(packageOrComponent);
821 if (TextUtils.equals(pkg, packageName)) {
822 approved.removeAt(k);
823 if (DEBUG) {
824 Slog.v(TAG, "Removing " + packageOrComponent
825 + " from approved list; uninstalled");
826 }
827 }
828 }
John Spurlock7340fc82014-04-24 18:50:12 -0400829 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200830 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400831 return removed;
832 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200833
Julia Reynoldsb852e562017-06-06 16:14:18 -0400834 protected String getPackageName(String packageOrComponent) {
835 final ComponentName component = ComponentName.unflattenFromString(packageOrComponent);
836 if (component != null) {
837 return component.getPackageName();
838 } else {
839 return packageOrComponent;
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200840 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400841 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200842
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -0400843 protected boolean isValidEntry(String packageOrComponent, int userId) {
844 return hasMatchingServices(packageOrComponent, userId);
845 }
846
Julia Reynoldsb852e562017-06-06 16:14:18 -0400847 private boolean hasMatchingServices(String packageOrComponent, int userId) {
848 if (!TextUtils.isEmpty(packageOrComponent)) {
849 final String packageName = getPackageName(packageOrComponent);
850 return queryPackageForServices(packageName, userId).size() > 0;
John Spurlock7340fc82014-04-24 18:50:12 -0400851 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400852 return false;
John Spurlock7340fc82014-04-24 18:50:12 -0400853 }
854
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400855 @VisibleForTesting
856 protected SparseArray<ArraySet<ComponentName>> getAllowedComponents(IntArray userIds) {
857 final int nUserIds = userIds.size();
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200858 final SparseArray<ArraySet<ComponentName>> componentsByUser = new SparseArray<>();
John Spurlock7340fc82014-04-24 18:50:12 -0400859
860 for (int i = 0; i < nUserIds; ++i) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400861 final int userId = userIds.get(i);
862 final ArrayMap<Boolean, ArraySet<String>> approvedLists = mApproved.get(userId);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400863 if (approvedLists != null) {
864 final int N = approvedLists.size();
865 for (int j = 0; j < N; j++) {
866 ArraySet<ComponentName> approvedByUser = componentsByUser.get(userId);
867 if (approvedByUser == null) {
868 approvedByUser = new ArraySet<>();
869 componentsByUser.put(userId, approvedByUser);
870 }
871 approvedByUser.addAll(
872 loadComponentNamesFromValues(approvedLists.valueAt(j), userId));
873 }
Julia Reynolds6e839b02016-04-13 10:01:17 -0400874 }
John Spurlock7340fc82014-04-24 18:50:12 -0400875 }
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400876 return componentsByUser;
877 }
John Spurlock7340fc82014-04-24 18:50:12 -0400878
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400879 @GuardedBy("mMutex")
880 protected void populateComponentsToBind(SparseArray<Set<ComponentName>> componentsToBind,
881 final IntArray activeUsers,
882 SparseArray<ArraySet<ComponentName>> approvedComponentsByUser) {
883 mEnabledServicesForCurrentProfiles.clear();
884 mEnabledServicesPackageNames.clear();
885 final int nUserIds = activeUsers.size();
John Spurlock7340fc82014-04-24 18:50:12 -0400886
887 for (int i = 0; i < nUserIds; ++i) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400888 // decode the list of components
889 final int userId = activeUsers.get(i);
890 final ArraySet<ComponentName> userComponents = approvedComponentsByUser.get(userId);
891 if (null == userComponents) {
892 componentsToBind.put(userId, new ArraySet<>());
893 continue;
894 }
895
896 final Set<ComponentName> add = new HashSet<>(userComponents);
897 add.removeAll(mSnoozingForCurrentProfiles);
898
899 componentsToBind.put(userId, add);
900
901 mEnabledServicesForCurrentProfiles.addAll(userComponents);
902
903 for (int j = 0; j < userComponents.size(); j++) {
904 final ComponentName component = userComponents.valueAt(j);
905 mEnabledServicesPackageNames.add(component.getPackageName());
906 }
907 }
908 }
909
910 @GuardedBy("mMutex")
911 protected Set<ManagedServiceInfo> getRemovableConnectedServices() {
912 final Set<ManagedServiceInfo> removableBoundServices = new ArraySet<>();
913 for (ManagedServiceInfo service : mServices) {
914 if (!service.isSystem && !service.isGuest(this)) {
915 removableBoundServices.add(service);
916 }
917 }
918 return removableBoundServices;
919 }
920
921 protected void populateComponentsToUnbind(
922 boolean forceRebind,
923 Set<ManagedServiceInfo> removableBoundServices,
924 SparseArray<Set<ComponentName>> allowedComponentsToBind,
925 SparseArray<Set<ComponentName>> componentsToUnbind) {
926 for (ManagedServiceInfo info : removableBoundServices) {
927 final Set<ComponentName> allowedComponents = allowedComponentsToBind.get(info.userid);
928 if (allowedComponents != null) {
929 if (forceRebind || !allowedComponents.contains(info.component)) {
930 Set<ComponentName> toUnbind =
931 componentsToUnbind.get(info.userid, new ArraySet<>());
932 toUnbind.add(info.component);
933 componentsToUnbind.put(info.userid, toUnbind);
934 }
935 }
936 }
937 }
938
939 /**
940 * Called whenever packages change, the user switches, or the secure setting
941 * is altered. (For example in response to USER_SWITCHED in our broadcast receiver)
942 */
943 protected void rebindServices(boolean forceRebind, int userToRebind) {
944 if (DEBUG) Slog.d(TAG, "rebindServices " + forceRebind + " " + userToRebind);
945 IntArray userIds = mUserProfiles.getCurrentProfileIds();
946 if (userToRebind != USER_ALL) {
947 userIds = new IntArray(1);
948 userIds.add(userToRebind);
949 }
950
951 final SparseArray<Set<ComponentName>> componentsToBind = new SparseArray<>();
952 final SparseArray<Set<ComponentName>> componentsToUnbind = new SparseArray<>();
953
954 synchronized (mMutex) {
955 final SparseArray<ArraySet<ComponentName>> approvedComponentsByUser =
956 getAllowedComponents(userIds);
957 final Set<ManagedServiceInfo> removableBoundServices = getRemovableConnectedServices();
958
959 // Filter approvedComponentsByUser to collect all of the components that are allowed
960 // for the currently active user(s).
961 populateComponentsToBind(componentsToBind, userIds, approvedComponentsByUser);
962
963 // For every current non-system connection, disconnect services that are no longer
964 // approved, or ALL services if we are force rebinding
965 populateComponentsToUnbind(
966 forceRebind, removableBoundServices, componentsToBind, componentsToUnbind);
967 }
968
969 unbindFromServices(componentsToUnbind);
970 bindToServices(componentsToBind);
971 }
972
973 protected void unbindFromServices(SparseArray<Set<ComponentName>> componentsToUnbind) {
974 for (int i = 0; i < componentsToUnbind.size(); i++) {
975 final int userId = componentsToUnbind.keyAt(i);
976 final Set<ComponentName> removableComponents = componentsToUnbind.get(userId);
977 for (ComponentName cn : removableComponents) {
978 // No longer allowed to be bound, or must rebind.
979 Slog.v(TAG, "disabling " + getCaption() + " for user " + userId + ": " + cn);
980 unregisterService(cn, userId);
981 }
982 }
983 }
984
985 // Attempt to bind to services, skipping those that cannot be found or lack the permission.
986 private void bindToServices(SparseArray<Set<ComponentName>> componentsToBind) {
987 for (int i = 0; i < componentsToBind.size(); i++) {
988 final int userId = componentsToBind.keyAt(i);
989 final Set<ComponentName> add = componentsToBind.get(userId);
Julia Reynolds9a86cc02016-02-10 15:38:15 -0500990 for (ComponentName component : add) {
Julia Reynoldsa75c7522017-03-21 17:34:25 -0400991 try {
992 ServiceInfo info = mPm.getServiceInfo(component,
993 PackageManager.MATCH_DIRECT_BOOT_AWARE
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400994 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
Julia Reynolds503ed942017-10-04 16:04:56 -0400995 if (info == null) {
996 Slog.w(TAG, "Not binding " + getCaption() + " service " + component
997 + ": service not found");
998 continue;
999 }
1000 if (!mConfig.bindPermission.equals(info.permission)) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04001001 Slog.w(TAG, "Not binding " + getCaption() + " service " + component
Julia Reynoldsa75c7522017-03-21 17:34:25 -04001002 + ": it does not require the permission " + mConfig.bindPermission);
1003 continue;
1004 }
1005 Slog.v(TAG,
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001006 "enabling " + getCaption() + " for " + userId + ": " + component);
1007 registerService(component, userId);
Julia Reynoldsa75c7522017-03-21 17:34:25 -04001008 } catch (RemoteException e) {
1009 e.rethrowFromSystemServer();
1010 }
John Spurlock7340fc82014-04-24 18:50:12 -04001011 }
1012 }
1013 }
1014
1015 /**
1016 * Version of registerService that takes the name of a service component to bind to.
1017 */
1018 private void registerService(final ComponentName name, final int userid) {
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001019 synchronized (mMutex) {
1020 registerServiceLocked(name, userid);
1021 }
1022 }
1023
Chris Wren0efdb882016-03-01 17:17:47 -05001024 /**
1025 * Inject a system service into the management list.
1026 */
1027 public void registerSystemService(final ComponentName name, final int userid) {
1028 synchronized (mMutex) {
1029 registerServiceLocked(name, userid, true /* isSystem */);
1030 }
1031 }
1032
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001033 private void registerServiceLocked(final ComponentName name, final int userid) {
Chris Wren0efdb882016-03-01 17:17:47 -05001034 registerServiceLocked(name, userid, false /* isSystem */);
1035 }
1036
1037 private void registerServiceLocked(final ComponentName name, final int userid,
1038 final boolean isSystem) {
John Spurlock7340fc82014-04-24 18:50:12 -04001039 if (DEBUG) Slog.v(TAG, "registerService: " + name + " u=" + userid);
1040
Andrew Zeng190c0672018-06-28 15:15:05 -07001041 final Pair<ComponentName, Integer> servicesBindingTag = Pair.create(name, userid);
1042 if (mServicesBound.contains(servicesBindingTag)) {
1043 Slog.v(TAG, "Not registering " + name + " is already bound");
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001044 // stop registering this thing already! we're working on it
1045 return;
1046 }
Andrew Zeng190c0672018-06-28 15:15:05 -07001047 mServicesBound.add(servicesBindingTag);
John Spurlock7340fc82014-04-24 18:50:12 -04001048
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001049 final int N = mServices.size();
1050 for (int i = N - 1; i >= 0; i--) {
1051 final ManagedServiceInfo info = mServices.get(i);
1052 if (name.equals(info.component)
1053 && info.userid == userid) {
1054 // cut old connections
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -04001055 Slog.v(TAG, " disconnecting old " + getCaption() + ": " + info.service);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001056 removeServiceLocked(i);
1057 if (info.connection != null) {
Andrew Zeng190c0672018-06-28 15:15:05 -07001058 unbindService(info.connection, info.component, info.userid);
John Spurlock7340fc82014-04-24 18:50:12 -04001059 }
1060 }
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001061 }
John Spurlock7340fc82014-04-24 18:50:12 -04001062
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001063 Intent intent = new Intent(mConfig.serviceInterface);
1064 intent.setComponent(name);
John Spurlock7340fc82014-04-24 18:50:12 -04001065
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001066 intent.putExtra(Intent.EXTRA_CLIENT_LABEL, mConfig.clientLabel);
John Spurlock7340fc82014-04-24 18:50:12 -04001067
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001068 final PendingIntent pendingIntent = PendingIntent.getActivity(
1069 mContext, 0, new Intent(mConfig.settingsAction), 0);
1070 intent.putExtra(Intent.EXTRA_CLIENT_INTENT, pendingIntent);
John Spurlock7340fc82014-04-24 18:50:12 -04001071
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001072 ApplicationInfo appInfo = null;
1073 try {
1074 appInfo = mContext.getPackageManager().getApplicationInfo(
1075 name.getPackageName(), 0);
1076 } catch (NameNotFoundException e) {
1077 // Ignore if the package doesn't exist we won't be able to bind to the service.
1078 }
1079 final int targetSdkVersion =
1080 appInfo != null ? appInfo.targetSdkVersion : Build.VERSION_CODES.BASE;
John Spurlock7340fc82014-04-24 18:50:12 -04001081
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001082 try {
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -04001083 Slog.v(TAG, "binding: " + intent);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001084 ServiceConnection serviceConnection = new ServiceConnection() {
1085 IInterface mService;
Denis Kuznetsov76c02682015-09-17 19:57:00 +02001086
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001087 @Override
1088 public void onServiceConnected(ComponentName name, IBinder binder) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001089 Slog.v(TAG, userid + " " + getCaption() + " service connected: " + name);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001090 boolean added = false;
1091 ManagedServiceInfo info = null;
1092 synchronized (mMutex) {
Ryan Lothian4a86a512017-12-04 11:56:58 -05001093 mServicesRebinding.remove(servicesBindingTag);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001094 try {
1095 mService = asInterface(binder);
1096 info = newServiceInfo(mService, name,
Chris Wren0efdb882016-03-01 17:17:47 -05001097 userid, isSystem, this, targetSdkVersion);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001098 binder.linkToDeath(info, 0);
1099 added = mServices.add(info);
1100 } catch (RemoteException e) {
1101 // already dead
Denis Kuznetsov76c02682015-09-17 19:57:00 +02001102 }
1103 }
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001104 if (added) {
1105 onServiceAdded(info);
Denis Kuznetsov76c02682015-09-17 19:57:00 +02001106 }
John Spurlock7340fc82014-04-24 18:50:12 -04001107 }
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001108
1109 @Override
1110 public void onServiceDisconnected(ComponentName name) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001111 Slog.v(TAG, userid + " " + getCaption() + " connection lost: " + name);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001112 }
Ryan Lothian4a86a512017-12-04 11:56:58 -05001113
1114 @Override
1115 public void onBindingDied(ComponentName name) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001116 Slog.w(TAG, userid + " " + getCaption() + " binding died: " + name);
Ryan Lothian4a86a512017-12-04 11:56:58 -05001117 synchronized (mMutex) {
Andrew Zeng190c0672018-06-28 15:15:05 -07001118 unbindService(this, name, userid);
Ryan Lothian4a86a512017-12-04 11:56:58 -05001119 if (!mServicesRebinding.contains(servicesBindingTag)) {
1120 mServicesRebinding.add(servicesBindingTag);
1121 mHandler.postDelayed(new Runnable() {
1122 @Override
1123 public void run() {
1124 registerService(name, userid);
1125 }
1126 }, ON_BINDING_DIED_REBIND_DELAY_MS);
1127 } else {
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001128 Slog.v(TAG, getCaption() + " not rebinding in user " + userid
1129 + " as a previous rebind attempt was made: " + name);
Ryan Lothian4a86a512017-12-04 11:56:58 -05001130 }
1131 }
1132 }
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001133 };
1134 if (!mContext.bindServiceAsUser(intent,
Amith Yamasanie5bfeee2018-09-05 18:52:35 -07001135 serviceConnection,
1136 getBindFlags(),
1137 new UserHandle(userid))) {
Andrew Zeng190c0672018-06-28 15:15:05 -07001138 mServicesBound.remove(servicesBindingTag);
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001139 Slog.w(TAG, "Unable to bind " + getCaption() + " service: " + intent
1140 + " in user " + userid);
John Spurlock7340fc82014-04-24 18:50:12 -04001141 return;
1142 }
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001143 } catch (SecurityException ex) {
Andrew Zeng190c0672018-06-28 15:15:05 -07001144 mServicesBound.remove(servicesBindingTag);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001145 Slog.e(TAG, "Unable to bind " + getCaption() + " service: " + intent, ex);
John Spurlock7340fc82014-04-24 18:50:12 -04001146 }
1147 }
1148
1149 /**
1150 * Remove a service for the given user by ComponentName
1151 */
1152 private void unregisterService(ComponentName name, int userid) {
1153 synchronized (mMutex) {
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001154 unregisterServiceLocked(name, userid);
1155 }
1156 }
1157
1158 private void unregisterServiceLocked(ComponentName name, int userid) {
1159 final int N = mServices.size();
1160 for (int i = N - 1; i >= 0; i--) {
1161 final ManagedServiceInfo info = mServices.get(i);
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -04001162 if (name.equals(info.component) && info.userid == userid) {
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001163 removeServiceLocked(i);
1164 if (info.connection != null) {
Andrew Zeng190c0672018-06-28 15:15:05 -07001165 unbindService(info.connection, info.component, info.userid);
John Spurlock7340fc82014-04-24 18:50:12 -04001166 }
1167 }
1168 }
1169 }
1170
1171 /**
1172 * Removes a service from the list but does not unbind
1173 *
1174 * @return the removed service.
1175 */
1176 private ManagedServiceInfo removeServiceImpl(IInterface service, final int userid) {
John Spurlocke77bb362014-04-26 10:24:59 -04001177 if (DEBUG) Slog.d(TAG, "removeServiceImpl service=" + service + " u=" + userid);
John Spurlock7340fc82014-04-24 18:50:12 -04001178 ManagedServiceInfo serviceInfo = null;
1179 synchronized (mMutex) {
1180 final int N = mServices.size();
Denis Kuznetsov76c02682015-09-17 19:57:00 +02001181 for (int i = N - 1; i >= 0; i--) {
John Spurlock7340fc82014-04-24 18:50:12 -04001182 final ManagedServiceInfo info = mServices.get(i);
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -04001183 if (info.service.asBinder() == service.asBinder() && info.userid == userid) {
1184 Slog.d(TAG, "Removing active service " + info.component);
John Spurlocke77bb362014-04-26 10:24:59 -04001185 serviceInfo = removeServiceLocked(i);
John Spurlock7340fc82014-04-24 18:50:12 -04001186 }
1187 }
1188 }
1189 return serviceInfo;
1190 }
1191
John Spurlocke77bb362014-04-26 10:24:59 -04001192 private ManagedServiceInfo removeServiceLocked(int i) {
1193 final ManagedServiceInfo info = mServices.remove(i);
1194 onServiceRemovedLocked(info);
1195 return info;
1196 }
1197
John Spurlock7340fc82014-04-24 18:50:12 -04001198 private void checkNotNull(IInterface service) {
1199 if (service == null) {
1200 throw new IllegalArgumentException(getCaption() + " must not be null");
1201 }
1202 }
1203
Christoph Studer3e144d32014-05-22 16:48:40 +02001204 private ManagedServiceInfo registerServiceImpl(final IInterface service,
John Spurlock7340fc82014-04-24 18:50:12 -04001205 final ComponentName component, final int userid) {
Chris Wren51017d02015-12-15 15:34:46 -05001206 ManagedServiceInfo info = newServiceInfo(service, component, userid,
1207 true /*isSystem*/, null /*connection*/, Build.VERSION_CODES.LOLLIPOP);
1208 return registerServiceImpl(info);
1209 }
1210
1211 private ManagedServiceInfo registerServiceImpl(ManagedServiceInfo info) {
John Spurlock7340fc82014-04-24 18:50:12 -04001212 synchronized (mMutex) {
1213 try {
Chris Wren51017d02015-12-15 15:34:46 -05001214 info.service.asBinder().linkToDeath(info, 0);
John Spurlock7340fc82014-04-24 18:50:12 -04001215 mServices.add(info);
Christoph Studer3e144d32014-05-22 16:48:40 +02001216 return info;
John Spurlock7340fc82014-04-24 18:50:12 -04001217 } catch (RemoteException e) {
1218 // already dead
1219 }
1220 }
Christoph Studer3e144d32014-05-22 16:48:40 +02001221 return null;
John Spurlock7340fc82014-04-24 18:50:12 -04001222 }
1223
1224 /**
1225 * Removes a service from the list and unbinds.
1226 */
1227 private void unregisterServiceImpl(IInterface service, int userid) {
1228 ManagedServiceInfo info = removeServiceImpl(service, userid);
Chris Wren51017d02015-12-15 15:34:46 -05001229 if (info != null && info.connection != null && !info.isGuest(this)) {
Andrew Zeng190c0672018-06-28 15:15:05 -07001230 unbindService(info.connection, info.component, info.userid);
1231 }
1232 }
1233
1234 private void unbindService(ServiceConnection connection, ComponentName component, int userId) {
1235 try {
1236 mContext.unbindService(connection);
1237 } catch (IllegalArgumentException e) {
1238 Slog.e(TAG, getCaption() + " " + component + " could not be unbound", e);
1239 }
1240 synchronized (mMutex) {
1241 mServicesBound.remove(Pair.create(component, userId));
John Spurlock7340fc82014-04-24 18:50:12 -04001242 }
1243 }
1244
John Spurlock7340fc82014-04-24 18:50:12 -04001245 public class ManagedServiceInfo implements IBinder.DeathRecipient {
1246 public IInterface service;
1247 public ComponentName component;
1248 public int userid;
1249 public boolean isSystem;
1250 public ServiceConnection connection;
1251 public int targetSdkVersion;
1252
1253 public ManagedServiceInfo(IInterface service, ComponentName component,
1254 int userid, boolean isSystem, ServiceConnection connection, int targetSdkVersion) {
1255 this.service = service;
1256 this.component = component;
1257 this.userid = userid;
1258 this.isSystem = isSystem;
1259 this.connection = connection;
1260 this.targetSdkVersion = targetSdkVersion;
1261 }
1262
Chris Wren51017d02015-12-15 15:34:46 -05001263 public boolean isGuest(ManagedServices host) {
1264 return ManagedServices.this != host;
1265 }
1266
Chris Wrenab41eec2016-01-04 18:01:27 -05001267 public ManagedServices getOwner() {
1268 return ManagedServices.this;
1269 }
1270
John Spurlocke77bb362014-04-26 10:24:59 -04001271 @Override
1272 public String toString() {
1273 return new StringBuilder("ManagedServiceInfo[")
1274 .append("component=").append(component)
1275 .append(",userid=").append(userid)
1276 .append(",isSystem=").append(isSystem)
1277 .append(",targetSdkVersion=").append(targetSdkVersion)
1278 .append(",connection=").append(connection == null ? null : "<connection>")
1279 .append(",service=").append(service)
1280 .append(']').toString();
1281 }
1282
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001283 public void writeToProto(ProtoOutputStream proto, long fieldId, ManagedServices host) {
1284 final long token = proto.start(fieldId);
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001285 component.writeToProto(proto, ManagedServiceInfoProto.COMPONENT);
Kweku Adams93304b62017-09-20 17:03:00 -07001286 proto.write(ManagedServiceInfoProto.USER_ID, userid);
1287 proto.write(ManagedServiceInfoProto.SERVICE, service.getClass().getName());
1288 proto.write(ManagedServiceInfoProto.IS_SYSTEM, isSystem);
1289 proto.write(ManagedServiceInfoProto.IS_GUEST, isGuest(host));
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001290 proto.end(token);
Kweku Adams93304b62017-09-20 17:03:00 -07001291 }
1292
Julia Reynolds70aaea72018-07-13 13:38:34 -04001293 public boolean isSameUser(int userId) {
1294 if (!isEnabledForCurrentProfiles()) {
1295 return false;
1296 }
1297 return this.userid == userId;
1298 }
1299
John Spurlock7340fc82014-04-24 18:50:12 -04001300 public boolean enabledAndUserMatches(int nid) {
1301 if (!isEnabledForCurrentProfiles()) {
1302 return false;
1303 }
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001304 if (this.userid == USER_ALL) return true;
Chris Wren0c4eeb42016-05-12 13:21:08 -04001305 if (this.isSystem) return true;
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001306 if (nid == USER_ALL || nid == this.userid) return true;
Esteban Talavera9c6458d2017-03-30 17:59:50 +01001307 return supportsProfiles()
1308 && mUserProfiles.isCurrentProfile(nid)
1309 && isPermittedForProfile(nid);
John Spurlock7340fc82014-04-24 18:50:12 -04001310 }
1311
1312 public boolean supportsProfiles() {
Dianne Hackborn955d8d62014-10-07 20:17:19 -07001313 return targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP;
John Spurlock7340fc82014-04-24 18:50:12 -04001314 }
1315
1316 @Override
1317 public void binderDied() {
John Spurlocke77bb362014-04-26 10:24:59 -04001318 if (DEBUG) Slog.d(TAG, "binderDied");
John Spurlock7340fc82014-04-24 18:50:12 -04001319 // Remove the service, but don't unbind from the service. The system will bring the
Esteban Talavera9c6458d2017-03-30 17:59:50 +01001320 // service back up, and the onServiceConnected handler will read the service with the
John Spurlock7340fc82014-04-24 18:50:12 -04001321 // new binding. If this isn't a bound service, and is just a registered
1322 // service, just removing it from the list is all we need to do anyway.
1323 removeServiceImpl(this.service, this.userid);
1324 }
1325
1326 /** convenience method for looking in mEnabledServicesForCurrentProfiles */
1327 public boolean isEnabledForCurrentProfiles() {
1328 if (this.isSystem) return true;
1329 if (this.connection == null) return false;
1330 return mEnabledServicesForCurrentProfiles.contains(this.component);
1331 }
Esteban Talavera9c6458d2017-03-30 17:59:50 +01001332
1333 /**
1334 * Returns true if this service is allowed to receive events for the given userId. A
1335 * managed profile owner can disallow non-system services running outside of the profile
1336 * from receiving events from the profile.
1337 */
1338 public boolean isPermittedForProfile(int userId) {
1339 if (!mUserProfiles.isManagedProfile(userId)) {
1340 return true;
1341 }
1342 DevicePolicyManager dpm =
1343 (DevicePolicyManager) mContext.getSystemService(DEVICE_POLICY_SERVICE);
1344 final long identity = Binder.clearCallingIdentity();
1345 try {
1346 return dpm.isNotificationListenerServicePermitted(
1347 component.getPackageName(), userId);
1348 } finally {
1349 Binder.restoreCallingIdentity(identity);
1350 }
1351 }
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001352
1353 @Override
1354 public boolean equals(Object o) {
1355 if (this == o) return true;
1356 if (o == null || getClass() != o.getClass()) return false;
1357 ManagedServiceInfo that = (ManagedServiceInfo) o;
1358 return userid == that.userid
1359 && isSystem == that.isSystem
1360 && targetSdkVersion == that.targetSdkVersion
1361 && Objects.equals(service, that.service)
1362 && Objects.equals(component, that.component)
1363 && Objects.equals(connection, that.connection);
1364 }
1365
1366 @Override
1367 public int hashCode() {
1368 return Objects.hash(service, component, userid, isSystem, connection, targetSdkVersion);
1369 }
John Spurlock7340fc82014-04-24 18:50:12 -04001370 }
1371
Chris Wrenab41eec2016-01-04 18:01:27 -05001372 /** convenience method for looking in mEnabledServicesForCurrentProfiles */
1373 public boolean isComponentEnabledForCurrentProfiles(ComponentName component) {
1374 return mEnabledServicesForCurrentProfiles.contains(component);
1375 }
1376
John Spurlock7340fc82014-04-24 18:50:12 -04001377 public static class UserProfiles {
1378 // Profiles of the current user.
Ruben Brunke24b9a62016-02-16 21:38:24 -08001379 private final SparseArray<UserInfo> mCurrentProfiles = new SparseArray<>();
John Spurlock7340fc82014-04-24 18:50:12 -04001380
Ruben Brunke24b9a62016-02-16 21:38:24 -08001381 public void updateCache(@NonNull Context context) {
John Spurlock7340fc82014-04-24 18:50:12 -04001382 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
1383 if (userManager != null) {
1384 int currentUserId = ActivityManager.getCurrentUser();
1385 List<UserInfo> profiles = userManager.getProfiles(currentUserId);
1386 synchronized (mCurrentProfiles) {
1387 mCurrentProfiles.clear();
1388 for (UserInfo user : profiles) {
1389 mCurrentProfiles.put(user.id, user);
1390 }
1391 }
1392 }
1393 }
1394
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001395 /**
1396 * Returns the currently active users (generally one user and its work profile).
1397 */
1398 public IntArray getCurrentProfileIds() {
John Spurlock7340fc82014-04-24 18:50:12 -04001399 synchronized (mCurrentProfiles) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001400 IntArray users = new IntArray(mCurrentProfiles.size());
John Spurlock7340fc82014-04-24 18:50:12 -04001401 final int N = mCurrentProfiles.size();
1402 for (int i = 0; i < N; ++i) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001403 users.add(mCurrentProfiles.keyAt(i));
John Spurlock7340fc82014-04-24 18:50:12 -04001404 }
1405 return users;
1406 }
1407 }
1408
1409 public boolean isCurrentProfile(int userId) {
1410 synchronized (mCurrentProfiles) {
1411 return mCurrentProfiles.get(userId) != null;
1412 }
1413 }
Esteban Talavera9c6458d2017-03-30 17:59:50 +01001414
1415 public boolean isManagedProfile(int userId) {
1416 synchronized (mCurrentProfiles) {
1417 UserInfo user = mCurrentProfiles.get(userId);
1418 return user != null && user.isManagedProfile();
1419 }
1420 }
John Spurlock7340fc82014-04-24 18:50:12 -04001421 }
1422
Ruben Brunke24b9a62016-02-16 21:38:24 -08001423 public static class Config {
1424 public String caption;
1425 public String serviceInterface;
1426 public String secureSettingName;
Julia Reynolds6e839b02016-04-13 10:01:17 -04001427 public String secondarySettingName;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001428 public String xmlTag;
Ruben Brunke24b9a62016-02-16 21:38:24 -08001429 public String bindPermission;
1430 public String settingsAction;
1431 public int clientLabel;
John Spurlock7340fc82014-04-24 18:50:12 -04001432 }
1433}