Merge changes from topic "cross_uid_embedding_verification"

* changes:
  Verify cross-uid activity embedding
  Add Cross-UID ActivityEmbedding trust model APIs
This commit is contained in:
TreeHugger Robot
2022-02-11 07:42:58 +00:00
committed by Android (Google) Code Review
24 changed files with 543 additions and 19 deletions

View File

@@ -343,6 +343,7 @@ package android {
field public static final int allowSingleTap = 16843353; // 0x1010259
field public static final int allowTaskReparenting = 16843268; // 0x1010204
field public static final int allowUndo = 16843999; // 0x10104df
field public static final int allowUntrustedActivityEmbedding;
field public static final int alpha = 16843551; // 0x101031f
field public static final int alphabeticModifiers = 16844110; // 0x101054e
field public static final int alphabeticShortcut = 16843235; // 0x10101e3
@@ -907,6 +908,7 @@ package android {
field public static final int keyboardNavigationCluster = 16844096; // 0x1010540
field public static final int keycode = 16842949; // 0x10100c5
field public static final int killAfterRestore = 16843420; // 0x101029c
field public static final int knownActivityEmbeddingCerts;
field public static final int knownCerts = 16844330; // 0x101062a
field public static final int lStar = 16844359; // 0x1010647
field public static final int label = 16842753; // 0x1010001
@@ -10969,6 +10971,7 @@ package android.content.pm {
ctor public ActivityInfo(android.content.pm.ActivityInfo);
method public int describeContents();
method public void dump(android.util.Printer, String);
method @NonNull public java.util.Set<java.lang.String> getKnownActivityEmbeddingCerts();
method public final int getThemeResource();
field public static final int COLOR_MODE_DEFAULT = 0; // 0x0
field public static final int COLOR_MODE_HDR = 2; // 0x2
@@ -10996,6 +10999,7 @@ package android.content.pm {
field public static final int DOCUMENT_LAUNCH_NEVER = 3; // 0x3
field public static final int DOCUMENT_LAUNCH_NONE = 0; // 0x0
field public static final int FLAG_ALLOW_TASK_REPARENTING = 64; // 0x40
field public static final int FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING = 268435456; // 0x10000000
field public static final int FLAG_ALWAYS_RETAIN_TASK_STATE = 8; // 0x8
field public static final int FLAG_AUTO_REMOVE_FROM_RECENTS = 8192; // 0x2000
field public static final int FLAG_CLEAR_TASK_ON_LAUNCH = 4; // 0x4
@@ -11085,6 +11089,7 @@ package android.content.pm {
method public void dump(android.util.Printer, String);
method public static CharSequence getCategoryTitle(android.content.Context, int);
method public int getGwpAsanMode();
method @NonNull public java.util.Set<java.lang.String> getKnownActivityEmbeddingCerts();
method public int getMemtagMode();
method public int getNativeHeapZeroInitialized();
method public int getRequestRawExternalStorageAccess();

View File

@@ -18,6 +18,8 @@ package android.content.pm;
import android.annotation.FloatRange;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
import android.app.Activity;
import android.app.compat.CompatChanges;
@@ -35,10 +37,16 @@ import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.UserHandle;
import android.util.ArraySet;
import android.util.Printer;
import com.android.internal.util.Parcelling;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Collections;
import java.util.Locale;
import java.util.Set;
/**
* Information you can retrieve about a particular application
@@ -48,6 +56,9 @@ import java.lang.annotation.RetentionPolicy;
*/
public class ActivityInfo extends ComponentInfo implements Parcelable {
private static final Parcelling.BuiltIn.ForStringSet sForStringSet =
Parcelling.Cache.getOrCreate(Parcelling.BuiltIn.ForStringSet.class);
// NOTE: When adding new data members be sure to update the copy-constructor, Parcel
// constructor, and writeToParcel.
@@ -524,6 +535,13 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
*/
public static final int FLAG_PREFER_MINIMAL_POST_PROCESSING = 0x2000000;
/**
* Bit in {@link #flags}: If set, indicates that the activity can be embedded by untrusted
* hosts. In this case the interactions with and visibility of the embedded activity may be
* limited. Set from the {@link android.R.attr#allowUntrustedActivityEmbedding} attribute.
*/
public static final int FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING = 0x10000000;
/**
* @hide Bit in {@link #flags}: If set, this component will only be seen
* by the system user. Only works with broadcast receivers. Set from the
@@ -561,7 +579,8 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
* {@link #FLAG_STATE_NOT_NEEDED}, {@link #FLAG_EXCLUDE_FROM_RECENTS},
* {@link #FLAG_ALLOW_TASK_REPARENTING}, {@link #FLAG_NO_HISTORY},
* {@link #FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS},
* {@link #FLAG_HARDWARE_ACCELERATED}, {@link #FLAG_SINGLE_USER}.
* {@link #FLAG_HARDWARE_ACCELERATED}, {@link #FLAG_SINGLE_USER},
* {@link #FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING}.
*/
public int flags;
@@ -1079,6 +1098,13 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
@EnabledSince(targetSdkVersion = Build.VERSION_CODES.S)
private static final long CHECK_MIN_WIDTH_HEIGHT_FOR_MULTI_WINDOW = 197654537L;
/**
* Optional set of a certificates identifying apps that are allowed to embed this activity. From
* the "knownActivityEmbeddingCerts" attribute.
*/
@Nullable
private Set<String> mKnownActivityEmbeddingCerts;
/**
* Convert Java change bits to native.
*
@@ -1227,6 +1253,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
launchMode = orig.launchMode;
documentLaunchMode = orig.documentLaunchMode;
permission = orig.permission;
mKnownActivityEmbeddingCerts = orig.mKnownActivityEmbeddingCerts;
taskAffinity = orig.taskAffinity;
targetActivity = orig.targetActivity;
flags = orig.flags;
@@ -1442,6 +1469,31 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
return mMinAspectRatio;
}
/**
* Gets the trusted host certificate digests of apps that are allowed to embed this activity.
* The digests are computed using the SHA-256 digest algorithm.
* @see android.R.attr#knownActivityEmbeddingCerts
*/
@NonNull
public Set<String> getKnownActivityEmbeddingCerts() {
return mKnownActivityEmbeddingCerts == null ? Collections.emptySet()
: mKnownActivityEmbeddingCerts;
}
/**
* Sets the trusted host certificates of apps that are allowed to embed this activity.
* @see #getKnownActivityEmbeddingCerts()
* @hide
*/
public void setKnownActivityEmbeddingCerts(@NonNull Set<String> knownActivityEmbeddingCerts) {
// Convert the provided digest to upper case for consistent Set membership
// checks when verifying the signing certificate digests of requesting apps.
mKnownActivityEmbeddingCerts = new ArraySet<>();
for (String knownCert : knownActivityEmbeddingCerts) {
mKnownActivityEmbeddingCerts.add(knownCert.toUpperCase(Locale.US));
}
}
private boolean isChangeEnabled(long changeId) {
return CompatChanges.isChangeEnabled(changeId, applicationInfo.packageName,
UserHandle.getUserHandleForUid(applicationInfo.uid));
@@ -1573,6 +1625,9 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
if (supportsSizeChanges) {
pw.println(prefix + "supportsSizeChanges=true");
}
if (mKnownActivityEmbeddingCerts != null) {
pw.println(prefix + "knownActivityEmbeddingCerts=" + mKnownActivityEmbeddingCerts);
}
super.dumpBack(pw, prefix, dumpFlags);
}
@@ -1618,6 +1673,7 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
dest.writeFloat(mMaxAspectRatio);
dest.writeFloat(mMinAspectRatio);
dest.writeBoolean(supportsSizeChanges);
sForStringSet.parcel(mKnownActivityEmbeddingCerts, dest, flags);
}
/**
@@ -1739,6 +1795,10 @@ public class ActivityInfo extends ComponentInfo implements Parcelable {
mMaxAspectRatio = source.readFloat();
mMinAspectRatio = source.readFloat();
supportsSizeChanges = source.readBoolean();
mKnownActivityEmbeddingCerts = sForStringSet.unparcel(source);
if (mKnownActivityEmbeddingCerts.isEmpty()) {
mKnownActivityEmbeddingCerts = null;
}
}
/**

View File

@@ -35,6 +35,7 @@ import android.os.Parcelable;
import android.os.UserHandle;
import android.os.storage.StorageManager;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Printer;
import android.util.SparseArray;
import android.util.proto.ProtoOutputStream;
@@ -52,7 +53,9 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
/**
@@ -62,6 +65,8 @@ import java.util.UUID;
*/
public class ApplicationInfo extends PackageItemInfo implements Parcelable {
private static ForBoolean sForBoolean = Parcelling.Cache.getOrCreate(ForBoolean.class);
private static final Parcelling.BuiltIn.ForStringSet sForStringSet =
Parcelling.Cache.getOrCreate(Parcelling.BuiltIn.ForStringSet.class);
/**
* Default task affinity of all activities in this application. See
@@ -1550,6 +1555,13 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
*/
private int localeConfigRes;
/**
* Optional set of a certificates identifying apps that are allowed to embed activities of this
* application. From the "knownActivityEmbeddingCerts" attribute.
*/
@Nullable
private Set<String> mKnownActivityEmbeddingCerts;
public void dump(Printer pw, String prefix) {
dump(pw, prefix, DUMP_FLAG_ALL);
}
@@ -1673,6 +1685,9 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
}
}
pw.println(prefix + "createTimestamp=" + createTimestamp);
if (mKnownActivityEmbeddingCerts != null) {
pw.println(prefix + "knownActivityEmbeddingCerts=" + mKnownActivityEmbeddingCerts);
}
super.dumpBack(pw, prefix);
}
@@ -1787,6 +1802,11 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
}
proto.end(detailToken);
}
if (!ArrayUtils.isEmpty(mKnownActivityEmbeddingCerts)) {
for (String knownCert : mKnownActivityEmbeddingCerts) {
proto.write(ApplicationInfoProto.KNOWN_ACTIVITY_EMBEDDING_CERTS, knownCert);
}
}
proto.end(token);
}
@@ -1837,6 +1857,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
super(orig);
taskAffinity = orig.taskAffinity;
permission = orig.permission;
mKnownActivityEmbeddingCerts = orig.mKnownActivityEmbeddingCerts;
processName = orig.processName;
className = orig.className;
theme = orig.theme;
@@ -2006,6 +2027,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
}
}
dest.writeInt(localeConfigRes);
sForStringSet.parcel(mKnownActivityEmbeddingCerts, dest, flags);
}
public static final @android.annotation.NonNull Parcelable.Creator<ApplicationInfo> CREATOR
@@ -2102,6 +2124,10 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
}
}
localeConfigRes = source.readInt();
mKnownActivityEmbeddingCerts = sForStringSet.unparcel(source);
if (mKnownActivityEmbeddingCerts.isEmpty()) {
mKnownActivityEmbeddingCerts = null;
}
}
/**
@@ -2658,7 +2684,6 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
return localeConfigRes;
}
/**
* List of all shared libraries this application is linked against. This
* list will only be set if the {@link PackageManager#GET_SHARED_LIBRARY_FILES
@@ -2675,4 +2700,29 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
return sharedLibraryInfos;
}
/**
* Gets the trusted host certificate digests of apps that are allowed to embed activities of
* this application. The digests are computed using the SHA-256 digest algorithm.
* @see android.R.attr#knownActivityEmbeddingCerts
*/
@NonNull
public Set<String> getKnownActivityEmbeddingCerts() {
return mKnownActivityEmbeddingCerts == null ? Collections.emptySet()
: mKnownActivityEmbeddingCerts;
}
/**
* Sets the trusted host certificates of apps that are allowed to embed activities of this
* application.
* @see #getKnownActivityEmbeddingCerts()
* @hide
*/
public void setKnownActivityEmbeddingCerts(@NonNull Set<String> knownActivityEmbeddingCerts) {
// Convert the provided digest to upper case for consistent Set membership
// checks when verifying the signing certificate digests of requesting apps.
mKnownActivityEmbeddingCerts = new ArraySet<>();
for (String knownCert : knownActivityEmbeddingCerts) {
mKnownActivityEmbeddingCerts.add(knownCert.toUpperCase(Locale.US));
}
}
}

