1 /*
2  * Copyright (C) 2011 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 android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.content.pm.ApplicationInfo;
22 import android.content.pm.SigningDetails;
23 import android.service.pm.PackageServiceDumpProto;
24 import android.util.ArrayMap;
25 import android.util.ArraySet;
26 import android.util.proto.ProtoOutputStream;
27 
28 import com.android.internal.pm.pkg.component.ComponentMutateUtils;
29 import com.android.internal.pm.pkg.component.ParsedProcess;
30 import com.android.internal.pm.pkg.component.ParsedProcessImpl;
31 import com.android.internal.util.ArrayUtils;
32 import com.android.server.pm.permission.LegacyPermissionState;
33 import com.android.server.pm.pkg.AndroidPackage;
34 import com.android.server.pm.pkg.PackageStateInternal;
35 import com.android.server.pm.pkg.SharedUserApi;
36 import com.android.server.utils.SnapshotCache;
37 import com.android.server.utils.Watchable;
38 import com.android.server.utils.WatchedArraySet;
39 import com.android.server.utils.Watcher;
40 
41 import libcore.util.EmptyArray;
42 
43 import java.util.ArrayList;
44 import java.util.Collections;
45 import java.util.List;
46 import java.util.Map;
47 
48 /**
49  * Settings data for a particular shared user ID we know about.
50  */
51 public final class SharedUserSetting extends SettingBase implements SharedUserApi {
52     final String name;
53 
54     int mAppId;
55 
56     /** @see SharedUserApi#getUidFlags() **/
57     int uidFlags;
58     int uidPrivateFlags;
59 
60     /** @see SharedUserApi#getSeInfoTargetSdkVersion() **/
61     int seInfoTargetSdkVersion;
62 
63     private final WatchedArraySet<PackageSetting> mPackages;
64     private final SnapshotCache<WatchedArraySet<PackageSetting>> mPackagesSnapshot;
65 
66     // It is possible for a system app to leave shared user ID by an update.
67     // We need to keep track of the shadowed PackageSettings so that it is possible to uninstall
68     // the update and revert the system app back into the original shared user ID.
69     final WatchedArraySet<PackageSetting> mDisabledPackages;
70     private final SnapshotCache<WatchedArraySet<PackageSetting>> mDisabledPackagesSnapshot;
71 
72     /**
73      * The observer that watches for changes from array members
74      */
75     private final Watcher mObserver = new Watcher() {
76         @Override
77         public void onChange(@Nullable Watchable what) {
78             SharedUserSetting.this.onChanged();
79         }
80     };
81 
82     final PackageSignatures signatures = new PackageSignatures();
83     Boolean signaturesChanged;
84 
85     final ArrayMap<String, ParsedProcess> processes;
86 
87     /**
88      * Snapshot support.
89      */
90     private final SnapshotCache<SharedUserSetting> mSnapshot;
91 
makeCache()92     private SnapshotCache<SharedUserSetting> makeCache() {
93         return new SnapshotCache<SharedUserSetting>(this, this) {
94             @Override
95             public SharedUserSetting createSnapshot() {
96                 return new SharedUserSetting(mSource);
97             }};
98     }
99 
100     SharedUserSetting(String _name, int _pkgFlags, int _pkgPrivateFlags) {
101         super(_pkgFlags, _pkgPrivateFlags);
102         uidFlags =  _pkgFlags;
103         uidPrivateFlags = _pkgPrivateFlags;
104         name = _name;
105         seInfoTargetSdkVersion = android.os.Build.VERSION_CODES.CUR_DEVELOPMENT;
106         mPackages = new WatchedArraySet<>();
107         mPackagesSnapshot = new SnapshotCache.Auto<>(mPackages, mPackages,
108                 "SharedUserSetting.packages");
109         mDisabledPackages = new WatchedArraySet<>();
110         mDisabledPackagesSnapshot = new SnapshotCache.Auto<>(mDisabledPackages, mDisabledPackages,
111                 "SharedUserSetting.mDisabledPackages");
112         processes = new ArrayMap<>();
113         registerObservers();
114         mSnapshot = makeCache();
115     }
116 
117     // The copy constructor is used to create a snapshot
118     private SharedUserSetting(SharedUserSetting orig) {
119         super(orig);
120         name = orig.name;
121         mAppId = orig.mAppId;
122         uidFlags = orig.uidFlags;
123         uidPrivateFlags = orig.uidPrivateFlags;
124         mPackages = orig.mPackagesSnapshot.snapshot();
125         mPackagesSnapshot = new SnapshotCache.Sealed<>();
126         mDisabledPackages = orig.mDisabledPackagesSnapshot.snapshot();
127         mDisabledPackagesSnapshot = new SnapshotCache.Sealed<>();
128         // A SigningDetails seems to consist solely of final attributes, so
129         // it is safe to copy the reference.
130         signatures.mSigningDetails = orig.signatures.mSigningDetails;
131         signaturesChanged = orig.signaturesChanged;
132         processes = new ArrayMap<>(orig.processes);
133         mSnapshot = new SnapshotCache.Sealed<>();
134     }
135 
136     private void registerObservers() {
137         mPackages.registerObserver(mObserver);
138         mDisabledPackages.registerObserver(mObserver);
139     }
140 
141     /**
142      * Return a read-only snapshot of this object.
143      */
144     public SharedUserSetting snapshot() {
145         return mSnapshot.snapshot();
146     }
147 
148     @Override
149     public String toString() {
150         return "SharedUserSetting{" + Integer.toHexString(System.identityHashCode(this)) + " "
151                 + name + "/" + mAppId + "}";
152     }
153 
154     public void dumpDebug(ProtoOutputStream proto, long fieldId) {
155         long token = proto.start(fieldId);
156         proto.write(PackageServiceDumpProto.SharedUserProto.UID, mAppId);
157         proto.write(PackageServiceDumpProto.SharedUserProto.NAME, name);
158         proto.end(token);
159     }
160 
161     void addProcesses(Map<String, ParsedProcess> newProcs) {
162         if (newProcs != null) {
163             for (String key : newProcs.keySet()) {
164                 ParsedProcess newProc = newProcs.get(key);
165                 ParsedProcess proc = processes.get(newProc.getName());
166                 if (proc == null) {
167                     proc = new ParsedProcessImpl(newProc);
168                     processes.put(newProc.getName(), proc);
169                 } else {
170                     ComponentMutateUtils.addStateFrom(proc, newProc);
171                 }
172             }
173             onChanged();
174         }
175     }
176 
177     boolean removePackage(PackageSetting packageSetting) {
178         if (!mPackages.remove(packageSetting)) {
179             return false;
180         }
181         // recalculate the pkgFlags for this shared user if needed
182         if ((this.getFlags() & packageSetting.getFlags()) != 0) {
183             int aggregatedFlags = uidFlags;
184             for (int i = 0; i < mPackages.size(); i++) {
185                 PackageSetting ps = mPackages.valueAt(i);
186                 aggregatedFlags |= ps.getFlags();
187             }
188             setFlags(aggregatedFlags);
189         }
190         if ((this.getPrivateFlags() & packageSetting.getPrivateFlags()) != 0) {
191             int aggregatedPrivateFlags = uidPrivateFlags;
192             for (int i = 0; i < mPackages.size(); i++) {
193                 PackageSetting ps = mPackages.valueAt(i);
194                 aggregatedPrivateFlags |= ps.getPrivateFlags();
195             }
196             setPrivateFlags(aggregatedPrivateFlags);
197         }
198         // recalculate processes.
199         updateProcesses();
200         onChanged();
201         return true;
202     }
203 
204     void addPackage(PackageSetting packageSetting) {
205         // If this is the first package added to this shared user, temporarily (until next boot) use
206         // its targetSdkVersion when assigning seInfo for the shared user.
207         if ((mPackages.size() == 0) && (packageSetting.getPkg() != null)) {
208             seInfoTargetSdkVersion = packageSetting.getPkg().getTargetSdkVersion();
209         }
210         if (mPackages.add(packageSetting)) {
211             setFlags(this.getFlags() | packageSetting.getFlags());
212             setPrivateFlags(this.getPrivateFlags() | packageSetting.getPrivateFlags());
213             onChanged();
214         }
215         if (packageSetting.getPkg() != null) {
216             addProcesses(packageSetting.getPkg().getProcesses());
217         }
218     }
219 
220     @NonNull
221     @Override
222     public List<AndroidPackage> getPackages() {
223         if (mPackages == null || mPackages.size() == 0) {
224             return Collections.emptyList();
225         }
226         final ArrayList<AndroidPackage> pkgList = new ArrayList<>(mPackages.size());
227         for (int i = 0; i < mPackages.size(); i++) {
228             PackageSetting ps = mPackages.valueAt(i);
229             if ((ps == null) || (ps.getPkg() == null)) {
230                 continue;
231             }
232             pkgList.add(ps.getPkg());
233         }
234         return pkgList;
235     }
236 
237     @Override
238     public boolean isPrivileged() {
239         return (this.getPrivateFlags() & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
240     }
241 
242     /**
243      * A shared user is considered "single user" if there is exactly one single package
244      * currently using it. In the case when that package is also a system app, the APK on
245      * the system partition has to also leave shared UID.
246      */
247     public boolean isSingleUser() {
248         if (mPackages.size() != 1) {
249             return false;
250         }
251         if (mDisabledPackages.size() > 1) {
252             return false;
253         }
254         if (mDisabledPackages.size() == 1) {
255             final AndroidPackage pkg = mDisabledPackages.valueAt(0).getPkg();
256             return pkg != null && pkg.isLeavingSharedUser();
257         }
258         return true;
259     }
260 
261     /**
262      * Determine the targetSdkVersion for a sharedUser and update pkg.applicationInfo.seInfo
263      * to ensure that all apps within the sharedUser share an SELinux domain. Use the lowest
264      * targetSdkVersion of all apps within the shared user, which corresponds to the least
265      * restrictive selinux domain.
266      */
267     public void fixSeInfoLocked() {
268         if (mPackages == null || mPackages.size() == 0) {
269             return;
270         }
271         for (int i = 0; i < mPackages.size(); i++) {
272             PackageSetting ps = mPackages.valueAt(i);
273             if ((ps == null) || (ps.getPkg() == null)) {
274                 continue;
275             }
276             if (ps.getPkg().getTargetSdkVersion() < seInfoTargetSdkVersion) {
277                 seInfoTargetSdkVersion = ps.getPkg().getTargetSdkVersion();
278                 onChanged();
279             }
280         }
281 
282         for (int i = 0; i < mPackages.size(); i++) {
283             PackageSetting ps = mPackages.valueAt(i);
284             if ((ps == null) || (ps.getPkg() == null)) {
285                 continue;
286             }
287             final boolean isPrivileged = isPrivileged() | ps.isPrivileged();
288             ps.getPkgState().setOverrideSeInfo(SELinuxMMAC.getSeInfo(ps, ps.getPkg(), isPrivileged,
289                     seInfoTargetSdkVersion));
290             onChanged();
291         }
292     }
293 
294     /**
295      * Update tracked data about processes based on all known packages in the shared user ID.
296      */
297     public void updateProcesses() {
298         processes.clear();
299         for (int i = mPackages.size() - 1; i >= 0; i--) {
300             final AndroidPackage pkg = mPackages.valueAt(i).getPkg();
301             if (pkg != null) {
302                 addProcesses(pkg.getProcesses());
303             }
304         }
305     }
306 
307     /** Returns userIds which doesn't have any packages with this sharedUserId */
308     public int[] getNotInstalledUserIds() {
309         int[] excludedUserIds = null;
310         for (int i = 0; i < mPackages.size(); i++) {
311             PackageSetting ps = mPackages.valueAt(i);
312             final int[] userIds = ps.getNotInstalledUserIds();
313             if (excludedUserIds == null) {
314                 excludedUserIds = userIds;
315             } else {
316                 for (int userId : excludedUserIds) {
317                     if (!ArrayUtils.contains(userIds, userId)) {
318                         excludedUserIds = ArrayUtils.removeInt(excludedUserIds, userId);
319                     }
320                 }
321             }
322         }
323         return excludedUserIds == null ? EmptyArray.INT : excludedUserIds;
324     }
325 
326     /** Updates all fields in this shared user setting from another. */
327     public SharedUserSetting updateFrom(SharedUserSetting sharedUser) {
328         super.copySettingBase(sharedUser);
329         this.mAppId = sharedUser.mAppId;
330         this.uidFlags = sharedUser.uidFlags;
331         this.uidPrivateFlags = sharedUser.uidPrivateFlags;
332         this.seInfoTargetSdkVersion = sharedUser.seInfoTargetSdkVersion;
333         this.mPackages.clear();
334         this.mPackages.addAll(sharedUser.mPackages);
335         this.signaturesChanged = sharedUser.signaturesChanged;
336         if (sharedUser.processes != null) {
337             final int numProcs = sharedUser.processes.size();
338             this.processes.clear();
339             this.processes.ensureCapacity(numProcs);
340             for (int i = 0; i < numProcs; i++) {
341                 ParsedProcess proc = new ParsedProcessImpl(sharedUser.processes.valueAt(i));
342                 this.processes.put(proc.getName(), proc);
343             }
344         } else {
345             this.processes.clear();
346         }
347         onChanged();
348         return this;
349     }
350 
351     @NonNull
352     @Override
353     public String getName() {
354         return name;
355     }
356 
357     @Override
358     public int getAppId() {
359         return mAppId;
360     }
361 
362     @Override
363     public int getUidFlags() {
364         return uidFlags;
365     }
366 
367     @Override
368     public int getPrivateUidFlags() {
369         return uidPrivateFlags;
370     }
371 
372     @Override
373     public int getSeInfoTargetSdkVersion() {
374         return seInfoTargetSdkVersion;
375     }
376 
377     public WatchedArraySet<PackageSetting> getPackageSettings() {
378         return mPackages;
379     }
380 
381     public WatchedArraySet<PackageSetting> getDisabledPackageSettings() {
382         return mDisabledPackages;
383     }
384 
385     @NonNull
386     @Override
387     public ArraySet<? extends PackageStateInternal> getPackageStates() {
388         return mPackages.untrackedStorage();
389     }
390 
391     @NonNull
392     @Override
393     public ArraySet<? extends PackageStateInternal> getDisabledPackageStates() {
394         return mDisabledPackages.untrackedStorage();
395     }
396 
397     @NonNull
398     @Override
399     public SigningDetails getSigningDetails() {
400         return signatures.mSigningDetails;
401     }
402 
403     @NonNull
404     @Override
405     public ArrayMap<String, ParsedProcess> getProcesses() {
406         return processes;
407     }
408 
409     @NonNull
410     @Override
411     public LegacyPermissionState getSharedUserLegacyPermissionState() {
412         return super.getLegacyPermissionState();
413     }
414 }
415