Adds queries tag to manifest
This change adds support for a new <queries> tag as a child of the <manifest> tag, allowing a package to declare the intents it intends to use to query for other apps on device. Bug: 136675067 Test: build and boot Change-Id: Ic8b40cabddee4b6404c220901efeaae680661c0c
This commit is contained in:
@@ -66,6 +66,7 @@ import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.TypedArray;
|
||||
import android.content.res.XmlResourceParser;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.FileUtils;
|
||||
@@ -2445,6 +2446,8 @@ public class PackageParser {
|
||||
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
|
||||
return null;
|
||||
|
||||
} else if (tagName.equals("queries")) {
|
||||
parseQueries(pkg, res, parser, flags, outError);
|
||||
} else {
|
||||
Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName()
|
||||
+ " at " + mArchiveSourcePath + " "
|
||||
@@ -3538,6 +3541,9 @@ public class PackageParser {
|
||||
owner.mRequiredAccountType = requiredAccountType;
|
||||
}
|
||||
|
||||
owner.mForceQueryable =
|
||||
sa.getBoolean(R.styleable.AndroidManifestApplication_forceQueryable, false);
|
||||
|
||||
if (sa.getBoolean(
|
||||
com.android.internal.R.styleable.AndroidManifestApplication_debuggable,
|
||||
false)) {
|
||||
@@ -3953,7 +3959,6 @@ public class PackageParser {
|
||||
ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PROFILEABLE_BY_SHELL;
|
||||
}
|
||||
XmlUtils.skipCurrentTag(parser);
|
||||
|
||||
} else {
|
||||
if (!RIGID_PARSER) {
|
||||
Slog.w(TAG, "Unknown element under <application>: " + tagName
|
||||
@@ -4000,6 +4005,67 @@ public class PackageParser {
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean parseQueries(Package owner, Resources res, XmlResourceParser parser, int flags,
|
||||
String[] outError)
|
||||
throws IOException, XmlPullParserException {
|
||||
|
||||
final int outerDepth = parser.getDepth();
|
||||
int type;
|
||||
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
|
||||
&& (type != XmlPullParser.END_TAG
|
||||
|| parser.getDepth() > outerDepth)) {
|
||||
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
|
||||
continue;
|
||||
}
|
||||
if (parser.getName().equals("intent")) {
|
||||
QueriesIntentInfo intentInfo = new QueriesIntentInfo();
|
||||
if (!parseIntent(res, parser, true /*allowGlobs*/, true /*allowAutoVerify*/,
|
||||
intentInfo, outError)) {
|
||||
return false;
|
||||
}
|
||||
Intent intent = new Intent();
|
||||
if (intentInfo.countActions() != 1) {
|
||||
outError[0] = "intent tags must contain exactly one action.";
|
||||
return false;
|
||||
}
|
||||
intent.setAction(intentInfo.getAction(0));
|
||||
for (int i = 0, max = intentInfo.countCategories(); i < max; i++) {
|
||||
intent.addCategory(intentInfo.getCategory(i));
|
||||
}
|
||||
Uri data = null;
|
||||
String dataType = null;
|
||||
if (intentInfo.countDataTypes() > 1) {
|
||||
outError[0] = "intent tag may have at most one data type.";
|
||||
return false;
|
||||
}
|
||||
if (intentInfo.countDataSchemes() > 1) {
|
||||
outError[0] = "intent tag may have at most one data scheme.";
|
||||
return false;
|
||||
}
|
||||
if (intentInfo.countDataTypes() == 1) {
|
||||
data = Uri.fromParts(intentInfo.getDataType(0), "", null);
|
||||
}
|
||||
if (intentInfo.countDataSchemes() == 1) {
|
||||
dataType = intentInfo.getDataScheme(0);
|
||||
}
|
||||
intent.setDataAndType(data, dataType);
|
||||
owner.mQueriesIntents = ArrayUtils.add(owner.mQueriesIntents, intent);
|
||||
} else if (parser.getName().equals("package")) {
|
||||
final TypedArray sa = res.obtainAttributes(parser,
|
||||
com.android.internal.R.styleable.AndroidManifestQueriesPackage);
|
||||
final String packageName =
|
||||
sa.getString(R.styleable.AndroidManifestQueriesPackage_name);
|
||||
if (TextUtils.isEmpty(packageName)) {
|
||||
outError[0] = "Package name is missing from package tag.";
|
||||
return false;
|
||||
}
|
||||
owner.mQueriesPackages =
|
||||
ArrayUtils.add(owner.mQueriesPackages, packageName.intern());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if one of the IntentFilter as both actions DEFAULT / VIEW and a HTTP/HTTPS data URI
|
||||
*/
|
||||
@@ -6514,6 +6580,9 @@ public class PackageParser {
|
||||
// The major version code declared for this package.
|
||||
public int mVersionCodeMajor;
|
||||
|
||||
// Whether the package declares that it should be queryable by all normal apps on device.
|
||||
public boolean mForceQueryable;
|
||||
|
||||
// Return long containing mVersionCode and mVersionCodeMajor.
|
||||
public long getLongVersionCode() {
|
||||
return PackageInfo.composeLongVersionCode(mVersionCodeMajor, mVersionCode);
|
||||
@@ -6619,6 +6688,9 @@ public class PackageParser {
|
||||
/** Whether or not the package is a stub and must be replaced by the full version. */
|
||||
public boolean isStub;
|
||||
|
||||
public ArrayList<String> mQueriesPackages;
|
||||
public ArrayList<Intent> mQueriesIntents;
|
||||
|
||||
@UnsupportedAppUsage
|
||||
public Package(String packageName) {
|
||||
this.packageName = packageName;
|
||||
@@ -7122,6 +7194,9 @@ public class PackageParser {
|
||||
use32bitAbi = (dest.readInt() == 1);
|
||||
restrictUpdateHash = dest.createByteArray();
|
||||
visibleToInstantApps = dest.readInt() == 1;
|
||||
mForceQueryable = dest.readBoolean();
|
||||
mQueriesIntents = dest.createTypedArrayList(Intent.CREATOR);
|
||||
mQueriesPackages = dest.createStringArrayList();
|
||||
}
|
||||
|
||||
private static void internStringArrayList(List<String> list) {
|
||||
@@ -7247,6 +7322,9 @@ public class PackageParser {
|
||||
dest.writeInt(use32bitAbi ? 1 : 0);
|
||||
dest.writeByteArray(restrictUpdateHash);
|
||||
dest.writeInt(visibleToInstantApps ? 1 : 0);
|
||||
dest.writeBoolean(mForceQueryable);
|
||||
dest.writeTypedList(mQueriesIntents);
|
||||
dest.writeList(mQueriesPackages);
|
||||
}
|
||||
|
||||
|
||||
@@ -8257,6 +8335,8 @@ public class PackageParser {
|
||||
}
|
||||
}
|
||||
|
||||
public static final class QueriesIntentInfo extends IntentInfo {}
|
||||
|
||||
public final static class ActivityIntentInfo extends IntentInfo {
|
||||
@UnsupportedAppUsage
|
||||
public Activity activity;
|
||||
|
||||
@@ -4598,6 +4598,7 @@
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.DeviceDefault.Light.DarkActionBar"
|
||||
android:defaultToDeviceProtectedStorage="true"
|
||||
android:forceQueryable="true"
|
||||
android:directBootAware="true">
|
||||
<activity android:name="com.android.internal.app.ChooserActivity"
|
||||
android:theme="@style/Theme.DeviceDefault.Resolver"
|
||||
|
||||
@@ -1743,6 +1743,13 @@
|
||||
- {@code true} for apps with targetSdkVersion < 29.
|
||||
-->
|
||||
<attr name="requestLegacyExternalStorage" format="boolean" />
|
||||
|
||||
<!-- If {@code true} this app declares that it should be visible to all other apps on
|
||||
device, regardless of what they declare via the {@code queries} tags in their
|
||||
manifest.
|
||||
|
||||
The default value is {@code false}. -->
|
||||
<attr name="forceQueryable" format="boolean" />
|
||||
</declare-styleable>
|
||||
<!-- The <code>permission</code> tag declares a security permission that can be
|
||||
used to control access from other packages to specific components or
|
||||
@@ -1977,6 +1984,12 @@
|
||||
<attr name="name" />
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="AndroidManifestQueries" parent="AndroidManifest" />
|
||||
<declare-styleable name="AndroidManifestQueriesPackage" parent="AndroidManifestQueries">
|
||||
<attr name="name" />
|
||||
</declare-styleable>
|
||||
<declare-styleable name="AndroidManifestQueriesIntent" parent="AndroidManifestQueries" />
|
||||
|
||||
|
||||
<!-- The <code>static-library</code> tag declares that this apk is providing itself
|
||||
as a static shared library for other applications to use. Any app can declare such
|
||||
@@ -2477,6 +2490,7 @@
|
||||
<!-- High dynamic range color mode. -->
|
||||
<enum name="hdr" value="2" />
|
||||
</attr>
|
||||
<attr name="forceQueryable" format="boolean" />
|
||||
</declare-styleable>
|
||||
|
||||
<!-- The <code>activity-alias</code> tag declares a new
|
||||
|
||||
@@ -1700,6 +1700,12 @@
|
||||
<!-- Add packages here -->
|
||||
</string-array>
|
||||
|
||||
<string-array name="config_forceQueryablePackages" translatable="false">
|
||||
<item>com.android.settings</item>
|
||||
<!-- Add packages here -->
|
||||
</string-array>
|
||||
|
||||
|
||||
<!-- Component name of the default wallpaper. This will be ImageWallpaper if not
|
||||
specified -->
|
||||
<string name="default_wallpaper_component" translatable="false">@null</string>
|
||||
|
||||
@@ -786,6 +786,7 @@
|
||||
<java-symbol type="string" name="widget_default_class_name" />
|
||||
<java-symbol type="string" name="emergency_calls_only" />
|
||||
<java-symbol type="array" name="config_ephemeralResolverPackage" />
|
||||
<java-symbol type="array" name="config_forceQueryablePackages" />
|
||||
<java-symbol type="string" name="eventTypeAnniversary" />
|
||||
<java-symbol type="string" name="eventTypeBirthday" />
|
||||
<java-symbol type="string" name="eventTypeCustom" />
|
||||
|
||||
@@ -22,6 +22,7 @@ import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.ConfigurationInfo;
|
||||
@@ -557,6 +558,9 @@ public class PackageParserTest {
|
||||
pkg.mRequiredForAllUsers = true;
|
||||
pkg.visibleToInstantApps = true;
|
||||
pkg.use32bitAbi = true;
|
||||
pkg.mForceQueryable = true;
|
||||
pkg.mQueriesPackages = new ArrayList<>(Arrays.asList("foo27"));
|
||||
pkg.mQueriesIntents = new ArrayList<>(Arrays.asList(new Intent("foo28")));
|
||||
}
|
||||
|
||||
private static void assertAllFieldsExist(PackageParser.Package pkg) throws Exception {
|
||||
|
||||
@@ -386,6 +386,9 @@ bool ManifestFixer::BuildRules(xml::XmlActionExecutor* executor,
|
||||
manifest_action["package-verifier"];
|
||||
manifest_action["meta-data"] = meta_data_action;
|
||||
manifest_action["uses-split"].Action(RequiredNameIsJavaPackage);
|
||||
manifest_action["queries"]["package"].Action(RequiredNameIsJavaPackage);
|
||||
manifest_action["queries"]["intent"] = intent_filter_action;
|
||||
// TODO: more complicated component name tag
|
||||
|
||||
manifest_action["key-sets"]["key-set"]["public-key"];
|
||||
manifest_action["key-sets"]["upgrade-key-set"];
|
||||
|
||||
Reference in New Issue
Block a user