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