• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
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  */
16 package com.android.server.vr;
17 
18 import android.annotation.NonNull;
19 import android.app.ActivityManager;
20 import android.content.ComponentName;
21 import android.content.ContentResolver;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.pm.PackageManager;
25 import android.content.pm.ResolveInfo;
26 import android.content.pm.ServiceInfo;
27 import android.os.Handler;
28 import android.os.Looper;
29 import android.os.UserHandle;
30 import android.os.UserManager;
31 import android.provider.Settings;
32 import android.text.TextUtils;
33 import android.util.ArraySet;
34 import android.util.Slog;
35 import android.util.SparseArray;
36 
37 import com.android.internal.content.PackageMonitor;
38 import com.android.server.vr.SettingsObserver.SettingChangeListener;
39 
40 import java.util.Collection;
41 import java.util.List;
42 import 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  */
50 public 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 PackageMonitor mPackageMonitor;
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          */
onEnabledComponentChanged()77         void onEnabledComponentChanged();
78     }
79 
EnabledComponentsObserver(@onNull Context context, @NonNull String settingName, @NonNull String servicePermission, @NonNull String serviceName, @NonNull Object lock, @NonNull Collection<EnabledComponentChangeListener> listeners, @NonNull Looper looper)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             @NonNull Looper looper) {
84         mLock = lock;
85         mContext = context;
86         mSettingName = settingName;
87         mServiceName = serviceName;
88         mServicePermission = servicePermission;
89         mEnabledComponentListeners.addAll(listeners);
90         mPackageMonitor = new PackageMonitor(true) {
91             @Override
92             public void onSomePackagesChanged() {
93                 onPackagesChanged();
94             }
95 
96             @Override
97             public void onPackageDisappeared(String packageName, int reason) {
98                 onPackagesChanged();
99             }
100 
101             @Override
102             public void onPackageModified(String packageName) {
103                 onPackagesChanged();
104             }
105 
106             @Override
107             public boolean onHandleForceStop(Intent intent, String[] packages, int uid,
108                     boolean doit) {
109                 onPackagesChanged();
110                 return super.onHandleForceStop(intent, packages, uid, doit);
111             }
112         };
113 
114         mPackageMonitor.register(context, looper, UserHandle.ALL, true);;
115     }
116 
117     /**
118      * Create a EnabledComponentObserver instance.
119      *
120      * @param context the context to query for changes.
121      * @param handler a handler to receive lifecycle events from system services on.
122      * @param settingName the name of a setting to monitor for a list of enabled components.
123      * @param looper a {@link Looper} to use for receiving package callbacks.
124      * @param servicePermission the permission required by the components to be bound.
125      * @param serviceName the intent action implemented by the tracked components.
126      * @param lock a lock object used to guard instance state in all callbacks and method calls.
127      * @return an EnableComponentObserver instance.
128      */
build(@onNull Context context, @NonNull Handler handler, @NonNull String settingName, @NonNull Looper looper, @NonNull String servicePermission, @NonNull String serviceName, @NonNull final Object lock, @NonNull Collection<EnabledComponentChangeListener> listeners)129     public static EnabledComponentsObserver build(@NonNull Context context,
130             @NonNull Handler handler, @NonNull String settingName, @NonNull Looper looper,
131             @NonNull String servicePermission, @NonNull String serviceName,
132             @NonNull final Object lock,
133             @NonNull Collection<EnabledComponentChangeListener> listeners) {
134 
135         SettingsObserver s = SettingsObserver.build(context, handler, settingName);
136 
137         final EnabledComponentsObserver o = new EnabledComponentsObserver(context, settingName,
138                 servicePermission, serviceName, lock, listeners, looper);
139         s.addListener(o);
140 
141         return o;
142 
143     }
144 
onPackagesChanged()145     public void onPackagesChanged() {
146         rebuildAll();
147     }
148 
149     @Override
onSettingChanged()150     public void onSettingChanged() {
151         rebuildAll();
152     }
153 
154     @Override
onSettingRestored(String prevValue, String newValue, int userId)155     public void onSettingRestored(String prevValue, String newValue, int userId) {
156         rebuildAll();
157     }
158 
onUsersChanged()159     public void onUsersChanged() {
160         rebuildAll();
161     }
162 
163     /**
164      * Rebuild the sets of allowed components for each current user profile.
165      */
rebuildAll()166     public void rebuildAll() {
167         synchronized (mLock) {
168             mInstalledSet.clear();
169             mEnabledSet.clear();
170             final int[] userIds = getCurrentProfileIds();
171             for (int i : userIds) {
172                 ArraySet<ComponentName> implementingPackages = loadComponentNamesForUser(i);
173                 ArraySet<ComponentName> packagesFromSettings =
174                         loadComponentNamesFromSetting(mSettingName, i);
175                 packagesFromSettings.retainAll(implementingPackages);
176 
177                 mInstalledSet.put(i, implementingPackages);
178                 mEnabledSet.put(i, packagesFromSettings);
179 
180             }
181         }
182         sendSettingChanged();
183     }
184 
185     /**
186      * Check whether a given component is present and enabled for the given user.
187      *
188      * @param component the component to check.
189      * @param userId the user ID for the component to check.
190      * @return {@code true} if present and enabled.
191      */
isValid(ComponentName component, int userId)192     public int isValid(ComponentName component, int userId) {
193         synchronized (mLock) {
194             ArraySet<ComponentName> installedComponents = mInstalledSet.get(userId);
195             if (installedComponents == null || !installedComponents.contains(component)) {
196                 return NOT_INSTALLED;
197             }
198             ArraySet<ComponentName> validComponents = mEnabledSet.get(userId);
199             if (validComponents == null || !validComponents.contains(component)) {
200                 return DISABLED;
201             }
202             return NO_ERROR;
203         }
204     }
205 
206     /**
207      * Return all VrListenerService components installed for this user.
208      *
209      * @param userId ID of the user to check.
210      * @return a set of {@link ComponentName}s.
211      */
getInstalled(int userId)212     public ArraySet<ComponentName> getInstalled(int userId) {
213         synchronized (mLock) {
214             ArraySet<ComponentName> ret = mInstalledSet.get(userId);
215             if (ret == null) {
216                 return new ArraySet<ComponentName>();
217             }
218             return ret;
219         }
220     }
221 
222     /**
223      * Return all VrListenerService components enabled for this user.
224      *
225      * @param userId ID of the user to check.
226      * @return a set of {@link ComponentName}s.
227      */
getEnabled(int userId)228     public ArraySet<ComponentName> getEnabled(int userId) {
229         synchronized (mLock) {
230             ArraySet<ComponentName> ret = mEnabledSet.get(userId);
231             if (ret == null) {
232                 return new ArraySet<ComponentName>();
233             }
234             return ret;
235 
236         }
237     }
238 
getCurrentProfileIds()239     private int[] getCurrentProfileIds() {
240         UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
241         if (userManager == null) {
242             return null;
243         }
244         return userManager.getEnabledProfileIds(ActivityManager.getCurrentUser());
245     }
246 
loadComponentNames(PackageManager pm, int userId, String serviceName, String permissionName)247     public static ArraySet<ComponentName> loadComponentNames(PackageManager pm, int userId,
248             String serviceName, String permissionName) {
249 
250         ArraySet<ComponentName> installed = new ArraySet<>();
251         Intent queryIntent = new Intent(serviceName);
252         List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser(
253                 queryIntent,
254                 PackageManager.GET_SERVICES | PackageManager.GET_META_DATA |
255                                     PackageManager.MATCH_DIRECT_BOOT_AWARE |
256                                     PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
257                 userId);
258         if (installedServices != null) {
259             for (int i = 0, count = installedServices.size(); i < count; i++) {
260                 ResolveInfo resolveInfo = installedServices.get(i);
261                 ServiceInfo info = resolveInfo.serviceInfo;
262 
263                 ComponentName component = new ComponentName(info.packageName, info.name);
264                 if (!permissionName.equals(info.permission)) {
265                     Slog.w(TAG, "Skipping service " + info.packageName + "/" + info.name
266                             + ": it does not require the permission "
267                             + permissionName);
268                     continue;
269                 }
270                 installed.add(component);
271             }
272         }
273         return installed;
274     }
275 
loadComponentNamesForUser(int userId)276     private ArraySet<ComponentName> loadComponentNamesForUser(int userId) {
277         return loadComponentNames(mContext.getPackageManager(), userId, mServiceName,
278                 mServicePermission);
279     }
280 
loadComponentNamesFromSetting(String settingName, int userId)281     private ArraySet<ComponentName> loadComponentNamesFromSetting(String settingName,
282             int userId) {
283         final ContentResolver cr = mContext.getContentResolver();
284         String settingValue = Settings.Secure.getStringForUser(
285                 cr,
286                 settingName,
287                 userId);
288         if (TextUtils.isEmpty(settingValue))
289             return new ArraySet<>();
290         String[] restored = settingValue.split(ENABLED_SERVICES_SEPARATOR);
291         ArraySet<ComponentName> result = new ArraySet<>(restored.length);
292         for (int i = 0; i < restored.length; i++) {
293             ComponentName value = ComponentName.unflattenFromString(restored[i]);
294             if (null != value) {
295                 result.add(value);
296             }
297         }
298         return result;
299     }
300 
sendSettingChanged()301     private void sendSettingChanged() {
302         for (EnabledComponentChangeListener l : mEnabledComponentListeners) {
303             l.onEnabledComponentChanged();
304         }
305     }
306 
307 }
308