• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 
17 package com.android.server.pm;
18 
19 import static android.content.pm.PackageManager.TYPE_ACTIVITY;
20 import static android.content.pm.PackageManager.TYPE_APPLICATION;
21 import static android.content.pm.PackageManager.TYPE_PROVIDER;
22 import static android.content.pm.PackageManager.TYPE_RECEIVER;
23 import static android.content.pm.PackageManager.TYPE_SERVICE;
24 
25 import android.annotation.NonNull;
26 import android.annotation.Nullable;
27 import android.content.pm.PackageManager;
28 import android.content.pm.PackageManager.Property;
29 import android.content.pm.PackageManager.PropertyLocation;
30 import android.content.pm.parsing.component.ParsedComponent;
31 import android.os.Binder;
32 import android.os.UserHandle;
33 import android.util.ArrayMap;
34 
35 import com.android.server.pm.parsing.pkg.AndroidPackage;
36 
37 import java.util.ArrayList;
38 import java.util.Iterator;
39 import java.util.List;
40 import java.util.Map;
41 import java.util.Objects;
42 import java.util.function.Predicate;
43 
44 /**
45  * Manages properties defined within a package using the <property> tag.
46  */
47 public class PackageProperty {
48     /**
49      * Mapping of property name to all defined defined properties.
50      * <p>This is a mapping of property name --> package map. The package
51      * map is a mapping of package name -> list of properties.
52      */
53     private ArrayMap<String, ArrayMap<String, ArrayList<Property>>> mApplicationProperties;
54     private ArrayMap<String, ArrayMap<String, ArrayList<Property>>> mActivityProperties;
55     private ArrayMap<String, ArrayMap<String, ArrayList<Property>>> mProviderProperties;
56     private ArrayMap<String, ArrayMap<String, ArrayList<Property>>> mReceiverProperties;
57     private ArrayMap<String, ArrayMap<String, ArrayList<Property>>> mServiceProperties;
58 
59     /**
60      * If the provided component is {@code null}, returns the property defined on the
61      * application. Otherwise, returns the property defined on the component.
62      */
getProperty(@onNull String propertyName, @NonNull String packageName, @Nullable String className)63     public Property getProperty(@NonNull String propertyName, @NonNull String packageName,
64             @Nullable String className) {
65         if (className == null) {
66             return getApplicationProperty(propertyName, packageName);
67         }
68         return getComponentProperty(propertyName, packageName, className);
69     }
70 
71     /**
72      * Returns all properties defined at the given location.
73      * <p>Valid locations are {@link PackageManager#TYPE_APPLICATION},
74      * {@link PackageManager#TYPE_ACTIVITY}, {@link PackageManager#TYPE_PROVIDER},
75      * {@link PackageManager#TYPE_RECEIVER}, or {@link PackageManager#TYPE_SERVICE}.
76      */
queryProperty(@onNull String propertyName, @PropertyLocation int componentType, Predicate<String> filter)77     public List<Property> queryProperty(@NonNull String propertyName,
78             @PropertyLocation int componentType, Predicate<String> filter) {
79         final ArrayMap<String, ArrayMap<String, ArrayList<Property>>> propertyMap;
80         if (componentType == TYPE_APPLICATION) {
81             propertyMap = mApplicationProperties;
82         } else if (componentType == TYPE_ACTIVITY) {
83             propertyMap = mActivityProperties;
84         } else if (componentType == TYPE_PROVIDER) {
85             propertyMap = mProviderProperties;
86         } else if (componentType == TYPE_RECEIVER) {
87             propertyMap = mReceiverProperties;
88         } else if (componentType == TYPE_SERVICE) {
89             propertyMap = mServiceProperties;
90         } else {
91             propertyMap = null;
92         }
93         if (propertyMap == null) {
94             return null;
95         }
96         final ArrayMap<String, ArrayList<Property>> packagePropertyMap =
97                 propertyMap.get(propertyName);
98         if (packagePropertyMap == null) {
99             return null;
100         }
101         final int callingUid = Binder.getCallingUid();
102         final int callingUserId = UserHandle.getCallingUserId();
103         final int mapSize = packagePropertyMap.size();
104         final List<Property> result = new ArrayList<>(mapSize);
105         for (int i = 0; i < mapSize; i++) {
106             final String packageName = packagePropertyMap.keyAt(i);
107             if (filter.test(packageName)) {
108                 continue;
109             }
110             result.addAll(packagePropertyMap.valueAt(i));
111         }
112         return result;
113     }
114 
115     /** Adds all properties defined for the given package */
addAllProperties(AndroidPackage pkg)116     void addAllProperties(AndroidPackage pkg) {
117         mApplicationProperties = addProperties(pkg.getProperties(), mApplicationProperties);
118         mActivityProperties = addComponentProperties(pkg.getActivities(), mActivityProperties);
119         mProviderProperties = addComponentProperties(pkg.getProviders(), mProviderProperties);
120         mReceiverProperties = addComponentProperties(pkg.getReceivers(), mReceiverProperties);
121         mServiceProperties = addComponentProperties(pkg.getServices(), mServiceProperties);
122     }
123 
124     /** Adds all properties defined for the given package */
removeAllProperties(AndroidPackage pkg)125     void removeAllProperties(AndroidPackage pkg) {
126         mApplicationProperties = removeProperties(pkg.getProperties(), mApplicationProperties);
127         mActivityProperties = removeComponentProperties(pkg.getActivities(), mActivityProperties);
128         mProviderProperties = removeComponentProperties(pkg.getProviders(), mProviderProperties);
129         mReceiverProperties = removeComponentProperties(pkg.getReceivers(), mReceiverProperties);
130         mServiceProperties = removeComponentProperties(pkg.getServices(), mServiceProperties);
131     }
132 
133     /** Add the properties defined on the given components to the property collection */
134     private static <T extends ParsedComponent>
addComponentProperties( @onNull List<T> components, @Nullable ArrayMap<String, ArrayMap<String, ArrayList<Property>>> propertyCollection)135                 ArrayMap<String, ArrayMap<String, ArrayList<Property>>> addComponentProperties(
136             @NonNull List<T> components,
137             @Nullable ArrayMap<String, ArrayMap<String, ArrayList<Property>>> propertyCollection) {
138         ArrayMap<String, ArrayMap<String, ArrayList<Property>>> returnCollection =
139                 propertyCollection;
140         final int componentsSize = components.size();
141         for (int i = 0; i < componentsSize; i++) {
142             final Map<String, Property> properties = components.get(i).getProperties();
143             if (properties.size() == 0) {
144                 continue;
145             }
146             returnCollection = addProperties(properties, returnCollection);
147         }
148         return returnCollection;
149     }
150 
151     /** Add the given properties to the property collection */
addProperties( @onNull Map<String, Property> properties, @Nullable ArrayMap<String, ArrayMap<String, ArrayList<Property>>> propertyCollection)152     private static ArrayMap<String, ArrayMap<String, ArrayList<Property>>> addProperties(
153             @NonNull Map<String, Property> properties,
154             @Nullable ArrayMap<String, ArrayMap<String, ArrayList<Property>>> propertyCollection) {
155         if (properties.size() == 0) {
156             return propertyCollection;
157         }
158         final ArrayMap<String, ArrayMap<String, ArrayList<Property>>> returnCollection =
159                 propertyCollection == null ? new ArrayMap<>(10) : propertyCollection;
160         final Iterator<Property> iter = properties.values().iterator();
161         while (iter.hasNext()) {
162             final Property property = iter.next();
163             final String propertyName = property.getName();
164             final String packageName = property.getPackageName();
165             ArrayMap<String, ArrayList<Property>> propertyMap = returnCollection.get(propertyName);
166             if (propertyMap == null) {
167                 propertyMap = new ArrayMap<>();
168                 returnCollection.put(propertyName, propertyMap);
169             }
170             ArrayList<Property> packageProperties = propertyMap.get(packageName);
171             if (packageProperties == null) {
172                 packageProperties = new ArrayList<>(properties.size());
173                 propertyMap.put(packageName, packageProperties);
174             }
175             packageProperties.add(property);
176         }
177         return returnCollection;
178     }
179 
180     /** Removes the properties defined on the given components from the property collection */
181     private static <T extends ParsedComponent>
removeComponentProperties( @onNull List<T> components, @Nullable ArrayMap<String, ArrayMap<String, ArrayList<Property>>> propertyCollection)182                 ArrayMap<String, ArrayMap<String, ArrayList<Property>>> removeComponentProperties(
183             @NonNull List<T> components,
184             @Nullable ArrayMap<String, ArrayMap<String, ArrayList<Property>>> propertyCollection) {
185         ArrayMap<String, ArrayMap<String, ArrayList<Property>>> returnCollection =
186                 propertyCollection;
187         final int componentsSize = components.size();
188         for (int i = 0; returnCollection != null && i < componentsSize; i++) {
189             final Map<String, Property> properties = components.get(i).getProperties();
190             if (properties.size() == 0) {
191                 continue;
192             }
193             returnCollection = removeProperties(properties, returnCollection);
194         }
195         return returnCollection;
196     }
197 
198     /** Removes the given properties from the property collection */
removeProperties( @onNull Map<String, Property> properties, @Nullable ArrayMap<String, ArrayMap<String, ArrayList<Property>>> propertyCollection)199     private static ArrayMap<String, ArrayMap<String, ArrayList<Property>>> removeProperties(
200             @NonNull Map<String, Property> properties,
201             @Nullable ArrayMap<String, ArrayMap<String, ArrayList<Property>>> propertyCollection) {
202         if (propertyCollection == null) {
203             return null;
204         }
205         final Iterator<Property> iter = properties.values().iterator();
206         while (iter.hasNext()) {
207             final Property property = iter.next();
208             final String propertyName = property.getName();
209             final String packageName = property.getPackageName();
210             ArrayMap<String, ArrayList<Property>> propertyMap =
211                     propertyCollection.get(propertyName);
212             if (propertyMap == null) {
213                 // error
214                 continue;
215             }
216             ArrayList<Property> packageProperties = propertyMap.get(packageName);
217             if (packageProperties == null) {
218                 //error
219                 continue;
220             }
221             packageProperties.remove(property);
222 
223             // clean up empty structures
224             if (packageProperties.size() == 0) {
225                 propertyMap.remove(packageName);
226             }
227             if (propertyMap.size() == 0) {
228                 propertyCollection.remove(propertyName);
229             }
230         }
231         if (propertyCollection.size() == 0) {
232             return null;
233         }
234         return propertyCollection;
235     }
236 
getProperty(String propertyName, String packageName, String className, ArrayMap<String, ArrayMap<String, ArrayList<Property>>> propertyMap)237     private static Property getProperty(String propertyName, String packageName, String className,
238             ArrayMap<String, ArrayMap<String, ArrayList<Property>>> propertyMap) {
239         final ArrayMap<String, ArrayList<Property>> packagePropertyMap =
240                 propertyMap.get(propertyName);
241         if (packagePropertyMap == null) {
242             return null;
243         }
244         final List<Property> propertyList = packagePropertyMap.get(packageName);
245         if (propertyList == null) {
246             return null;
247         }
248         for (int i = propertyList.size() - 1; i >= 0; i--) {
249             final Property property = propertyList.get(i);
250             if (Objects.equals(className, property.getClassName())) {
251                 return property;
252             }
253         }
254         return null;
255     }
256 
getComponentProperty( String propertyName, String packageName, String className)257     private Property getComponentProperty(
258             String propertyName, String packageName, String className) {
259         Property property = null;
260         if (property == null && mActivityProperties != null) {
261             property = getProperty(propertyName, packageName, className, mActivityProperties);
262         }
263         if (property == null && mProviderProperties != null) {
264             property = getProperty(propertyName, packageName, className, mProviderProperties);
265         }
266         if (property == null && mReceiverProperties != null) {
267             property = getProperty(propertyName, packageName, className, mReceiverProperties);
268         }
269         if (property == null && mServiceProperties != null) {
270             property = getProperty(propertyName, packageName, className, mServiceProperties);
271         }
272         return property;
273     }
274 
getApplicationProperty(String propertyName, String packageName)275     private Property getApplicationProperty(String propertyName, String packageName) {
276         final ArrayMap<String, ArrayList<Property>> packagePropertyMap =
277                 mApplicationProperties != null ? mApplicationProperties.get(propertyName) : null;
278         if (packagePropertyMap == null) {
279             return null;
280         }
281         final List<Property> propertyList = packagePropertyMap.get(packageName);
282         if (propertyList == null) {
283             return null;
284         }
285         return propertyList.get(0);
286     }
287 }
288