Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 388eb8c4 authored by Todd Kennedy's avatar Todd Kennedy
Browse files

Implicitly expose activities

Activities that have a browsable web intent filter [action.VIEW,
category.BROWSABLE and http(s) scheme] are implicitly exposed to
instant apps. Authors can explicitly hide these activities by
using the attribute android:visibleToInstantApp="false".

Bug: 25119046
Test: cts-tradefed run commandAndExit cts-dev -m CtsAppSecurityHostTestCases -t android.appsecurity.cts.EphemeralTest
Change-Id: I88b277a719e7ecd5631f8cbd281757eb3e3d2ce6
parent d5f7e305
Loading
Loading
Loading
Loading
+44 −9
Original line number Original line Diff line number Diff line
@@ -3780,6 +3780,8 @@ public class PackageParser {
                    ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE;
                    ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE;
        }
        }


        final boolean hasVisibleToEphemeral =
                sa.hasValue(R.styleable.AndroidManifestActivity_visibleToEphemeral);
        final boolean isEphemeral = ((flags & PARSE_IS_EPHEMERAL) != 0);
        final boolean isEphemeral = ((flags & PARSE_IS_EPHEMERAL) != 0);
        final boolean visibleToEphemeral = isEphemeral
        final boolean visibleToEphemeral = isEphemeral
                || sa.getBoolean(R.styleable.AndroidManifestActivity_visibleToEphemeral, false);
                || sa.getBoolean(R.styleable.AndroidManifestActivity_visibleToEphemeral, false);
