blob: 4828bbfff67622a7aeead5cacace2c92faceccc2 [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:");
Julia Reynolds77f1e4d2019-07-25 12:36:14 -0400199 synchronized (mApproved) {
200 final int N = mApproved.size();
201 for (int i = 0; i < N; i++) {
202 final int userId = mApproved.keyAt(i);
203 final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
204 if (approvedByType != null) {
205 final int M = approvedByType.size();
206 for (int j = 0; j < M; j++) {
207 final boolean isPrimary = approvedByType.keyAt(j);
208 final ArraySet<String> approved = approvedByType.valueAt(j);
209 if (approvedByType != null && approvedByType.size() > 0) {
210 pw.println(" " + String.join(ENABLED_SERVICES_SEPARATOR, approved)
211 + " (user: " + userId + " isPrimary: " + isPrimary + ")");
212 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400213 }
214 }
215 }
216 }
217
John Spurlocke77bb362014-04-26 10:24:59 -0400218 pw.println(" All " + getCaption() + "s (" + mEnabledServicesForCurrentProfiles.size()
John Spurlock7340fc82014-04-24 18:50:12 -0400219 + ") enabled for current profiles:");
220 for (ComponentName cmpt : mEnabledServicesForCurrentProfiles) {
John Spurlock25e2d242014-06-27 13:58:23 -0400221 if (filter != null && !filter.matches(cmpt)) continue;
John Spurlocke77bb362014-04-26 10:24:59 -0400222 pw.println(" " + cmpt);
John Spurlock7340fc82014-04-24 18:50:12 -0400223 }
224
John Spurlocke77bb362014-04-26 10:24:59 -0400225 pw.println(" Live " + getCaption() + "s (" + mServices.size() + "):");
Julia Reynolds3ff1fd92018-08-29 09:57:11 -0400226 synchronized (mMutex) {
227 for (ManagedServiceInfo info : mServices) {
228 if (filter != null && !filter.matches(info.component)) continue;
229 pw.println(" " + info.component
230 + " (user " + info.userid + "): " + info.service
231 + (info.isSystem ? " SYSTEM" : "")
232 + (info.isGuest(this) ? " GUEST" : ""));
233 }
John Spurlock7340fc82014-04-24 18:50:12 -0400234 }
Chris Wrenab41eec2016-01-04 18:01:27 -0500235
236 pw.println(" Snoozed " + getCaption() + "s (" +
237 mSnoozingForCurrentProfiles.size() + "):");
238 for (ComponentName name : mSnoozingForCurrentProfiles) {
239 pw.println(" " + name.flattenToShortString());
240 }
John Spurlock7340fc82014-04-24 18:50:12 -0400241 }
242
Kweku Adams93304b62017-09-20 17:03:00 -0700243 public void dump(ProtoOutputStream proto, DumpFilter filter) {
244 proto.write(ManagedServicesProto.CAPTION, getCaption());
Julia Reynolds77f1e4d2019-07-25 12:36:14 -0400245 synchronized (mApproved) {
246 final int N = mApproved.size();
247 for (int i = 0; i < N; i++) {
248 final int userId = mApproved.keyAt(i);
249 final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
250 if (approvedByType != null) {
251 final int M = approvedByType.size();
252 for (int j = 0; j < M; j++) {
253 final boolean isPrimary = approvedByType.keyAt(j);
254 final ArraySet<String> approved = approvedByType.valueAt(j);
255 if (approvedByType != null && approvedByType.size() > 0) {
256 final long sToken = proto.start(ManagedServicesProto.APPROVED);
257 for (String s : approved) {
258 proto.write(ServiceProto.NAME, s);
259 }
260 proto.write(ServiceProto.USER_ID, userId);
261 proto.write(ServiceProto.IS_PRIMARY, isPrimary);
262 proto.end(sToken);
Kweku Adams93304b62017-09-20 17:03:00 -0700263 }
Kweku Adams93304b62017-09-20 17:03:00 -0700264 }
265 }
266 }
267 }
268
269 for (ComponentName cmpt : mEnabledServicesForCurrentProfiles) {
270 if (filter != null && !filter.matches(cmpt)) continue;
Kweku Adams85f2fbc2017-12-18 12:04:12 -0800271 cmpt.writeToProto(proto, ManagedServicesProto.ENABLED);
Kweku Adams93304b62017-09-20 17:03:00 -0700272 }
273
Julia Reynolds3ff1fd92018-08-29 09:57:11 -0400274 synchronized (mMutex) {
275 for (ManagedServiceInfo info : mServices) {
276 if (filter != null && !filter.matches(info.component)) continue;
277 info.writeToProto(proto, ManagedServicesProto.LIVE_SERVICES, this);
278 }
Kweku Adams93304b62017-09-20 17:03:00 -0700279 }
280
281 for (ComponentName name : mSnoozingForCurrentProfiles) {
Kweku Adams85f2fbc2017-12-18 12:04:12 -0800282 name.writeToProto(proto, ManagedServicesProto.SNOOZED);
Kweku Adams93304b62017-09-20 17:03:00 -0700283 }
284 }
285
Julia Reynoldsfa206a42017-08-14 13:22:23 -0400286 protected void onSettingRestored(String element, String value, int backupSdkInt, int userId) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400287 if (!mUseXml) {
288 Slog.d(TAG, "Restored managed service setting: " + element);
289 if (mConfig.secureSettingName.equals(element) ||
290 (mConfig.secondarySettingName != null
291 && mConfig.secondarySettingName.equals(element))) {
Julia Reynoldsfa206a42017-08-14 13:22:23 -0400292 if (backupSdkInt < Build.VERSION_CODES.O) {
293 // automatic system grants were added in O, so append the approved apps
294 // rather than wiping out the setting
295 String currentSetting =
296 getApproved(userId, mConfig.secureSettingName.equals(element));
297 if (!TextUtils.isEmpty(currentSetting)) {
298 if (!TextUtils.isEmpty(value)) {
299 value = value + ENABLED_SERVICES_SEPARATOR + currentSetting;
300 } else {
301 value = currentSetting;
302 }
303 }
304 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400305 Settings.Secure.putStringForUser(
306 mContext.getContentResolver(), element, value, userId);
307 loadAllowedComponentsFromSettings();
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400308 rebindServices(false, userId);
Christopher Tate6597e342015-02-17 12:15:25 -0800309 }
310 }
311 }
312
Annie Meng8b646fd2019-02-01 18:46:42 +0000313 public void writeXml(XmlSerializer out, boolean forBackup, int userId) throws IOException {
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400314 out.startTag(null, getConfig().xmlTag);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400315
Julia Reynolds7380d872018-01-12 10:28:26 -0500316 out.attribute(null, ATT_VERSION, String.valueOf(DB_VERSION));
317
Julia Reynoldsb852e562017-06-06 16:14:18 -0400318 if (forBackup) {
Annie Meng8b646fd2019-02-01 18:46:42 +0000319 trimApprovedListsAccordingToInstalledServices(userId);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400320 }
321
Julia Reynolds77f1e4d2019-07-25 12:36:14 -0400322 synchronized (mApproved) {
323 final int N = mApproved.size();
324 for (int i = 0; i < N; i++) {
325 final int approvedUserId = mApproved.keyAt(i);
326 if (forBackup && approvedUserId != userId) {
327 continue;
328 }
329 final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
330 if (approvedByType != null) {
331 final int M = approvedByType.size();
332 for (int j = 0; j < M; j++) {
333 final boolean isPrimary = approvedByType.keyAt(j);
334 final Set<String> approved = approvedByType.valueAt(j);
335 if (approved != null) {
336 String allowedItems = String.join(ENABLED_SERVICES_SEPARATOR, approved);
337 out.startTag(null, TAG_MANAGED_SERVICES);
338 out.attribute(null, ATT_APPROVED_LIST, allowedItems);
339 out.attribute(null, ATT_USER_ID, Integer.toString(approvedUserId));
340 out.attribute(null, ATT_IS_PRIMARY, Boolean.toString(isPrimary));
341 writeExtraAttributes(out, approvedUserId);
342 out.endTag(null, TAG_MANAGED_SERVICES);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400343
Julia Reynolds77f1e4d2019-07-25 12:36:14 -0400344 if (!forBackup && isPrimary) {
345 // Also write values to settings, for observers who haven't migrated yet
346 Settings.Secure.putStringForUser(mContext.getContentResolver(),
347 getConfig().secureSettingName, allowedItems,
348 approvedUserId);
349 }
350
Julia Reynoldsb852e562017-06-06 16:14:18 -0400351 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400352 }
353 }
354 }
355 }
Julia Reynoldsad6dd352019-03-07 16:46:22 -0500356
357 writeExtraXmlTags(out);
358
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400359 out.endTag(null, getConfig().xmlTag);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400360 }
361
Tony Mak9a3c1f12019-03-04 16:04:42 +0000362 /**
363 * Writes extra xml attributes to {@link #TAG_MANAGED_SERVICES} tag.
364 */
365 protected void writeExtraAttributes(XmlSerializer out, int userId) throws IOException {}
366
Julia Reynoldsad6dd352019-03-07 16:46:22 -0500367 /**
368 * Writes extra xml tags within the parent tag specified in {@link Config#xmlTag}.
369 */
370 protected void writeExtraXmlTags(XmlSerializer out) throws IOException {}
371
372 /**
373 * This is called to process tags other than {@link #TAG_MANAGED_SERVICES}.
374 */
375 protected void readExtraTag(String tag, XmlPullParser parser) throws IOException {}
376
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400377 protected void migrateToXml() {
378 loadAllowedComponentsFromSettings();
379 }
380
Annie Meng8b646fd2019-02-01 18:46:42 +0000381 public void readXml(
382 XmlPullParser parser,
Julia Reynoldsd0ceefa2019-03-03 16:10:52 -0500383 TriPredicate<String, Integer, String> allowedManagedServicePackages,
Annie Meng8b646fd2019-02-01 18:46:42 +0000384 boolean forRestore,
385 int userId)
Julia Reynoldsb852e562017-06-06 16:14:18 -0400386 throws XmlPullParserException, IOException {
Julia Reynolds7380d872018-01-12 10:28:26 -0500387 // read grants
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400388 int type;
389 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
390 String tag = parser.getName();
391 if (type == XmlPullParser.END_TAG
392 && getConfig().xmlTag.equals(tag)) {
393 break;
394 }
395 if (type == XmlPullParser.START_TAG) {
396 if (TAG_MANAGED_SERVICES.equals(tag)) {
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -0400397 Slog.i(TAG, "Read " + mConfig.caption + " permissions from xml");
Julia Reynolds7380d872018-01-12 10:28:26 -0500398
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400399 final String approved = XmlUtils.readStringAttribute(parser, ATT_APPROVED_LIST);
Annie Meng8b646fd2019-02-01 18:46:42 +0000400 // Ignore parser's user id for restore.
401 final int resolvedUserId = forRestore
402 ? userId : XmlUtils.readIntAttribute(parser, ATT_USER_ID, 0);
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -0400403 final boolean isPrimary =
404 XmlUtils.readBooleanAttribute(parser, ATT_IS_PRIMARY, true);
Tony Mak9a3c1f12019-03-04 16:04:42 +0000405 readExtraAttributes(tag, parser, resolvedUserId);
Julia Reynoldsd0ceefa2019-03-03 16:10:52 -0500406 if (allowedManagedServicePackages == null || allowedManagedServicePackages.test(
407 getPackageName(approved), resolvedUserId, getRequiredPermission())) {
Annie Meng8b646fd2019-02-01 18:46:42 +0000408 if (mUm.getUserInfo(resolvedUserId) != null) {
409 addApprovedList(approved, resolvedUserId, isPrimary);
Kristian Monsen05f34792018-04-09 10:27:16 +0200410 }
411 mUseXml = true;
Julia Reynolds45523002017-09-12 09:43:57 -0400412 }
Julia Reynoldsad6dd352019-03-07 16:46:22 -0500413 } else {
414 readExtraTag(tag, parser);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400415 }
416 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400417 }
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400418 rebindServices(false, USER_ALL);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400419 }
420
Tony Mak9a3c1f12019-03-04 16:04:42 +0000421 /**
422 * Read extra attributes in the {@link #TAG_MANAGED_SERVICES} tag.
423 */
424 protected void readExtraAttributes(String tag, XmlPullParser parser, int userId)
425 throws IOException {}
426
Julia Reynoldsd0ceefa2019-03-03 16:10:52 -0500427 protected abstract String getRequiredPermission();
428
Julia Reynoldsb852e562017-06-06 16:14:18 -0400429 private void loadAllowedComponentsFromSettings() {
Julia Reynoldse0d711f2017-09-01 08:50:47 -0400430 for (UserInfo user : mUm.getUsers()) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400431 final ContentResolver cr = mContext.getContentResolver();
432 addApprovedList(Settings.Secure.getStringForUser(
433 cr,
434 getConfig().secureSettingName,
435 user.id), user.id, true);
436 if (!TextUtils.isEmpty(getConfig().secondarySettingName)) {
437 addApprovedList(Settings.Secure.getStringForUser(
438 cr,
439 getConfig().secondarySettingName,
440 user.id), user.id, false);
441 }
442 }
443 Slog.d(TAG, "Done loading approved values from settings");
444 }
445
Julia Reynolds7380d872018-01-12 10:28:26 -0500446 protected void addApprovedList(String approved, int userId, boolean isPrimary) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400447 if (TextUtils.isEmpty(approved)) {
448 approved = "";
449 }
Julia Reynolds77f1e4d2019-07-25 12:36:14 -0400450 synchronized (mApproved) {
451 ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId);
452 if (approvedByType == null) {
453 approvedByType = new ArrayMap<>();
454 mApproved.put(userId, approvedByType);
455 }
Artem Iglikovbec96172018-04-24 12:46:44 +0100456
Julia Reynolds77f1e4d2019-07-25 12:36:14 -0400457 ArraySet<String> approvedList = approvedByType.get(isPrimary);
458 if (approvedList == null) {
459 approvedList = new ArraySet<>();
460 approvedByType.put(isPrimary, approvedList);
461 }
Artem Iglikovbec96172018-04-24 12:46:44 +0100462
Julia Reynolds77f1e4d2019-07-25 12:36:14 -0400463 String[] approvedArray = approved.split(ENABLED_SERVICES_SEPARATOR);
464 for (String pkgOrComponent : approvedArray) {
465 String approvedItem = getApprovedValue(pkgOrComponent);
466 if (approvedItem != null) {
467 approvedList.add(approvedItem);
468 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400469 }
470 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400471 }
472
473 protected boolean isComponentEnabledForPackage(String pkg) {
John Spurlock80774932015-05-07 17:38:50 -0400474 return mEnabledServicesPackageNames.contains(pkg);
475 }
476
Julia Reynoldsb852e562017-06-06 16:14:18 -0400477 protected void setPackageOrComponentEnabled(String pkgOrComponent, int userId,
478 boolean isPrimary, boolean enabled) {
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -0400479 Slog.i(TAG,
480 (enabled ? " Allowing " : "Disallowing ") + mConfig.caption + " " + pkgOrComponent);
Julia Reynolds77f1e4d2019-07-25 12:36:14 -0400481 synchronized (mApproved) {
482 ArrayMap<Boolean, ArraySet<String>> allowedByType = mApproved.get(userId);
483 if (allowedByType == null) {
484 allowedByType = new ArrayMap<>();
485 mApproved.put(userId, allowedByType);
486 }
487 ArraySet<String> approved = allowedByType.get(isPrimary);
488 if (approved == null) {
489 approved = new ArraySet<>();
490 allowedByType.put(isPrimary, approved);
491 }
492 String approvedItem = getApprovedValue(pkgOrComponent);
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200493
Julia Reynolds77f1e4d2019-07-25 12:36:14 -0400494 if (approvedItem != null) {
495 if (enabled) {
496 approved.add(approvedItem);
497 } else {
498 approved.remove(approvedItem);
499 }
John Spurlock7340fc82014-04-24 18:50:12 -0400500 }
501 }
502
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400503 rebindServices(false, userId);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400504 }
505
506 private String getApprovedValue(String pkgOrComponent) {
507 if (mApprovalLevel == APPROVAL_BY_COMPONENT) {
508 if(ComponentName.unflattenFromString(pkgOrComponent) != null) {
509 return pkgOrComponent;
John Spurlock7340fc82014-04-24 18:50:12 -0400510 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400511 return null;
512 } else {
513 return getPackageName(pkgOrComponent);
514 }
515 }
516
Julia Reynoldsfa206a42017-08-14 13:22:23 -0400517 protected String getApproved(int userId, boolean primary) {
Julia Reynolds77f1e4d2019-07-25 12:36:14 -0400518 synchronized (mApproved) {
519 final ArrayMap<Boolean, ArraySet<String>> allowedByType =
520 mApproved.getOrDefault(userId, new ArrayMap<>());
521 ArraySet<String> approved = allowedByType.getOrDefault(primary, new ArraySet<>());
522 return String.join(ENABLED_SERVICES_SEPARATOR, approved);
523 }
Julia Reynoldsfa206a42017-08-14 13:22:23 -0400524 }
525
Julia Reynoldsb852e562017-06-06 16:14:18 -0400526 protected List<ComponentName> getAllowedComponents(int userId) {
527 final List<ComponentName> allowedComponents = new ArrayList<>();
Julia Reynolds77f1e4d2019-07-25 12:36:14 -0400528 synchronized (mApproved) {
529 final ArrayMap<Boolean, ArraySet<String>> allowedByType =
530 mApproved.getOrDefault(userId, new ArrayMap<>());
531 for (int i = 0; i < allowedByType.size(); i++) {
532 final ArraySet<String> allowed = allowedByType.valueAt(i);
533 for (int j = 0; j < allowed.size(); j++) {
534 ComponentName cn = ComponentName.unflattenFromString(allowed.valueAt(j));
535 if (cn != null) {
536 allowedComponents.add(cn);
537 }
Julia Reynolds2f496962018-04-16 13:17:01 -0400538 }
539 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400540 }
541 return allowedComponents;
542 }
543
544 protected List<String> getAllowedPackages(int userId) {
545 final List<String> allowedPackages = new ArrayList<>();
Julia Reynolds77f1e4d2019-07-25 12:36:14 -0400546 synchronized (mApproved) {
547 final ArrayMap<Boolean, ArraySet<String>> allowedByType =
548 mApproved.getOrDefault(userId, new ArrayMap<>());
549 for (int i = 0; i < allowedByType.size(); i++) {
550 final ArraySet<String> allowed = allowedByType.valueAt(i);
551 for (int j = 0; j < allowed.size(); j++) {
552 String pkgName = getPackageName(allowed.valueAt(j));
553 if (!TextUtils.isEmpty(pkgName)) {
554 allowedPackages.add(pkgName);
555 }
Julia Reynolds2f496962018-04-16 13:17:01 -0400556 }
557 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400558 }
559 return allowedPackages;
560 }
561
562 protected boolean isPackageOrComponentAllowed(String pkgOrComponent, int userId) {
Julia Reynolds77f1e4d2019-07-25 12:36:14 -0400563 synchronized (mApproved) {
564 ArrayMap<Boolean, ArraySet<String>> allowedByType =
565 mApproved.getOrDefault(userId, new ArrayMap<>());
566 for (int i = 0; i < allowedByType.size(); i++) {
567 ArraySet<String> allowed = allowedByType.valueAt(i);
568 if (allowed.contains(pkgOrComponent)) {
569 return true;
570 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400571 }
572 }
573 return false;
574 }
575
Julia Reynolds14590742018-07-30 09:25:35 -0400576 protected boolean isPackageAllowed(String pkg, int userId) {
577 if (pkg == null) {
578 return false;
579 }
Julia Reynolds77f1e4d2019-07-25 12:36:14 -0400580 synchronized (mApproved) {
581 ArrayMap<Boolean, ArraySet<String>> allowedByType =
582 mApproved.getOrDefault(userId, new ArrayMap<>());
583 for (int i = 0; i < allowedByType.size(); i++) {
584 ArraySet<String> allowed = allowedByType.valueAt(i);
585 for (String allowedEntry : allowed) {
586 ComponentName component = ComponentName.unflattenFromString(allowedEntry);
587 if (component != null) {
588 if (pkg.equals(component.getPackageName())) {
589 return true;
590 }
591 } else {
592 if (pkg.equals(allowedEntry)) {
593 return true;
594 }
Julia Reynolds14590742018-07-30 09:25:35 -0400595 }
596 }
597 }
598 }
599 return false;
600 }
601
Julia Reynoldsb852e562017-06-06 16:14:18 -0400602 public void onPackagesChanged(boolean removingPackage, String[] pkgList, int[] uidList) {
603 if (DEBUG) Slog.d(TAG, "onPackagesChanged removingPackage=" + removingPackage
604 + " pkgList=" + (pkgList == null ? null : Arrays.asList(pkgList))
605 + " mEnabledServicesPackageNames=" + mEnabledServicesPackageNames);
606
607 if (pkgList != null && (pkgList.length > 0)) {
608 boolean anyServicesInvolved = false;
609 // Remove notification settings for uninstalled package
Beverly42d01902019-01-03 12:47:57 -0500610 if (removingPackage && uidList != null) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400611 int size = Math.min(pkgList.length, uidList.length);
612 for (int i = 0; i < size; i++) {
613 final String pkg = pkgList[i];
614 final int userId = UserHandle.getUserId(uidList[i]);
615 anyServicesInvolved = removeUninstalledItemsFromApprovedLists(userId, pkg);
616 }
617 }
618 for (String pkgName : pkgList) {
619 if (mEnabledServicesPackageNames.contains(pkgName)) {
620 anyServicesInvolved = true;
621 }
Beverly42d01902019-01-03 12:47:57 -0500622 if (uidList != null && uidList.length > 0) {
623 for (int uid : uidList) {
624 if (isPackageAllowed(pkgName, UserHandle.getUserId(uid))) {
625 anyServicesInvolved = true;
626 }
Julia Reynolds14590742018-07-30 09:25:35 -0400627 }
628 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400629 }
630
631 if (anyServicesInvolved) {
632 // make sure we're still bound to any of our services who may have just upgraded
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400633 rebindServices(false, USER_ALL);
Julia Reynoldsb852e562017-06-06 16:14:18 -0400634 }
John Spurlock7340fc82014-04-24 18:50:12 -0400635 }
636 }
637
Julia Reynolds5aa13a42017-08-24 09:10:23 -0400638 public void onUserRemoved(int user) {
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -0400639 Slog.i(TAG, "Removing approved services for removed user " + user);
Julia Reynolds77f1e4d2019-07-25 12:36:14 -0400640 synchronized (mApproved) {
641 mApproved.remove(user);
642 }
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400643 rebindServices(true, user);
Julia Reynolds5aa13a42017-08-24 09:10:23 -0400644 }
645
John Spurlock1b8b22b2015-05-20 09:47:13 -0400646 public void onUserSwitched(int user) {
647 if (DEBUG) Slog.d(TAG, "onUserSwitched u=" + user);
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400648 rebindServices(true, user);
Christoph Studerb53dfd42014-09-12 14:45:59 +0200649 }
650
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -0500651 public void onUserUnlocked(int user) {
652 if (DEBUG) Slog.d(TAG, "onUserUnlocked u=" + user);
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400653 rebindServices(false, user);
Julia Reynoldsa3dcaff2016-02-03 15:04:05 -0500654 }
655
Julia Reynoldsb852e562017-06-06 16:14:18 -0400656 private ManagedServiceInfo getServiceFromTokenLocked(IInterface service) {
Chris Wrenab41eec2016-01-04 18:01:27 -0500657 if (service == null) {
658 return null;
659 }
John Spurlock7340fc82014-04-24 18:50:12 -0400660 final IBinder token = service.asBinder();
661 final int N = mServices.size();
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200662 for (int i = 0; i < N; i++) {
John Spurlock7340fc82014-04-24 18:50:12 -0400663 final ManagedServiceInfo info = mServices.get(i);
664 if (info.service.asBinder() == token) return info;
665 }
Chris Wrenab41eec2016-01-04 18:01:27 -0500666 return null;
667 }
668
Julia Reynolds503ed942017-10-04 16:04:56 -0400669 protected boolean isServiceTokenValidLocked(IInterface service) {
670 if (service == null) {
671 return false;
672 }
673 ManagedServiceInfo info = getServiceFromTokenLocked(service);
674 if (info != null) {
675 return true;
676 }
677 return false;
678 }
679
Julia Reynoldsb852e562017-06-06 16:14:18 -0400680 protected ManagedServiceInfo checkServiceTokenLocked(IInterface service) {
Chris Wrenab41eec2016-01-04 18:01:27 -0500681 checkNotNull(service);
682 ManagedServiceInfo info = getServiceFromTokenLocked(service);
683 if (info != null) {
684 return info;
685 }
John Spurlock7340fc82014-04-24 18:50:12 -0400686 throw new SecurityException("Disallowed call from unknown " + getCaption() + ": "
Julia Reynoldscb507b82017-09-07 13:53:40 -0400687 + service + " " + service.getClass());
John Spurlock7340fc82014-04-24 18:50:12 -0400688 }
689
Julia Reynolds70aaea72018-07-13 13:38:34 -0400690 public boolean isSameUser(IInterface service, int userId) {
691 checkNotNull(service);
Julia Reynolds3ff1fd92018-08-29 09:57:11 -0400692 synchronized (mMutex) {
693 ManagedServiceInfo info = getServiceFromTokenLocked(service);
694 if (info != null) {
695 return info.isSameUser(userId);
696 }
697 return false;
Julia Reynolds70aaea72018-07-13 13:38:34 -0400698 }
Julia Reynolds70aaea72018-07-13 13:38:34 -0400699 }
700
John Spurlock7340fc82014-04-24 18:50:12 -0400701 public void unregisterService(IInterface service, int userid) {
702 checkNotNull(service);
703 // no need to check permissions; if your service binder is in the list,
704 // that's proof that you had permission to add it in the first place
705 unregisterServiceImpl(service, userid);
706 }
707
708 public void registerService(IInterface service, ComponentName component, int userid) {
709 checkNotNull(service);
Christoph Studer3e144d32014-05-22 16:48:40 +0200710 ManagedServiceInfo info = registerServiceImpl(service, component, userid);
711 if (info != null) {
712 onServiceAdded(info);
713 }
John Spurlock7340fc82014-04-24 18:50:12 -0400714 }
715
Chris Wren51017d02015-12-15 15:34:46 -0500716 /**
717 * Add a service to our callbacks. The lifecycle of this service is managed externally,
Julia Reynoldsb852e562017-06-06 16:14:18 -0400718 * but unlike a system service, it should not be considered privileged.
Chris Wren51017d02015-12-15 15:34:46 -0500719 * */
Julia Reynoldsb852e562017-06-06 16:14:18 -0400720 protected void registerGuestService(ManagedServiceInfo guest) {
Chris Wren51017d02015-12-15 15:34:46 -0500721 checkNotNull(guest.service);
Ruben Brunke24b9a62016-02-16 21:38:24 -0800722 if (!checkType(guest.service)) {
723 throw new IllegalArgumentException();
724 }
Chris Wren51017d02015-12-15 15:34:46 -0500725 if (registerServiceImpl(guest) != null) {
726 onServiceAdded(guest);
Chris Wrenab41eec2016-01-04 18:01:27 -0500727 }
728 }
729
Julia Reynoldsb852e562017-06-06 16:14:18 -0400730 protected void setComponentState(ComponentName component, boolean enabled) {
Chris Wrenab41eec2016-01-04 18:01:27 -0500731 boolean previous = !mSnoozingForCurrentProfiles.contains(component);
732 if (previous == enabled) {
733 return;
734 }
735
736 if (enabled) {
737 mSnoozingForCurrentProfiles.remove(component);
738 } else {
739 mSnoozingForCurrentProfiles.add(component);
740 }
741
742 // State changed
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -0400743 Slog.d(TAG, ((enabled) ? "Enabling " : "Disabling ") + "component " +
744 component.flattenToShortString());
Chris Wrenab41eec2016-01-04 18:01:27 -0500745
Chris Wren0efdb882016-03-01 17:17:47 -0500746 synchronized (mMutex) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400747 final IntArray userIds = mUserProfiles.getCurrentProfileIds();
Chris Wren0efdb882016-03-01 17:17:47 -0500748
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400749 for (int i = 0; i < userIds.size(); i++) {
750 final int userId = userIds.get(i);
Chris Wren0efdb882016-03-01 17:17:47 -0500751 if (enabled) {
Beverly363da782018-10-09 16:05:15 -0400752 if (isPackageOrComponentAllowed(component.flattenToString(), userId)
Beverly2d783fc2018-09-07 13:38:21 -0400753 || isPackageOrComponentAllowed(component.getPackageName(), userId)) {
Julia Reynolds00fa8402018-07-25 08:57:58 -0400754 registerServiceLocked(component, userId);
755 } else {
756 Slog.d(TAG, component + " no longer has permission to be bound");
757 }
Chris Wren0efdb882016-03-01 17:17:47 -0500758 } else {
759 unregisterServiceLocked(component, userId);
760 }
Chris Wrenab41eec2016-01-04 18:01:27 -0500761 }
Chris Wren51017d02015-12-15 15:34:46 -0500762 }
763 }
764
Julia Reynoldsb852e562017-06-06 16:14:18 -0400765 private @NonNull ArraySet<ComponentName> loadComponentNamesFromValues(
766 ArraySet<String> approved, int userId) {
767 if (approved == null || approved.size() == 0)
Julia Reynolds6e839b02016-04-13 10:01:17 -0400768 return new ArraySet<>();
Julia Reynoldsb852e562017-06-06 16:14:18 -0400769 ArraySet<ComponentName> result = new ArraySet<>(approved.size());
770 for (int i = 0; i < approved.size(); i++) {
771 final String packageOrComponent = approved.valueAt(i);
772 if (!TextUtils.isEmpty(packageOrComponent)) {
773 ComponentName component = ComponentName.unflattenFromString(packageOrComponent);
774 if (component != null) {
775 result.add(component);
776 } else {
777 result.addAll(queryPackageForServices(packageOrComponent, userId));
778 }
Christopher Tate6597e342015-02-17 12:15:25 -0800779 }
780 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200781 return result;
782 }
John Spurlock7340fc82014-04-24 18:50:12 -0400783
Julia Reynoldsc279b992015-10-30 08:23:51 -0400784 protected Set<ComponentName> queryPackageForServices(String packageName, int userId) {
Julia Reynoldsb852e562017-06-06 16:14:18 -0400785 return queryPackageForServices(packageName, 0, userId);
786 }
787
788 protected Set<ComponentName> queryPackageForServices(String packageName, int extraFlags,
789 int userId) {
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200790 Set<ComponentName> installed = new ArraySet<>();
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200791 final PackageManager pm = mContext.getPackageManager();
Julia Reynoldsc279b992015-10-30 08:23:51 -0400792 Intent queryIntent = new Intent(mConfig.serviceInterface);
793 if (!TextUtils.isEmpty(packageName)) {
794 queryIntent.setPackage(packageName);
795 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200796 List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser(
Julia Reynoldsc279b992015-10-30 08:23:51 -0400797 queryIntent,
Julia Reynoldsb852e562017-06-06 16:14:18 -0400798 PackageManager.GET_SERVICES | PackageManager.GET_META_DATA | extraFlags,
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200799 userId);
800 if (DEBUG)
801 Slog.v(TAG, mConfig.serviceInterface + " services: " + installedServices);
Julia Reynolds50f05142015-10-30 17:03:59 -0400802 if (installedServices != null) {
803 for (int i = 0, count = installedServices.size(); i < count; i++) {
804 ResolveInfo resolveInfo = installedServices.get(i);
805 ServiceInfo info = resolveInfo.serviceInfo;
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200806
Julia Reynolds50f05142015-10-30 17:03:59 -0400807 ComponentName component = new ComponentName(info.packageName, info.name);
808 if (!mConfig.bindPermission.equals(info.permission)) {
809 Slog.w(TAG, "Skipping " + getCaption() + " service "
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800810 + info.packageName + "/" + info.name
811 + ": it does not require the permission "
812 + mConfig.bindPermission);
Julia Reynolds50f05142015-10-30 17:03:59 -0400813 continue;
814 }
815 installed.add(component);
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200816 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200817 }
Julia Reynoldsc279b992015-10-30 08:23:51 -0400818 return installed;
819 }
820
Julia Reynolds4c456dd2019-01-07 12:22:00 -0500821 protected Set<String> getAllowedPackages() {
822 final Set<String> allowedPackages = new ArraySet<>();
Julia Reynolds77f1e4d2019-07-25 12:36:14 -0400823 synchronized (mApproved) {
824 for (int k = 0; k < mApproved.size(); k++) {
825 ArrayMap<Boolean, ArraySet<String>> allowedByType = mApproved.valueAt(k);
826 for (int i = 0; i < allowedByType.size(); i++) {
827 final ArraySet<String> allowed = allowedByType.valueAt(i);
828 for (int j = 0; j < allowed.size(); j++) {
829 String pkgName = getPackageName(allowed.valueAt(j));
830 if (!TextUtils.isEmpty(pkgName)) {
831 allowedPackages.add(pkgName);
832 }
Julia Reynolds4c456dd2019-01-07 12:22:00 -0500833 }
834 }
835 }
836 }
837 return allowedPackages;
838 }
839
Annie Meng8b646fd2019-02-01 18:46:42 +0000840 private void trimApprovedListsAccordingToInstalledServices(int userId) {
Julia Reynolds77f1e4d2019-07-25 12:36:14 -0400841 synchronized (mApproved) {
842 final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId);
843 if (approvedByType == null) {
844 return;
845 }
846 for (int i = 0; i < approvedByType.size(); i++) {
847 final ArraySet<String> approved = approvedByType.valueAt(i);
848 for (int j = approved.size() - 1; j >= 0; j--) {
849 final String approvedPackageOrComponent = approved.valueAt(j);
850 if (!isValidEntry(approvedPackageOrComponent, userId)) {
851 approved.removeAt(j);
852 Slog.v(TAG, "Removing " + approvedPackageOrComponent
853 + " from approved list; no matching services found");
854 } else {
855 if (DEBUG) {
856 Slog.v(TAG, "Keeping " + approvedPackageOrComponent
857 + " on approved list; matching services found");
858 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400859 }
John Spurlock7340fc82014-04-24 18:50:12 -0400860 }
John Spurlock7340fc82014-04-24 18:50:12 -0400861 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400862 }
863 }
John Spurlock7340fc82014-04-24 18:50:12 -0400864
Julia Reynoldsb852e562017-06-06 16:14:18 -0400865 private boolean removeUninstalledItemsFromApprovedLists(int uninstalledUserId, String pkg) {
866 boolean removed = false;
Julia Reynolds77f1e4d2019-07-25 12:36:14 -0400867 synchronized (mApproved) {
868 final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(
869 uninstalledUserId);
870 if (approvedByType != null) {
871 int M = approvedByType.size();
872 for (int j = 0; j < M; j++) {
873 final ArraySet<String> approved = approvedByType.valueAt(j);
874 int O = approved.size();
875 for (int k = O - 1; k >= 0; k--) {
876 final String packageOrComponent = approved.valueAt(k);
877 final String packageName = getPackageName(packageOrComponent);
878 if (TextUtils.equals(pkg, packageName)) {
879 approved.removeAt(k);
880 if (DEBUG) {
881 Slog.v(TAG, "Removing " + packageOrComponent
882 + " from approved list; uninstalled");
883 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400884 }
885 }
886 }
John Spurlock7340fc82014-04-24 18:50:12 -0400887 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200888 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400889 return removed;
890 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200891
Julia Reynoldsb852e562017-06-06 16:14:18 -0400892 protected String getPackageName(String packageOrComponent) {
893 final ComponentName component = ComponentName.unflattenFromString(packageOrComponent);
894 if (component != null) {
895 return component.getPackageName();
896 } else {
897 return packageOrComponent;
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200898 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400899 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200900
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -0400901 protected boolean isValidEntry(String packageOrComponent, int userId) {
902 return hasMatchingServices(packageOrComponent, userId);
903 }
904
Julia Reynoldsb852e562017-06-06 16:14:18 -0400905 private boolean hasMatchingServices(String packageOrComponent, int userId) {
906 if (!TextUtils.isEmpty(packageOrComponent)) {
907 final String packageName = getPackageName(packageOrComponent);
908 return queryPackageForServices(packageName, userId).size() > 0;
John Spurlock7340fc82014-04-24 18:50:12 -0400909 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400910 return false;
John Spurlock7340fc82014-04-24 18:50:12 -0400911 }
912
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400913 @VisibleForTesting
914 protected SparseArray<ArraySet<ComponentName>> getAllowedComponents(IntArray userIds) {
915 final int nUserIds = userIds.size();
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200916 final SparseArray<ArraySet<ComponentName>> componentsByUser = new SparseArray<>();
John Spurlock7340fc82014-04-24 18:50:12 -0400917
918 for (int i = 0; i < nUserIds; ++i) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400919 final int userId = userIds.get(i);
Julia Reynolds77f1e4d2019-07-25 12:36:14 -0400920 synchronized (mApproved) {
921 final ArrayMap<Boolean, ArraySet<String>> approvedLists = mApproved.get(userId);
922 if (approvedLists != null) {
923 final int N = approvedLists.size();
924 for (int j = 0; j < N; j++) {
925 ArraySet<ComponentName> approvedByUser = componentsByUser.get(userId);
926 if (approvedByUser == null) {
927 approvedByUser = new ArraySet<>();
928 componentsByUser.put(userId, approvedByUser);
929 }
930 approvedByUser.addAll(
931 loadComponentNamesFromValues(approvedLists.valueAt(j), userId));
Julia Reynoldsb852e562017-06-06 16:14:18 -0400932 }
Julia Reynoldsb852e562017-06-06 16:14:18 -0400933 }
Julia Reynolds6e839b02016-04-13 10:01:17 -0400934 }
John Spurlock7340fc82014-04-24 18:50:12 -0400935 }
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400936 return componentsByUser;
937 }
John Spurlock7340fc82014-04-24 18:50:12 -0400938
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400939 @GuardedBy("mMutex")
940 protected void populateComponentsToBind(SparseArray<Set<ComponentName>> componentsToBind,
941 final IntArray activeUsers,
942 SparseArray<ArraySet<ComponentName>> approvedComponentsByUser) {
943 mEnabledServicesForCurrentProfiles.clear();
944 mEnabledServicesPackageNames.clear();
945 final int nUserIds = activeUsers.size();
John Spurlock7340fc82014-04-24 18:50:12 -0400946
947 for (int i = 0; i < nUserIds; ++i) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -0400948 // decode the list of components
949 final int userId = activeUsers.get(i);
950 final ArraySet<ComponentName> userComponents = approvedComponentsByUser.get(userId);
951 if (null == userComponents) {
952 componentsToBind.put(userId, new ArraySet<>());
953 continue;
954 }
955
956 final Set<ComponentName> add = new HashSet<>(userComponents);
957 add.removeAll(mSnoozingForCurrentProfiles);
958
959 componentsToBind.put(userId, add);
960
961 mEnabledServicesForCurrentProfiles.addAll(userComponents);
962
963 for (int j = 0; j < userComponents.size(); j++) {
964 final ComponentName component = userComponents.valueAt(j);
965 mEnabledServicesPackageNames.add(component.getPackageName());
966 }
967 }
968 }
969
970 @GuardedBy("mMutex")
971 protected Set<ManagedServiceInfo> getRemovableConnectedServices() {
972 final Set<ManagedServiceInfo> removableBoundServices = new ArraySet<>();
973 for (ManagedServiceInfo service : mServices) {
974 if (!service.isSystem && !service.isGuest(this)) {
975 removableBoundServices.add(service);
976 }
977 }
978 return removableBoundServices;
979 }
980
981 protected void populateComponentsToUnbind(
982 boolean forceRebind,
983 Set<ManagedServiceInfo> removableBoundServices,
984 SparseArray<Set<ComponentName>> allowedComponentsToBind,
985 SparseArray<Set<ComponentName>> componentsToUnbind) {
986 for (ManagedServiceInfo info : removableBoundServices) {
987 final Set<ComponentName> allowedComponents = allowedComponentsToBind.get(info.userid);
988 if (allowedComponents != null) {
989 if (forceRebind || !allowedComponents.contains(info.component)) {
990 Set<ComponentName> toUnbind =
991 componentsToUnbind.get(info.userid, new ArraySet<>());
992 toUnbind.add(info.component);
993 componentsToUnbind.put(info.userid, toUnbind);
994 }
995 }
996 }
997 }
998
999 /**
1000 * Called whenever packages change, the user switches, or the secure setting
1001 * is altered. (For example in response to USER_SWITCHED in our broadcast receiver)
1002 */
1003 protected void rebindServices(boolean forceRebind, int userToRebind) {
1004 if (DEBUG) Slog.d(TAG, "rebindServices " + forceRebind + " " + userToRebind);
1005 IntArray userIds = mUserProfiles.getCurrentProfileIds();
1006 if (userToRebind != USER_ALL) {
1007 userIds = new IntArray(1);
1008 userIds.add(userToRebind);
1009 }
1010
1011 final SparseArray<Set<ComponentName>> componentsToBind = new SparseArray<>();
1012 final SparseArray<Set<ComponentName>> componentsToUnbind = new SparseArray<>();
1013
1014 synchronized (mMutex) {
1015 final SparseArray<ArraySet<ComponentName>> approvedComponentsByUser =
1016 getAllowedComponents(userIds);
1017 final Set<ManagedServiceInfo> removableBoundServices = getRemovableConnectedServices();
1018
1019 // Filter approvedComponentsByUser to collect all of the components that are allowed
1020 // for the currently active user(s).
1021 populateComponentsToBind(componentsToBind, userIds, approvedComponentsByUser);
1022
1023 // For every current non-system connection, disconnect services that are no longer
1024 // approved, or ALL services if we are force rebinding
1025 populateComponentsToUnbind(
1026 forceRebind, removableBoundServices, componentsToBind, componentsToUnbind);
1027 }
1028
1029 unbindFromServices(componentsToUnbind);
1030 bindToServices(componentsToBind);
1031 }
1032
1033 protected void unbindFromServices(SparseArray<Set<ComponentName>> componentsToUnbind) {
1034 for (int i = 0; i < componentsToUnbind.size(); i++) {
1035 final int userId = componentsToUnbind.keyAt(i);
1036 final Set<ComponentName> removableComponents = componentsToUnbind.get(userId);
1037 for (ComponentName cn : removableComponents) {
1038 // No longer allowed to be bound, or must rebind.
1039 Slog.v(TAG, "disabling " + getCaption() + " for user " + userId + ": " + cn);
1040 unregisterService(cn, userId);
1041 }
1042 }
1043 }
1044
1045 // Attempt to bind to services, skipping those that cannot be found or lack the permission.
1046 private void bindToServices(SparseArray<Set<ComponentName>> componentsToBind) {
1047 for (int i = 0; i < componentsToBind.size(); i++) {
1048 final int userId = componentsToBind.keyAt(i);
1049 final Set<ComponentName> add = componentsToBind.get(userId);
Julia Reynolds9a86cc02016-02-10 15:38:15 -05001050 for (ComponentName component : add) {
Julia Reynoldsa75c7522017-03-21 17:34:25 -04001051 try {
1052 ServiceInfo info = mPm.getServiceInfo(component,
1053 PackageManager.MATCH_DIRECT_BOOT_AWARE
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001054 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
Julia Reynolds503ed942017-10-04 16:04:56 -04001055 if (info == null) {
1056 Slog.w(TAG, "Not binding " + getCaption() + " service " + component
1057 + ": service not found");
1058 continue;
1059 }
1060 if (!mConfig.bindPermission.equals(info.permission)) {
Julia Reynoldsb852e562017-06-06 16:14:18 -04001061 Slog.w(TAG, "Not binding " + getCaption() + " service " + component
Julia Reynoldsa75c7522017-03-21 17:34:25 -04001062 + ": it does not require the permission " + mConfig.bindPermission);
1063 continue;
1064 }
1065 Slog.v(TAG,
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001066 "enabling " + getCaption() + " for " + userId + ": " + component);
1067 registerService(component, userId);
Julia Reynoldsa75c7522017-03-21 17:34:25 -04001068 } catch (RemoteException e) {
1069 e.rethrowFromSystemServer();
1070 }
John Spurlock7340fc82014-04-24 18:50:12 -04001071 }
1072 }
1073 }
1074
1075 /**
1076 * Version of registerService that takes the name of a service component to bind to.
1077 */
1078 private void registerService(final ComponentName name, final int userid) {
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001079 synchronized (mMutex) {
1080 registerServiceLocked(name, userid);
1081 }
1082 }
1083
Chris Wren0efdb882016-03-01 17:17:47 -05001084 /**
1085 * Inject a system service into the management list.
1086 */
1087 public void registerSystemService(final ComponentName name, final int userid) {
1088 synchronized (mMutex) {
1089 registerServiceLocked(name, userid, true /* isSystem */);
1090 }
1091 }
1092
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001093 private void registerServiceLocked(final ComponentName name, final int userid) {
Chris Wren0efdb882016-03-01 17:17:47 -05001094 registerServiceLocked(name, userid, false /* isSystem */);
1095 }
1096
1097 private void registerServiceLocked(final ComponentName name, final int userid,
1098 final boolean isSystem) {
John Spurlock7340fc82014-04-24 18:50:12 -04001099 if (DEBUG) Slog.v(TAG, "registerService: " + name + " u=" + userid);
1100
Andrew Zeng190c0672018-06-28 15:15:05 -07001101 final Pair<ComponentName, Integer> servicesBindingTag = Pair.create(name, userid);
1102 if (mServicesBound.contains(servicesBindingTag)) {
1103 Slog.v(TAG, "Not registering " + name + " is already bound");
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001104 // stop registering this thing already! we're working on it
1105 return;
1106 }
Andrew Zeng190c0672018-06-28 15:15:05 -07001107 mServicesBound.add(servicesBindingTag);
John Spurlock7340fc82014-04-24 18:50:12 -04001108
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001109 final int N = mServices.size();
1110 for (int i = N - 1; i >= 0; i--) {
1111 final ManagedServiceInfo info = mServices.get(i);
1112 if (name.equals(info.component)
1113 && info.userid == userid) {
1114 // cut old connections
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -04001115 Slog.v(TAG, " disconnecting old " + getCaption() + ": " + info.service);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001116 removeServiceLocked(i);
1117 if (info.connection != null) {
Andrew Zeng190c0672018-06-28 15:15:05 -07001118 unbindService(info.connection, info.component, info.userid);
John Spurlock7340fc82014-04-24 18:50:12 -04001119 }
1120 }
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001121 }
John Spurlock7340fc82014-04-24 18:50:12 -04001122
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001123 Intent intent = new Intent(mConfig.serviceInterface);
1124 intent.setComponent(name);
John Spurlock7340fc82014-04-24 18:50:12 -04001125
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001126 intent.putExtra(Intent.EXTRA_CLIENT_LABEL, mConfig.clientLabel);
John Spurlock7340fc82014-04-24 18:50:12 -04001127
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001128 final PendingIntent pendingIntent = PendingIntent.getActivity(
1129 mContext, 0, new Intent(mConfig.settingsAction), 0);
1130 intent.putExtra(Intent.EXTRA_CLIENT_INTENT, pendingIntent);
John Spurlock7340fc82014-04-24 18:50:12 -04001131
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001132 ApplicationInfo appInfo = null;
1133 try {
1134 appInfo = mContext.getPackageManager().getApplicationInfo(
1135 name.getPackageName(), 0);
1136 } catch (NameNotFoundException e) {
1137 // Ignore if the package doesn't exist we won't be able to bind to the service.
1138 }
1139 final int targetSdkVersion =
1140 appInfo != null ? appInfo.targetSdkVersion : Build.VERSION_CODES.BASE;
John Spurlock7340fc82014-04-24 18:50:12 -04001141
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001142 try {
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -04001143 Slog.v(TAG, "binding: " + intent);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001144 ServiceConnection serviceConnection = new ServiceConnection() {
1145 IInterface mService;
Denis Kuznetsov76c02682015-09-17 19:57:00 +02001146
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001147 @Override
1148 public void onServiceConnected(ComponentName name, IBinder binder) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001149 Slog.v(TAG, userid + " " + getCaption() + " service connected: " + name);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001150 boolean added = false;
1151 ManagedServiceInfo info = null;
1152 synchronized (mMutex) {
Ryan Lothian4a86a512017-12-04 11:56:58 -05001153 mServicesRebinding.remove(servicesBindingTag);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001154 try {
1155 mService = asInterface(binder);
1156 info = newServiceInfo(mService, name,
Chris Wren0efdb882016-03-01 17:17:47 -05001157 userid, isSystem, this, targetSdkVersion);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001158 binder.linkToDeath(info, 0);
1159 added = mServices.add(info);
1160 } catch (RemoteException e) {
Tony Mak180a9c42019-03-08 13:33:08 +00001161 Slog.e(TAG, "Failed to linkToDeath, already dead", e);
Denis Kuznetsov76c02682015-09-17 19:57:00 +02001162 }
1163 }
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001164 if (added) {
1165 onServiceAdded(info);
Denis Kuznetsov76c02682015-09-17 19:57:00 +02001166 }
John Spurlock7340fc82014-04-24 18:50:12 -04001167 }
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001168
1169 @Override
1170 public void onServiceDisconnected(ComponentName name) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001171 Slog.v(TAG, userid + " " + getCaption() + " connection lost: " + name);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001172 }
Ryan Lothian4a86a512017-12-04 11:56:58 -05001173
1174 @Override
1175 public void onBindingDied(ComponentName name) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001176 Slog.w(TAG, userid + " " + getCaption() + " binding died: " + name);
Ryan Lothian4a86a512017-12-04 11:56:58 -05001177 synchronized (mMutex) {
Andrew Zeng190c0672018-06-28 15:15:05 -07001178 unbindService(this, name, userid);
Ryan Lothian4a86a512017-12-04 11:56:58 -05001179 if (!mServicesRebinding.contains(servicesBindingTag)) {
1180 mServicesRebinding.add(servicesBindingTag);
1181 mHandler.postDelayed(new Runnable() {
1182 @Override
1183 public void run() {
1184 registerService(name, userid);
1185 }
1186 }, ON_BINDING_DIED_REBIND_DELAY_MS);
1187 } else {
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001188 Slog.v(TAG, getCaption() + " not rebinding in user " + userid
1189 + " as a previous rebind attempt was made: " + name);
Ryan Lothian4a86a512017-12-04 11:56:58 -05001190 }
1191 }
1192 }
Tony Mak180a9c42019-03-08 13:33:08 +00001193
1194 @Override
1195 public void onNullBinding(ComponentName name) {
1196 Slog.v(TAG, "onNullBinding() called with: name = [" + name + "]");
Julia Reynolds8a4f2ab2019-04-10 10:08:21 -04001197 mServicesBound.remove(servicesBindingTag);
Tony Mak180a9c42019-03-08 13:33:08 +00001198 }
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001199 };
1200 if (!mContext.bindServiceAsUser(intent,
Amith Yamasanie5bfeee2018-09-05 18:52:35 -07001201 serviceConnection,
1202 getBindFlags(),
1203 new UserHandle(userid))) {
Andrew Zeng190c0672018-06-28 15:15:05 -07001204 mServicesBound.remove(servicesBindingTag);
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001205 Slog.w(TAG, "Unable to bind " + getCaption() + " service: " + intent
1206 + " in user " + userid);
John Spurlock7340fc82014-04-24 18:50:12 -04001207 return;
1208 }
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001209 } catch (SecurityException ex) {
Andrew Zeng190c0672018-06-28 15:15:05 -07001210 mServicesBound.remove(servicesBindingTag);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001211 Slog.e(TAG, "Unable to bind " + getCaption() + " service: " + intent, ex);
John Spurlock7340fc82014-04-24 18:50:12 -04001212 }
1213 }
1214
Julia Reynolds8a4f2ab2019-04-10 10:08:21 -04001215 boolean isBound(ComponentName cn, int userId) {
1216 final Pair<ComponentName, Integer> servicesBindingTag = Pair.create(cn, userId);
1217 return mServicesBound.contains(servicesBindingTag);
1218 }
1219
John Spurlock7340fc82014-04-24 18:50:12 -04001220 /**
1221 * Remove a service for the given user by ComponentName
1222 */
1223 private void unregisterService(ComponentName name, int userid) {
1224 synchronized (mMutex) {
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001225 unregisterServiceLocked(name, userid);
1226 }
1227 }
1228
1229 private void unregisterServiceLocked(ComponentName name, int userid) {
1230 final int N = mServices.size();
1231 for (int i = N - 1; i >= 0; i--) {
1232 final ManagedServiceInfo info = mServices.get(i);
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -04001233 if (name.equals(info.component) && info.userid == userid) {
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08001234 removeServiceLocked(i);
1235 if (info.connection != null) {
Andrew Zeng190c0672018-06-28 15:15:05 -07001236 unbindService(info.connection, info.component, info.userid);
John Spurlock7340fc82014-04-24 18:50:12 -04001237 }
1238 }
1239 }
1240 }
1241
1242 /**
1243 * Removes a service from the list but does not unbind
1244 *
1245 * @return the removed service.
1246 */
1247 private ManagedServiceInfo removeServiceImpl(IInterface service, final int userid) {
John Spurlocke77bb362014-04-26 10:24:59 -04001248 if (DEBUG) Slog.d(TAG, "removeServiceImpl service=" + service + " u=" + userid);
John Spurlock7340fc82014-04-24 18:50:12 -04001249 ManagedServiceInfo serviceInfo = null;
1250 synchronized (mMutex) {
1251 final int N = mServices.size();
Denis Kuznetsov76c02682015-09-17 19:57:00 +02001252 for (int i = N - 1; i >= 0; i--) {
John Spurlock7340fc82014-04-24 18:50:12 -04001253 final ManagedServiceInfo info = mServices.get(i);
Julia Reynoldse5ce071bf2017-09-15 14:26:32 -04001254 if (info.service.asBinder() == service.asBinder() && info.userid == userid) {
1255 Slog.d(TAG, "Removing active service " + info.component);
John Spurlocke77bb362014-04-26 10:24:59 -04001256 serviceInfo = removeServiceLocked(i);
John Spurlock7340fc82014-04-24 18:50:12 -04001257 }
1258 }
1259 }
1260 return serviceInfo;
1261 }
1262
John Spurlocke77bb362014-04-26 10:24:59 -04001263 private ManagedServiceInfo removeServiceLocked(int i) {
1264 final ManagedServiceInfo info = mServices.remove(i);
1265 onServiceRemovedLocked(info);
1266 return info;
1267 }
1268
John Spurlock7340fc82014-04-24 18:50:12 -04001269 private void checkNotNull(IInterface service) {
1270 if (service == null) {
1271 throw new IllegalArgumentException(getCaption() + " must not be null");
1272 }
1273 }
1274
Christoph Studer3e144d32014-05-22 16:48:40 +02001275 private ManagedServiceInfo registerServiceImpl(final IInterface service,
John Spurlock7340fc82014-04-24 18:50:12 -04001276 final ComponentName component, final int userid) {
Chris Wren51017d02015-12-15 15:34:46 -05001277 ManagedServiceInfo info = newServiceInfo(service, component, userid,
1278 true /*isSystem*/, null /*connection*/, Build.VERSION_CODES.LOLLIPOP);
1279 return registerServiceImpl(info);
1280 }
1281
1282 private ManagedServiceInfo registerServiceImpl(ManagedServiceInfo info) {
John Spurlock7340fc82014-04-24 18:50:12 -04001283 synchronized (mMutex) {
1284 try {
Chris Wren51017d02015-12-15 15:34:46 -05001285 info.service.asBinder().linkToDeath(info, 0);
John Spurlock7340fc82014-04-24 18:50:12 -04001286 mServices.add(info);
Christoph Studer3e144d32014-05-22 16:48:40 +02001287 return info;
John Spurlock7340fc82014-04-24 18:50:12 -04001288 } catch (RemoteException e) {
1289 // already dead
1290 }
1291 }
Christoph Studer3e144d32014-05-22 16:48:40 +02001292 return null;
John Spurlock7340fc82014-04-24 18:50:12 -04001293 }
1294
1295 /**
1296 * Removes a service from the list and unbinds.
1297 */
1298 private void unregisterServiceImpl(IInterface service, int userid) {
1299 ManagedServiceInfo info = removeServiceImpl(service, userid);
Chris Wren51017d02015-12-15 15:34:46 -05001300 if (info != null && info.connection != null && !info.isGuest(this)) {
Andrew Zeng190c0672018-06-28 15:15:05 -07001301 unbindService(info.connection, info.component, info.userid);
1302 }
1303 }
1304
1305 private void unbindService(ServiceConnection connection, ComponentName component, int userId) {
1306 try {
1307 mContext.unbindService(connection);
1308 } catch (IllegalArgumentException e) {
1309 Slog.e(TAG, getCaption() + " " + component + " could not be unbound", e);
1310 }
1311 synchronized (mMutex) {
1312 mServicesBound.remove(Pair.create(component, userId));
John Spurlock7340fc82014-04-24 18:50:12 -04001313 }
1314 }
1315
John Spurlock7340fc82014-04-24 18:50:12 -04001316 public class ManagedServiceInfo implements IBinder.DeathRecipient {
1317 public IInterface service;
1318 public ComponentName component;
1319 public int userid;
1320 public boolean isSystem;
1321 public ServiceConnection connection;
1322 public int targetSdkVersion;
1323
1324 public ManagedServiceInfo(IInterface service, ComponentName component,
1325 int userid, boolean isSystem, ServiceConnection connection, int targetSdkVersion) {
1326 this.service = service;
1327 this.component = component;
1328 this.userid = userid;
1329 this.isSystem = isSystem;
1330 this.connection = connection;
1331 this.targetSdkVersion = targetSdkVersion;
1332 }
1333
Chris Wren51017d02015-12-15 15:34:46 -05001334 public boolean isGuest(ManagedServices host) {
1335 return ManagedServices.this != host;
1336 }
1337
Chris Wrenab41eec2016-01-04 18:01:27 -05001338 public ManagedServices getOwner() {
1339 return ManagedServices.this;
1340 }
1341
John Spurlocke77bb362014-04-26 10:24:59 -04001342 @Override
1343 public String toString() {
1344 return new StringBuilder("ManagedServiceInfo[")
1345 .append("component=").append(component)
1346 .append(",userid=").append(userid)
1347 .append(",isSystem=").append(isSystem)
1348 .append(",targetSdkVersion=").append(targetSdkVersion)
1349 .append(",connection=").append(connection == null ? null : "<connection>")
1350 .append(",service=").append(service)
1351 .append(']').toString();
1352 }
1353
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001354 public void writeToProto(ProtoOutputStream proto, long fieldId, ManagedServices host) {
1355 final long token = proto.start(fieldId);
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001356 component.writeToProto(proto, ManagedServiceInfoProto.COMPONENT);
Kweku Adams93304b62017-09-20 17:03:00 -07001357 proto.write(ManagedServiceInfoProto.USER_ID, userid);
1358 proto.write(ManagedServiceInfoProto.SERVICE, service.getClass().getName());
1359 proto.write(ManagedServiceInfoProto.IS_SYSTEM, isSystem);
1360 proto.write(ManagedServiceInfoProto.IS_GUEST, isGuest(host));
Kweku Adams85f2fbc2017-12-18 12:04:12 -08001361 proto.end(token);
Kweku Adams93304b62017-09-20 17:03:00 -07001362 }
1363
Julia Reynolds70aaea72018-07-13 13:38:34 -04001364 public boolean isSameUser(int userId) {
1365 if (!isEnabledForCurrentProfiles()) {
1366 return false;
1367 }
1368 return this.userid == userId;
1369 }
1370
John Spurlock7340fc82014-04-24 18:50:12 -04001371 public boolean enabledAndUserMatches(int nid) {
1372 if (!isEnabledForCurrentProfiles()) {
1373 return false;
1374 }
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001375 if (this.userid == USER_ALL) return true;
Chris Wren0c4eeb42016-05-12 13:21:08 -04001376 if (this.isSystem) return true;
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001377 if (nid == USER_ALL || nid == this.userid) return true;
Esteban Talavera9c6458d2017-03-30 17:59:50 +01001378 return supportsProfiles()
1379 && mUserProfiles.isCurrentProfile(nid)
1380 && isPermittedForProfile(nid);
John Spurlock7340fc82014-04-24 18:50:12 -04001381 }
1382
1383 public boolean supportsProfiles() {
Dianne Hackborn955d8d62014-10-07 20:17:19 -07001384 return targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP;
John Spurlock7340fc82014-04-24 18:50:12 -04001385 }
1386
1387 @Override
1388 public void binderDied() {
John Spurlocke77bb362014-04-26 10:24:59 -04001389 if (DEBUG) Slog.d(TAG, "binderDied");
John Spurlock7340fc82014-04-24 18:50:12 -04001390 // Remove the service, but don't unbind from the service. The system will bring the
Esteban Talavera9c6458d2017-03-30 17:59:50 +01001391 // service back up, and the onServiceConnected handler will read the service with the
John Spurlock7340fc82014-04-24 18:50:12 -04001392 // new binding. If this isn't a bound service, and is just a registered
1393 // service, just removing it from the list is all we need to do anyway.
1394 removeServiceImpl(this.service, this.userid);
1395 }
1396
1397 /** convenience method for looking in mEnabledServicesForCurrentProfiles */
1398 public boolean isEnabledForCurrentProfiles() {
1399 if (this.isSystem) return true;
1400 if (this.connection == null) return false;
1401 return mEnabledServicesForCurrentProfiles.contains(this.component);
1402 }
Esteban Talavera9c6458d2017-03-30 17:59:50 +01001403
1404 /**
1405 * Returns true if this service is allowed to receive events for the given userId. A
1406 * managed profile owner can disallow non-system services running outside of the profile
1407 * from receiving events from the profile.
1408 */
1409 public boolean isPermittedForProfile(int userId) {
1410 if (!mUserProfiles.isManagedProfile(userId)) {
1411 return true;
1412 }
1413 DevicePolicyManager dpm =
1414 (DevicePolicyManager) mContext.getSystemService(DEVICE_POLICY_SERVICE);
1415 final long identity = Binder.clearCallingIdentity();
1416 try {
1417 return dpm.isNotificationListenerServicePermitted(
1418 component.getPackageName(), userId);
1419 } finally {
1420 Binder.restoreCallingIdentity(identity);
1421 }
1422 }
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001423
1424 @Override
1425 public boolean equals(Object o) {
1426 if (this == o) return true;
1427 if (o == null || getClass() != o.getClass()) return false;
1428 ManagedServiceInfo that = (ManagedServiceInfo) o;
1429 return userid == that.userid
1430 && isSystem == that.isSystem
1431 && targetSdkVersion == that.targetSdkVersion
1432 && Objects.equals(service, that.service)
1433 && Objects.equals(component, that.component)
1434 && Objects.equals(connection, that.connection);
1435 }
1436
1437 @Override
1438 public int hashCode() {
1439 return Objects.hash(service, component, userid, isSystem, connection, targetSdkVersion);
1440 }
John Spurlock7340fc82014-04-24 18:50:12 -04001441 }
1442
Chris Wrenab41eec2016-01-04 18:01:27 -05001443 /** convenience method for looking in mEnabledServicesForCurrentProfiles */
1444 public boolean isComponentEnabledForCurrentProfiles(ComponentName component) {
1445 return mEnabledServicesForCurrentProfiles.contains(component);
1446 }
1447
John Spurlock7340fc82014-04-24 18:50:12 -04001448 public static class UserProfiles {
1449 // Profiles of the current user.
Ruben Brunke24b9a62016-02-16 21:38:24 -08001450 private final SparseArray<UserInfo> mCurrentProfiles = new SparseArray<>();
John Spurlock7340fc82014-04-24 18:50:12 -04001451
Ruben Brunke24b9a62016-02-16 21:38:24 -08001452 public void updateCache(@NonNull Context context) {
John Spurlock7340fc82014-04-24 18:50:12 -04001453 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
1454 if (userManager != null) {
1455 int currentUserId = ActivityManager.getCurrentUser();
1456 List<UserInfo> profiles = userManager.getProfiles(currentUserId);
1457 synchronized (mCurrentProfiles) {
1458 mCurrentProfiles.clear();
1459 for (UserInfo user : profiles) {
1460 mCurrentProfiles.put(user.id, user);
1461 }
1462 }
1463 }
1464 }
1465
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001466 /**
1467 * Returns the currently active users (generally one user and its work profile).
1468 */
1469 public IntArray getCurrentProfileIds() {
John Spurlock7340fc82014-04-24 18:50:12 -04001470 synchronized (mCurrentProfiles) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001471 IntArray users = new IntArray(mCurrentProfiles.size());
John Spurlock7340fc82014-04-24 18:50:12 -04001472 final int N = mCurrentProfiles.size();
1473 for (int i = 0; i < N; ++i) {
Julia Reynoldsca8e5352018-09-18 13:39:26 -04001474 users.add(mCurrentProfiles.keyAt(i));
John Spurlock7340fc82014-04-24 18:50:12 -04001475 }
1476 return users;
1477 }
1478 }
1479
1480 public boolean isCurrentProfile(int userId) {
1481 synchronized (mCurrentProfiles) {
1482 return mCurrentProfiles.get(userId) != null;
1483 }
1484 }
Esteban Talavera9c6458d2017-03-30 17:59:50 +01001485
1486 public boolean isManagedProfile(int userId) {
1487 synchronized (mCurrentProfiles) {
1488 UserInfo user = mCurrentProfiles.get(userId);
1489 return user != null && user.isManagedProfile();
1490 }
1491 }
John Spurlock7340fc82014-04-24 18:50:12 -04001492 }
1493
Ruben Brunke24b9a62016-02-16 21:38:24 -08001494 public static class Config {
1495 public String caption;
1496 public String serviceInterface;
1497 public String secureSettingName;
Julia Reynolds6e839b02016-04-13 10:01:17 -04001498 public String secondarySettingName;
Julia Reynoldsd1bf5f02017-07-11 10:39:58 -04001499 public String xmlTag;
Ruben Brunke24b9a62016-02-16 21:38:24 -08001500 public String bindPermission;
1501 public String settingsAction;
1502 public int clientLabel;
John Spurlock7340fc82014-04-24 18:50:12 -04001503 }
1504}