View File

@@ -115,4 +115,5 @@ message ApplicationInfoProto {
}
optional Detail detail = 17;
repeated string overlay_paths = 18;
repeated string known_activity_embedding_certs = 19;
}

View File

@@ -1048,6 +1048,24 @@
<p>The default value of this attribute is <code>false</code>. -->
<attr name="allowEmbedded" format="boolean" />
<!-- A reference to an array resource containing the signing certificate digests, one of which a
client is required to be signed with in order to embed the activity. If the client is not
signed with one of the certificates in the set, and the activity does not allow embedding
by untrusted hosts via {@link android.R.attr#allowUntrustedActivityEmbedding} flag, the
embedding request will fail.
<p>The digest should be computed over the DER encoding of the trusted certificate using the
SHA-256 digest algorithm.
<p>If only a single signer is declared this can also be a string resource, or the digest
can be declared inline as the value for this attribute.
<p>If the attribute is declared both on the application and the activity level, the value
on the activity level takes precedence. -->
<attr name="knownActivityEmbeddingCerts" format="reference|string" />
<!-- Indicate that the activity can be embedded by untrusted hosts. In this case the
interactions and visibility of the embedded activity may be limited.
<p>The default value of this attribute is <code>false</code>. -->
<attr name="allowUntrustedActivityEmbedding" format="boolean" />
<!-- Specifies whether this {@link android.app.Activity} should be shown on
top of the lock screen whenever the lockscreen is up and this activity has another
activity behind it with the {@link android.R.attr#showWhenLocked} attribute set. That
@@ -2011,6 +2029,7 @@
when the application's user data is cleared. The default value is false.
-->
<attr name="resetEnabledSettingsOnAppDataCleared" format="boolean" />
<attr name="knownActivityEmbeddingCerts" />
</declare-styleable>
<!-- An attribution is a logical part of an app and is identified by a tag.
@@ -3033,6 +3052,8 @@
<!-- Indicates whether the activity can be displayed on a remote device which may or
may not be running Android. -->
<attr name="canDisplayOnRemoteDevices" format="boolean"/>
<attr name="allowUntrustedActivityEmbedding" />
<attr name="knownActivityEmbeddingCerts" />
</declare-styleable>
<!-- The <code>activity-alias</code> tag declares a new
@@ -3073,6 +3094,8 @@
<attr name="exported" />
<attr name="parentActivityName" />
<attr name="attributionTags" />
<attr name="allowUntrustedActivityEmbedding" />
<attr name="knownActivityEmbeddingCerts" />
</declare-styleable>
<!-- The <code>meta-data</code> tag is used to attach additional

View File

@@ -3276,6 +3276,8 @@
<public name="toExtendBottom" />
<public name="tileService" />
<public name="windowSplashScreenBehavior" />
<public name="allowUntrustedActivityEmbedding" />
<public name="knownActivityEmbeddingCerts" />
</staging-public-group>
<staging-public-group type="id" first-id="0x01de0000">

View File

@@ -924,6 +924,7 @@ public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmen
* Checks if an activity is embedded and its presentation is customized by a
* {@link android.window.TaskFragmentOrganizer} to only occupy a portion of Task bounds.
*/
@Override
public boolean isActivityEmbedded(@NonNull Activity activity) {
return mPresenter.isActivityEmbedded(activity.getActivityToken());
}

View File

@@ -20,6 +20,8 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.pm.ActivityInfo;
import java.util.Set;
/** @hide **/
//@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
public interface ParsedActivity extends ParsedMainComponent {
@@ -59,6 +61,12 @@ public interface ParsedActivity extends ParsedMainComponent {
@Nullable
String getPermission();
/**
* Gets the trusted host certificates of apps that are allowed to embed this activity.
*/
@NonNull
Set<String> getKnownActivityEmbeddingCerts();
int getPersistableMode();
int getPrivateFlags();

View File

@@ -23,6 +23,7 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
import static com.android.server.pm.pkg.parsing.ParsingPackageImpl.sForInternedString;
import static com.android.server.pm.pkg.parsing.ParsingPackageImpl.sForStringSet;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -33,12 +34,17 @@ import android.content.pm.PackageManager;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import android.util.ArraySet;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DataClass;
import com.android.internal.util.Parcelling.BuiltIn.ForInternedString;
import com.android.server.pm.pkg.parsing.ParsingUtils;
import java.util.Collections;
import java.util.Locale;
import java.util.Set;
/**
* @hide
**/
@@ -63,6 +69,8 @@ public class ParsedActivityImpl extends ParsedMainComponentImpl implements Parse
@Nullable
@DataClass.ParcelWith(ForInternedString.class)
private String permission;
@Nullable
private Set<String> mKnownActivityEmbeddingCerts;
private int launchMode;
private int documentLaunchMode;
@@ -113,6 +121,7 @@ public class ParsedActivityImpl extends ParsedMainComponentImpl implements Parse
this.rotationAnimation = other.rotationAnimation;
this.colorMode = other.colorMode;
this.windowLayout = other.windowLayout;
this.mKnownActivityEmbeddingCerts = other.mKnownActivityEmbeddingCerts;
}
/**
@@ -239,6 +248,25 @@ public class ParsedActivityImpl extends ParsedMainComponentImpl implements Parse
return this;
}
@NonNull
@Override
public Set<String> getKnownActivityEmbeddingCerts() {
return mKnownActivityEmbeddingCerts == null ? Collections.emptySet()
: mKnownActivityEmbeddingCerts;
}
/**
* Sets the trusted host certificates of apps that are allowed to embed this activity.
*/
public void setKnownActivityEmbeddingCerts(@NonNull Set<String> knownActivityEmbeddingCerts) {
// Convert the provided digest to upper case for consistent Set membership
// checks when verifying the signing certificate digests of requesting apps.
this.mKnownActivityEmbeddingCerts = new ArraySet<>();
for (String knownCert : knownActivityEmbeddingCerts) {
this.mKnownActivityEmbeddingCerts.add(knownCert.toUpperCase(Locale.US));
}
}
public String toString() {
StringBuilder sb = new StringBuilder(128);
sb.append("Activity{");
@@ -287,6 +315,7 @@ public class ParsedActivityImpl extends ParsedMainComponentImpl implements Parse
} else {
dest.writeBoolean(false);
}
sForStringSet.parcel(this.mKnownActivityEmbeddingCerts, dest, flags);
}
public ParsedActivityImpl() {
@@ -320,6 +349,7 @@ public class ParsedActivityImpl extends ParsedMainComponentImpl implements Parse
if (in.readBoolean()) {
windowLayout = new ActivityInfo.WindowLayout(in);
}
this.mKnownActivityEmbeddingCerts = sForStringSet.unparcel(in);
}
@NonNull
@@ -344,7 +374,7 @@ public class ParsedActivityImpl extends ParsedMainComponentImpl implements Parse
// CHECKSTYLE:OFF Generated code
//
// To regenerate run:
// $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/parsing/component/ParsedActivityImpl.java
// $ codegen $ANDROID_BUILD_TOP/frameworks/base/services/core/java/com/android/server/pm/pkg/component/ParsedActivityImpl.java
//
// To exclude the generated code from IntelliJ auto-formatting enable (one-time):
// Settings > Editor > Code Style > Formatter Control
@@ -360,6 +390,7 @@ public class ParsedActivityImpl extends ParsedMainComponentImpl implements Parse
@Nullable String taskAffinity,
int privateFlags,
@Nullable String permission,
@Nullable Set<String> knownActivityEmbeddingCerts,
int launchMode,
int documentLaunchMode,
int maxRecents,
@@ -383,6 +414,7 @@ public class ParsedActivityImpl extends ParsedMainComponentImpl implements Parse
this.taskAffinity = taskAffinity;
this.privateFlags = privateFlags;
this.permission = permission;
this.mKnownActivityEmbeddingCerts = knownActivityEmbeddingCerts;
this.launchMode = launchMode;
this.documentLaunchMode = documentLaunchMode;
this.maxRecents = maxRecents;
@@ -645,10 +677,10 @@ public class ParsedActivityImpl extends ParsedMainComponentImpl implements Parse
}
@DataClass.Generated(
time = 1641431949361L,
time = 1644372875433L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedActivityImpl.java",
inputSignatures = "private int theme\nprivate int uiOptions\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String targetActivity\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String parentActivityName\nprivate @android.annotation.Nullable java.lang.String taskAffinity\nprivate int privateFlags\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String permission\nprivate int launchMode\nprivate int documentLaunchMode\nprivate int maxRecents\nprivate int configChanges\nprivate int softInputMode\nprivate int persistableMode\nprivate int lockTaskLaunchMode\nprivate int screenOrientation\nprivate int resizeMode\nprivate float maxAspectRatio\nprivate float minAspectRatio\nprivate boolean supportsSizeChanges\nprivate @android.annotation.Nullable java.lang.String requestedVrComponent\nprivate int rotationAnimation\nprivate int colorMode\nprivate @android.annotation.Nullable android.content.pm.ActivityInfo.WindowLayout windowLayout\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator<android.content.pm.parsing.component.ParsedActivityImpl> CREATOR\nstatic @android.annotation.NonNull android.content.pm.parsing.component.ParsedActivityImpl makeAppDetailsActivity(java.lang.String,java.lang.String,int,java.lang.String,boolean)\nstatic @android.annotation.NonNull android.content.pm.parsing.component.ParsedActivityImpl makeAlias(java.lang.String,android.content.pm.parsing.component.ParsedActivity)\npublic android.content.pm.parsing.component.ParsedActivityImpl setMaxAspectRatio(int,float)\npublic android.content.pm.parsing.component.ParsedActivityImpl setMinAspectRatio(int,float)\npublic android.content.pm.parsing.component.ParsedActivityImpl setTargetActivity(java.lang.String)\npublic android.content.pm.parsing.component.ParsedActivityImpl setPermission(java.lang.String)\npublic java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedActivityImpl extends android.content.pm.parsing.component.ParsedMainComponentImpl implements [android.content.pm.parsing.component.ParsedActivity, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=false)")
sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/component/ParsedActivityImpl.java",
inputSignatures = "private int theme\nprivate int uiOptions\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String targetActivity\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String parentActivityName\nprivate @android.annotation.Nullable java.lang.String taskAffinity\nprivate int privateFlags\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String permission\nprivate @android.annotation.Nullable java.util.Set<java.lang.String> mKnownActivityEmbeddingCerts\nprivate int launchMode\nprivate int documentLaunchMode\nprivate int maxRecents\nprivate int configChanges\nprivate int softInputMode\nprivate int persistableMode\nprivate int lockTaskLaunchMode\nprivate int screenOrientation\nprivate int resizeMode\nprivate float maxAspectRatio\nprivate float minAspectRatio\nprivate boolean supportsSizeChanges\nprivate @android.annotation.Nullable java.lang.String requestedVrComponent\nprivate int rotationAnimation\nprivate int colorMode\nprivate @android.annotation.Nullable android.content.pm.ActivityInfo.WindowLayout windowLayout\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator<com.android.server.pm.pkg.component.ParsedActivityImpl> CREATOR\nstatic @android.annotation.NonNull com.android.server.pm.pkg.component.ParsedActivityImpl makeAppDetailsActivity(java.lang.String,java.lang.String,int,java.lang.String,boolean)\nstatic @android.annotation.NonNull com.android.server.pm.pkg.component.ParsedActivityImpl makeAlias(java.lang.String,com.android.server.pm.pkg.component.ParsedActivity)\npublic com.android.server.pm.pkg.component.ParsedActivityImpl setMaxAspectRatio(int,float)\npublic com.android.server.pm.pkg.component.ParsedActivityImpl setMinAspectRatio(int,float)\npublic com.android.server.pm.pkg.component.ParsedActivityImpl setTargetActivity(java.lang.String)\npublic com.android.server.pm.pkg.component.ParsedActivityImpl setPermission(java.lang.String)\npublic @android.annotation.NonNull @java.lang.Override java.util.Set<java.lang.String> getKnownActivityEmbeddingCerts()\npublic void setKnownActivityEmbeddingCerts(java.util.Set<java.lang.String>)\npublic java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedActivityImpl extends com.android.server.pm.pkg.component.ParsedMainComponentImpl implements [com.android.server.pm.pkg.component.ParsedActivity, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=false)")
@Deprecated
private void __metadata() {}

