SharedUserSetting.java revision dfd822be8fff9aeb6bd0c2098708a79380fc0729
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        seInfoTargetSdkVersion = android.os.Build.VERSION_CODES.CUR_DEVELOPMENT;
56    }
57
58    @Override
59    public String toString() {
60        return "SharedUserSetting{" + Integer.toHexString(System.identityHashCode(this)) + " "
61                + name + "/" + userId + "}";
62    }
63
64    public void writeToProto(ProtoOutputStream proto, long fieldId) {
65        long token = proto.start(fieldId);
66        proto.write(PackageServiceDumpProto.SharedUserProto.USER_ID, userId);
67        proto.write(PackageServiceDumpProto.SharedUserProto.NAME, name);
68        proto.end(token);
69    }
70
71    void removePackage(PackageSetting packageSetting) {
72        if (packages.remove(packageSetting)) {
73            // recalculate the pkgFlags for this shared user if needed
74            if ((this.pkgFlags & packageSetting.pkgFlags) != 0) {
75                int aggregatedFlags = uidFlags;
76                for (PackageSetting ps : packages) {
77                    aggregatedFlags |= ps.pkgFlags;
78                }
79                setFlags(aggregatedFlags);
80            }
81            if ((this.pkgPrivateFlags & packageSetting.pkgPrivateFlags) != 0) {
82                int aggregatedPrivateFlags = uidPrivateFlags;
83                for (PackageSetting ps : packages) {
84                    aggregatedPrivateFlags |= ps.pkgPrivateFlags;
85                }
86                setPrivateFlags(aggregatedPrivateFlags);
87            }
88        }
89    }
90
91    void addPackage(PackageSetting packageSetting) {
92        // If this is the first package added to this shared user, temporarily (until next boot) use
93        // its targetSdkVersion when assigning seInfo for the shared user.
94        if ((packages.size() == 0) && (packageSetting.pkg != null)) {
95            seInfoTargetSdkVersion = packageSetting.pkg.applicationInfo.targetSdkVersion;
96        }
97        if (packages.add(packageSetting)) {
98            setFlags(this.pkgFlags | packageSetting.pkgFlags);
99            setPrivateFlags(this.pkgPrivateFlags | packageSetting.pkgPrivateFlags);
100        }
101    }
102
103    public @Nullable List<PackageParser.Package> getPackages() {
104        if (packages == null || packages.size() == 0) {
105            return null;
106        }
107        final ArrayList<PackageParser.Package> pkgList = new ArrayList<>(packages.size());
108        for (PackageSetting ps : packages) {
109            if ((ps == null) || (ps.pkg == null)) {
110                continue;
111            }
112            pkgList.add(ps.pkg);
113        }
114        return pkgList;
115    }
116
117    public boolean isPrivileged() {
118        return (this.pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0;
119    }
120
121    /**
122     * Determine the targetSdkVersion for a sharedUser and update pkg.applicationInfo.seInfo
123     * to ensure that all apps within the sharedUser share an SELinux domain. Use the lowest
124     * targetSdkVersion of all apps within the shared user, which corresponds to the least
125     * restrictive selinux domain.
126     */
127    public void fixSeInfoLocked() {
128        final List<PackageParser.Package> pkgList = getPackages();
129        if (pkgList == null || pkgList.size() == 0) {
130            return;
131        }
132
133        for (PackageParser.Package pkg : pkgList) {
134            if (pkg.applicationInfo.targetSdkVersion < seInfoTargetSdkVersion) {
135                seInfoTargetSdkVersion = pkg.applicationInfo.targetSdkVersion;
136            }
137        }
138        for (PackageParser.Package pkg : pkgList) {
139            final boolean isPrivileged = isPrivileged() | pkg.isPrivileged();
140            pkg.applicationInfo.seInfo = SELinuxMMAC.getSeInfo(pkg, isPrivileged,
141                pkg.applicationInfo.targetSandboxVersion, seInfoTargetSdkVersion);
142        }
143    }
144
145}
146