Skip to content

Commit

Permalink
[Xamarin.Android.Build.Tasks] add //manifest/queries for API 30 (dotn…
Browse files Browse the repository at this point in the history
…et#4846)

Context: https://developer.android.com/preview/privacy/package-visibility#package-name

If using Fast Deployment with an API 30 device or emulator and
`AndroidManifest.xml` sets `//uses-sdk/@android:targetSdkVersion`=30,
the app will crash on startup with:

	I AppsFilter: interaction: PackageSetting{f346c3d com.companyname.app72/10152} -> PackageSetting{67adc32 Mono.Android.Platform.ApiLevel_30/10151} BLOCKED
	…
	E AndroidRuntime: java.lang.RuntimeException: Unable to get provider mono.MonoRuntimeProvider: java.lang.RuntimeException: Unable to find application Mono.Android.Platform.ApiLevel_30!
	E AndroidRuntime:        at android.app.ActivityThread.installProvider(ActivityThread.java:7135)
	E AndroidRuntime:        at android.app.ActivityThread.installContentProviders(ActivityThread.java:6675)
	E AndroidRuntime:        at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6592)
	E AndroidRuntime:        at android.app.ActivityThread.access$1300(ActivityThread.java:233)
	E AndroidRuntime:        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1896)
	E AndroidRuntime:        at android.os.Handler.dispatchMessage(Handler.java:106)
	E AndroidRuntime:        at android.os.Looper.loop(Looper.java:223)
	E AndroidRuntime:        at android.app.ActivityThread.main(ActivityThread.java:7523)
	E AndroidRuntime:        at java.lang.reflect.Method.invoke(Native Method)
	E AndroidRuntime:        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
	E AndroidRuntime:        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:941)
	E AndroidRuntime: Caused by: java.lang.RuntimeException: Unable to find application Mono.Android.Platform.ApiLevel_30!
	E AndroidRuntime:        at mono.MonoRuntimeProvider.attachInfo(MonoRuntimeProvider.java:38)
	E AndroidRuntime:        at android.app.ActivityThread.installProvider(ActivityThread.java:7130)
	E AndroidRuntime:        ... 10 more
	E AndroidRuntime: Caused by: android.content.pm.PackageManager$NameNotFoundException: Mono.Android.Platform.ApiLevel_30
	E AndroidRuntime:        at android.app.ApplicationPackageManager.getApplicationInfoAsUser(ApplicationPackageManager.java:419)
	E AndroidRuntime:        at android.app.ApplicationPackageManager.getApplicationInfo(ApplicationPackageManager.java:408)
	E AndroidRuntime:        at mono.MonoRuntimeProvider.attachInfo(MonoRuntimeProvider.java:35)
	E AndroidRuntime:        ... 11 more

On Android 11, any calls to [`PackageManager.getApplicationInfo()`][0],
as is done in [`MonoRuntimeProvider.java`][1], will now throw
`PackageManager.NameNotFoundException` *unless* the requested package
name is explicitly listed in the new (and undocumented)
`/manifest/queries/package/@android:name` attribute:

	<?xml version="1.0" encoding="utf-8"?>
	<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.xamarin.android.helloworld">
	    <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="30" />
	    …
	    <queries>
	        <package android:name="Mono.Android.Platform.ApiLevel_30" />
	        <package android:name="Mono.Android.DebugRuntime" />
	    </queries>
	</manifest>

Update `ManifestDocument.cs` to generate the appropriate
`//queries/package` elements when:

  * `$(AndroidUseSharedRuntime)` is True
  * `android:targetSdkVersion` is 30 or higher

The only problem with the new `<queries/>` element is that older
versions of `aapt2` will fail with:

	error APT2263: unexpected element <queries> found in <manifest>.

Luckily in cbdb5d1, we bumped to a version of `aapt2` that works.
`aapt` appears to already work; it must not do any validation against
new XML element names.

I added a test for this scenario as well.

Finally, bump to manifest-merger 27.0.0 (2c6f5cd), as that is also
required to fully support the new `<queries/>` element.

[0]: https://developer.android.com/reference/android/content/pm/PackageManager#getApplicationInfo(java.lang.String,%20int)
[1]: https://github.com/xamarin/xamarin-android/blob/17db4dc1e8ba6438fc02fdbb0e2fbe6c16fb4b58/src/Xamarin.Android.Build.Tasks/Resources/MonoRuntimeProvider.Shared.java#L35
  • Loading branch information
jonathanpeppers authored Jun 23, 2020
1 parent 88215f9 commit 86737ca
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 1 deletion.
28 changes: 28 additions & 0 deletions Documentation/release-notes/api30-queries.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#### Application and library build and deployment

Starting in [Android 11][0], for Fast Deployment to work on an API 30
device or emulator, the following `<queries/>` entries must be present in
`AndroidManifest.xml`:

```xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.xamarin.android.helloworld">
<uses-sdk android:targetSdkVersion="30" />
<!-- ... -->
<queries>
<package android:name="Mono.Android.DebugRuntime" />
<package android:name="Mono.Android.Platform.ApiLevel_30" />
</queries>
</manifest>
```

These will be generated if `$(AndroidUseSharedRuntime)` is `true` and
`android:targetSdkVersion` is 30 or higher.

### manifestmerger.jar version update to 27.0.0

The version of the [manifest merger][1] included in Xamarin.Android
has been updated from 26.5.0 to 27.0.0.

[0]: https://developer.android.com/preview/privacy/package-visibility#package-name
[1]: https://developer.android.com/studio/build/manifest-merge.html
1 change: 1 addition & 0 deletions src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ void Run (DirectoryAssemblyResolver res)
manifest.MultiDex = MultiDex;
manifest.NeedsInternet = NeedsInternet;
manifest.InstantRunEnabled = InstantRunEnabled;
manifest.UseSharedRuntime = UseSharedRuntime;

var additionalProviders = manifest.Merge (Log, cache, allJavaTypes, ApplicationJavaClass, EmbedAssemblies, BundledWearApplicationName, MergedManifestDocuments);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -835,5 +835,34 @@ public void AllServiceAttributeProperties ([Values ("legacy", "manifestmerger.ja
Assert.AreEqual (expectedOutput, string.Join (" ", e.Attributes ()));
}
}

[Test]
public void Queries_API30 ([Values (true, false)] bool useAapt2)
{
if (!CommercialBuildAvailable) {
Assert.Ignore ("$(AndroidUseSharedRuntime) is required for this test.");
return;
}

var proj = new XamarinAndroidApplicationProject {
AndroidUseSharedRuntime = true,
EmbedAssembliesIntoApk = false,
};
proj.SetProperty ("AndroidUseAapt2", useAapt2.ToString ());
proj.AndroidManifest = proj.AndroidManifest.Replace ("<uses-sdk />", "<uses-sdk android:targetSdkVersion=\"30\" />");
using (var b = CreateApkBuilder ()) {
Assert.IsTrue (b.Build (proj), "Build should have succeeded");

string manifest = b.Output.GetIntermediaryAsText (Path.Combine ("android", "AndroidManifest.xml"));
var doc = XDocument.Parse (manifest);
var ns = XNamespace.Get ("http://schemas.android.com/apk/res/android");
var names = doc.Element ("manifest")?
.Element ("queries")?
.Elements ("package")?
.Select (e => e.Attribute (ns + "name")?.Value);
StringAssertEx.Contains ("Mono.Android.DebugRuntime", names);
StringAssertEx.Contains ("Mono.Android.Platform.ApiLevel_30", names);
}
}
}
}
14 changes: 14 additions & 0 deletions src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocument.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ internal class ManifestDocument
public bool MultiDex { get; set; }
public bool NeedsInternet { get; set; }
public bool InstantRunEnabled { get; set; }
public bool UseSharedRuntime { get; set; }
public string VersionCode {
get {
XAttribute attr = doc.Root.Attribute (androidNs + "versionCode");
Expand Down Expand Up @@ -404,6 +405,8 @@ public IList<string> Merge (TaskLoggingHelper log, TypeDefinitionCache cache, Li
AddUsesPermissions (app);
AddUsesFeatures (app);
AddSupportsGLTextures (app);
if (UseSharedRuntime && targetSdkVersionValue >= 30)
AddQueries (app, targetSdkVersionValue);

ReorderActivityAliases (log, app);
ReorderElements (app);
Expand Down Expand Up @@ -826,6 +829,17 @@ void AddUsesPermissions (XElement application)
application.AddBeforeSelf (upa.ToElement (PackageName));
}

void AddQueries (XElement application, int targetSdkVersion)
{
var queries = application.Parent.Element ("queries");
if (queries == null) {
application.AddAfterSelf (queries = new XElement ("queries"));
}

queries.Add (new XElement ("package", new XAttribute (androidNs + "name", "Mono.Android.DebugRuntime")));
queries.Add (new XElement ("package", new XAttribute (androidNs + "name", $"Mono.Android.Platform.ApiLevel_{targetSdkVersion}")));
}

void AddUsesConfigurations (XElement application, IEnumerable<UsesConfigurationAttribute> configs)
{
foreach (var uca in configs)
Expand Down
2 changes: 1 addition & 1 deletion src/manifestmerger/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ repositories {

dependencies {
// https://mvnrepository.com/artifact/com.android.tools.build/manifest-merger
compile group: 'com.android.tools.build', name: 'manifest-merger', version: '26.5.0'
compile group: 'com.android.tools.build', name: 'manifest-merger', version: '27.0.0'
}

sourceSets {
Expand Down

0 comments on commit 86737ca

Please sign in to comment.