View File

@@ -21,6 +21,7 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static com.android.server.pm.pkg.component.ComponentParseUtils.flag;
import static com.android.server.pm.pkg.parsing.ParsingUtils.NOT_SET;
import static com.android.server.pm.pkg.parsing.ParsingUtils.parseKnownActivityEmbeddingCerts;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -151,7 +152,8 @@ public class ParsedActivityUtils {
| flag(ActivityInfo.FLAG_SHOW_WHEN_LOCKED, R.styleable.AndroidManifestActivity_showWhenLocked, sa)
| flag(ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE, R.styleable.AndroidManifestActivity_supportsPictureInPicture, sa)
| flag(ActivityInfo.FLAG_TURN_SCREEN_ON, R.styleable.AndroidManifestActivity_turnScreenOn, sa)
| flag(ActivityInfo.FLAG_PREFER_MINIMAL_POST_PROCESSING, R.styleable.AndroidManifestActivity_preferMinimalPostProcessing, sa)));
| flag(ActivityInfo.FLAG_PREFER_MINIMAL_POST_PROCESSING, R.styleable.AndroidManifestActivity_preferMinimalPostProcessing, sa))
| flag(ActivityInfo.FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING, R.styleable.AndroidManifestActivity_allowUntrustedActivityEmbedding, sa));
activity.setPrivateFlags(activity.getPrivateFlags() | (flag(ActivityInfo.FLAG_INHERIT_SHOW_WHEN_LOCKED,
R.styleable.AndroidManifestActivity_inheritShowWhenLocked, sa)
@@ -338,6 +340,20 @@ public class ParsedActivityUtils {
activity.setPermission(permission != null ? permission : pkg.getPermission());
}
final ParseResult<Set<String>> knownActivityEmbeddingCertsResult =
parseKnownActivityEmbeddingCerts(array, resources, isAlias
? R.styleable.AndroidManifestActivityAlias_knownActivityEmbeddingCerts
: R.styleable.AndroidManifestActivity_knownActivityEmbeddingCerts, input);
if (knownActivityEmbeddingCertsResult.isError()) {
return input.error(knownActivityEmbeddingCertsResult);
} else {
final Set<String> knownActivityEmbeddingCerts = knownActivityEmbeddingCertsResult
.getResult();
if (knownActivityEmbeddingCerts != null) {
activity.setKnownActivityEmbeddingCerts(knownActivityEmbeddingCerts);
}
}
final boolean setExported = array.hasValue(exportedAttr);
if (setExported) {
activity.setExported(array.getBoolean(exportedAttr, false));

View File

@@ -549,6 +549,7 @@ public class PackageInfoWithoutStateUtils {
ai.metaData = a.getMetaData();
}
ai.applicationInfo = applicationInfo;
ai.setKnownActivityEmbeddingCerts(a.getKnownActivityEmbeddingCerts());
return ai;
}

View File

@@ -381,6 +381,12 @@ public interface ParsingPackage extends ParsingPackageRead {
ParsingPackage setLocaleConfigRes(int localeConfigRes);
/**
* Sets the trusted host certificates of apps that are allowed to embed activities of this
* application.
*/
ParsingPackage setKnownActivityEmbeddingCerts(Set<String> knownActivityEmbeddingCerts);
// TODO(b/135203078): This class no longer has access to ParsedPackage, find a replacement
// for moving to the next step
@CallSuper

View File

@@ -563,6 +563,9 @@ public class ParsingPackageImpl implements ParsingPackage, ParsingPackageHidden,
return (mBooleans & flag) != 0;
}
@Nullable
private Set<String> mKnownActivityEmbeddingCerts;
// Derived fields
@NonNull
private UUID mStorageUuid;
@@ -1150,6 +1153,9 @@ public class ParsingPackageImpl implements ParsingPackage, ParsingPackageHidden,
appInfo.setVersionCode(mLongVersionCode);
appInfo.setAppClassNamesByProcess(buildAppClassNamesByProcess());
appInfo.setLocaleConfigRes(mLocaleConfigRes);
if (mKnownActivityEmbeddingCerts != null) {
appInfo.setKnownActivityEmbeddingCerts(mKnownActivityEmbeddingCerts);
}
return appInfo;
}
@@ -1329,6 +1335,7 @@ public class ParsingPackageImpl implements ParsingPackage, ParsingPackageHidden,
dest.writeInt(this.nativeHeapZeroInitialized);
sForBoolean.parcel(this.requestRawExternalStorageAccess, dest, flags);
dest.writeInt(this.mLocaleConfigRes);
sForStringSet.parcel(mKnownActivityEmbeddingCerts, dest, flags);
}
public ParsingPackageImpl(Parcel in) {
@@ -1477,6 +1484,7 @@ public class ParsingPackageImpl implements ParsingPackage, ParsingPackageHidden,
this.nativeHeapZeroInitialized = in.readInt();
this.requestRawExternalStorageAccess = sForBoolean.unparcel(in);
this.mLocaleConfigRes = in.readInt();
this.mKnownActivityEmbeddingCerts = sForStringSet.unparcel(in);
assignDerivedFields();
}
@@ -2376,6 +2384,13 @@ public class ParsingPackageImpl implements ParsingPackage, ParsingPackageHidden,
return getBoolean(Booleans.RESET_ENABLED_SETTINGS_ON_APP_DATA_CLEARED);
}
@NonNull
@Override
public Set<String> getKnownActivityEmbeddingCerts() {
return mKnownActivityEmbeddingCerts == null ? Collections.emptySet()
: mKnownActivityEmbeddingCerts;
}
@Override
public boolean shouldInheritKeyStoreKeys() {
return getBoolean(Booleans.INHERIT_KEYSTORE_KEYS);
@@ -2973,4 +2988,11 @@ public class ParsingPackageImpl implements ParsingPackage, ParsingPackageHidden,
mLocaleConfigRes = value;
return this;
}
@Override
public ParsingPackage setKnownActivityEmbeddingCerts(
@Nullable Set<String> knownEmbeddingCerts) {
mKnownActivityEmbeddingCerts = knownEmbeddingCerts;
return this;
}
}

