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