blob: 7126cb51b57fd4d872e3e7417a799b861873da63 [file] [log] [blame]
Ruben Brunke24b9a62016-02-16 21:38:24 -08001/**
2 * Copyright (C) 2016 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 */
16package com.android.server.vr;
17
18import android.annotation.NonNull;
19import android.app.ActivityManager;
20import android.content.ComponentName;
21import android.content.ContentResolver;
22import android.content.Context;
23import android.content.Intent;
24import android.content.pm.PackageManager;
25import android.content.pm.ResolveInfo;
26import android.content.pm.ServiceInfo;
Ruben Brunke24b9a62016-02-16 21:38:24 -080027import android.os.Handler;
28import android.os.Looper;
29import android.os.UserHandle;
30import android.os.UserManager;
31import android.provider.Settings;
32import android.text.TextUtils;
33import android.util.ArraySet;
34import android.util.Slog;
35import android.util.SparseArray;
36
37import com.android.internal.content.PackageMonitor;
38import com.android.server.vr.SettingsObserver.SettingChangeListener;
39
40import java.util.Collection;
41import java.util.List;
42import java.util.Set;
43
44/**
45 * Detects changes in packages, settings, and current users that may affect whether components
46 * implementing a given service can be run.
47 *
48 * @hide
49 */
50public class EnabledComponentsObserver implements SettingChangeListener {
51
52 private static final String TAG = EnabledComponentsObserver.class.getSimpleName();
53 private static final String ENABLED_SERVICES_SEPARATOR = ":";
54
55 public static final int NO_ERROR = 0;
56 public static final int DISABLED = -1;
57 public static final int NOT_INSTALLED = -2;
58
59 private final Object mLock;
60 private final Context mContext;
61 private final String mSettingName;
62 private final String mServiceName;
63 private final String mServicePermission;
64 private final SparseArray<ArraySet<ComponentName>> mInstalledSet = new SparseArray<>();
65 private final SparseArray<ArraySet<ComponentName>> mEnabledSet = new SparseArray<>();
66 private final Set<EnabledComponentChangeListener> mEnabledComponentListeners = new ArraySet<>();
67
68 /**
69 * Implement this to receive callbacks when relevant changes to the allowed components occur.
70 */
71 public interface EnabledComponentChangeListener {
72
73 /**
74 * Called when a change in the allowed components occurs.
75 */
76 void onEnabledComponentChanged();
77 }
78
79 private EnabledComponentsObserver(@NonNull Context context, @NonNull String settingName,
80 @NonNull String servicePermission, @NonNull String serviceName, @NonNull Object lock,
81 @NonNull Collection<EnabledComponentChangeListener> listeners) {
82 mLock = lock;
83 mContext = context;
84 mSettingName = settingName;
85 mServiceName = serviceName;
86 mServicePermission = servicePermission;
87 mEnabledComponentListeners.addAll(listeners);
88 }
89
90 /**
91 * Create a EnabledComponentObserver instance.
92 *
93 * @param context the context to query for changes.
94 * @param handler a handler to receive lifecycle events from system services on.
95 * @param settingName the name of a setting to monitor for a list of enabled components.
96 * @param looper a {@link Looper} to use for receiving package callbacks.
97 * @param servicePermission the permission required by the components to be bound.
98 * @param serviceName the intent action implemented by the tracked components.
99 * @param lock a lock object used to guard instance state in all callbacks and method calls.
100 * @return an EnableComponentObserver instance.
101 */
102 public static EnabledComponentsObserver build(@NonNull Context context,
103 @NonNull Handler handler, @NonNull String settingName, @NonNull Looper looper,
104 @NonNull String servicePermission, @NonNull String serviceName,
105 @NonNull final Object lock,
106 @NonNull Collection<EnabledComponentChangeListener> listeners) {
107
108 SettingsObserver s = SettingsObserver.build(context, handler, settingName);
109
110 final EnabledComponentsObserver o = new EnabledComponentsObserver(context, settingName,
111 servicePermission, serviceName, lock, listeners);
112
113 PackageMonitor packageMonitor = new PackageMonitor() {
114 @Override
115 public void onSomePackagesChanged() {
116 o.onPackagesChanged();
117
118 }
119
120 @Override
121 public void onPackageDisappeared(String packageName, int reason) {
122 o.onPackagesChanged();
123
124 }
125
126 @Override
127 public void onPackageModified(String packageName) {
128 o.onPackagesChanged();
129
130 }
131
132 @Override
133 public boolean onHandleForceStop(Intent intent, String[] packages, int uid,
134 boolean doit) {
135 o.onPackagesChanged();
136
137 return super.onHandleForceStop(intent, packages, uid, doit);
138 }
139 };
140
141 packageMonitor.register(context, looper, UserHandle.ALL, true);
142
143 s.addListener(o);
144
145 return o;
146
147 }
148
149 public void onPackagesChanged() {
150 rebuildAll();
151 }
152
153 @Override
154 public void onSettingChanged() {
155 rebuildAll();
156 }
157
158 @Override
159 public void onSettingRestored(String prevValue, String newValue, int userId) {
160 rebuildAll();
161 }
162
163 public void onUsersChanged() {
164 rebuildAll();
165 }
166
167 /**
168 * Rebuild the sets of allowed components for each current user profile.
169 */
170 public void rebuildAll() {
171 synchronized (mLock) {
172 mInstalledSet.clear();
173 mEnabledSet.clear();
174 final int[] userIds = getCurrentProfileIds();
175 for (int i : userIds) {
176 ArraySet<ComponentName> implementingPackages = loadComponentNamesForUser(i);
177 ArraySet<ComponentName> packagesFromSettings =
178 loadComponentNamesFromSetting(mSettingName, i);
179 packagesFromSettings.retainAll(implementingPackages);
180
181 mInstalledSet.put(i, implementingPackages);
182 mEnabledSet.put(i, packagesFromSettings);
183
184 }
185 }
186 sendSettingChanged();
187 }
188
189 /**
190 * Check whether a given component is present and enabled for the given user.
191 *
192 * @param component the component to check.
193 * @param userId the user ID for the component to check.
194 * @return {@code true} if present and enabled.
195 */
196 public int isValid(ComponentName component, int userId) {
197 synchronized (mLock) {
198 ArraySet<ComponentName> installedComponents = mInstalledSet.get(userId);
199 if (installedComponents == null || !installedComponents.contains(component)) {
200 return NOT_INSTALLED;
201 }
202 ArraySet<ComponentName> validComponents = mEnabledSet.get(userId);
203 if (validComponents == null || !validComponents.contains(component)) {
204 return DISABLED;
205 }
206 return NO_ERROR;
207 }
208 }
209
Ruben Brunk2ff9c012016-04-28 10:58:29 -0700210 /**
211 * Return all VrListenerService components installed for this user.
212 *
213 * @param userId ID of the user to check.
214 * @return a set of {@link ComponentName}s.
215 */
216 public ArraySet<ComponentName> getInstalled(int userId) {
217 synchronized (mLock) {
Ruben Brunk0ec069a2016-07-18 17:08:55 -0700218 ArraySet<ComponentName> ret = mInstalledSet.get(userId);
219 if (ret == null) {
220 return new ArraySet<ComponentName>();
221 }
222 return ret;
Ruben Brunk2ff9c012016-04-28 10:58:29 -0700223 }
224 }
225
226 /**
227 * Return all VrListenerService components enabled for this user.
228 *
229 * @param userId ID of the user to check.
230 * @return a set of {@link ComponentName}s.
231 */
232 public ArraySet<ComponentName> getEnabled(int userId) {
233 synchronized (mLock) {
Ruben Brunk0ec069a2016-07-18 17:08:55 -0700234 ArraySet<ComponentName> ret = mEnabledSet.get(userId);
235 if (ret == null) {
236 return new ArraySet<ComponentName>();
237 }
238 return ret;
239
Ruben Brunk2ff9c012016-04-28 10:58:29 -0700240 }
241 }
242
Ruben Brunke24b9a62016-02-16 21:38:24 -0800243 private int[] getCurrentProfileIds() {
244 UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
245 if (userManager == null) {
246 return null;
247 }
Ruben Brunk49506e02016-04-18 18:10:47 -0700248 return userManager.getEnabledProfileIds(ActivityManager.getCurrentUser());
Ruben Brunke24b9a62016-02-16 21:38:24 -0800249 }
250
Ruben Brunk98576cf2016-03-07 18:54:28 -0800251 public static ArraySet<ComponentName> loadComponentNames(PackageManager pm, int userId,
252 String serviceName, String permissionName) {
253
Ruben Brunke24b9a62016-02-16 21:38:24 -0800254 ArraySet<ComponentName> installed = new ArraySet<>();
Ruben Brunk98576cf2016-03-07 18:54:28 -0800255 Intent queryIntent = new Intent(serviceName);
Ruben Brunke24b9a62016-02-16 21:38:24 -0800256 List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser(
257 queryIntent,
Ruben Brunk715fa572016-07-11 10:58:49 -0700258 PackageManager.GET_SERVICES | PackageManager.GET_META_DATA |
259 PackageManager.MATCH_DIRECT_BOOT_AWARE |
260 PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
Ruben Brunke24b9a62016-02-16 21:38:24 -0800261 userId);
262 if (installedServices != null) {
263 for (int i = 0, count = installedServices.size(); i < count; i++) {
264 ResolveInfo resolveInfo = installedServices.get(i);
265 ServiceInfo info = resolveInfo.serviceInfo;
266
267 ComponentName component = new ComponentName(info.packageName, info.name);
Ruben Brunk98576cf2016-03-07 18:54:28 -0800268 if (!permissionName.equals(info.permission)) {
Ruben Brunke24b9a62016-02-16 21:38:24 -0800269 Slog.w(TAG, "Skipping service " + info.packageName + "/" + info.name
270 + ": it does not require the permission "
Ruben Brunk98576cf2016-03-07 18:54:28 -0800271 + permissionName);
Ruben Brunke24b9a62016-02-16 21:38:24 -0800272 continue;
273 }
274 installed.add(component);
275 }
276 }
277 return installed;
278 }
279
Ruben Brunk98576cf2016-03-07 18:54:28 -0800280 private ArraySet<ComponentName> loadComponentNamesForUser(int userId) {
281 return loadComponentNames(mContext.getPackageManager(), userId, mServiceName,
282 mServicePermission);
283 }
284
Ruben Brunke24b9a62016-02-16 21:38:24 -0800285 private ArraySet<ComponentName> loadComponentNamesFromSetting(String settingName,
286 int userId) {
287 final ContentResolver cr = mContext.getContentResolver();
288 String settingValue = Settings.Secure.getStringForUser(
289 cr,
290 settingName,
291 userId);
292 if (TextUtils.isEmpty(settingValue))
293 return new ArraySet<>();
294 String[] restored = settingValue.split(ENABLED_SERVICES_SEPARATOR);
295 ArraySet<ComponentName> result = new ArraySet<>(restored.length);
296 for (int i = 0; i < restored.length; i++) {
297 ComponentName value = ComponentName.unflattenFromString(restored[i]);
298 if (null != value) {
299 result.add(value);
300 }
301 }
302 return result;
303 }
304
305 private void sendSettingChanged() {
306 for (EnabledComponentChangeListener l : mEnabledComponentListeners) {
307 l.onEnabledComponentChanged();
308 }
309 }
310
311}