View File

@@ -30,6 +30,8 @@ import static android.os.Build.VERSION_CODES.DONUT;
import static android.os.Build.VERSION_CODES.O;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import static com.android.server.pm.pkg.parsing.ParsingUtils.parseKnownActivityEmbeddingCerts;
import android.annotation.AnyRes;
import android.annotation.CheckResult;
import android.annotation.IntDef;
@@ -2009,6 +2011,19 @@ public class ParsingPackageUtils {
.AndroidManifestApplication_requestForegroundServiceExemption,
false));
}
final ParseResult<Set<String>> knownActivityEmbeddingCertsResult =
parseKnownActivityEmbeddingCerts(sa, res,
R.styleable.AndroidManifestApplication_knownActivityEmbeddingCerts,
input);
if (knownActivityEmbeddingCertsResult.isError()) {
return input.error(knownActivityEmbeddingCertsResult);
} else {
final Set<String> knownActivityEmbeddingCerts = knownActivityEmbeddingCertsResult
.getResult();
if (knownActivityEmbeddingCerts != null) {
pkg.setKnownActivityEmbeddingCerts(knownActivityEmbeddingCerts);
}
}
} finally {
sa.recycle();
}

View File

@@ -22,6 +22,8 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.pm.parsing.result.ParseInput;
import android.content.pm.parsing.result.ParseResult;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.os.Parcel;
import android.os.Parcelable;
@@ -38,6 +40,7 @@ import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/** @hide **/
public class ParsingUtils {
@@ -168,4 +171,50 @@ public class ParsingUtils {
return list;
}
}
/**
* Parse the {@link android.R.attr#knownActivityEmbeddingCerts} attribute, if available.
*/
@NonNull
public static ParseResult<Set<String>> parseKnownActivityEmbeddingCerts(@NonNull TypedArray sa,
@NonNull Resources res, int resourceId, @NonNull ParseInput input) {
if (!sa.hasValue(resourceId)) {
return input.success(null);
}
final int knownActivityEmbeddingCertsResource = sa.getResourceId(resourceId, 0);
if (knownActivityEmbeddingCertsResource != 0) {
// The knownCerts attribute supports both a string array resource as well as a
// string resource for the case where the permission should only be granted to a
// single known signer.
Set<String> knownEmbeddingCertificates = null;
final String resourceType = res.getResourceTypeName(
knownActivityEmbeddingCertsResource);
if (resourceType.equals("array")) {
final String[] knownCerts = res.getStringArray(knownActivityEmbeddingCertsResource);
if (knownCerts != null) {
knownEmbeddingCertificates = Set.of(knownCerts);
}
} else {
final String knownCert = res.getString(knownActivityEmbeddingCertsResource);
if (knownCert != null) {
knownEmbeddingCertificates = Set.of(knownCert);
}
}
if (knownEmbeddingCertificates == null || knownEmbeddingCertificates.isEmpty()) {
return input.error("Defined a knownActivityEmbeddingCerts attribute but the "
+ "provided resource is null");
}
return input.success(knownEmbeddingCertificates);
}
// If the knownCerts resource ID is null - the app specified a string value for the
// attribute representing a single trusted signer.
final String knownCert = sa.getString(resourceId);
if (knownCert == null || knownCert.isEmpty()) {
return input.error("Defined a knownActivityEmbeddingCerts attribute but the provided "
+ "string is empty");
}
return input.success(Set.of(knownCert));
}
}