@@ -3818,7 +3820,7 @@ public class PackageParser {
                    return null;
                    return null;
                }
                }
                intent.setEphemeral(isEphemeral);
                intent.setEphemeral(isEphemeral);
                intent.setVisibleToEphemeral(visibleToEphemeral);
                intent.setVisibleToEphemeral(visibleToEphemeral || isWebBrowsableIntent(intent));
                if (intent.countActions() == 0) {
                if (intent.countActions() == 0) {
                    Slog.w(TAG, "No actions in intent filter at "
                    Slog.w(TAG, "No actions in intent filter at "
                            + mArchiveSourcePath + " "
                            + mArchiveSourcePath + " "
@@ -3826,6 +3828,10 @@ public class PackageParser {
                } else {
                } else {
                    a.intents.add(intent);
                    a.intents.add(intent);
                }
                }
                // adjust activity flags when we implicitly expose it via a browsable filter
                if (!hasVisibleToEphemeral && intent.isVisibleToEphemeral()) {
                    a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_EPHEMERAL;
                }
            } else if (!receiver && parser.getName().equals("preferred")) {
            } else if (!receiver && parser.getName().equals("preferred")) {
                ActivityIntentInfo intent = new ActivityIntentInfo(a);
                ActivityIntentInfo intent = new ActivityIntentInfo(a);
                if (!parseIntent(res, parser, false /*allowGlobs*/, false /*allowAutoVerify*/,
                if (!parseIntent(res, parser, false /*allowGlobs*/, false /*allowAutoVerify*/,
@@ -3833,7 +3839,7 @@ public class PackageParser {
                    return null;
                    return null;
                }
                }
                intent.setEphemeral(isEphemeral);
                intent.setEphemeral(isEphemeral);
                intent.setVisibleToEphemeral(visibleToEphemeral);
                intent.setVisibleToEphemeral(visibleToEphemeral || isWebBrowsableIntent(intent));
                if (intent.countActions() == 0) {
                if (intent.countActions() == 0) {
                    Slog.w(TAG, "No actions in preferred at "
                    Slog.w(TAG, "No actions in preferred at "
                            + mArchiveSourcePath + " "
                            + mArchiveSourcePath + " "
@@ -3844,6 +3850,10 @@ public class PackageParser {
                    }
                    }
                    owner.preferredActivityFilters.add(intent);
                    owner.preferredActivityFilters.add(intent);
                }
                }
                // adjust activity flags when we implicitly expose it via a browsable filter
                if (!hasVisibleToEphemeral && intent.isVisibleToEphemeral()) {
                    a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_EPHEMERAL;
                }
            } else if (parser.getName().equals("meta-data")) {
            } else if (parser.getName().equals("meta-data")) {
                if ((a.metaData = parseMetaData(res, parser, a.metaData,
                if ((a.metaData = parseMetaData(res, parser, a.metaData,
                        outError)) == null) {
                        outError)) == null) {
@@ -4084,6 +4094,7 @@ public class PackageParser {
            }
            }
        }
        }


        // TODO add visibleToInstantApp attribute to activity alias
        final boolean isEphemeral = ((flags & PARSE_IS_EPHEMERAL) != 0);
        final boolean isEphemeral = ((flags & PARSE_IS_EPHEMERAL) != 0);
        final boolean visibleToEphemeral = isEphemeral
        final boolean visibleToEphemeral = isEphemeral
                || ((a.info.flags & ActivityInfo.FLAG_VISIBLE_TO_EPHEMERAL) != 0);
                || ((a.info.flags & ActivityInfo.FLAG_VISIBLE_TO_EPHEMERAL) != 0);
@@ -4115,9 +4126,14 @@ public class PackageParser {
                            + parser.getPositionDescription());
                            + parser.getPositionDescription());
                } else {
                } else {
                    intent.setEphemeral(isEphemeral);
                    intent.setEphemeral(isEphemeral);
                    intent.setVisibleToEphemeral(visibleToEphemeral);
                    intent.setVisibleToEphemeral(visibleToEphemeral
                            || isWebBrowsableIntent(intent));
                    a.intents.add(intent);
                    a.intents.add(intent);
                }
                }
                // adjust activity flags when we implicitly expose it via a browsable filter
                if (intent.isVisibleToEphemeral()) {
                    a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_EPHEMERAL;
                }
            } else if (parser.getName().equals("meta-data")) {
            } else if (parser.getName().equals("meta-data")) {
                if ((a.metaData=parseMetaData(res, parser, a.metaData,
                if ((a.metaData=parseMetaData(res, parser, a.metaData,
                        outError)) == null) {
                        outError)) == null) {
@@ -4253,6 +4269,8 @@ public class PackageParser {
                    ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE;
                    ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE;
        }
        }


        final boolean hasVisibleToEphemeral =
                sa.hasValue(R.styleable.AndroidManifestProvider_visibleToEphemeral);
        final boolean isEphemeral = ((flags & PARSE_IS_EPHEMERAL) != 0);
        final boolean isEphemeral = ((flags & PARSE_IS_EPHEMERAL) != 0);
        final boolean visibleToEphemeral = isEphemeral
        final boolean visibleToEphemeral = isEphemeral
                || sa.getBoolean(R.styleable.AndroidManifestProvider_visibleToEphemeral, false);
                || sa.getBoolean(R.styleable.AndroidManifestProvider_visibleToEphemeral, false);
@@ -4282,7 +4300,8 @@ public class PackageParser {
        }
        }
        p.info.authority = cpname.intern();
        p.info.authority = cpname.intern();


        if (!parseProviderTags(res, parser, isEphemeral, visibleToEphemeral, p, outError)) {
        if (!parseProviderTags(
                res, parser, isEphemeral, hasVisibleToEphemeral, visibleToEphemeral, p, outError)) {
            return null;
            return null;
        }
        }


@@ -4290,7 +4309,8 @@ public class PackageParser {
    }
    }


    private boolean parseProviderTags(Resources res, XmlResourceParser parser,
    private boolean parseProviderTags(Resources res, XmlResourceParser parser,
            boolean isEphemeral, boolean visibleToEphemeral, Provider outInfo, String[] outError)
            boolean isEphemeral, boolean hasVisibleToEphemeral, boolean visibleToEphemeral,
            Provider outInfo, String[] outError)
                    throws XmlPullParserException, IOException {
                    throws XmlPullParserException, IOException {
        int outerDepth = parser.getDepth();
        int outerDepth = parser.getDepth();
        int type;
        int type;
@@ -4308,8 +4328,12 @@ public class PackageParser {
                    return false;
                    return false;
                }
                }
                intent.setEphemeral(isEphemeral);
                intent.setEphemeral(isEphemeral);
                intent.setVisibleToEphemeral(visibleToEphemeral);
                intent.setVisibleToEphemeral(visibleToEphemeral || isWebBrowsableIntent(intent));
                outInfo.intents.add(intent);
                outInfo.intents.add(intent);
                // adjust provider flags when we implicitly expose it via a browsable filter
                if (!hasVisibleToEphemeral && intent.isVisibleToEphemeral()) {
                    outInfo.info.flags |= ProviderInfo.FLAG_VISIBLE_TO_EPHEMERAL;
                }


            } else if (parser.getName().equals("meta-data")) {
            } else if (parser.getName().equals("meta-data")) {
                if ((outInfo.metaData=parseMetaData(res, parser,
                if ((outInfo.metaData=parseMetaData(res, parser,
@@ -4556,6 +4580,8 @@ public class PackageParser {
                    ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE;
                    ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE;
        }
        }


        final boolean hasVisibleToEphemeral =
                sa.hasValue(R.styleable.AndroidManifestService_visibleToEphemeral);
        final boolean isEphemeral = ((flags & PARSE_IS_EPHEMERAL) != 0);
        final boolean isEphemeral = ((flags & PARSE_IS_EPHEMERAL) != 0);
        final boolean visibleToEphemeral = isEphemeral
        final boolean visibleToEphemeral = isEphemeral
                || sa.getBoolean(R.styleable.AndroidManifestService_visibleToEphemeral, false);
                || sa.getBoolean(R.styleable.AndroidManifestService_visibleToEphemeral, false);
@@ -4591,8 +4617,11 @@ public class PackageParser {
                    return null;
                    return null;
                }
                }
                intent.setEphemeral(isEphemeral);
                intent.setEphemeral(isEphemeral);
                intent.setVisibleToEphemeral(visibleToEphemeral);
                intent.setVisibleToEphemeral(visibleToEphemeral || isWebBrowsableIntent(intent));

                // adjust activity flags when we implicitly expose it via a browsable filter
                if (!hasVisibleToEphemeral && intent.isVisibleToEphemeral()) {
                    s.info.flags |= ServiceInfo.FLAG_VISIBLE_TO_EPHEMERAL;
                }
                s.intents.add(intent);
                s.intents.add(intent);
            } else if (parser.getName().equals("meta-data")) {
            } else if (parser.getName().equals("meta-data")) {
                if ((s.metaData=parseMetaData(res, parser, s.metaData,
                if ((s.metaData=parseMetaData(res, parser, s.metaData,
@@ -4620,6 +4649,12 @@ public class PackageParser {
        return s;
        return s;
    }
    }


    private boolean isWebBrowsableIntent(IntentInfo intent) {
        return intent.hasAction(Intent.ACTION_VIEW)
                && intent.hasCategory(Intent.CATEGORY_BROWSABLE)
                && (intent.hasDataScheme("http") || intent.hasDataScheme("https"));
    }

    private boolean parseAllMetaData(Resources res, XmlResourceParser parser, String tag,
    private boolean parseAllMetaData(Resources res, XmlResourceParser parser, String tag,
            Component<?> outInfo, String[] outError) throws XmlPullParserException, IOException {
            Component<?> outInfo, String[] outError) throws XmlPullParserException, IOException {
        int outerDepth = parser.getDepth();
        int outerDepth = parser.getDepth();