Description
Context: https://issuetracker.google.com/issues/116182838
Context: 4073f3e
In 2018-September, Google started providing various XML files which were not valid XML. We worked around this in commit 4073f3e by using HtmlAgilityPack to "loosely parse" the XML.
The problem with commit 4073f3e is that the resulting "intermediate" XML isn't "the same". Given XML of:
<!-- valid XML; API-28 -->
<item name="android.accounts.AccountManager android.accounts.AccountManagerFuture<android.os.Bundle> addAccount(java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler)">
<annotation name="android.support.annotation.RequiresPermission">
<val name="value" val=""android.permission.MANAGE_ACCOUNTS"" />
<val name="apis" val=""..22"" />
</annotation>
</item>
<!-- invalid XML; API-29 -->
<item name="android.accounts.AccountManager android.accounts.AccountManagerFuture<android.os.Bundle> addAccount(java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler)">
<annotation name="androidx.annotation.RequiresPermission">
<val name="value" val=""android.permission.MANAGE_ACCOUNTS"" />
<val name="apis" val=""..22"" />
</annotation>
</item>
Consider this fragment:
using System;
using System.Collections.Generic;
using System.Linq;
using Xamarin.AndroidTools.AnnotationSupport;
class App {
public static void Main ()
{
Console.WriteLine ("- API-28");
var a28 = AndroidAnnotationsSupport.ParseArchive ("$HOME/android-toolchain/sdk/platforms/android-28/data/annotations.zip");
Console.WriteLine ("- API-29");
var a29 = AndroidAnnotationsSupport.ParseArchive ("$HOME/android-toolchain/sdk/platforms/android-29/data/annotations.zip");
var addAccount_28 = a28.Where (a => a.TypeName == "android.accounts.AccountManager" && a.MemberName == "addAccount")
.First ();
var addAccount_29 = a29.Where (a => a.TypeName == "android.accounts.AccountManager" && a.MemberName == "addAccount")
.First ();
Console.WriteLine ($"API-28: {addAccount_28}");
foreach (var a in addAccount_28.Annotations) {
Console.WriteLine ($" Name={a.Name}");
var v = string.Join (", ", a.Values);
Console.WriteLine ($" Values={v}");
}
Console.WriteLine ($"API-29: {addAccount_29}");
foreach (var a in addAccount_29.Annotations) {
Console.WriteLine ($" Name={a.Name}");
var v = string.Join (", ", a.Values);
Console.WriteLine ($" Values={v}");
}
}
}
When run, we get:
API-28: @RequiresPermission(value=System.String[], apis=System.String[]) android.accounts.AccountManager.addAccount(java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler)
Name=RequiresPermission
Values=value = "android.permission.MANAGE_ACCOUNTS", apis = "..22"
API-29: @RequiresPermission(value=System.String[], apis=System.String[]) android.accounts.AccountManager.addAccount(java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler)
Name=RequiresPermission
Values=value = "android.permission.MANAGE_ACCOUNTS", apis = "..22"
Note how the Values
value changes, from android.permission.MANAGE_ACCOUNTS
to "android.permission.MANAGE_ACCOUNTS"
. This value eventually becomes the RequiresPermission
attribute value, resulting in "downstream" Mono.Android.dll
changes:
-[global::Android.Runtime.RequiresPermission ("android.permission.MANAGE_ACCOUNTS")]
+[global::Android.Runtime.RequiresPermission ("quot;android.permission.MANAGE_ACCOUNTS"")]
which results in hundreds of "API changes" reported by the _CheckApiCompatibility
target.
For Great Sanity™, we want the "invalid XML" path to produce the same value as the "valid XML" path, especially considering that the //item/annotation/val/@val
attribute value is the same.