summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/content/pm/ProcessInfo.java88
-rw-r--r--core/java/android/content/pm/parsing/AndroidPackage.java4
-rw-r--r--core/java/android/content/pm/parsing/ApkParseUtils.java15
-rw-r--r--core/java/android/content/pm/parsing/ComponentParseUtils.java250
-rw-r--r--core/java/android/content/pm/parsing/PackageImpl.java30
-rw-r--r--core/java/android/content/pm/parsing/PackageInfoUtils.java21
-rw-r--r--core/java/android/content/pm/parsing/ParsingPackage.java3
-rw-r--r--core/res/res/values/attrs_manifest.xml49
-rw-r--r--services/core/java/android/content/pm/PackageManagerInternal.java22
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java162
-rw-r--r--services/core/java/com/android/server/am/ProcessList.java23
-rw-r--r--services/core/java/com/android/server/am/ProcessRecord.java9
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java40
-rw-r--r--services/core/java/com/android/server/pm/SharedUserSetting.java49
14 files changed, 704 insertions, 61 deletions
diff --git a/core/java/android/content/pm/ProcessInfo.java b/core/java/android/content/pm/ProcessInfo.java
new file mode 100644
index 000000000000..c77a267958f5
--- /dev/null
+++ b/core/java/android/content/pm/ProcessInfo.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.ArraySet;
+
+/**
+ * Information about a process an app may run. This corresponds to information collected from the
+ * AndroidManifest.xml's <permission-group> tags.
+ * @hide
+ */
+public class ProcessInfo implements Parcelable {
+ /**
+ * The name of the process, fully-qualified based on the app's package name.
+ */
+ public String name;
+
+ /**
+ * If non-null, these are permissions that are not allowed in this process.
+ */
+ @Nullable
+ public ArraySet<String> deniedPermissions;
+
+ public ProcessInfo(String name, ArraySet<String> deniedPermissions) {
+ this.name = name;
+ this.deniedPermissions = deniedPermissions;
+ }
+
+ @Deprecated
+ public ProcessInfo(@NonNull ProcessInfo orig) {
+ this.name = orig.name;
+ this.deniedPermissions = orig.deniedPermissions;
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int parcelableFlags) {
+ dest.writeString(this.name);
+ final int numDenied = this.deniedPermissions != null
+ ? this.deniedPermissions.size() : 0;
+ dest.writeInt(numDenied);
+ for (int i = 0; i < numDenied; i++) {
+ dest.writeString(this.deniedPermissions.valueAt(i));
+ }
+ }
+
+ public static final @NonNull Creator<ProcessInfo> CREATOR =
+ new Creator<ProcessInfo>() {
+ public ProcessInfo createFromParcel(Parcel source) {
+ return new ProcessInfo(source);
+ }
+ public ProcessInfo[] newArray(int size) {
+ return new ProcessInfo[size];
+ }
+ };
+
+ private ProcessInfo(Parcel source) {
+ this.name = source.readString();
+ final int numDenied = source.readInt();
+ if (numDenied > 0) {
+ this.deniedPermissions = new ArraySet<>(numDenied);
+ for (int i = numDenied - 1; i >= 0; i--) {
+ this.deniedPermissions.add(TextUtils.safeIntern(source.readString()));
+ }
+ }
+ }
+}
diff --git a/core/java/android/content/pm/parsing/AndroidPackage.java b/core/java/android/content/pm/parsing/AndroidPackage.java
index 990c8359e698..fbe5a48ad61e 100644
--- a/core/java/android/content/pm/parsing/AndroidPackage.java
+++ b/core/java/android/content/pm/parsing/AndroidPackage.java
@@ -36,6 +36,7 @@ import android.content.pm.parsing.ComponentParseUtils.ParsedService;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.SparseArray;
@@ -379,6 +380,9 @@ public interface AndroidPackage extends Parcelable {
@Nullable
long[] getUsesStaticLibrariesVersions();
+ @Nullable
+ ArrayMap<String, ComponentParseUtils.ParsedProcess> getProcesses();
+
int getVersionCode();
int getVersionCodeMajor();
diff --git a/core/java/android/content/pm/parsing/ApkParseUtils.java b/core/java/android/content/pm/parsing/ApkParseUtils.java
index a001ada8df4a..02030a6b5982 100644
--- a/core/java/android/content/pm/parsing/ApkParseUtils.java
+++ b/core/java/android/content/pm/parsing/ApkParseUtils.java
@@ -2364,6 +2364,21 @@ public class ApkParseUtils {
XmlUtils.skipCurrentTag(parser);
break;
+ case "processes":
+ ArrayMap<String, ComponentParseUtils.ParsedProcess> processes =
+ ComponentParseUtils.parseProcesses(separateProcesses,
+ parsingPackage,
+ res, parser, flags,
+ outError);
+ if (processes == null) {
+ return parseInput.error(
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ outError[0]
+ );
+ }
+
+ parsingPackage.setProcesses(processes);
+ break;
case "uses-package":
// Dependencies for app installers; we don't currently try to
// enforce this.
diff --git a/core/java/android/content/pm/parsing/ComponentParseUtils.java b/core/java/android/content/pm/parsing/ComponentParseUtils.java
index f04a30ce4239..75226c9bbb2d 100644
--- a/core/java/android/content/pm/parsing/ComponentParseUtils.java
+++ b/core/java/android/content/pm/parsing/ComponentParseUtils.java
@@ -50,6 +50,7 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.os.PatternMatcher;
import android.text.TextUtils;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AttributeSet;
import android.util.Log;
@@ -1357,6 +1358,72 @@ public class ComponentParseUtils {
};
}
+ public static class ParsedProcess implements Parcelable {
+
+ public String name;
+ @Nullable
+ public ArraySet<String> deniedPermissions;
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(this.name);
+ final int numDenied = this.deniedPermissions != null
+ ? this.deniedPermissions.size() : 0;
+ dest.writeInt(numDenied);
+ for (int i = 0; i < numDenied; i++) {
+ dest.writeString(this.deniedPermissions.valueAt(i));
+ }
+ }
+
+ public ParsedProcess() {
+ }
+
+ public ParsedProcess(@NonNull ParsedProcess other) {
+ name = other.name;
+ if (other.deniedPermissions != null) {
+ deniedPermissions = new ArraySet<>(other.deniedPermissions);
+ }
+ }
+
+ public void addStateFrom(@NonNull ParsedProcess other) {
+ if (other.deniedPermissions != null) {
+ for (int i = other.deniedPermissions.size() - 1; i >= 0; i--) {
+ if (deniedPermissions == null) {
+ deniedPermissions = new ArraySet<>(other.deniedPermissions.size());
+ }
+ deniedPermissions.add(other.deniedPermissions.valueAt(i));
+ }
+ }
+ }
+
+ protected ParsedProcess(Parcel in) {
+ this.name = TextUtils.safeIntern(in.readString());
+ final int numDenied = in.readInt();
+ if (numDenied > 0) {
+ this.deniedPermissions = new ArraySet<>(numDenied);
+ this.deniedPermissions.add(TextUtils.safeIntern(in.readString()));
+ }
+ }
+
+ public static final Creator<ParsedProcess> CREATOR =
+ new Creator<ParsedProcess>() {
+ @Override
+ public ParsedProcess createFromParcel(Parcel source) {
+ return new ParsedProcess(source);
+ }
+
+ @Override
+ public ParsedProcess[] newArray(int size) {
+ return new ParsedProcess[size];
+ }
+ };
+ }
+
public static ParsedActivity parseActivity(
String[] separateProcesses,
ParsingPackage parsingPackage,
@@ -3253,6 +3320,189 @@ public class ComponentParseUtils {
return result;
}
+ private static @Nullable ArraySet<String> parseDenyPermission(
+ ArraySet<String> perms,
+ Resources res,
+ XmlResourceParser parser,
+ String[] outError
+ ) throws IOException, XmlPullParserException {
+ TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestDenyPermission);
+ if (sa == null) {
+ outError[0] = "<deny-permission> could not be parsed";
+ return null;
+ }
+
+ try {
+ String perm = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestDenyPermission_name,0);
+ if (perm != null && perm.equals(android.Manifest.permission.INTERNET)) {
+ if (perms == null) {
+ perms = new ArraySet<>();
+ }
+ perms.add(perm);
+ }
+ } finally {
+ sa.recycle();
+ }
+ XmlUtils.skipCurrentTag(parser);
+ return perms;
+ }
+
+ private static ArraySet<String> parseAllowPermission(
+ ArraySet<String> perms,
+ Resources res,
+ XmlResourceParser parser,
+ String[] outError
+ ) throws IOException, XmlPullParserException {
+ TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestAllowPermission);
+ if (sa == null) {
+ outError[0] = "<allow-permission> could not be parsed";
+ return null;
+ }
+
+ try {
+ String perm = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestAllowPermission_name,0);
+ if (perm != null && perm.equals(android.Manifest.permission.INTERNET)
+ && perms != null) {
+ perms.remove(perm);
+ if (perms.size() <= 0) {
+ perms = null;
+ }
+ }
+ } finally {
+ sa.recycle();
+ }
+ XmlUtils.skipCurrentTag(parser);
+ return perms;
+ }
+
+ public static ParsedProcess parseProcess(
+ ArraySet<String> perms,
+ String[] separateProcesses,
+ ParsingPackage parsingPackage,
+ Resources res,
+ XmlResourceParser parser,
+ int flags,
+ String[] outError
+ ) throws IOException, XmlPullParserException {
+ TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestProcess);
+ if (sa == null) {
+ outError[0] = "<process> could not be parsed";
+ return null;
+ }
+
+ ParsedProcess proc = new ParsedProcess();
+ if (perms != null) {
+ proc.deniedPermissions = new ArraySet(perms);
+ }
+
+ try {
+ proc.name = sa.getNonConfigurationString(
+ R.styleable.AndroidManifestProcess_process,0);
+ proc.name = PackageParser.buildProcessName(parsingPackage.getPackageName(),
+ null, proc.name, flags, separateProcesses, outError);
+
+ if (proc.name == null || proc.name.length() <= 0) {
+ outError[0] = "<process> does not specify android:process";
+ return null;
+ }
+ proc.name = PackageParser.buildProcessName(parsingPackage.getPackageName(),
+ parsingPackage.getPackageName(), proc.name,
+ flags, separateProcesses, outError);
+ if (outError[0] != null) {
+ return null;
+ }
+ } finally {
+ sa.recycle();
+ }
+
+ int type;
+ final int innerDepth = parser.getDepth();
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals("deny-permission")) {
+ proc.deniedPermissions = parseDenyPermission(proc.deniedPermissions, res, parser,
+ outError);
+ if (outError[0] != null) {
+ return null;
+ }
+ } else if (tagName.equals("allow-permission")) {
+ proc.deniedPermissions = parseAllowPermission(proc.deniedPermissions, res, parser,
+ outError);
+ if (outError[0] != null) {
+ return null;
+ }
+ } else {
+ Slog.w(TAG, "Unknown element under <process>: " + tagName
+ + " at " + parsingPackage.getBaseCodePath() + " "
+ + parser.getPositionDescription());
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+ }
+ }
+
+ return proc;
+ }
+
+ public static ArrayMap<String, ParsedProcess> parseProcesses(
+ String[] separateProcesses,
+ ParsingPackage parsingPackage,
+ Resources res,
+ XmlResourceParser parser,
+ int flags,
+ String[] outError
+ ) throws IOException, XmlPullParserException {
+ ArraySet<String> deniedPerms = null;
+ ArrayMap<String, ParsedProcess> processes = new ArrayMap<>();
+
+ int type;
+ final int innerDepth = parser.getDepth();
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals("deny-permission")) {
+ deniedPerms = parseDenyPermission(deniedPerms, res, parser, outError);
+ if (outError[0] != null) {
+ return null;
+ }
+ } else if (tagName.equals("allow-permission")) {
+ deniedPerms = parseAllowPermission(deniedPerms, res, parser, outError);
+ if (outError[0] != null) {
+ return null;
+ }
+ } else if (tagName.equals("process")) {
+ ParsedProcess proc = parseProcess(deniedPerms, separateProcesses, parsingPackage,
+ res, parser, flags, outError);
+ if (outError[0] != null) {
+ return null;
+ }
+ if (processes.get(proc.name) != null) {
+ outError[0] = "<process> specified existing name '" + proc.name + "'";
+ return null;
+ }
+ processes.put(proc.name, proc);
+ } else {
+ Slog.w(TAG, "Unknown element under <processes>: " + tagName
+ + " at " + parsingPackage.getBaseCodePath() + " "
+ + parser.getPositionDescription());
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+ }
+ }
+
+ return processes;
+ }
+
public static ActivityInfo.WindowLayout parseLayout(Resources res, AttributeSet attrs) {
TypedArray sw = res.obtainAttributes(attrs,
R.styleable.AndroidManifestLayout);
diff --git a/core/java/android/content/pm/parsing/PackageImpl.java b/core/java/android/content/pm/parsing/PackageImpl.java
index 8677fced18fa..9baf3258a230 100644
--- a/core/java/android/content/pm/parsing/PackageImpl.java
+++ b/core/java/android/content/pm/parsing/PackageImpl.java
@@ -215,6 +215,9 @@ public final class PackageImpl implements ParsingPackage, ParsedPackage, Android
@Nullable
private ArrayList<String> queriesPackages;
+ @Nullable
+ private ArrayMap<String, ComponentParseUtils.ParsedProcess> processes;
+
private String[] splitClassLoaderNames;
private String[] splitCodePaths;
private SparseArray<int[]> splitDependencies;
@@ -527,6 +530,12 @@ public final class PackageImpl implements ParsingPackage, ParsedPackage, Android
return usesStaticLibraries;
}
+ @Nullable
+ @Override
+ public ArrayMap<String, ComponentParseUtils.ParsedProcess> getProcesses() {
+ return processes;
+ }
+
@Override
public boolean isBaseHardwareAccelerated() {
return baseHardwareAccelerated;
@@ -948,6 +957,12 @@ public final class PackageImpl implements ParsingPackage, ParsedPackage, Android
}
@Override
+ public PackageImpl setProcesses(ArrayMap<String, ComponentParseUtils.ParsedProcess> processes) {
+ this.processes = processes;
+ return this;
+ }
+
+ @Override
public PackageImpl setSupportsSmallScreens(int supportsSmallScreens) {
if (supportsSmallScreens == 1) {
return this;
@@ -3010,6 +3025,11 @@ public final class PackageImpl implements ParsingPackage, ParsedPackage, Android
dest.writeStringList(this.usesOptionalLibraries);
dest.writeStringList(this.usesStaticLibraries);
dest.writeLongArray(this.usesStaticLibrariesVersions);
+ final int numProcesses = this.processes != null ? this.processes.size() : 0;
+ dest.writeInt(numProcesses);
+ for (int i = 0; i < numProcesses; i++) {
+ this.processes.valueAt(i).writeToParcel(dest, 0);
+ }
if (this.usesStaticLibrariesCertDigests == null) {
dest.writeInt(-1);
@@ -3161,6 +3181,16 @@ public final class PackageImpl implements ParsingPackage, ParsedPackage, Android
this.usesStaticLibraries = in.createStringArrayList();
internStringArrayList(usesStaticLibraries);
this.usesStaticLibrariesVersions = in.createLongArray();
+ final int numProcesses = in.readInt();
+ if (numProcesses > 0) {
+ this.processes = new ArrayMap<>(numProcesses);
+ for (int i = 0; i < numProcesses; i++) {
+ ComponentParseUtils.ParsedProcess proc = new ComponentParseUtils.ParsedProcess(in);
+ this.processes.put(proc.name, proc);
+ }
+ } else {
+ this.processes = null;
+ }
int digestsSize = in.readInt();
if (digestsSize >= 0) {
diff --git a/core/java/android/content/pm/parsing/PackageInfoUtils.java b/core/java/android/content/pm/parsing/PackageInfoUtils.java
index 73a8d2a7dc0f..41de4ffc7e2f 100644
--- a/core/java/android/content/pm/parsing/PackageInfoUtils.java
+++ b/core/java/android/content/pm/parsing/PackageInfoUtils.java
@@ -32,6 +32,7 @@ import android.content.pm.PackageParser;
import android.content.pm.PackageUserState;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
+import android.content.pm.ProcessInfo;
import android.content.pm.ProviderInfo;
import android.content.pm.SELinuxUtil;
import android.content.pm.ServiceInfo;
@@ -41,11 +42,11 @@ import android.content.pm.parsing.ComponentParseUtils.ParsedActivity;
import android.content.pm.parsing.ComponentParseUtils.ParsedInstrumentation;
import android.content.pm.parsing.ComponentParseUtils.ParsedPermission;
import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup;
+import android.util.ArrayMap;
import android.util.ArraySet;
import com.android.internal.util.ArrayUtils;
-import java.util.LinkedHashSet;
import java.util.Set;
/** @hide */
@@ -458,6 +459,24 @@ public class PackageInfoUtils {
return ii;
}
+ public static ArrayMap<String, ProcessInfo> generateProcessInfo(
+ ArrayMap<String, ComponentParseUtils.ParsedProcess> procs,
+ @PackageManager.ComponentInfoFlags int flags) {
+ if (procs == null) {
+ return null;
+ }
+
+ final int numProcs = procs.size();
+ ArrayMap<String, ProcessInfo> retProcs = new ArrayMap(numProcs);
+ for (int i = 0; i < numProcs; i++) {
+ ComponentParseUtils.ParsedProcess proc = procs.valueAt(i);
+ retProcs.put(proc.name, new ProcessInfo(proc.name,
+ proc.deniedPermissions != null
+ ? new ArraySet<>(proc.deniedPermissions) : null));
+ }
+ return retProcs;
+ }
+
public static PermissionInfo generatePermissionInfo(ParsedPermission p,
@PackageManager.ComponentInfoFlags int flags) {
if (p == null) return null;
diff --git a/core/java/android/content/pm/parsing/ParsingPackage.java b/core/java/android/content/pm/parsing/ParsingPackage.java
index 411c74991594..9ddcc0995fd4 100644
--- a/core/java/android/content/pm/parsing/ParsingPackage.java
+++ b/core/java/android/content/pm/parsing/ParsingPackage.java
@@ -31,6 +31,7 @@ import android.content.pm.parsing.ComponentParseUtils.ParsedPermissionGroup;
import android.content.pm.parsing.ComponentParseUtils.ParsedProvider;
import android.content.pm.parsing.ComponentParseUtils.ParsedService;
import android.os.Bundle;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.SparseArray;
@@ -99,6 +100,8 @@ public interface ParsingPackage extends AndroidPackage {
ParsingPackage addQueriesPackage(String packageName);
+ ParsingPackage setProcesses(ArrayMap<String, ComponentParseUtils.ParsedProcess> processes);
+
ParsingPackage asSplit(
String[] splitNames,
String[] splitCodePaths,
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 6435cddebd1e..17403bc50de0 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -2235,6 +2235,55 @@
<attr name="name" />
</declare-styleable>
+ <!-- The <code>processes</code> tag specifies the processes the application will run code in
+ and optionally characteristics of those processes. This tag is optional; if not
+ specified, components will simply run in the processes they specify. If supplied,
+ they can only specify processes that are enumerated here, and if they don't this
+ will be treated as a corrupt apk and result in an install failure.
+
+ <p>This appears as a child tag of the
+ {@link #AndroidManifestApplication application} tag. -->
+ <declare-styleable name="AndroidManifestProcesses" parent="AndroidManifestApplication">
+ </declare-styleable>
+
+ <!-- The <code>process</code> tag enumerates one of the available processes under its
+ containing <code>processes</code> tag.
+
+ <p>This appears as a child tag of the
+ {@link #AndroidManifestProcesses processes} tag. -->
+ <declare-styleable name="AndroidManifestProcess" parent="AndroidManifestProcesses">
+ <!-- Required name of the process that is allowed -->
+ <attr name="process" />
+ </declare-styleable>
+
+ <!-- The <code>deny-permission</code> tag specifies that a permission is to be denied
+ for a particular process (if specified under the
+ {@link #AndroidManifestProcess process} tag) or by default for all
+ processes {if specified under the
+ @link #AndroidManifestProcesses processes} tag).
+
+ <p>This appears as a child tag of the
+ {@link #AndroidManifestProcesses processes} and
+ {@link #AndroidManifestProcess process} tags. -->
+ <declare-styleable name="AndroidManifestDenyPermission"
+ parent="AndroidManifestProcesses">
+ <!-- Required name of the permission that is to be denied -->
+ <attr name="name" />
+ </declare-styleable>
+
+ <!-- The <code>allow-permission</code> tag specifies that a permission is to be allowed
+ for a particular process, when it was previously denied for all processes through
+ {@link #AndroidManifestDenyPermission deny-permission}
+
+ <p>This appears as a child tag of the
+ {@link #AndroidManifestProcesses processes} and
+ {@link #AndroidManifestProcess process} tags. -->
+ <declare-styleable name="AndroidManifestAllowPermission"
+ parent="AndroidManifestProcesses">
+ <!-- Required name of the permission that is to be allowed. -->
+ <attr name="name" />
+ </declare-styleable>
+
<!-- The <code>provider</code> tag declares a
{@link android.content.ContentProvider} class that is available
as part of the package's application components, supplying structured
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 368416b0d4a1..c3cc5dee0e14 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -33,6 +33,7 @@ import android.content.pm.parsing.AndroidPackage;
import android.content.pm.parsing.ComponentParseUtils;
import android.os.Bundle;
import android.os.PersistableBundle;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.SparseArray;
@@ -689,6 +690,27 @@ public abstract class PackageManagerInternal {
int userId);
/**
+ * Return the processes that have been declared for a uid.
+ *
+ * @param uid The uid to query.
+ *
+ * @return Returns null if there are no declared processes for the uid; otherwise,
+ * returns the set of processes it declared.
+ */
+ public abstract ArrayMap<String, ProcessInfo> getProcessesForUid(int uid);
+
+ /**
+ * Return the gids associated with a particular permission.
+ *
+ * @param permissionName The name of the permission to query.
+ * @param userId The user id the gids will be associated with.
+ *
+ * @return Returns null if there are no gids associated with the permission, otherwise an
+ * array if the gid ints.
+ */
+ public abstract int[] getPermissionGids(String permissionName, int userId);
+
+ /**
* Return if device is currently in a "core" boot environment, typically
* used to support full-disk encryption. Only apps marked with
* {@code coreApp} attribute are available.
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index c21adb08270e..d0e25327a2e0 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -213,6 +213,7 @@ import android.content.pm.PackageParser;
import android.content.pm.ParceledListSlice;
import android.content.pm.PathPermission;
import android.content.pm.PermissionInfo;
+import android.content.pm.ProcessInfo;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.SELinuxUtil;
@@ -749,67 +750,23 @@ public class ActivityManagerService extends IActivityManager.Stub
}
/**
+ * These are the currently running processes for which we have a ProcessInfo.
+ * Note: needs to be static since the permission checking call chain is static. This
+ * all probably should be refactored into a separate permission checking object.
+ */
+ @GuardedBy("sActiveProcessInfoSelfLocked")
+ static final SparseArray<ProcessInfo> sActiveProcessInfoSelfLocked = new SparseArray<>();
+
+ /**
* All of the processes we currently have running organized by pid.
* The keys are the pid running the application.
*
* <p>NOTE: This object is protected by its own lock, NOT the global activity manager lock!
*/
final PidMap mPidsSelfLocked = new PidMap();
- final class PidMap {
+ static final class PidMap {
private final SparseArray<ProcessRecord> mPidMap = new SparseArray<>();
- /**
- * Puts the process record in the map.
- * <p>NOTE: Callers should avoid acquiring the mPidsSelfLocked lock before calling this
- * method.
- */
- void put(ProcessRecord app) {
- synchronized (this) {
- mPidMap.put(app.pid, app);
- }
- mAtmInternal.onProcessMapped(app.pid, app.getWindowProcessController());
- }
-
- /**
- * Removes the process record from the map.
- * <p>NOTE: Callers should avoid acquiring the mPidsSelfLocked lock before calling this
- * method.
- */
- void remove(ProcessRecord app) {
- boolean removed = false;
- synchronized (this) {
- final ProcessRecord existingApp = mPidMap.get(app.pid);
- if (existingApp != null && existingApp.startSeq == app.startSeq) {
- mPidMap.remove(app.pid);
- removed = true;
- }
- }
- if (removed) {
- mAtmInternal.onProcessUnMapped(app.pid);
- }
- }
-
- /**
- * Removes the process record from the map if it has a thread.
- * <p>NOTE: Callers should avoid acquiring the mPidsSelfLocked lock before calling this
- * method.
- */
- boolean removeIfNoThread(ProcessRecord app) {
- boolean removed = false;
- synchronized (this) {
- final ProcessRecord existingApp = get(app.pid);
- if (existingApp != null && existingApp.startSeq == app.startSeq
- && app.thread == null) {
- mPidMap.remove(app.pid);
- removed = true;
- }
- }
- if (removed) {
- mAtmInternal.onProcessUnMapped(app.pid);
- }
- return removed;
- }
-
ProcessRecord get(int pid) {
return mPidMap.get(pid);
}
@@ -829,6 +786,82 @@ public class ActivityManagerService extends IActivityManager.Stub
int indexOfKey(int key) {
return mPidMap.indexOfKey(key);
}
+
+ void doAddInternal(ProcessRecord app) {
+ mPidMap.put(app.pid, app);
+ }
+
+ boolean doRemoveInternal(ProcessRecord app) {
+ final ProcessRecord existingApp = mPidMap.get(app.pid);
+ if (existingApp != null && existingApp.startSeq == app.startSeq) {
+ mPidMap.remove(app.pid);
+ return true;
+ }
+ return false;
+ }
+
+ boolean doRemoveIfNoThreadInternal(ProcessRecord app) {
+ if (app == null || app.thread != null) {
+ return false;
+ }
+ return doRemoveInternal(app);
+ }
+ }
+
+ /**
+ * Puts the process record in the map.
+ * <p>NOTE: Callers should avoid acquiring the mPidsSelfLocked lock before calling this
+ * method.
+ */
+ void addPidLocked(ProcessRecord app) {
+ synchronized (mPidsSelfLocked) {
+ mPidsSelfLocked.doAddInternal(app);
+ }
+ synchronized (sActiveProcessInfoSelfLocked) {
+ if (app.processInfo != null) {
+ sActiveProcessInfoSelfLocked.put(app.pid, app.processInfo);
+ } else {
+ sActiveProcessInfoSelfLocked.remove(app.pid);
+ }
+ }
+ mAtmInternal.onProcessMapped(app.pid, app.getWindowProcessController());
+ }
+
+ /**
+ * Removes the process record from the map.
+ * <p>NOTE: Callers should avoid acquiring the mPidsSelfLocked lock before calling this
+ * method.
+ */
+ void removePidLocked(ProcessRecord app) {
+ final boolean removed;
+ synchronized (mPidsSelfLocked) {
+ removed = mPidsSelfLocked.doRemoveInternal(app);
+ }
+ if (removed) {
+ synchronized (sActiveProcessInfoSelfLocked) {
+ sActiveProcessInfoSelfLocked.remove(app.pid);
+ }
+ mAtmInternal.onProcessUnMapped(app.pid);
+ }
+ }
+
+ /**
+ * Removes the process record from the map if it doesn't have a thread.
+ * <p>NOTE: Callers should avoid acquiring the mPidsSelfLocked lock before calling this
+ * method.
+ */
+ boolean removePidIfNoThread(ProcessRecord app) {
+ final boolean removed;
+ synchronized (mPidsSelfLocked) {
+ removed = mPidsSelfLocked.doRemoveIfNoThreadInternal(app);
+ }
+ if (removed) {
+ synchronized (sActiveProcessInfoSelfLocked) {
+ sActiveProcessInfoSelfLocked.remove(app.pid);
+ }
+ mAtmInternal.onProcessUnMapped(app.pid);
+ }
+ return removed;
}
/**
@@ -2058,7 +2091,7 @@ public class ActivityManagerService extends IActivityManager.Stub
app.getWindowProcessController().setPid(MY_PID);
app.maxAdj = ProcessList.SYSTEM_ADJ;
app.makeActive(mSystemThread.getApplicationThread(), mProcessStats);
- mPidsSelfLocked.put(app);
+ addPidLocked(app);
mProcessList.updateLruProcessLocked(app, false, null);
updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE);
}
@@ -4715,7 +4748,7 @@ public class ActivityManagerService extends IActivityManager.Stub
@GuardedBy("this")
private final void processStartTimedOutLocked(ProcessRecord app) {
final int pid = app.pid;
- boolean gone = mPidsSelfLocked.removeIfNoThread(app);
+ boolean gone = removePidIfNoThread(app);
if (gone) {
Slog.w(TAG, "Process " + app + " failed to attach");
@@ -4788,7 +4821,7 @@ public class ActivityManagerService extends IActivityManager.Stub
// If there is already an app occupying that pid that hasn't been cleaned up
cleanUpApplicationRecordLocked(app, false, false, -1,
true /*replacingPid*/);
- mPidsSelfLocked.remove(app);
+ removePidLocked(app);
app = null;
}
} else {
@@ -5886,6 +5919,21 @@ public class ActivityManagerService extends IActivityManager.Stub
if (pid == MY_PID) {
return PackageManager.PERMISSION_GRANTED;
}
+ // If there is an explicit permission being checked, and this is coming from a process
+ // that has been denied access to that permission, then just deny. Ultimately this may
+ // not be quite right -- it means that even if the caller would have access for another
+ // reason (such as being the owner of the component it is trying to access), it would still
+ // fail. This also means the system and root uids would be able to deny themselves
+ // access to permissions, which... well okay. ¯\_(ツ)_/¯
+ if (permission != null) {
+ synchronized (sActiveProcessInfoSelfLocked) {
+ ProcessInfo procInfo = sActiveProcessInfoSelfLocked.get(pid);
+ if (procInfo != null && procInfo.deniedPermissions != null
+ && procInfo.deniedPermissions.contains(permission)) {
+ return PackageManager.PERMISSION_DENIED;
+ }
+ }
+ }
return ActivityManager.checkComponentPermission(permission, uid,
owningUid, exported);
}
@@ -14255,7 +14303,7 @@ public class ActivityManagerService extends IActivityManager.Stub
return true;
} else if (app.pid > 0 && app.pid != MY_PID) {
// Goodbye!
- mPidsSelfLocked.remove(app);
+ removePidLocked(app);
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
mBatteryStatsService.noteProcessFinish(app.processName, app.info.uid);
if (app.isolated) {
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index e11008c246dd..e4a61a69e7e8 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -1516,7 +1516,7 @@ public final class ProcessList {
long startTime = SystemClock.uptimeMillis();
if (app.pid > 0 && app.pid != ActivityManagerService.MY_PID) {
checkSlow(startTime, "startProcess: removing from pids map");
- mService.mPidsSelfLocked.remove(app);
+ mService.removePidLocked(app);
mService.mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
checkSlow(startTime, "startProcess: done removing from pids map");
app.setPid(0);
@@ -1561,10 +1561,27 @@ public final class ProcessList {
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
+
+ // Remove any gids needed if the process has been denied permissions.
+ // NOTE: eventually we should probably have the package manager pre-compute
+ // this for us?
+ if (app.processInfo != null && app.processInfo.deniedPermissions != null) {
+ for (int i = app.processInfo.deniedPermissions.size() - 1; i >= 0; i--) {
+ int[] denyGids = mService.mPackageManagerInt.getPermissionGids(
+ app.processInfo.deniedPermissions.valueAt(i), app.userId);
+ if (denyGids != null) {
+ for (int gid : denyGids) {
+ permGids = ArrayUtils.removeInt(permGids, gid);
+ }
+ }
+ }
+ }
+
int numGids = 3;
if (mountExternal == Zygote.MOUNT_EXTERNAL_ANDROID_WRITABLE) {
numGids++;
}
+
/*
* Add shared application and profile GIDs so applications can share some
* resources like shared libraries and access user-wide resources
@@ -2291,7 +2308,7 @@ public final class ProcessList {
mService.cleanUpApplicationRecordLocked(oldApp, false, false, -1,
true /*replacingPid*/);
}
- mService.mPidsSelfLocked.put(app);
+ mService.addPidLocked(app);
synchronized (mService.mPidsSelfLocked) {
if (!procAttached) {
Message msg = mService.mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
@@ -2464,7 +2481,7 @@ public final class ProcessList {
.pendingStart)) {
int pid = app.pid;
if (pid > 0) {
- mService.mPidsSelfLocked.remove(app);
+ mService.removePidLocked(app);
mService.mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
mService.mBatteryStatsService.noteProcessFinish(app.processName, app.info.uid);
if (app.isolated) {
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 1fef3538165a..eff7667d3dd6 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -32,6 +32,7 @@ import android.app.IApplicationThread;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ApplicationInfo;
+import android.content.pm.ProcessInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.VersionedPackage;
import android.content.res.CompatibilityInfo;
@@ -83,6 +84,7 @@ class ProcessRecord implements WindowProcessListener {
private final ActivityManagerService mService; // where we came from
final ApplicationInfo info; // all about the first app in the process
+ final ProcessInfo processInfo; // if non-null, process-specific manifest info
final boolean isolated; // true if this is a special isolated process
final boolean appZygote; // true if this is forked from the app zygote
final int uid; // uid of process; may be different from 'info' if isolated
@@ -602,6 +604,13 @@ class ProcessRecord implements WindowProcessListener {
int _uid) {
mService = _service;
info = _info;
+ if (_service.mPackageManagerInt != null) {
+ ArrayMap<String, ProcessInfo> processes =
+ _service.mPackageManagerInt.getProcessesForUid(_uid);
+ processInfo = processes != null ? processes.get(_processName) : null;
+ } else {
+ processInfo = null;
+ }
isolated = _info.uid != _uid;
appZygote = (UserHandle.getAppId(_uid) >= Process.FIRST_APP_ZYGOTE_ISOLATED_UID
&& UserHandle.getAppId(_uid) <= Process.LAST_APP_ZYGOTE_ISOLATED_UID);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 159b4e49bfea..e61737c3a0b8 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -184,6 +184,7 @@ import android.content.pm.PackageUserState;
import android.content.pm.ParceledListSlice;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
+import android.content.pm.ProcessInfo;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.SELinuxUtil;
@@ -3155,6 +3156,7 @@ public class PackageManagerService extends IPackageManager.Stub
// Adjust seInfo to ensure apps which share a sharedUserId are placed in the same
// SELinux domain.
setting.fixSeInfoLocked();
+ setting.updateProcesses();
}
// Now that we know all the packages we are keeping,
@@ -23443,6 +23445,20 @@ public class PackageManagerService extends IPackageManager.Stub
}
@Override
+ public ArrayMap<String, ProcessInfo> getProcessesForUid(int uid) {
+ synchronized (mLock) {
+ return getProcessesForUidLocked(uid);
+ }
+ }
+
+ @Override
+ public int[] getPermissionGids(String permissionName, int userId) {
+ synchronized (mLock) {
+ return getPermissionGidsLocked(permissionName, userId);
+ }
+ }
+
+ @Override
public boolean isOnlyCoreApps() {
return PackageManagerService.this.isOnlyCoreApps();
}
@@ -23697,6 +23713,30 @@ public class PackageManagerService extends IPackageManager.Stub
return res != null ? res : EmptyArray.STRING;
}
+ @GuardedBy("mLock")
+ public ArrayMap<String, ProcessInfo> getProcessesForUidLocked(int uid) {
+ final int appId = UserHandle.getAppId(uid);
+ final SettingBase obj = mSettings.getSettingLPr(appId);
+ if (obj instanceof SharedUserSetting) {
+ final SharedUserSetting sus = (SharedUserSetting) obj;
+ return PackageInfoUtils.generateProcessInfo(sus.processes, 0);
+ } else if (obj instanceof PackageSetting) {
+ final PackageSetting ps = (PackageSetting) obj;
+ return PackageInfoUtils.generateProcessInfo(ps.pkg.getProcesses(), 0);
+ }
+ return null;
+ }
+
+ @GuardedBy("mLock")
+ public int[] getPermissionGidsLocked(String permissionName, int userId) {
+ BasePermission perm
+ = mPermissionManager.getPermissionSettings().getPermission(permissionName);
+ if (perm != null) {
+ return perm.computeGids(userId);
+ }
+ return null;
+ }
+
@Override
public int getRuntimePermissionsVersion(@UserIdInt int userId) {
Preconditions.checkArgumentNonnegative(userId);
diff --git a/services/core/java/com/android/server/pm/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java
index 0a42ccf1c5ba..b9bb9e0ad0d8 100644
--- a/services/core/java/com/android/server/pm/SharedUserSetting.java
+++ b/services/core/java/com/android/server/pm/SharedUserSetting.java
@@ -19,7 +19,9 @@ package com.android.server.pm;
import android.annotation.Nullable;
import android.content.pm.ApplicationInfo;
import android.content.pm.parsing.AndroidPackage;
+import android.content.pm.parsing.ComponentParseUtils;
import android.service.pm.PackageServiceDumpProto;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.proto.ProtoOutputStream;
@@ -51,6 +53,8 @@ public final class SharedUserSetting extends SettingBase {
final PackageSignatures signatures = new PackageSignatures();
Boolean signaturesChanged;
+ ArrayMap<String, ComponentParseUtils.ParsedProcess> processes;
+
SharedUserSetting(String _name, int _pkgFlags, int _pkgPrivateFlags) {
super(_pkgFlags, _pkgPrivateFlags);
uidFlags = _pkgFlags;
@@ -72,6 +76,25 @@ public final class SharedUserSetting extends SettingBase {
proto.end(token);
}
+ void addProcesses(ArrayMap<String, ComponentParseUtils.ParsedProcess> newProcs) {
+ if (newProcs != null) {
+ final int numProcs = newProcs.size();
+ if (processes == null) {
+ processes = new ArrayMap<>(numProcs);
+ }
+ for (int i = 0; i < numProcs; i++) {
+ ComponentParseUtils.ParsedProcess newProc = newProcs.valueAt(i);
+ ComponentParseUtils.ParsedProcess proc = processes.get(newProc.name);
+ if (proc == null) {
+ proc = new ComponentParseUtils.ParsedProcess(newProc);
+ processes.put(newProc.name, proc);
+ } else {
+ proc.addStateFrom(newProc);
+ }
+ }
+ }
+ }
+
boolean removePackage(PackageSetting packageSetting) {
if (!packages.remove(packageSetting)) {
return false;
@@ -91,6 +114,8 @@ public final class SharedUserSetting extends SettingBase {
}
setPrivateFlags(aggregatedPrivateFlags);
}
+ // recalculate processes.
+ updateProcesses();
return true;
}
@@ -104,6 +129,9 @@ public final class SharedUserSetting extends SettingBase {
setFlags(this.pkgFlags | packageSetting.pkgFlags);
setPrivateFlags(this.pkgPrivateFlags | packageSetting.pkgPrivateFlags);
}
+ if (packageSetting.pkg != null) {
+ addProcesses(packageSetting.pkg.getProcesses());
+ }
}
public @Nullable List<AndroidPackage> getPackages() {
@@ -148,6 +176,16 @@ public final class SharedUserSetting extends SettingBase {
}
}
+ /**
+ * Update tracked data about processes based on all known packages in the shared user ID.
+ */
+ public void updateProcesses() {
+ processes = null;
+ for (int i = packages.size() - 1; i >= 0; i--) {
+ addProcesses(packages.valueAt(i).pkg.getProcesses());
+ }
+ }
+
/** Returns userIds which doesn't have any packages with this sharedUserId */
public int[] getNotInstalledUserIds() {
int[] excludedUserIds = null;
@@ -176,6 +214,17 @@ public final class SharedUserSetting extends SettingBase {
this.packages.clear();
this.packages.addAll(sharedUser.packages);
this.signaturesChanged = sharedUser.signaturesChanged;
+ if (sharedUser.processes != null) {
+ final int numProcs = sharedUser.processes.size();
+ this.processes = new ArrayMap<>(numProcs);
+ for (int i = 0; i < numProcs; i++) {
+ ComponentParseUtils.ParsedProcess proc =
+ new ComponentParseUtils.ParsedProcess(sharedUser.processes.valueAt(i));
+ this.processes.put(proc.name, proc);
+ }
+ } else {
+ this.processes = null;
+ }
return this;
}
}