SharedUserSetting.java revision 54807bb15b1a853ce09bf2ffce4f84f36cc37245
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
17package com.android.server.pm;
18
19import android.annotation.Nullable;
20import android.content.pm.ApplicationInfo;
21import android.content.pm.PackageParser;
22import android.service.pm.PackageServiceDumpProto;
23import android.util.ArraySet;
24import android.util.proto.ProtoOutputStream;
25
26import java.util.ArrayList;
27import java.util.Collection;
28import java.util.List;
29
30/**
31 * Settings data for a particular shared user ID we know about.
32 */
33public final class SharedUserSetting extends SettingBase {
34    final String name;
35
36    int userId;
37
38    // flags that are associated with this uid, regardless of any package flags
39    int uidFlags;
40    int uidPrivateFlags;
41
42    // The lowest targetSdkVersion of all apps in the sharedUserSetting, used to assign seinfo so
43    // that all apps within the sharedUser run in the same selinux context.
44    int seInfoTargetSdkVersion;
45
46    final ArraySet<PackageSetting> packages = new ArraySet<PackageSetting>();
47
48    final PackageSignatures signatures = new PackageSignatures();
49
50    SharedUserSetting(String _name, int _pkgFlags, int _pkgPrivateFlags) {
51        super(_pkgFlags, _pkgPrivateFlags);
52        uidFlags =  _pkgFlags;
53        uidPrivateFlags = _pkgPrivateFlags;
54        name = _name;
55    }
56
57    @Override
58    public String toString() {
59        return "SharedUserSetting{" + Integer.toHexString(System.identityHashCode(this)) + " "
60                + name + "/" + userId + "}";
61    }
62
63    public void writeToProto(ProtoOutputStream proto, long fieldId) {
64        long token = proto.start(fieldId);
65        proto.write(PackageServiceDumpProto.SharedUserProto.USER_ID, userId);
66        proto.write(PackageServiceDumpProto.SharedUserProto.NAME, name);
67        proto.end(token);
68    }
69
70    void removePackage(PackageSetting packageSetting) {
71        if (packages.remove(packageSetting)) {
72            // recalculate the pkgFlags for this shared user if needed
73            if ((this.pkgFlags & packageSetting.pkgFlags) != 0) {
74                int aggregatedFlags = uidFlags;
75                for (PackageSetting ps : packages) {
76                    aggregatedFlags |= ps.pkgFlags;
77                }
78                setFlags(aggregatedFlags);
79            }
80            if ((this.pkgPrivateFlags & packageSetting.pkgPrivateFlags) != 0) {
81                int aggregatedPrivateFlags = uidPrivateFlags;
82                for (PackageSetting ps : packages) {
83                    aggregatedPrivateFlags |= ps.pkgPrivateFlags;
84                }
85                setPrivateFlags(aggregatedPrivateFlags);
86            }
87        }
88    }
89
90    void addPackage(PackageSetting packageSetting) {
91        // If this is the first package added to this shared user, temporarily (until next boot) use
92        // its targetSdkVersion when assigning seInfo for the shared user.
93        if ((packages.size() == 0) && (packageSetting.pkg != null)) {
94            seInfoTargetSdkVersion = packageSetting.pkg.applicationInfo.targetSdkVersion;
95        }
96        if (packages.add(packageSetting)) {
97            setFlags(this.pkgFlags | packageSetting.pkgFlags);
98            setPrivateFlags(this.pkgPrivateFlags | packageSetting.pkgPrivateFlags);
99        }
100    }
101
102    public @Nullable List<PackageParser.Package> getPackages() {
103        if (packages == null || packages.size() == 0) {
104            return null;
105        }
106        final ArrayList<PackageParser.Package> pkgList = new ArrayList<>(packages.size());
107        for (PackageSetting ps : packages) {
108            if ((ps == null) || (ps.pkg == null)) {
109                continue;
110            }
111            pkgList.add(ps.pkg);
112        }
113        return pkgList;
114    }
115
116    public boolean isPrivileged() {
117        return (this.pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
118    }
119
120    /**
121     * Determine the targetSdkVersion for a sharedUser and update pkg.applicationInfo.seInfo
122     * to ensure that all apps within the sharedUser share an SELinux domain. Use the lowest
123     * targetSdkVersion of all apps within the shared user, which corresponds to the least
124     * restrictive selinux domain.
125     */
126    public void fixSeInfoLocked() {
127        final List<PackageParser.Package> pkgList = getPackages();
128        if (pkgList == null || pkgList.size() == 0) {
129            return;
130        }
131
132        for (PackageParser.Package pkg : pkgList) {
133            if (pkg.applicationInfo.targetSdkVersion < seInfoTargetSdkVersion) {
134                seInfoTargetSdkVersion = pkg.applicationInfo.targetSdkVersion;
135            }
136        }
137        for (PackageParser.Package pkg : pkgList) {
138            final boolean isPrivileged = isPrivileged() | pkg.isPrivileged();
139            pkg.applicationInfo.seInfo = SELinuxMMAC.getSeInfo(pkg, isPrivileged,
140                pkg.applicationInfo.targetSandboxVersion, seInfoTargetSdkVersion);
141        }
142    }
143
144}
145