View File

@@ -21,6 +21,8 @@ import android.annotation.Nullable;
import android.content.pm.ApplicationInfo;
import android.util.SparseArray;
import java.util.Set;
/**
* Container for fields that are eventually exposed through {@link ApplicationInfo}.
* <p>
@@ -284,6 +286,13 @@ public interface PkgWithoutStateAppInfo {
@Nullable
String getPermission();
/**
* @see ApplicationInfo#knownActivityEmbeddingCerts
* @see R.styleable#AndroidManifestApplication_knownActivityEmbeddingCerts
*/
@NonNull
Set<String> getKnownActivityEmbeddingCerts();
/**
* @see ApplicationInfo#processName
* @see R.styleable#AndroidManifestApplication_process

View File

@@ -2003,8 +2003,8 @@ class ActivityStarter {
* @param targetTask the target task for launching activity, which could be different from
* the one who hosting the embedding.
*/
private boolean canEmbedActivity(@NonNull TaskFragment taskFragment, ActivityRecord starting,
boolean newTask, Task targetTask) {
private boolean canEmbedActivity(@NonNull TaskFragment taskFragment,
@NonNull ActivityRecord starting, boolean newTask, Task targetTask) {
final Task hostTask = taskFragment.getTask();
if (hostTask == null) {
return false;
@@ -2016,8 +2016,7 @@ class ActivityStarter {
return true;
}
// Not allowed embedding an activity of another app.
if (hostUid != starting.getUid()) {
if (!taskFragment.isAllowedToEmbedActivity(starting)) {
return false;
}

View File

@@ -25,6 +25,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.pm.ActivityInfo.FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING;
import static android.content.pm.ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
@@ -95,6 +96,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.internal.util.function.pooled.PooledPredicate;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -102,6 +104,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -504,6 +507,56 @@ class TaskFragment extends WindowContainer<WindowContainer> {
return false;
}
/**
* Checks if the organized task fragment is allowed to have the specified activity, which is
* allowed if an activity allows embedding in untrusted mode, or if the trusted mode can be
* enabled.
* @see #isAllowedToEmbedActivityInTrustedMode(ActivityRecord)
*/
boolean isAllowedToEmbedActivity(@NonNull ActivityRecord a) {
if ((a.info.flags & FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING)
== FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING) {
return true;
}
return isAllowedToEmbedActivityInTrustedMode(a);
}
/**
* Checks if the organized task fragment is allowed to embed activity in fully trusted mode,
* which means that all transactions are allowed. This is supported in the following cases:
* <li>the activity belongs to the same app as the organizer host;</li>
* <li>the activity has declared the organizer host as trusted explicitly via known
* certificate.</li>
*/
private boolean isAllowedToEmbedActivityInTrustedMode(@NonNull ActivityRecord a) {
if (mTaskFragmentOrganizerUid == a.getUid()) {
// Activities from the same UID can be embedded freely by the host.
return true;
}
Set<String> knownActivityEmbeddingCerts = a.info.getKnownActivityEmbeddingCerts();
if (knownActivityEmbeddingCerts.isEmpty()) {
// An application must either declare that it allows untrusted embedding, or specify
// a set of app certificates that are allowed to embed it in trusted mode.
return false;
}
AndroidPackage hostPackage = mAtmService.getPackageManagerInternalLocked()
.getPackage(mTaskFragmentOrganizerUid);
return hostPackage != null && hostPackage.getSigningDetails().hasAncestorOrSelfWithDigest(
knownActivityEmbeddingCerts);
}
/**
* Checks if all activities in the task fragment are allowed to be embedded in trusted mode.
* @see #isAllowedToEmbedActivityInTrustedMode(ActivityRecord)
*/
boolean isAllowedToBeEmbeddedInTrustedMode() {
return forAllActivities(this::isAllowedToEmbedActivityInTrustedMode);
}
/**
* Returns the TaskFragment that is being organized, which could be this or the ascendant
* TaskFragment.

View File

@@ -294,14 +294,28 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
}
}
/** Gets the {@link RemoteAnimationDefinition} set on the given organizer if exists. */
/**
* Gets the {@link RemoteAnimationDefinition} set on the given organizer if exists. Returns
* {@code null} if it doesn't, or if the organizer has activity(ies) embedded in untrusted mode.
*/
@Nullable
public RemoteAnimationDefinition getRemoteAnimationDefinition(
ITaskFragmentOrganizer organizer) {
synchronized (mGlobalLock) {
final TaskFragmentOrganizerState organizerState =
mTaskFragmentOrganizerState.get(organizer.asBinder());
return organizerState != null ? organizerState.mRemoteAnimationDefinition : null;
if (organizerState == null) {
return null;
}
for (TaskFragment tf : organizerState.mOrganizedTaskFragments) {
if (!tf.isAllowedToBeEmbeddedInTrustedMode()) {
// Disable client-driven animations for organizer if at least one of the
// embedded task fragments is not embedding in trusted mode.
// TODO(b/197364677): replace with a stub or Shell-driven one instead of skip?
return null;
}
}
return organizerState.mRemoteAnimationDefinition;
}
}

View File

@@ -19,6 +19,8 @@ package com.android.server.wm;
import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
import static android.app.ActivityManager.isStartResultSuccessful;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.window.WindowContainerTransaction.Change.CHANGE_BOUNDS_TRANSACTION;
import static android.window.WindowContainerTransaction.Change.CHANGE_BOUNDS_TRANSACTION_RECT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT;
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT;
@@ -1224,10 +1226,14 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
while (entries.hasNext()) {
final Map.Entry<IBinder, WindowContainerTransaction.Change> entry = entries.next();
// Only allow to apply changes to TaskFragment that is created by this organizer.
enforceTaskFragmentOrganized(func, WindowContainer.fromBinder(entry.getKey()),
organizer);
WindowContainer wc = WindowContainer.fromBinder(entry.getKey());
enforceTaskFragmentOrganized(func, wc, organizer);
enforceTaskFragmentConfigChangeAllowed(func, wc, entry.getValue(), organizer);
}
// TODO(b/197364677): Enforce safety of hierarchy operations in untrusted mode. E.g. one
// could first change a trusted TF, and then start/reparent untrusted activity there.
// Hierarchy changes
final List<WindowContainerTransaction.HierarchyOp> hops = t.getHierarchyOps();
for (int i = hops.size() - 1; i >= 0; i--) {
@@ -1297,6 +1303,57 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
}
}
/**
* Makes sure that SurfaceControl transactions and the ability to set bounds outside of the
* parent bounds are not allowed for embedding without full trust between the host and the
* target.
* TODO(b/197364677): Allow SC transactions when the client-driven animations are protected from
* tapjacking.
*/
private void enforceTaskFragmentConfigChangeAllowed(String func, @Nullable WindowContainer wc,
WindowContainerTransaction.Change change, ITaskFragmentOrganizer organizer) {
if (wc == null) {
Slog.e(TAG, "Attempt to operate on task fragment that no longer exists");
return;
}
// Check if TaskFragment is embedded in fully trusted mode
if (wc.asTaskFragment().isAllowedToBeEmbeddedInTrustedMode()) {
// Fully trusted, no need to check further
return;
}
if (change == null) {
return;
}
final int changeMask = change.getChangeMask();
if ((changeMask & (CHANGE_BOUNDS_TRANSACTION | CHANGE_BOUNDS_TRANSACTION_RECT)) != 0) {
String msg = "Permission Denial: " + func + " from pid="
+ Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
+ " trying to apply SurfaceControl changes to TaskFragment in non-trusted "
+ "embedding mode, TaskFragmentOrganizer=" + organizer;
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
if (change.getWindowSetMask() == 0) {
// Nothing else to check.
return;
}
WindowConfiguration requestedWindowConfig = change.getConfiguration().windowConfiguration;
WindowContainer wcParent = wc.getParent();
if (wcParent == null) {
Slog.e(TAG, "Attempt to set bounds on task fragment that has no parent");
return;
}
if (!wcParent.getBounds().contains(requestedWindowConfig.getBounds())) {
String msg = "Permission Denial: " + func + " from pid="
+ Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
+ " trying to apply bounds outside of parent for non-trusted host,"
+ " TaskFragmentOrganizer=" + organizer;
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
}
void createTaskFragment(@NonNull TaskFragmentCreationParams creationParams,
@Nullable IBinder errorCallbackToken, @NonNull CallerInfo caller) {
final ActivityRecord ownerActivity =

View File

@@ -508,7 +508,8 @@ class AndroidPackageTest : ParcelableComponentTest(AndroidPackage::class, Packag
AndroidPackage::shouldInheritKeyStoreKeys,
ParsingPackage::setInheritKeyStoreKeys,
true
)
),
getter(AndroidPackage::getKnownActivityEmbeddingCerts, setOf("TESTEMBEDDINGCERT"))
)
override fun initialObject() = PackageImpl.forParsing(

View File

@@ -53,7 +53,7 @@ class ParsedActivityTest : ParsedMainComponentTest(
ParsedActivity::getTaskAffinity,
ParsedActivity::getTheme,
ParsedActivity::getUiOptions,
ParsedActivity::isSupportsSizeChanges,
ParsedActivity::isSupportsSizeChanges
)
override fun mainComponentSubclassExtraParams() = listOf(
@@ -73,6 +73,7 @@ class ParsedActivityTest : ParsedMainComponentTest(
ActivityInfo.WindowLayout::minHeight
)
}
)
),
getter(ParsedActivity::getKnownActivityEmbeddingCerts, setOf("TESTEMBEDDINGCERT"))
)
}

View File

@@ -895,6 +895,7 @@ public class PackageParserTest {
assertEquals(a.networkSecurityConfigRes, that.networkSecurityConfigRes);
assertEquals(a.taskAffinity, that.taskAffinity);
assertEquals(a.permission, that.permission);
assertEquals(a.getKnownActivityEmbeddingCerts(), that.getKnownActivityEmbeddingCerts());
assertEquals(a.processName, that.processName);
assertEquals(a.className, that.className);
assertEquals(a.manageSpaceActivityName, that.manageSpaceActivityName);

View File

@@ -75,6 +75,7 @@ import android.content.pm.ActivityInfo.WindowLayout;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.SigningDetails;
import android.graphics.Rect;
import android.os.Binder;
import android.os.IBinder;
@@ -84,9 +85,11 @@ import android.platform.test.annotations.Presubmit;
import android.service.voice.IVoiceInteractionSession;
import android.util.Pair;
import android.view.Gravity;
import android.window.TaskFragmentOrganizerToken;
import androidx.test.filters.SmallTest;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.wm.LaunchParamsController.LaunchParamsModifier;
import com.android.server.wm.utils.MockTracker;
@@ -94,6 +97,10 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
/**
* Tests for the {@link ActivityStarter} class.
*
@@ -1109,7 +1116,7 @@ public class ActivityStarterTests extends WindowTestsBase {
}
@Test
public void testStartActivityInner_inTaskFragment() {
public void testStartActivityInner_inTaskFragment_failsByDefault() {
final ActivityStarter starter = prepareStarter(0, false);
final ActivityRecord targetRecord = new ActivityBuilder(mAtm).build();
final ActivityRecord sourceRecord = new ActivityBuilder(mAtm).setCreateTask(true).build();
@@ -1117,6 +1124,97 @@ public class ActivityStarterTests extends WindowTestsBase {
true /* createdByOrganizer */);
sourceRecord.getTask().addChild(taskFragment, POSITION_TOP);
starter.startActivityInner(
/* r */targetRecord,
/* sourceRecord */ sourceRecord,
/* voiceSession */null,
/* voiceInteractor */ null,
/* startFlags */ 0,
/* doResume */true,
/* options */null,
/* inTask */null,
/* inTaskFragment */ taskFragment,
/* restrictedBgActivity */false,
/* intentGrants */null);
assertFalse(taskFragment.hasChild());
}
@Test
public void testStartActivityInner_inTaskFragment_allowedForSameUid() {
final ActivityStarter starter = prepareStarter(0, false);
final ActivityRecord targetRecord = new ActivityBuilder(mAtm).build();
final ActivityRecord sourceRecord = new ActivityBuilder(mAtm).setCreateTask(true).build();
final TaskFragment taskFragment = new TaskFragment(mAtm, sourceRecord.token,
true /* createdByOrganizer */);
sourceRecord.getTask().addChild(taskFragment, POSITION_TOP);
taskFragment.setTaskFragmentOrganizer(mock(TaskFragmentOrganizerToken.class),
targetRecord.getUid(), "test_process_name");
starter.startActivityInner(
/* r */targetRecord,
/* sourceRecord */ sourceRecord,
/* voiceSession */null,
/* voiceInteractor */ null,
/* startFlags */ 0,
/* doResume */true,
/* options */null,
/* inTask */null,
/* inTaskFragment */ taskFragment,
/* restrictedBgActivity */false,
/* intentGrants */null);
assertTrue(taskFragment.hasChild());
}
@Test
public void testStartActivityInner_inTaskFragment_allowedTrustedCertUid() {
final ActivityStarter starter = prepareStarter(0, false);
final ActivityRecord targetRecord = new ActivityBuilder(mAtm).build();
final ActivityRecord sourceRecord = new ActivityBuilder(mAtm).setCreateTask(true).build();
final TaskFragment taskFragment = new TaskFragment(mAtm, sourceRecord.token,
true /* createdByOrganizer */);
sourceRecord.getTask().addChild(taskFragment, POSITION_TOP);
taskFragment.setTaskFragmentOrganizer(mock(TaskFragmentOrganizerToken.class),
12345, "test_process_name");
AndroidPackage androidPackage = mock(AndroidPackage.class);
doReturn(androidPackage).when(mMockPackageManager).getPackage(eq(12345));
Set<String> certs = new HashSet(Arrays.asList("test_cert1", "test_cert1"));
targetRecord.info.setKnownActivityEmbeddingCerts(certs);
SigningDetails signingDetails = mock(SigningDetails.class);
doReturn(true).when(signingDetails).hasAncestorOrSelfWithDigest(any());
doReturn(signingDetails).when(androidPackage).getSigningDetails();
starter.startActivityInner(
/* r */targetRecord,
/* sourceRecord */ sourceRecord,
/* voiceSession */null,
/* voiceInteractor */ null,
/* startFlags */ 0,
/* doResume */true,
/* options */null,
/* inTask */null,
/* inTaskFragment */ taskFragment,
/* restrictedBgActivity */false,
/* intentGrants */null);
assertTrue(taskFragment.hasChild());
}
@Test
public void testStartActivityInner_inTaskFragment_allowedForUntrustedEmbedding() {
final ActivityStarter starter = prepareStarter(0, false);
final ActivityRecord targetRecord = new ActivityBuilder(mAtm).build();
final ActivityRecord sourceRecord = new ActivityBuilder(mAtm).setCreateTask(true).build();
final TaskFragment taskFragment = new TaskFragment(mAtm, sourceRecord.token,
true /* createdByOrganizer */);
sourceRecord.getTask().addChild(taskFragment, POSITION_TOP);
targetRecord.info.flags |= ActivityInfo.FLAG_ALLOW_UNTRUSTED_ACTIVITY_EMBEDDING;
starter.startActivityInner(
/* r */targetRecord,
/* sourceRecord */ sourceRecord,