Commit e5b1c92
[Xamarin.Android.Build.Tasks] <GenerateJavaStubs /> generates a shorter acw-map.txt (#1131)
Fixes: https://bugzilla.xamarin.com/show_bug.cgi?id=61073
Context: dotnet/java-interop@429dc2a
Methods such as `JNIEnv.GetJniName(Type)` and
`TypeManager.GetJavaToManagedType(string)` are used to map
`System.Type` values to JNI type references, and to map from JNI type
references to `System.Type`-compatible values. Once upon a time this
was done through System.Reflection; see
[`JavaNativeTypeManager.ToJniName(Type)`][to-jni] and
[`JavaNativeTypeManager.ToCliType(string)`][from-jni].
[to-jni]: https://github.com/xamarin/java.interop/blob/5e77d91085820611ce3eda65537a6e7c19df90ef/src/Java.Interop.Tools.TypeNameMappings/Java.Interop.Tools.TypeNameMappings/JavaNativeTypeManager.cs#L147-L151
[from-jni]: https://github.com/xamarin/java.interop/blob/5e77d91085820611ce3eda65537a6e7c19df90ef/src/Java.Interop.Tools.TypeNameMappings/Java.Interop.Tools.TypeNameMappings/JavaNativeTypeManager.cs#L117-L126
Heavy use of reflection was deemed a terrible mistake, so as a fast
path we added support for ["type mapping files"][typemap-format], a
pair of files generated at packaging time. The `typemap.jm` file
contained mappings from JNI type references to Assembly-Qualified
type names, while the `typemap.mj` file contained mappings from
Assembly-Qualified type names to JNI type references.
(Reflection was preserved as a fallback in case we missed something
in the introduction of type mapping files.)
[typemap-format]: https://github.com/xamarin/java.interop/blob/5e77d91085820611ce3eda65537a6e7c19df90ef/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/TypeNameMapGenerator.cs#L15-L57
For example, `typemap.jm` would contain:
android/app/Activity
Android.App.Activity, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=84e04ff9cfb79065
The type mapping files are found in the intermediate dir after a
build in `obj/$(Configuration)/acw-map.txt`, or `$(_AcwMapFile)`.
(Use `strings` in order to easily read the contents of a file; the
type mapping files are in a baroque binary file format.)
Unfortunately, Assembly-Qualified names interact with
[`AssemblyVersionAttribute`][ava]. `AssemblyVersionAttribute` is used
to specify the assembly version, and the C# compiler allows this
attribute to contain *wildcards*:
[ava]: https://msdn.microsoft.com/en-us/library/system.reflection.assemblyversionattribute(v=vs.110).aspx
[assembly: AssemblyVersion ("1.0.0.*")]
If the `AssemblyVersionAttribute` contains a wildcard, then the
assembly version will change on *every build*. For example, on the
first build, there might be an Assembly-Qualified name of:
Foo.Bar, Example, Version=1.0.0.0, Culture=neutral, PublicKeyToken=
On the next build, it may change to:
Foo.Bar, Example, Version=1.0.0.1, Culture=neutral, PublicKeyToken=
The type mapping files use the Assembly-Qualified names, but they are
only rebuilt when `<GenerateJavaStubs>` executes, which is not
necessarily when the assembly changes. (This is intentional for
commercial fast deployment support: if the Java Callable Wrappers or
type mapping files changed, then the `.apk` would need to be rebuilt
and redeployed, slowing down the deployment+debug cycle.)
In short, type mapping files are acting as a cache, and that cache
can be invalidated by using the `[AssemblyVersion]` custom attribute.
The result is that it's possible to raise a
`Java.Lang.ClassNotFoundException` by simply rebuilding and
re-running a project:
1. Create a new Xamarin.Android application project.
2. Add an `[AssemblyVersion]` custom attribute which contains a
wildcard.
3. Run the application in Debug configuration, with fast deployment
enabled (which is the default with the commercial SDK).
4. Touch a `.cs` file in the application project, and re-run the app.
The app *should* work. Instead, it may fail:
JNIEnv.FindClass(Type) caught unexpected exception: Java.Lang.ClassNotFoundException: md50039d44cbb3b194ba4f4e52eaa252795.BrowserPagerAdapter
---> Java.Lang.ClassNotFoundException: Didn't find class "md50039d44cbb3b194ba4f4e52eaa252795.BrowserPagerAdapter" on path: DexPathList[[zip file "/data/app/com.outcoder.browser-1/base.apk"],nativeLibraryDirectories=[/data/app/com.outcoder.browser-1/lib/arm, /vendor/lib, /system/lib]]
--- End of inner exception stack trace ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <657aa8fea4454dc898a9e5f379c58734>:0
at Java.Interop.JniEnvironment+StaticMethods.CallStaticObjectMethod (Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo method, Java.Interop.JniArgumentValue* args) [0x00069] in <54816278eed9488eb28d3597fecd78f8>:0
at Android.Runtime.JNIEnv.CallStaticObjectMethod (System.IntPtr jclass, System.IntPtr jmethod, Android.Runtime.JValue* parms) [0x0000e] in <28e323a707a2414f8b493f6d4bb27c8d>:0
at Android.Runtime.JNIEnv.CallStaticObjectMethod (System.IntPtr jclass, System.IntPtr jmethod, Android.Runtime.JValue[] parms) [0x00017] in <28e323a707a2414f8b493f6d4bb27c8d>:0
at Android.Runtime.JNIEnv.FindClass (System.String classname) [0x0003d] in <28e323a707a2414f8b493f6d4bb27c8d>:0
at Android.Runtime.JNIEnv.FindClass (System.Type type) [0x00015] in <28e323a707a2414f8b493f6d4bb27c8d>:0
--- End of managed Java.Lang.ClassNotFoundException stack trace ---
java.lang.ClassNotFoundException: md50039d44cbb3b194ba4f4e52eaa252795.BrowserPagerAdapter
at java.lang.Class.classForName(Native Method)
at java.lang.Class.forName(Class.java:309)
...
Caused by: java.lang.ClassNotFoundException: Didn't find class "md50039d44cbb3b194ba4f4e52eaa252795.BrowserPagerAdapter" on path: DexPathList[[zip file "/data/app/com.outcoder.browser-1/base.apk"],nativeLibraryDirectories=[/data/app/com.outcoder.browser-1/lib/arm, /vendor/lib, /system/lib]]
...
Fix this by no longer using Assembly-Qualified names in the type
mapping files. Instead, use a *partially* Assembly-Qualified name,
which is just the type name and assembly, no version, culture, or
PublicKeyToken information:
Foo.Bar, Example
Bump to Java.Interop/master/429dc2a, which updates
`TypeNameMapGenerator` to generate partial Assembly-Qualified names.
Update `JNIEnv.GetJniName(Type)` to use a partial Assembly-Qualified
name for the `monodroid_typemap_managed_to_java()` invocation.
Update the `<GenerateJavaStubs>` task so that it no longer emits
lines containing full Assembly-Qualified names. (It was already
emitting partially Assembly-Qualified names.)
Fix `JnienvTest` so that the correct format is tested.
Add a test case to ensure that using `[assembly:AssemblyVersion]`
doesn't result in changes `acw-map.txt`.1 parent eb175c5 commit e5b1c92
File tree
5 files changed
+39
-7
lines changed- external
- src
- Mono.Android
- Android.Runtime
- Test/Java.Interop
- Xamarin.Android.Build.Tasks
- Tasks
- Tests/Xamarin.Android.Build.Tests
5 files changed
+39
-7
lines changedSubmodule Java.Interop updated from 57d5d51 to 429dc2a
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
880 | 880 | | |
881 | 881 | | |
882 | 882 | | |
883 | | - | |
| 883 | + | |
884 | 884 | | |
885 | 885 | | |
886 | 886 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
388 | 388 | | |
389 | 389 | | |
390 | 390 | | |
| 391 | + | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
391 | 396 | | |
392 | 397 | | |
393 | 398 | | |
394 | | - | |
395 | | - | |
396 | | - | |
397 | | - | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
398 | 403 | | |
399 | 404 | | |
400 | 405 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
163 | 163 | | |
164 | 164 | | |
165 | 165 | | |
166 | | - | |
167 | 166 | | |
168 | 167 | | |
169 | 168 | | |
| |||
Lines changed: 28 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
| 5 | + | |
5 | 6 | | |
6 | 7 | | |
7 | 8 | | |
| |||
174 | 175 | | |
175 | 176 | | |
176 | 177 | | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
177 | 205 | | |
178 | 206 | | |
179 | 207 | | |
| |||
0 commit comments