blob: 4a6eb276bd02f86028a0643a02af60eb0b297911 [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;
Julia Reynoldsd0ceefa2019-03-03 16:10:52 -050067import com.android.internal.util.function.TriPredicate;
John Spurlock25e2d242014-06-27 13:58:23 -040068import com.android.server.notification.NotificationManagerService.DumpFilter;
69
Julia Reynoldsb852e562017-06-06 16:14:18 -040070import org.xmlpull.v1.XmlPullParser;
71import org.xmlpull.v1.XmlPullParserException;
72import org.xmlpull.v1.XmlSerializer;
73
74import java.io.IOException;
John Spurlock7340fc82014-04-24 18:50:12 -040075import java.io.PrintWriter;
76import java.util.ArrayList;
John Spurlocke77bb362014-04-26 10:24:59 -040077import java.util.Arrays;
Julia Reynolds9a86cc02016-02-10 15:38:15 -050078import java.util.HashSet;
John Spurlock7340fc82014-04-24 18:50:12 -040079import java.util.List;
Julia Reynoldsca8e5352018-09-18 13:39:26 -040080import java.util.Objects;
John Spurlock7340fc82014-04-24 18:50:12 -040081import java.util.Set;
82
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));
Tony Mak9a3c1f12019-03-04 16:04:42 +0000336 writeExtraAttributes(out, approvedUserId);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400337 out.endTag(null, TAG_MANAGED_SERVICES);
338
339 if (!forBackup && isPrimary) {
340 // Also write values to settings, for observers who haven't migrated yet
341 Settings.Secure.putStringForUser(mContext.getContentResolver(),
Annie Meng8b646fd2019-02-01 18:46:42 +0000342 getConfig().secureSettingName, allowedItems, approvedUserId);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400343 }
344
345 }
346 }
347 }
348 }
Julia Reynoldsad6dd352019-03-07 16:46:22 -0500349
350 writeExtraXmlTags(out);
351
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400352 out.endTag(null, getConfig().xmlTag);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400353 }
354
Tony Mak9a3c1f12019-03-04 16:04:42 +0000355 /**
356 * Writes extra xml attributes to {@link #TAG_MANAGED_SERVICES} tag.
357 */
358 protected void writeExtraAttributes(XmlSerializer out, int userId) throws IOException {}
359
Julia Reynoldsad6dd352019-03-07 16:46:22 -0500360 /**
361 * Writes extra xml tags within the parent tag specified in {@link Config#xmlTag}.
362 */
363 protected void writeExtraXmlTags(XmlSerializer out) throws IOException {}
364
365 /**
366 * This is called to process tags other than {@link #TAG_MANAGED_SERVICES}.
367 */
368 protected void readExtraTag(String tag, XmlPullParser parser) throws IOException {}
369
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400370 protected void migrateToXml() {
371 loadAllowedComponentsFromSettings();
372 }
373
Annie Meng8b646fd2019-02-01 18:46:42 +0000374 public void readXml(
375 XmlPullParser parser,
Julia Reynoldsd0ceefa2019-03-03 16:10:52 -0500376 TriPredicate<String, Integer, String> allowedManagedServicePackages,
Annie Meng8b646fd2019-02-01 18:46:42 +0000377 boolean forRestore,
378 int userId)
Julia Reynoldsb852e562017-06-06 16:14:18 -0400379 throws XmlPullParserException, IOException {
Julia Reynolds7380d872018-01-12 10:28:26 -0500380 // read grants
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400381 int type;
382 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
383 String tag = parser.getName();
384 if (type == XmlPullParser.END_TAG
385 && getConfig().xmlTag.equals(tag)) {
386 break;
387 }
388 if (type == XmlPullParser.START_TAG) {
389 if (TAG_MANAGED_SERVICES.equals(tag)) {
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -0400390 Slog.i(TAG, "Read " + mConfig.caption + " permissions from xml");
Julia Reynolds7380d872018-01-12 10:28:26 -0500391
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400392 final String approved = XmlUtils.readStringAttribute(parser, ATT_APPROVED_LIST);
Annie Meng8b646fd2019-02-01 18:46:42 +0000393 // Ignore parser's user id for restore.
394 final int resolvedUserId = forRestore
395 ? userId : XmlUtils.readIntAttribute(parser, ATT_USER_ID, 0);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400396 final boolean isPrimary =
397 XmlUtils.readBooleanAttribute(parser, ATT_IS_PRIMARY, true);
Tony Mak9a3c1f12019-03-04 16:04:42 +0000398 readExtraAttributes(tag, parser, resolvedUserId);
Julia Reynoldsd0ceefa2019-03-03 16:10:52 -0500399 if (allowedManagedServicePackages == null || allowedManagedServicePackages.test(
400 getPackageName(approved), resolvedUserId, getRequiredPermission())) {
Annie Meng8b646fd2019-02-01 18:46:42 +0000401 if (mUm.getUserInfo(resolvedUserId) != null) {
402 addApprovedList(approved, resolvedUserId, isPrimary);
Kristian Monsen05f34792018-04-09 10:27:16 +0200403 }
404 mUseXml = true;
Julia Reynolds45523002017-09-12 09:43:57 -0400405 }
Julia Reynoldsad6dd352019-03-07 16:46:22 -0500406 } else {
407 readExtraTag(tag, parser);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400408 }
409 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400410 }
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400411 rebindServices(false, USER_ALL);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400412 }
413
Tony Mak9a3c1f12019-03-04 16:04:42 +0000414 /**
415 * Read extra attributes in the {@link #TAG_MANAGED_SERVICES} tag.
416 */
417 protected void readExtraAttributes(String tag, XmlPullParser parser, int userId)
418 throws IOException {}
419
Julia Reynoldsd0ceefa2019-03-03 16:10:52 -0500420 protected abstract String getRequiredPermission();
421
Julia Reynoldsb852e562017-06-06 16:14:18 -0400422 private void loadAllowedComponentsFromSettings() {
Julia Reynoldse0d711f2017-09-01 08:50:47 -0400423 for (UserInfo user : mUm.getUsers()) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400424 final ContentResolver cr = mContext.getContentResolver();
425 addApprovedList(Settings.Secure.getStringForUser(
426 cr,
427 getConfig().secureSettingName,
428 user.id), user.id, true);
429 if (!TextUtils.isEmpty(getConfig().secondarySettingName)) {
430 addApprovedList(Settings.Secure.getStringForUser(
431 cr,
432 getConfig().secondarySettingName,
433 user.id), user.id, false);
434 }
435 }
436 Slog.d(TAG, "Done loading approved values from settings");
437 }
438
Julia Reynolds7380d872018-01-12 10:28:26 -0500439 protected void addApprovedList(String approved, int userId, boolean isPrimary) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400440 if (TextUtils.isEmpty(approved)) {
441 approved = "";
442 }
443 ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId);
444 if (approvedByType == null) {
445 approvedByType = new ArrayMap<>();
446 mApproved.put(userId, approvedByType);
447 }
Artem Iglikovbec96172018-04-24 12:46:44 +0100448
449 ArraySet<String> approvedList = approvedByType.get(isPrimary);
450 if (approvedList == null) {
451 approvedList = new ArraySet<>();
452 approvedByType.put(isPrimary, approvedList);
453 }
454
Julia Reynoldsb852e562017-06-06 16:14:18 -0400455 String[] approvedArray = approved.split(ENABLED_SERVICES_SEPARATOR);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400456 for (String pkgOrComponent : approvedArray) {
457 String approvedItem = getApprovedValue(pkgOrComponent);
458 if (approvedItem != null) {
459 approvedList.add(approvedItem);
460 }
461 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400462 }
463
464 protected boolean isComponentEnabledForPackage(String pkg) {
John Spurlock80774932015-05-07 17:38:50 -0400465 return mEnabledServicesPackageNames.contains(pkg);
466 }
467
Julia Reynoldsb852e562017-06-06 16:14:18 -0400468 protected void setPackageOrComponentEnabled(String pkgOrComponent, int userId,
469 boolean isPrimary, boolean enabled) {
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -0400470 Slog.i(TAG,
471 (enabled ? " Allowing " : "Disallowing ") + mConfig.caption + " " + pkgOrComponent);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400472 ArrayMap<Boolean, ArraySet<String>> allowedByType = mApproved.get(userId);
473 if (allowedByType == null) {
474 allowedByType = new ArrayMap<>();
475 mApproved.put(userId, allowedByType);
476 }
477 ArraySet<String> approved = allowedByType.get(isPrimary);
478 if (approved == null) {
479 approved = new ArraySet<>();
480 allowedByType.put(isPrimary, approved);
481 }
482 String approvedItem = getApprovedValue(pkgOrComponent);
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200483
Julia Reynoldsb852e562017-06-06 16:14:18 -0400484 if (approvedItem != null) {
485 if (enabled) {
486 approved.add(approvedItem);
487 } else {
488 approved.remove(approvedItem);
John Spurlock7340fc82014-04-24 18:50:12 -0400489 }
490 }
491
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400492 rebindServices(false, userId);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400493 }
494
495 private String getApprovedValue(String pkgOrComponent) {
496 if (mApprovalLevel == APPROVAL_BY_COMPONENT) {
497 if(ComponentName.unflattenFromString(pkgOrComponent) != null) {
498 return pkgOrComponent;
John Spurlock7340fc82014-04-24 18:50:12 -0400499 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400500 return null;
501 } else {
502 return getPackageName(pkgOrComponent);
503 }
504 }
505
Julia Reynoldsfa206a42017-08-14 13:22:23 -0400506 protected String getApproved(int userId, boolean primary) {
507 final ArrayMap<Boolean, ArraySet<String>> allowedByType =
508 mApproved.getOrDefault(userId, new ArrayMap<>());
509 ArraySet<String> approved = allowedByType.getOrDefault(primary, new ArraySet<>());
510 return String.join(ENABLED_SERVICES_SEPARATOR, approved);
511 }
512
Julia Reynoldsb852e562017-06-06 16:14:18 -0400513 protected List<ComponentName> getAllowedComponents(int userId) {
514 final List<ComponentName> allowedComponents = new ArrayList<>();
515 final ArrayMap<Boolean, ArraySet<String>> allowedByType =
516 mApproved.getOrDefault(userId, new ArrayMap<>());
517 for (int i = 0; i < allowedByType.size(); i++) {
518 final ArraySet<String> allowed = allowedByType.valueAt(i);
Julia Reynolds2f496962018-04-16 13:17:01 -0400519 for (int j = 0; j < allowed.size(); j++) {
520 ComponentName cn = ComponentName.unflattenFromString(allowed.valueAt(j));
521 if (cn != null) {
522 allowedComponents.add(cn);
523 }
524 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400525 }
526 return allowedComponents;
527 }
528
529 protected List<String> getAllowedPackages(int userId) {
530 final List<String> allowedPackages = new ArrayList<>();
531 final ArrayMap<Boolean, ArraySet<String>> allowedByType =
532 mApproved.getOrDefault(userId, new ArrayMap<>());
533 for (int i = 0; i < allowedByType.size(); i++) {
534 final ArraySet<String> allowed = allowedByType.valueAt(i);
Julia Reynolds2f496962018-04-16 13:17:01 -0400535 for (int j = 0; j < allowed.size(); j++) {
536 String pkgName = getPackageName(allowed.valueAt(j));
537 if (!TextUtils.isEmpty(pkgName)) {
538 allowedPackages.add(pkgName);
539 }
540 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400541 }
542 return allowedPackages;
543 }
544
545 protected boolean isPackageOrComponentAllowed(String pkgOrComponent, int userId) {
546 ArrayMap<Boolean, ArraySet<String>> allowedByType =
547 mApproved.getOrDefault(userId, new ArrayMap<>());
548 for (int i = 0; i < allowedByType.size(); i++) {
549 ArraySet<String> allowed = allowedByType.valueAt(i);
550 if (allowed.contains(pkgOrComponent)) {
551 return true;
552 }
553 }
554 return false;
555 }
556
Julia Reynolds14590742018-07-30 09:25:35 -0400557 protected boolean isPackageAllowed(String pkg, int userId) {
558 if (pkg == null) {
559 return false;
560 }
561 ArrayMap<Boolean, ArraySet<String>> allowedByType =
562 mApproved.getOrDefault(userId, new ArrayMap<>());
563 for (int i = 0; i < allowedByType.size(); i++) {
564 ArraySet<String> allowed = allowedByType.valueAt(i);
565 for (String allowedEntry : allowed) {
566 ComponentName component = ComponentName.unflattenFromString(allowedEntry);
567 if (component != null) {
568 if (pkg.equals(component.getPackageName())) {
569 return true;
570 }
571 } else {
572 if (pkg.equals(allowedEntry)) {
573 return true;
574 }
575 }
576 }
577 }
578 return false;
579 }
580
Julia Reynoldsb852e562017-06-06 16:14:18 -0400581 public void onPackagesChanged(boolean removingPackage, String[] pkgList, int[] uidList) {
582 if (DEBUG) Slog.d(TAG, "onPackagesChanged removingPackage=" + removingPackage
583 + " pkgList=" + (pkgList == null ? null : Arrays.asList(pkgList))
584 + " mEnabledServicesPackageNames=" + mEnabledServicesPackageNames);
585
586 if (pkgList != null && (pkgList.length > 0)) {
587 boolean anyServicesInvolved = false;
588 // Remove notification settings for uninstalled package
Beverly42d01902019-01-03 12:47:57 -0500589 if (removingPackage && uidList != null) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400590 int size = Math.min(pkgList.length, uidList.length);
591 for (int i = 0; i < size; i++) {
592 final String pkg = pkgList[i];
593 final int userId = UserHandle.getUserId(uidList[i]);
594 anyServicesInvolved = removeUninstalledItemsFromApprovedLists(userId, pkg);
595 }
596 }
597 for (String pkgName : pkgList) {
598 if (mEnabledServicesPackageNames.contains(pkgName)) {
599 anyServicesInvolved = true;
600 }
Beverly42d01902019-01-03 12:47:57 -0500601 if (uidList != null && uidList.length > 0) {
602 for (int uid : uidList) {
603 if (isPackageAllowed(pkgName, UserHandle.getUserId(uid))) {
604 anyServicesInvolved = true;
605 }
Julia Reynolds14590742018-07-30 09:25:35 -0400606 }
607 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400608 }
609
610 if (anyServicesInvolved) {
611 // make sure we're still bound to any of our services who may have just upgraded
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400612 rebindServices(false, USER_ALL);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400613 }
John Spurlock7340fc82014-04-24 18:50:12 -0400614 }
615 }
616
Julia Reynolds5aa13a42017-08-24 09:10:23 -0400617 public void onUserRemoved(int user) {
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -0400618 Slog.i(TAG, "Removing approved services for removed user " + user);
Julia Reynolds5aa13a42017-08-24 09:10:23 -0400619 mApproved.remove(user);
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400620 rebindServices(true, user);
Julia Reynolds5aa13a42017-08-24 09:10:23 -0400621 }
622
John Spurlock1b8b22b2015-05-20 09:47:13 -0400623 public void onUserSwitched(int user) {
624 if (DEBUG) Slog.d(TAG, "onUserSwitched u=" + user);
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400625 rebindServices(true, user);
Christoph Studerb53dfd42014-09-12 14:45:59 +0200626 }
627
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -0500628 public void onUserUnlocked(int user) {
629 if (DEBUG) Slog.d(TAG, "onUserUnlocked u=" + user);
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400630 rebindServices(false, user);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -0500631 }
632
Julia Reynoldsb852e562017-06-06 16:14:18 -0400633 private ManagedServiceInfo getServiceFromTokenLocked(IInterface service) {
Chris Wrenab41eec2016-01-04 18:01:27 -0500634 if (service == null) {
635 return null;
636 }
John Spurlock7340fc82014-04-24 18:50:12 -0400637 final IBinder token = service.asBinder();
638 final int N = mServices.size();
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200639 for (int i = 0; i < N; i++) {
John Spurlock7340fc82014-04-24 18:50:12 -0400640 final ManagedServiceInfo info = mServices.get(i);
641 if (info.service.asBinder() == token) return info;
642 }
Chris Wrenab41eec2016-01-04 18:01:27 -0500643 return null;
644 }
645
Julia Reynolds503ed942017-10-04 16:04:56 -0400646 protected boolean isServiceTokenValidLocked(IInterface service) {
647 if (service == null) {
648 return false;
649 }
650 ManagedServiceInfo info = getServiceFromTokenLocked(service);
651 if (info != null) {
652 return true;
653 }
654 return false;
655 }
656
Julia Reynoldsb852e562017-06-06 16:14:18 -0400657 protected ManagedServiceInfo checkServiceTokenLocked(IInterface service) {
Chris Wrenab41eec2016-01-04 18:01:27 -0500658 checkNotNull(service);
659 ManagedServiceInfo info = getServiceFromTokenLocked(service);
660 if (info != null) {
661 return info;
662 }
John Spurlock7340fc82014-04-24 18:50:12 -0400663 throw new SecurityException("Disallowed call from unknown " + getCaption() + ": "
Julia Reynoldscb507b82017-09-07 13:53:40 -0400664 + service + " " + service.getClass());
John Spurlock7340fc82014-04-24 18:50:12 -0400665 }
666
Julia Reynolds70aaea72018-07-13 13:38:34 -0400667 public boolean isSameUser(IInterface service, int userId) {
668 checkNotNull(service);
Julia Reynolds3ff1fd92018-08-29 09:57:11 -0400669 synchronized (mMutex) {
670 ManagedServiceInfo info = getServiceFromTokenLocked(service);
671 if (info != null) {
672 return info.isSameUser(userId);
673 }
674 return false;
Julia Reynolds70aaea72018-07-13 13:38:34 -0400675 }
Julia Reynolds70aaea72018-07-13 13:38:34 -0400676 }
677
John Spurlock7340fc82014-04-24 18:50:12 -0400678 public void unregisterService(IInterface service, int userid) {
679 checkNotNull(service);
680 // no need to check permissions; if your service binder is in the list,
681 // that's proof that you had permission to add it in the first place
682 unregisterServiceImpl(service, userid);
683 }
684
685 public void registerService(IInterface service, ComponentName component, int userid) {
686 checkNotNull(service);
Christoph Studer3e144d32014-05-22 16:48:40 +0200687 ManagedServiceInfo info = registerServiceImpl(service, component, userid);
688 if (info != null) {
689 onServiceAdded(info);
690 }
John Spurlock7340fc82014-04-24 18:50:12 -0400691 }
692
Chris Wren51017d02015-12-15 15:34:46 -0500693 /**
694 * Add a service to our callbacks. The lifecycle of this service is managed externally,
Julia Reynoldsb852e562017-06-06 16:14:18 -0400695 * but unlike a system service, it should not be considered privileged.
Chris Wren51017d02015-12-15 15:34:46 -0500696 * */
Julia Reynoldsb852e562017-06-06 16:14:18 -0400697 protected void registerGuestService(ManagedServiceInfo guest) {
Chris Wren51017d02015-12-15 15:34:46 -0500698 checkNotNull(guest.service);
Ruben Brunke24b9a62016-02-16 21:38:24 -0800699 if (!checkType(guest.service)) {
700 throw new IllegalArgumentException();
701 }
Chris Wren51017d02015-12-15 15:34:46 -0500702 if (registerServiceImpl(guest) != null) {
703 onServiceAdded(guest);
Chris Wrenab41eec2016-01-04 18:01:27 -0500704 }
705 }
706
Julia Reynoldsb852e562017-06-06 16:14:18 -0400707 protected void setComponentState(ComponentName component, boolean enabled) {
Chris Wrenab41eec2016-01-04 18:01:27 -0500708 boolean previous = !mSnoozingForCurrentProfiles.contains(component);
709 if (previous == enabled) {
710 return;
711 }
712
713 if (enabled) {
714 mSnoozingForCurrentProfiles.remove(component);
715 } else {
716 mSnoozingForCurrentProfiles.add(component);
717 }
718
719 // State changed
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -0400720 Slog.d(TAG, ((enabled) ? "Enabling " : "Disabling ") + "component " +
721 component.flattenToShortString());
Chris Wrenab41eec2016-01-04 18:01:27 -0500722
Chris Wren0efdb882016-03-01 17:17:47 -0500723 synchronized (mMutex) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400724 final IntArray userIds = mUserProfiles.getCurrentProfileIds();
Chris Wren0efdb882016-03-01 17:17:47 -0500725
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400726 for (int i = 0; i < userIds.size(); i++) {
727 final int userId = userIds.get(i);
Chris Wren0efdb882016-03-01 17:17:47 -0500728 if (enabled) {
Beverly363da782018-10-09 16:05:15 -0400729 if (isPackageOrComponentAllowed(component.flattenToString(), userId)
Beverly2d783fc2018-09-07 13:38:21 -0400730 || isPackageOrComponentAllowed(component.getPackageName(), userId)) {
Julia Reynolds00fa8402018-07-25 08:57:58 -0400731 registerServiceLocked(component, userId);
732 } else {
733 Slog.d(TAG, component + " no longer has permission to be bound");
734 }
Chris Wren0efdb882016-03-01 17:17:47 -0500735 } else {
736 unregisterServiceLocked(component, userId);
737 }
Chris Wrenab41eec2016-01-04 18:01:27 -0500738 }
Chris Wren51017d02015-12-15 15:34:46 -0500739 }
740 }
741
Julia Reynoldsb852e562017-06-06 16:14:18 -0400742 private @NonNull ArraySet<ComponentName> loadComponentNamesFromValues(
743 ArraySet<String> approved, int userId) {
744 if (approved == null || approved.size() == 0)
Julia Reynolds6e839b02016-04-13 10:01:17 -0400745 return new ArraySet<>();
Julia Reynoldsb852e562017-06-06 16:14:18 -0400746 ArraySet<ComponentName> result = new ArraySet<>(approved.size());
747 for (int i = 0; i < approved.size(); i++) {
748 final String packageOrComponent = approved.valueAt(i);
749 if (!TextUtils.isEmpty(packageOrComponent)) {
750 ComponentName component = ComponentName.unflattenFromString(packageOrComponent);
751 if (component != null) {
752 result.add(component);
753 } else {
754 result.addAll(queryPackageForServices(packageOrComponent, userId));
755 }
Christopher Tate6597e342015-02-17 12:15:25 -0800756 }
757 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200758 return result;
759 }
John Spurlock7340fc82014-04-24 18:50:12 -0400760
Julia Reynoldsc279b992015-10-30 08:23:51 -0400761 protected Set<ComponentName> queryPackageForServices(String packageName, int userId) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400762 return queryPackageForServices(packageName, 0, userId);
763 }
764
765 protected Set<ComponentName> queryPackageForServices(String packageName, int extraFlags,
766 int userId) {
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200767 Set<ComponentName> installed = new ArraySet<>();
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200768 final PackageManager pm = mContext.getPackageManager();
Julia Reynoldsc279b992015-10-30 08:23:51 -0400769 Intent queryIntent = new Intent(mConfig.serviceInterface);
770 if (!TextUtils.isEmpty(packageName)) {
771 queryIntent.setPackage(packageName);
772 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200773 List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser(
Julia Reynoldsc279b992015-10-30 08:23:51 -0400774 queryIntent,
Julia Reynoldsb852e562017-06-06 16:14:18 -0400775 PackageManager.GET_SERVICES | PackageManager.GET_META_DATA | extraFlags,
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200776 userId);
777 if (DEBUG)
778 Slog.v(TAG, mConfig.serviceInterface + " services: " + installedServices);
Julia Reynolds50f05142015-10-30 17:03:59 -0400779 if (installedServices != null) {
780 for (int i = 0, count = installedServices.size(); i < count; i++) {
781 ResolveInfo resolveInfo = installedServices.get(i);
782 ServiceInfo info = resolveInfo.serviceInfo;
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200783
Julia Reynolds50f05142015-10-30 17:03:59 -0400784 ComponentName component = new ComponentName(info.packageName, info.name);
785 if (!mConfig.bindPermission.equals(info.permission)) {
786 Slog.w(TAG, "Skipping " + getCaption() + " service "
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800787 + info.packageName + "/" + info.name
788 + ": it does not require the permission "
789 + mConfig.bindPermission);
Julia Reynolds50f05142015-10-30 17:03:59 -0400790 continue;
791 }
792 installed.add(component);
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200793 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200794 }
Julia Reynoldsc279b992015-10-30 08:23:51 -0400795 return installed;
796 }
797
Julia Reynolds4c456dd2019-01-07 12:22:00 -0500798 protected Set<String> getAllowedPackages() {
799 final Set<String> allowedPackages = new ArraySet<>();
800 for (int k = 0; k < mApproved.size(); k++) {
801 ArrayMap<Boolean, ArraySet<String>> allowedByType = mApproved.valueAt(k);
802 for (int i = 0; i < allowedByType.size(); i++) {
803 final ArraySet<String> allowed = allowedByType.valueAt(i);
804 for (int j = 0; j < allowed.size(); j++) {
805 String pkgName = getPackageName(allowed.valueAt(j));
806 if (!TextUtils.isEmpty(pkgName)) {
807 allowedPackages.add(pkgName);
808 }
809 }
810 }
811 }
812 return allowedPackages;
813 }
814
Annie Meng8b646fd2019-02-01 18:46:42 +0000815 private void trimApprovedListsAccordingToInstalledServices(int userId) {
816 final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId);
817 if (approvedByType == null) {
818 return;
819 }
820 for (int i = 0; i < approvedByType.size(); i++) {
821 final ArraySet<String> approved = approvedByType.valueAt(i);
822 for (int j = approved.size() - 1; j >= 0; j--) {
823 final String approvedPackageOrComponent = approved.valueAt(j);
824 if (!isValidEntry(approvedPackageOrComponent, userId)){
825 approved.removeAt(j);
826 Slog.v(TAG, "Removing " + approvedPackageOrComponent
827 + " from approved list; no matching services found");
828 } else {
829 if (DEBUG) {
830 Slog.v(TAG, "Keeping " + approvedPackageOrComponent
831 + " on approved list; matching services found");
Julia Reynoldsb852e562017-06-06 16:14:18 -0400832 }
John Spurlock7340fc82014-04-24 18:50:12 -0400833 }
John Spurlock7340fc82014-04-24 18:50:12 -0400834 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400835 }
836 }
John Spurlock7340fc82014-04-24 18:50:12 -0400837
Julia Reynoldsb852e562017-06-06 16:14:18 -0400838 private boolean removeUninstalledItemsFromApprovedLists(int uninstalledUserId, String pkg) {
839 boolean removed = false;
840 final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(uninstalledUserId);
841 if (approvedByType != null) {
842 int M = approvedByType.size();
843 for (int j = 0; j < M; j++) {
844 final ArraySet<String> approved = approvedByType.valueAt(j);
845 int O = approved.size();
846 for (int k = O - 1; k >= 0; k--) {
847 final String packageOrComponent = approved.valueAt(k);
848 final String packageName = getPackageName(packageOrComponent);
849 if (TextUtils.equals(pkg, packageName)) {
850 approved.removeAt(k);
851 if (DEBUG) {
852 Slog.v(TAG, "Removing " + packageOrComponent
853 + " from approved list; uninstalled");
854 }
855 }
856 }
John Spurlock7340fc82014-04-24 18:50:12 -0400857 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200858 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400859 return removed;
860 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200861
Julia Reynoldsb852e562017-06-06 16:14:18 -0400862 protected String getPackageName(String packageOrComponent) {
863 final ComponentName component = ComponentName.unflattenFromString(packageOrComponent);
864 if (component != null) {
865 return component.getPackageName();
866 } else {
867 return packageOrComponent;
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200868 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400869 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200870
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -0400871 protected boolean isValidEntry(String packageOrComponent, int userId) {
872 return hasMatchingServices(packageOrComponent, userId);
873 }
874
Julia Reynoldsb852e562017-06-06 16:14:18 -0400875 private boolean hasMatchingServices(String packageOrComponent, int userId) {
876 if (!TextUtils.isEmpty(packageOrComponent)) {
877 final String packageName = getPackageName(packageOrComponent);
878 return queryPackageForServices(packageName, userId).size() > 0;
John Spurlock7340fc82014-04-24 18:50:12 -0400879 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400880 return false;
John Spurlock7340fc82014-04-24 18:50:12 -0400881 }
882
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400883 @VisibleForTesting
884 protected SparseArray<ArraySet<ComponentName>> getAllowedComponents(IntArray userIds) {
885 final int nUserIds = userIds.size();
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200886 final SparseArray<ArraySet<ComponentName>> componentsByUser = new SparseArray<>();
John Spurlock7340fc82014-04-24 18:50:12 -0400887
888 for (int i = 0; i < nUserIds; ++i) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400889 final int userId = userIds.get(i);
890 final ArrayMap<Boolean, ArraySet<String>> approvedLists = mApproved.get(userId);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400891 if (approvedLists != null) {
892 final int N = approvedLists.size();
893 for (int j = 0; j < N; j++) {
894 ArraySet<ComponentName> approvedByUser = componentsByUser.get(userId);
895 if (approvedByUser == null) {
896 approvedByUser = new ArraySet<>();
897 componentsByUser.put(userId, approvedByUser);
898 }
899 approvedByUser.addAll(
900 loadComponentNamesFromValues(approvedLists.valueAt(j), userId));
901 }
Julia Reynolds6e839b02016-04-13 10:01:17 -0400902 }
John Spurlock7340fc82014-04-24 18:50:12 -0400903 }
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400904 return componentsByUser;
905 }
John Spurlock7340fc82014-04-24 18:50:12 -0400906
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400907 @GuardedBy("mMutex")
908 protected void populateComponentsToBind(SparseArray<Set<ComponentName>> componentsToBind,
909 final IntArray activeUsers,
910 SparseArray<ArraySet<ComponentName>> approvedComponentsByUser) {
911 mEnabledServicesForCurrentProfiles.clear();
912 mEnabledServicesPackageNames.clear();
913 final int nUserIds = activeUsers.size();
John Spurlock7340fc82014-04-24 18:50:12 -0400914
915 for (int i = 0; i < nUserIds; ++i) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400916 // decode the list of components
917 final int userId = activeUsers.get(i);
918 final ArraySet<ComponentName> userComponents = approvedComponentsByUser.get(userId);
919 if (null == userComponents) {
920 componentsToBind.put(userId, new ArraySet<>());
921 continue;
922 }
923
924 final Set<ComponentName> add = new HashSet<>(userComponents);
925 add.removeAll(mSnoozingForCurrentProfiles);
926
927 componentsToBind.put(userId, add);
928
929 mEnabledServicesForCurrentProfiles.addAll(userComponents);
930
931 for (int j = 0; j < userComponents.size(); j++) {
932 final ComponentName component = userComponents.valueAt(j);
933 mEnabledServicesPackageNames.add(component.getPackageName());
934 }
935 }
936 }
937
938 @GuardedBy("mMutex")
939 protected Set<ManagedServiceInfo> getRemovableConnectedServices() {
940 final Set<ManagedServiceInfo> removableBoundServices = new ArraySet<>();
941 for (ManagedServiceInfo service : mServices) {
942 if (!service.isSystem && !service.isGuest(this)) {
943 removableBoundServices.add(service);
944 }
945 }
946 return removableBoundServices;
947 }
948
949 protected void populateComponentsToUnbind(
950 boolean forceRebind,
951 Set<ManagedServiceInfo> removableBoundServices,
952 SparseArray<Set<ComponentName>> allowedComponentsToBind,
953 SparseArray<Set<ComponentName>> componentsToUnbind) {
954 for (ManagedServiceInfo info : removableBoundServices) {
955 final Set<ComponentName> allowedComponents = allowedComponentsToBind.get(info.userid);
956 if (allowedComponents != null) {
957 if (forceRebind || !allowedComponents.contains(info.component)) {
958 Set<ComponentName> toUnbind =
959 componentsToUnbind.get(info.userid, new ArraySet<>());
960 toUnbind.add(info.component);
961 componentsToUnbind.put(info.userid, toUnbind);
962 }
963 }
964 }
965 }
966
967 /**
968 * Called whenever packages change, the user switches, or the secure setting
969 * is altered. (For example in response to USER_SWITCHED in our broadcast receiver)
970 */
971 protected void rebindServices(boolean forceRebind, int userToRebind) {
972 if (DEBUG) Slog.d(TAG, "rebindServices " + forceRebind + " " + userToRebind);
973 IntArray userIds = mUserProfiles.getCurrentProfileIds();
974 if (userToRebind != USER_ALL) {
975 userIds = new IntArray(1);
976 userIds.add(userToRebind);
977 }
978
979 final SparseArray<Set<ComponentName>> componentsToBind = new SparseArray<>();
980 final SparseArray<Set<ComponentName>> componentsToUnbind = new SparseArray<>();
981
982 synchronized (mMutex) {
983 final SparseArray<ArraySet<ComponentName>> approvedComponentsByUser =
984 getAllowedComponents(userIds);
985 final Set<ManagedServiceInfo> removableBoundServices = getRemovableConnectedServices();
986
987 // Filter approvedComponentsByUser to collect all of the components that are allowed
988 // for the currently active user(s).
989 populateComponentsToBind(componentsToBind, userIds, approvedComponentsByUser);
990
991 // For every current non-system connection, disconnect services that are no longer
992 // approved, or ALL services if we are force rebinding
993 populateComponentsToUnbind(
994 forceRebind, removableBoundServices, componentsToBind, componentsToUnbind);
995 }
996
997 unbindFromServices(componentsToUnbind);
998 bindToServices(componentsToBind);
999 }
1000
1001 protected void unbindFromServices(SparseArray<Set<ComponentName>> componentsToUnbind) {
1002 for (int i = 0; i < componentsToUnbind.size(); i++) {
1003 final int userId = componentsToUnbind.keyAt(i);
1004 final Set<ComponentName> removableComponents = componentsToUnbind.get(userId);
1005 for (ComponentName cn : removableComponents) {
1006 // No longer allowed to be bound, or must rebind.
1007 Slog.v(TAG, "disabling " + getCaption() + " for user " + userId + ": " + cn);
1008 unregisterService(cn, userId);
1009 }
1010 }
1011 }
1012
1013 // Attempt to bind to services, skipping those that cannot be found or lack the permission.
1014 private void bindToServices(SparseArray<Set<ComponentName>> componentsToBind) {
1015 for (int i = 0; i < componentsToBind.size(); i++) {
1016 final int userId = componentsToBind.keyAt(i);
1017 final Set<ComponentName> add = componentsToBind.get(userId);
Julia Reynolds9a86cc02016-02-10 15:38:15 -05001018 for (ComponentName component : add) {
Julia Reynoldsa75c7522017-03-21 17:34:25 -04001019 try {
1020 ServiceInfo info = mPm.getServiceInfo(component,
1021 PackageManager.MATCH_DIRECT_BOOT_AWARE
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001022 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
Julia Reynolds503ed942017-10-04 16:04:56 -04001023 if (info == null) {
1024 Slog.w(TAG, "Not binding " + getCaption() + " service " + component
1025 + ": service not found");
1026 continue;
1027 }
1028 if (!mConfig.bindPermission.equals(info.permission)) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04001029 Slog.w(TAG, "Not binding " + getCaption() + " service " + component
Julia Reynoldsa75c7522017-03-21 17:34:25 -04001030 + ": it does not require the permission " + mConfig.bindPermission);
1031 continue;
1032 }
1033 Slog.v(TAG,
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001034 "enabling " + getCaption() + " for " + userId + ": " + component);
1035 registerService(component, userId);
Julia Reynoldsa75c7522017-03-21 17:34:25 -04001036 } catch (RemoteException e) {
1037 e.rethrowFromSystemServer();
1038 }
John Spurlock7340fc82014-04-24 18:50:12 -04001039 }
1040 }
1041 }
1042
1043 /**
1044 * Version of registerService that takes the name of a service component to bind to.
1045 */
1046 private void registerService(final ComponentName name, final int userid) {
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001047 synchronized (mMutex) {
1048 registerServiceLocked(name, userid);
1049 }
1050 }
1051
Chris Wren0efdb882016-03-01 17:17:47 -05001052 /**
1053 * Inject a system service into the management list.
1054 */
1055 public void registerSystemService(final ComponentName name, final int userid) {
1056 synchronized (mMutex) {
1057 registerServiceLocked(name, userid, true /* isSystem */);
1058 }
1059 }
1060
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001061 private void registerServiceLocked(final ComponentName name, final int userid) {
Chris Wren0efdb882016-03-01 17:17:47 -05001062 registerServiceLocked(name, userid, false /* isSystem */);
1063 }
1064
1065 private void registerServiceLocked(final ComponentName name, final int userid,
1066 final boolean isSystem) {
John Spurlock7340fc82014-04-24 18:50:12 -04001067 if (DEBUG) Slog.v(TAG, "registerService: " + name + " u=" + userid);
1068
Andrew Zeng190c0672018-06-28 15:15:05 -07001069 final Pair<ComponentName, Integer> servicesBindingTag = Pair.create(name, userid);
1070 if (mServicesBound.contains(servicesBindingTag)) {
1071 Slog.v(TAG, "Not registering " + name + " is already bound");
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001072 // stop registering this thing already! we're working on it
1073 return;
1074 }
Andrew Zeng190c0672018-06-28 15:15:05 -07001075 mServicesBound.add(servicesBindingTag);
John Spurlock7340fc82014-04-24 18:50:12 -04001076
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001077 final int N = mServices.size();
1078 for (int i = N - 1; i >= 0; i--) {
1079 final ManagedServiceInfo info = mServices.get(i);
1080 if (name.equals(info.component)
1081 && info.userid == userid) {
1082 // cut old connections
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -04001083 Slog.v(TAG, " disconnecting old " + getCaption() + ": " + info.service);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001084 removeServiceLocked(i);
1085 if (info.connection != null) {
Andrew Zeng190c0672018-06-28 15:15:05 -07001086 unbindService(info.connection, info.component, info.userid);
John Spurlock7340fc82014-04-24 18:50:12 -04001087 }
1088 }
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001089 }
John Spurlock7340fc82014-04-24 18:50:12 -04001090
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001091 Intent intent = new Intent(mConfig.serviceInterface);
1092 intent.setComponent(name);
John Spurlock7340fc82014-04-24 18:50:12 -04001093
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001094 intent.putExtra(Intent.EXTRA_CLIENT_LABEL, mConfig.clientLabel);
John Spurlock7340fc82014-04-24 18:50:12 -04001095
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001096 final PendingIntent pendingIntent = PendingIntent.getActivity(
1097 mContext, 0, new Intent(mConfig.settingsAction), 0);
1098 intent.putExtra(Intent.EXTRA_CLIENT_INTENT, pendingIntent);
John Spurlock7340fc82014-04-24 18:50:12 -04001099
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001100 ApplicationInfo appInfo = null;
1101 try {
1102 appInfo = mContext.getPackageManager().getApplicationInfo(
1103 name.getPackageName(), 0);
1104 } catch (NameNotFoundException e) {
1105 // Ignore if the package doesn't exist we won't be able to bind to the service.
1106 }
1107 final int targetSdkVersion =
1108 appInfo != null ? appInfo.targetSdkVersion : Build.VERSION_CODES.BASE;
John Spurlock7340fc82014-04-24 18:50:12 -04001109
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001110 try {
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -04001111 Slog.v(TAG, "binding: " + intent);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001112 ServiceConnection serviceConnection = new ServiceConnection() {
1113 IInterface mService;
Denis Kuznetsov76c02682015-09-17 19:57:00 +02001114
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001115 @Override
1116 public void onServiceConnected(ComponentName name, IBinder binder) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001117 Slog.v(TAG, userid + " " + getCaption() + " service connected: " + name);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001118 boolean added = false;
1119 ManagedServiceInfo info = null;
1120 synchronized (mMutex) {
Ryan Lothian4a86a512017-12-04 11:56:58 -05001121 mServicesRebinding.remove(servicesBindingTag);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001122 try {
1123 mService = asInterface(binder);
1124 info = newServiceInfo(mService, name,
Chris Wren0efdb882016-03-01 17:17:47 -05001125 userid, isSystem, this, targetSdkVersion);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001126 binder.linkToDeath(info, 0);
1127 added = mServices.add(info);
1128 } catch (RemoteException e) {
Tony Mak180a9c42019-03-08 13:33:08 +00001129 Slog.e(TAG, "Failed to linkToDeath, already dead", e);
Denis Kuznetsov76c02682015-09-17 19:57:00 +02001130 }
1131 }
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001132 if (added) {
1133 onServiceAdded(info);
Denis Kuznetsov76c02682015-09-17 19:57:00 +02001134 }
John Spurlock7340fc82014-04-24 18:50:12 -04001135 }
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001136
1137 @Override
1138 public void onServiceDisconnected(ComponentName name) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001139 Slog.v(TAG, userid + " " + getCaption() + " connection lost: " + name);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001140 }
Ryan Lothian4a86a512017-12-04 11:56:58 -05001141
1142 @Override
1143 public void onBindingDied(ComponentName name) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001144 Slog.w(TAG, userid + " " + getCaption() + " binding died: " + name);
Ryan Lothian4a86a512017-12-04 11:56:58 -05001145 synchronized (mMutex) {
Andrew Zeng190c0672018-06-28 15:15:05 -07001146 unbindService(this, name, userid);
Ryan Lothian4a86a512017-12-04 11:56:58 -05001147 if (!mServicesRebinding.contains(servicesBindingTag)) {
1148 mServicesRebinding.add(servicesBindingTag);
1149 mHandler.postDelayed(new Runnable() {
1150 @Override
1151 public void run() {
1152 registerService(name, userid);
1153 }
1154 }, ON_BINDING_DIED_REBIND_DELAY_MS);
1155 } else {
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001156 Slog.v(TAG, getCaption() + " not rebinding in user " + userid
1157 + " as a previous rebind attempt was made: " + name);
Ryan Lothian4a86a512017-12-04 11:56:58 -05001158 }
1159 }
1160 }
Tony Mak180a9c42019-03-08 13:33:08 +00001161
1162 @Override
1163 public void onNullBinding(ComponentName name) {
1164 Slog.v(TAG, "onNullBinding() called with: name = [" + name + "]");
Julia Reynolds8a4f2ab2019-04-10 10:08:21 -04001165 mServicesBound.remove(servicesBindingTag);
Tony Mak180a9c42019-03-08 13:33:08 +00001166 }
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001167 };
1168 if (!mContext.bindServiceAsUser(intent,
Amith Yamasanie5bfeee2018-09-05 18:52:35 -07001169 serviceConnection,
1170 getBindFlags(),
1171 new UserHandle(userid))) {
Andrew Zeng190c0672018-06-28 15:15:05 -07001172 mServicesBound.remove(servicesBindingTag);
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001173 Slog.w(TAG, "Unable to bind " + getCaption() + " service: " + intent
1174 + " in user " + userid);
John Spurlock7340fc82014-04-24 18:50:12 -04001175 return;
1176 }
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001177 } catch (SecurityException ex) {
Andrew Zeng190c0672018-06-28 15:15:05 -07001178 mServicesBound.remove(servicesBindingTag);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001179 Slog.e(TAG, "Unable to bind " + getCaption() + " service: " + intent, ex);
John Spurlock7340fc82014-04-24 18:50:12 -04001180 }
1181 }
1182
Julia Reynolds8a4f2ab2019-04-10 10:08:21 -04001183 boolean isBound(ComponentName cn, int userId) {
1184 final Pair<ComponentName, Integer> servicesBindingTag = Pair.create(cn, userId);
1185 return mServicesBound.contains(servicesBindingTag);
1186 }
1187
John Spurlock7340fc82014-04-24 18:50:12 -04001188 /**
1189 * Remove a service for the given user by ComponentName
1190 */
1191 private void unregisterService(ComponentName name, int userid) {
1192 synchronized (mMutex) {
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001193 unregisterServiceLocked(name, userid);
1194 }
1195 }
1196
1197 private void unregisterServiceLocked(ComponentName name, int userid) {
1198 final int N = mServices.size();
1199 for (int i = N - 1; i >= 0; i--) {
1200 final ManagedServiceInfo info = mServices.get(i);
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -04001201 if (name.equals(info.component) && info.userid == userid) {
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001202 removeServiceLocked(i);
1203 if (info.connection != null) {
Andrew Zeng190c0672018-06-28 15:15:05 -07001204 unbindService(info.connection, info.component, info.userid);
John Spurlock7340fc82014-04-24 18:50:12 -04001205 }
1206 }
1207 }
1208 }
1209
1210 /**
1211 * Removes a service from the list but does not unbind
1212 *
1213 * @return the removed service.
1214 */
1215 private ManagedServiceInfo removeServiceImpl(IInterface service, final int userid) {
John Spurlocke77bb362014-04-26 10:24:59 -04001216 if (DEBUG) Slog.d(TAG, "removeServiceImpl service=" + service + " u=" + userid);
John Spurlock7340fc82014-04-24 18:50:12 -04001217 ManagedServiceInfo serviceInfo = null;
1218 synchronized (mMutex) {
1219 final int N = mServices.size();
Denis Kuznetsov76c02682015-09-17 19:57:00 +02001220 for (int i = N - 1; i >= 0; i--) {
John Spurlock7340fc82014-04-24 18:50:12 -04001221 final ManagedServiceInfo info = mServices.get(i);
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -04001222 if (info.service.asBinder() == service.asBinder() && info.userid == userid) {
1223 Slog.d(TAG, "Removing active service " + info.component);
John Spurlocke77bb362014-04-26 10:24:59 -04001224 serviceInfo = removeServiceLocked(i);
John Spurlock7340fc82014-04-24 18:50:12 -04001225 }
1226 }
1227 }
1228 return serviceInfo;
1229 }
1230
John Spurlocke77bb362014-04-26 10:24:59 -04001231 private ManagedServiceInfo removeServiceLocked(int i) {
1232 final ManagedServiceInfo info = mServices.remove(i);
1233 onServiceRemovedLocked(info);
1234 return info;
1235 }
1236
John Spurlock7340fc82014-04-24 18:50:12 -04001237 private void checkNotNull(IInterface service) {
1238 if (service == null) {
1239 throw new IllegalArgumentException(getCaption() + " must not be null");
1240 }
1241 }
1242
Christoph Studer3e144d32014-05-22 16:48:40 +02001243 private ManagedServiceInfo registerServiceImpl(final IInterface service,
John Spurlock7340fc82014-04-24 18:50:12 -04001244 final ComponentName component, final int userid) {
Chris Wren51017d02015-12-15 15:34:46 -05001245 ManagedServiceInfo info = newServiceInfo(service, component, userid,
1246 true /*isSystem*/, null /*connection*/, Build.VERSION_CODES.LOLLIPOP);
1247 return registerServiceImpl(info);
1248 }
1249
1250 private ManagedServiceInfo registerServiceImpl(ManagedServiceInfo info) {
John Spurlock7340fc82014-04-24 18:50:12 -04001251 synchronized (mMutex) {
1252 try {
Chris Wren51017d02015-12-15 15:34:46 -05001253 info.service.asBinder().linkToDeath(info, 0);
John Spurlock7340fc82014-04-24 18:50:12 -04001254 mServices.add(info);
Christoph Studer3e144d32014-05-22 16:48:40 +02001255 return info;
John Spurlock7340fc82014-04-24 18:50:12 -04001256 } catch (RemoteException e) {
1257 // already dead
1258 }
1259 }
Christoph Studer3e144d32014-05-22 16:48:40 +02001260 return null;
John Spurlock7340fc82014-04-24 18:50:12 -04001261 }
1262
1263 /**
1264 * Removes a service from the list and unbinds.
1265 */
1266 private void unregisterServiceImpl(IInterface service, int userid) {
1267 ManagedServiceInfo info = removeServiceImpl(service, userid);
Chris Wren51017d02015-12-15 15:34:46 -05001268 if (info != null && info.connection != null && !info.isGuest(this)) {
Andrew Zeng190c0672018-06-28 15:15:05 -07001269 unbindService(info.connection, info.component, info.userid);
1270 }
1271 }
1272
1273 private void unbindService(ServiceConnection connection, ComponentName component, int userId) {
1274 try {
1275 mContext.unbindService(connection);
1276 } catch (IllegalArgumentException e) {
1277 Slog.e(TAG, getCaption() + " " + component + " could not be unbound", e);
1278 }
1279 synchronized (mMutex) {
1280 mServicesBound.remove(Pair.create(component, userId));
John Spurlock7340fc82014-04-24 18:50:12 -04001281 }
1282 }
1283
John Spurlock7340fc82014-04-24 18:50:12 -04001284 public class ManagedServiceInfo implements IBinder.DeathRecipient {
1285 public IInterface service;
1286 public ComponentName component;
1287 public int userid;
1288 public boolean isSystem;
1289 public ServiceConnection connection;
1290 public int targetSdkVersion;
1291
1292 public ManagedServiceInfo(IInterface service, ComponentName component,
1293 int userid, boolean isSystem, ServiceConnection connection, int targetSdkVersion) {
1294 this.service = service;
1295 this.component = component;
1296 this.userid = userid;
1297 this.isSystem = isSystem;
1298 this.connection = connection;
1299 this.targetSdkVersion = targetSdkVersion;
1300 }
1301
Chris Wren51017d02015-12-15 15:34:46 -05001302 public boolean isGuest(ManagedServices host) {
1303 return ManagedServices.this != host;
1304 }
1305
Chris Wrenab41eec2016-01-04 18:01:27 -05001306 public ManagedServices getOwner() {
1307 return ManagedServices.this;
1308 }
1309
John Spurlocke77bb362014-04-26 10:24:59 -04001310 @Override
1311 public String toString() {
1312 return new StringBuilder("ManagedServiceInfo[")
1313 .append("component=").append(component)
1314 .append(",userid=").append(userid)
1315 .append(",isSystem=").append(isSystem)
1316 .append(",targetSdkVersion=").append(targetSdkVersion)
1317 .append(",connection=").append(connection == null ? null : "<connection>")
1318 .append(",service=").append(service)
1319 .append(']').toString();
1320 }
1321
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001322 public void writeToProto(ProtoOutputStream proto, long fieldId, ManagedServices host) {
1323 final long token = proto.start(fieldId);
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001324 component.writeToProto(proto, ManagedServiceInfoProto.COMPONENT);
Kweku Adams93304b62017-09-20 17:03:00 -07001325 proto.write(ManagedServiceInfoProto.USER_ID, userid);
1326 proto.write(ManagedServiceInfoProto.SERVICE, service.getClass().getName());
1327 proto.write(ManagedServiceInfoProto.IS_SYSTEM, isSystem);
1328 proto.write(ManagedServiceInfoProto.IS_GUEST, isGuest(host));
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001329 proto.end(token);
Kweku Adams93304b62017-09-20 17:03:00 -07001330 }
1331
Julia Reynolds70aaea72018-07-13 13:38:34 -04001332 public boolean isSameUser(int userId) {
1333 if (!isEnabledForCurrentProfiles()) {
1334 return false;
1335 }
1336 return this.userid == userId;
1337 }
1338
John Spurlock7340fc82014-04-24 18:50:12 -04001339 public boolean enabledAndUserMatches(int nid) {
1340 if (!isEnabledForCurrentProfiles()) {
1341 return false;
1342 }
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001343 if (this.userid == USER_ALL) return true;
Chris Wren0c4eeb42016-05-12 13:21:08 -04001344 if (this.isSystem) return true;
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001345 if (nid == USER_ALL || nid == this.userid) return true;
Esteban Talavera9c6458d2017-03-30 17:59:50 +01001346 return supportsProfiles()
1347 && mUserProfiles.isCurrentProfile(nid)
1348 && isPermittedForProfile(nid);
John Spurlock7340fc82014-04-24 18:50:12 -04001349 }
1350
1351 public boolean supportsProfiles() {
Dianne Hackborn955d8d62014-10-07 20:17:19 -07001352 return targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP;
John Spurlock7340fc82014-04-24 18:50:12 -04001353 }
1354
1355 @Override
1356 public void binderDied() {
John Spurlocke77bb362014-04-26 10:24:59 -04001357 if (DEBUG) Slog.d(TAG, "binderDied");
John Spurlock7340fc82014-04-24 18:50:12 -04001358 // Remove the service, but don't unbind from the service. The system will bring the
Esteban Talavera9c6458d2017-03-30 17:59:50 +01001359 // service back up, and the onServiceConnected handler will read the service with the
John Spurlock7340fc82014-04-24 18:50:12 -04001360 // new binding. If this isn't a bound service, and is just a registered
1361 // service, just removing it from the list is all we need to do anyway.
1362 removeServiceImpl(this.service, this.userid);
1363 }
1364
1365 /** convenience method for looking in mEnabledServicesForCurrentProfiles */
1366 public boolean isEnabledForCurrentProfiles() {
1367 if (this.isSystem) return true;
1368 if (this.connection == null) return false;
1369 return mEnabledServicesForCurrentProfiles.contains(this.component);
1370 }
Esteban Talavera9c6458d2017-03-30 17:59:50 +01001371
1372 /**
1373 * Returns true if this service is allowed to receive events for the given userId. A
1374 * managed profile owner can disallow non-system services running outside of the profile
1375 * from receiving events from the profile.
1376 */
1377 public boolean isPermittedForProfile(int userId) {
1378 if (!mUserProfiles.isManagedProfile(userId)) {
1379 return true;
1380 }
1381 DevicePolicyManager dpm =
1382 (DevicePolicyManager) mContext.getSystemService(DEVICE_POLICY_SERVICE);
1383 final long identity = Binder.clearCallingIdentity();
1384 try {
1385 return dpm.isNotificationListenerServicePermitted(
1386 component.getPackageName(), userId);
1387 } finally {
1388 Binder.restoreCallingIdentity(identity);
1389 }
1390 }
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001391
1392 @Override
1393 public boolean equals(Object o) {
1394 if (this == o) return true;
1395 if (o == null || getClass() != o.getClass()) return false;
1396 ManagedServiceInfo that = (ManagedServiceInfo) o;
1397 return userid == that.userid
1398 && isSystem == that.isSystem
1399 && targetSdkVersion == that.targetSdkVersion
1400 && Objects.equals(service, that.service)
1401 && Objects.equals(component, that.component)
1402 && Objects.equals(connection, that.connection);
1403 }
1404
1405 @Override
1406 public int hashCode() {
1407 return Objects.hash(service, component, userid, isSystem, connection, targetSdkVersion);
1408 }
John Spurlock7340fc82014-04-24 18:50:12 -04001409 }
1410
Chris Wrenab41eec2016-01-04 18:01:27 -05001411 /** convenience method for looking in mEnabledServicesForCurrentProfiles */
1412 public boolean isComponentEnabledForCurrentProfiles(ComponentName component) {
1413 return mEnabledServicesForCurrentProfiles.contains(component);
1414 }
1415
John Spurlock7340fc82014-04-24 18:50:12 -04001416 public static class UserProfiles {
1417 // Profiles of the current user.
Ruben Brunke24b9a62016-02-16 21:38:24 -08001418 private final SparseArray<UserInfo> mCurrentProfiles = new SparseArray<>();
John Spurlock7340fc82014-04-24 18:50:12 -04001419
Ruben Brunke24b9a62016-02-16 21:38:24 -08001420 public void updateCache(@NonNull Context context) {
John Spurlock7340fc82014-04-24 18:50:12 -04001421 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
1422 if (userManager != null) {
1423 int currentUserId = ActivityManager.getCurrentUser();
1424 List<UserInfo> profiles = userManager.getProfiles(currentUserId);
1425 synchronized (mCurrentProfiles) {
1426 mCurrentProfiles.clear();
1427 for (UserInfo user : profiles) {
1428 mCurrentProfiles.put(user.id, user);
1429 }
1430 }
1431 }
1432 }
1433
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001434 /**
1435 * Returns the currently active users (generally one user and its work profile).
1436 */
1437 public IntArray getCurrentProfileIds() {
John Spurlock7340fc82014-04-24 18:50:12 -04001438 synchronized (mCurrentProfiles) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001439 IntArray users = new IntArray(mCurrentProfiles.size());
John Spurlock7340fc82014-04-24 18:50:12 -04001440 final int N = mCurrentProfiles.size();
1441 for (int i = 0; i < N; ++i) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001442 users.add(mCurrentProfiles.keyAt(i));
John Spurlock7340fc82014-04-24 18:50:12 -04001443 }
1444 return users;
1445 }
1446 }
1447
1448 public boolean isCurrentProfile(int userId) {
1449 synchronized (mCurrentProfiles) {
1450 return mCurrentProfiles.get(userId) != null;
1451 }
1452 }
Esteban Talavera9c6458d2017-03-30 17:59:50 +01001453
1454 public boolean isManagedProfile(int userId) {
1455 synchronized (mCurrentProfiles) {
1456 UserInfo user = mCurrentProfiles.get(userId);
1457 return user != null && user.isManagedProfile();
1458 }
1459 }
John Spurlock7340fc82014-04-24 18:50:12 -04001460 }
1461
Ruben Brunke24b9a62016-02-16 21:38:24 -08001462 public static class Config {
1463 public String caption;
1464 public String serviceInterface;
1465 public String secureSettingName;
Julia Reynolds6e839b02016-04-13 10:01:17 -04001466 public String secondarySettingName;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001467 public String xmlTag;
Ruben Brunke24b9a62016-02-16 21:38:24 -08001468 public String bindPermission;
1469 public String settingsAction;
1470 public int clientLabel;
John Spurlock7340fc82014-04-24 18:50:12 -04001471 }
1472}