Troubleshooting Getting Diagnostic Information

Transcription

Troubleshooting Getting Diagnostic Information
Troubleshooting
Getting Diagnostic Information
Xamarin.Android has a few places to look when tracking down various bugs. These include:
1. Diagnostic MSBuild output.
2. Device deployment logs.
3. Android Debug Log Output.
Diagnostic MSBuild Output
Diagnostic MSBuild can contain additional information relating to package building and may contain some package deployment information.
To enable diagnostic MSBuild output within Visual Studio:
1. Click Tools > Options...
2. In the left-hand tree view, select Projects and Solutions > Build and Run
3. In the right-hand panel, set the MSBuild build output verbosity dropdown to Diagnostic
4. Click OK
5. Clean and rebuild your package.
6. Diagnostic output is visible within the Output panel.
To enable diagnostic MSBuild outout within Xamarin Studio/OS X:
1. Click Xamarin Studio > Preferences...
2. In the left-hand tree view, select Projects > Build
3. In the right-hand panel, set the Log verbosity drop-down to Diagnostic
4. Click OK
5. Restart Xamarin Studio
6. Clean and rebuild your package.
7. Diagnostic output is visible within the Errors Pad ( View > Pads > Errors ), by clicking the Build Output button.
Device Deployment Logs
To enable device deployment logging within Visual Studio:
1. Tools > Options...>
2. In the left-hand tree view, select Xamarin > Android Settings
3. In the right-hand panel, enable the [X] extension debug logging (writes monodroid.log to your desktop) check box.
4. Log messages are written to the monodroid.log file on your desktop.
Xamarin Studio always writes device deployment logs. FInding them is slightly more difficult; a AndroidUtils log file is created for every day +
time that a deployment occurs, e.g. AndroidTools-2012-10-24__12-35-45.log.
On Windows, log files are written to %LOCALAPPDATA%\XamarinStudio-{VERSION}\Logs .
On OS X, log files are written to $HOME/Library/Logs/XamarinStudio-{VERSION} .
Android Debug Log Output
Android will write many messages to the Android Debug Log. Xamarin.Android uses Android system properties to control the generation of
additional messages to the Android Debug Log. Android system properties can be set through the setprop command within the Android Debug
Bridge (adb):
adb shell setprop PROPERTY_NAME PROPERTY_VALUE
System properties are read during process startup, and thus must be either set before the application is launched or the application must be
restarted after the system properties are changed.
Xamarin.Android System Properties
Xamarin.Android supports the following system properties:
debug.mono.debug: If a non-empty string, this is equivalent to `mono --debug`.
debug.mono.env: A pipe-separated ('|') list of environment variables to export during application startup, before mono has been
initialized. This allows setting environment variables that control mono logging.
Note: Since the value is '|'-separated, the value must have an extra level of quoting, as the `adb shell` command will remove a set
of quotes.
Note: Android system property values can be no longer than 92 characters in length.
Example:
adb shell setprop debug.mono.env "'MONO_LOG_LEVEL=info|MONO_LOG_MASK=asm'"
debug.mono.log: A comma-separated (',') list of components that should print additional messages to the Android Debug Log. By
default, nothing is set. Components include:
all: Print all messages
gc: Print GC-related messages.
gref: Print (weak, global) reference allocation and deallocation messages.
lref: Print local reference allocation and deallocation messages.
Note: these are extremely verbose. Do not enable unless you really need to.
debug.mono.trace: Allows setting the `mono --trace=PROPERTY_VALUE` setting.
GC Messages
GC component messages can be viewed by setting the debug.mono.log system property to a value that contains gc.
GC messages are generated whenever the GC executes and provides information about how much work the GC did:
I/monodroid-gc(12331): GC cleanup summary: 81 objects tested - resurrecting 21.
Additional GC information such as timing information can be generated by setting the MONO_LOG_LEVEL environment variable to debug:
adb shell setprop debug.mono.env MONO_LOG_LEVEL=debug
This will result in (lots of) additional Mono messages, including these three of consequence:
D/Mono (15723): GC_BRIDGE num-objects 1 num_hash_entries 81226 sccs size 81223 init 0.00ms df1 285.36ms
sort 38.56ms dfs2 50.04ms setup-cb 9.95ms free-data 106.54ms user-cb 20.12ms clenanup 0.05ms links
5523436/5523436/5523096/1 dfs passes 1104 6883/11046605
D/Mono (15723): GC_MINOR: (Nursery full) pause 2.01ms, total 287.45ms, bridge 225.60 promoted 0K major
325184K los 1816K
D/Mono ( 2073): GC_MAJOR: (user request) pause 2.17ms, total 2.47ms, bridge 28.77 major 576K/576K los
0K/16K
In the GC_BRIDGE message, num-objects is the number of bridge objects this pass is considering, and num_hash_entries is the number
of objects processed during this invocation of the bridge code.
In the GC_MINOR and GC_MAJOR messages, total is the amount of time while the world is paused (no threads are executing), while bridge
is the amount of time taken in the bridge processing code (which deals with the Java VM). The world is not paused while bridge processing
occurs.
In general, the larger the value of num_hash_entries, the more time that the bridge collections will take, and the larger the total time
spent collecting will be.
Global Reference Messages
To enable Global Reference loggig (GREF) logging, the debug.mono.log system property must contain gref, e.g.:
adb shell setprop debug.mono.log gref
Xamarin.Android uses Android global references to provide mappings between Java instances and the associated managed instances, as
when invoking a Java method a Java instance needs to be provided to Java.
Unfortunately, Android emulators only allow 2000 global references to exist at a time. Hardware has a much higher limit of 52000 global
references. The lower limit can be problematic when running applications on the emulator, so knowing where the instance came from can be
very useful.
Note: the global reference count is internal to Xamarin.Android, and does not (and cannot) include global references taken out by other native
libraries loaded into the process. Use the global reference count as an estimate.
I/monodroid-gref(12405): +g+ grefc 108 gwrefc 0 obj-handle 0x40517468/L -> new-handle 0x40517468/L from
at Java.Lang.Object.RegisterInstance(IJavaObject instance, IntPtr value, JniHandleOwnership transfer)
I/monodroid-gref(12405):
at Java.Lang.Object.SetHandle(IntPtr value, JniHandleOwnership transfer)
I/monodroid-gref(12405):
at Java.Lang.Object..ctor(IntPtr handle, JniHandleOwnership transfer)
I/monodroid-gref(12405):
at Java.Lang.Thread+RunnableImplementor..ctor(System.Action handler, Boolean
removable)
I/monodroid-gref(12405):
at Java.Lang.Thread+RunnableImplementor..ctor(System.Action handler)
I/monodroid-gref(12405):
at Android.App.Activity.RunOnUiThread(System.Action action)
I/monodroid-gref(12405):
at Mono.Samples.Hello.HelloActivity.UseLotsOfMemory(Android.Widget.TextView
textview)
I/monodroid-gref(12405):
at Mono.Samples.Hello.HelloActivity.<OnCreate>m__3(System.Object o)
I/monodroid-gref(12405): handle 0x40517468; key_handle 0x40517468: Java Type:
`mono/java/lang/RunnableImplementor`; MCW type: `Java.Lang.Thread+RunnableImplementor`
I/monodroid-gref(12405): Disposing handle 0x40517468
I/monodroid-gref(12405): -g- grefc 107 gwrefc 0 handle 0x40517468/L from
at
Java.Lang.Object.Dispose(System.Object instance, IntPtr handle, IntPtr key_handle, JObjectRefType
handle_type)
I/monodroid-gref(12405):
at Java.Lang.Object.Dispose()
I/monodroid-gref(12405):
at Java.Lang.Thread+RunnableImplementor.Run()
I/monodroid-gref(12405):
at Java.Lang.IRunnableInvoker.n_Run(IntPtr jnienv, IntPtr native__this)
I/monodroid-gref(12405):
at System.Object.c200fe6f-ac33-441b-a3a0-47659e3f6750(IntPtr , IntPtr )
I/monodroid-gref(27679): +w+ grefc 1916 gwrefc 296 obj-handle 0x406b2b98/G -> new-handle 0xde68f4bf/W
from take_weak_global_ref_jni
I/monodroid-gref(27679): -w- grefc 1915 gwrefc 294 handle 0xde691aaf/W from take_global_ref_jni
There are four messages of consequence:
Global reference creation: these are the lines that start with +g+ , and will provide a stack trace for the creating code path.
Global reference destruction: these are the lines that start with -g- , and may provide a stack trace for the code path disposing of the
global reference. If the GC is disposing of the gref, no stack trace will be provided.
Weak global reference creation: these are the lines that start with +w+ .
Weak global reference destruction: these are lines that start with -w- .
In all messages, The grefc value is the count of global references that Xamarin.Android has created, while the grefwc value is the count of
weak global references that Xamarin.Android has created. The handle or obj-handle value is the JNI handle value, and the character after the '
/' is the type of handle value: /L for local reference, /G for global references, and /W for weak global references.
As part of the GC process, global references (+g+) are converted into weak global references (causing a +w+ and -g-), a Java-side GC is
kicked, and then the weak global reference is checked to see if it was collected. If it's still alive, a new gref is created around the weak ref
(+g+, -w-), otherwise the weak ref is destroyed (-w).
# Java instance is created and wrapped by a MCW
I/monodroid-gref(27679): +g+ grefc 2211 gwrefc 0 obj-handle 0x4066df10/L -> new-handle 0x4066df10/L from
...
I/monodroid-gref(27679): handle 0x4066df10; key_handle 0x4066df10: Java Type:
`android/graphics/drawable/TransitionDrawable`; MCW type: `Android.Graphics.Drawables.TransitionDrawable`
# A GC is being performed...
I/monodroid-gref(27679): +w+ grefc 1953 gwrefc 259 obj-handle 0x4066df10/G -> new-handle 0xde68f95f/W
from take_weak_global_ref_jni
I/monodroid-gref(27679): -g- grefc 1952 gwrefc 259 handle 0x4066df10/G from take_weak_global_ref_jni
# Object is still alive, as handle != null
# wref turned back into a gref
I/monodroid-gref(27679): *try_take_global obj=0x4976f080 -> wref=0xde68f95f handle=0x4066df10
I/monodroid-gref(27679): +g+ grefc 1930 gwrefc 39 obj-handle 0xde68f95f/W -> new-handle 0x4066df10/G from
take_global_ref_jni
I/monodroid-gref(27679): -w- grefc 1930 gwrefc 38 handle 0xde68f95f/W from take_global_ref_jni
# Object is dead, as handle == null
# wref is freed, no new gref created
I/monodroid-gref(27679): *try_take_global obj=0x4976f080 -> wref=0xde68f95f handle=0x0
I/monodroid-gref(27679): -w- grefc 1914 gwrefc 296 handle 0xde68f95f/W from take_global_ref_jni
There is one "interesing" wrinkle here: on targets running Android prior to 4.0, the gref value is equal to the address of the Java object in the
Android runtime's memory. (That is, the GC is a non-moving, conservative, collector, and it's handing out direct references to those objects.)
Thus after a +g+, +w+, -g-, +g+, -w- sequence, the resulting gref will have the same value as the original gref value. This makes grepping
through logs fairly straightforward.
Android 4.0, however, has a moving collector and no longer hands out direct references to Android runtime VM objects. Consequently, after a
+g+, +w+, -g-, +g+, -w- sequence, the gref value will be different. If the object survives multiple GCs, it will go by several gref values, making it
harder to determine where an instance was actually allocated from.
Offline Activation
If you're unable to activate Xamarin.Android on Windows, or unable to install the full version of Xamarin.Android on Mac OS X, please see the
Offline Activation page.
Can't upgrade to Indie/Business from Trial Account
If you recently purchased Xamarin.Android and previously started a Xamarin.Android Trial, you may need to complete the following steps to
get this license change picked up by Xamarin Studio or Visual Studio.
Close Xamarin Studio/Visual Studio
Remove all files from ~/Library/MonoAndroid on Mac or %PROGRAMDATA%\Mono for Android\License\ for Windows
Re-open Xamarin Studio/Visual Studio and build a Xamarin.Android project
This should get you up and running. If you continue to have problems, you may want to try an Offline Activation to complete the activation of
your workstation.
Receiving 'Activation Incomplete Error Message
This issue may occur when using Xamarin.Android for Visual Studio. To resolve this issue, please send the logs from the following location to
[email protected].
Log location: %LocalAppData%\Xamarin\Logs
Receiving 'Error Retrieving Update Information' Error Message
From time to time, an update will fail with this following error, which will often occur when checking for updates:
A majority of the time, this error can be resolved simply by logging out of your Xamarin account, and then logging back in.
To accomplish this, please find your platform of choice below and follow the steps:
On Mac:
1. Open Xamarin Studio
2. Select Xamarin Studio > Account...
3. Click Log Out
4. Click Log In
5. Enter Your Credentials
6. Check for Updates
On PC using Xamarin Studio:
1. Open Xamarin Studio
2. Select Tools > Account
3. Click Log Out
4. Click Log In
5. Enter Your Credentials
6. Check for Updates
On PC using Visual Studo:
1. Open Visual Studio
2. Select Tools > Xamarin Account
3. Click Log Out
4. Click Log In
5. Enter Your Credentials
6. Check for Updates
If this error message continues to appear, please e-mail [email protected].
Receiving 'Invalid License' Error Message
This error message may appear if the user attempting to activate a workstation has not been invited to a seat. This may be resolved by the
account manager logging into their Xamarin Store Account and selecting ‘Manage Subscriptions’.
Once the account holder has invited a developer to a seat, the developer may then sign into the IDE and activate successfully.
Android Debug Logs
The Android Debug Logs may provide additional context regarding any runtime errors you're seeing.
Floating-Point performance is terrible!
Alternatively, "My app runs 10x faster with the Debug build than with the Release build!"
Xamarin.Android supports multiple device ABIs: armeabi, armeabi-v7a, and x86. Device ABIs can be specified within Project Properties >
Application tab > Supported architectures.
Debug builds use an Android package which provides all ABIs, and thus will use the fastest ABI for the target device.
Release builds will only include the ABIs selected in the Project Properties tab. More than once can be selected.
armeabi is the default ABI, and has the broadest device support. However, armeabi doesn't support multi-CPU devices and hardware floatingpoint, amont other things. Consequently, apps using the armeabi Release runtime will be tied to a single core and will be using a soft-float
implementation. Both of these can contribute to significantly slower performance for your app.
If your app requires decent floating-point performance (e.g. games), you should enable the armeabi-v7a ABI. You may want to only support
the armeabi-v7a runtime, though this means that older devices which only support armeabi will be unable to run your app.
Could not locate Android SDK
There are 2 downloads available from Google for the Android SDK for Windows. If you choose the .exe installer, it will write registry keys that
tell Xamarin.Android where it was installed. If you choose the .zip file and unzip it yourself, Xamarin.Android does not know where to look for
the SDK. You can tell Xamarin.Android where the SDK is in Visual Studio by going to Tools
-> Options
-> Xamarin -> Android Settings
, or in Xamarin Studio by going to Xamarin Studio -> Preferences -> SDK Locations:
IDE does not display target device
Sometimes you will attempt to deploy your application to a device, but the device you want to deploy to isn't shown in the Select Device dialog.
This can happen when the Android Debug Bridge decides to go on vacation.
To diagnose this issue, find the adb program, then run:
adb devices
If your device isn't present, then you need to restart the Android Debug Bridge server so that your device can be found:
adb kill-server
adb start-server
HTC Sync software may prevent `adb start-server` from working properly. If the `adb start-server` command doesn't print out which port it's
starting on, please exit the HTC Sync software and try restarting the adb server.
The specified task executable "keytool" could not be run
This means that your PATH does not contain the directory where the Java SDK's bin directory is located. Check that you followed those steps
from the Installation guide.
monodroid.exe or aresgen.exe exited with code 1
To help you debug this problem, go into Visual Studio and change the MSBuild verbosity level, to do this, select: Tools->Options->Project and
Solutions->Build and Run->MSBuild Project Build Output Verbosity and set this value to Normal.
Rebuild, and check Visual Studio's Output pane, which should contain the full error.
There is not enough storage space on the device to deploy the
package
This occurs when you don't start the emulator from within Visual Studio. When starting the emulator outside of Visual Studio, you need to pass
the -partition-size 512 options, e.g.
emulator -partition-size 512 -avd MonoDroid
Ensure you use the correct simulator name, i.e. the name you used when configuring the simulator.
INSTALL_FAILED_INVALID_APK when installing a package
Android package names must contain a period ('.'). Edit your package name so that it contains a period.
Within Visual Studio:
Right click your project > Properties
Click the Android Manifest tab on the left.
Update the Package name field.
If you see the message "No AndroidManifest.xml found. Click to add one.", click the link and then update the Package name
field.
Within Xamarin Studio:
Right click your project > Options.
Navigate to the Build / Android Application section.
Change the Package name field to contain a '.'.
INSTALL_FAILED_MISSING_SHARED_LIBRARY when installing a
package
A "shared library" in this context is not a native shared library (libfoo.so) file; it is instead a library that must be separately installed on the
target device, such as Google Maps.
The Android package specifies which shared libraries are required with the <uses-library/> element. If a required library is not present on the
target device (e.g. //uses-library/@android:required is true, which is the default), then package installation will fail with
INSTALL_FAILED_MISSING_SHARED_LIBRARY.
To determine which shared libraries are required, view the generated AndroidManifest.xml file (e.g. obj\Debug\android\AndroidManifest.xml)
and look for the <uses-library/> elements. <uses-library/> elements can be added manually in your project's Properties\AndroidManifest.xml
file and via the UsesLibraryAttribute custom attribute.
For example, adding an assembly reference to Mono.Android.GoogleMaps.dll will implicitly add a <uses-library/> for the Google Maps shared
library.
INSTALL_FAILED_UPDATE_INCOMPATIBLE when installing a
package
Android packages have three requirements:
They must contain a '.' (see previous entry)
They must have a unique string package name (hence the reverse-tld convention seen in Android app names, e.g. com.android.chrome
for the Chrome app)
When upgrading packages, the package must have the same signing key.
Thus, imagine this scenario:
1. You build & deploy your app as a Debug app
2. You change the signing key, e.g. to use as a Release app (or because you don't like the default-provided Debug signing key)
3. You install your app without removing it first, e.g. Debug > Start Without Debugging within Visual Studio
When this happens, package installation will fail with a INSTALL_FAILED_UPDATE_INCOMPATIBLE error, because the package name didn't
change while the signing key did. The Android Debug Log will also contain a message similar to:
E/PackageManager(
146): Package [PackageName] signatures do not match the previously installed version;
ignoring!
To fix this error, completely remove the application from your device before re-installing.
INSTALLFAILEDUID_CHANGED when installing a package
When an Android package is installed, it is assigned a user id (UID). Sometimes, for currently unknown reasons, when installing over an
already installed app, the installation will fail with INSTALL_FAILED_UID_CHANGED:
ERROR [2015-03-23 11:19:01Z]: ANDROID: Deployment failed
Mono.AndroidTools.InstallFailedException: Failure [INSTALL_FAILED_UID_CHANGED]
at Mono.AndroidTools.Internal.AdbOutputParsing.CheckInstallSuccess(String output, String packageName)
at Mono.AndroidTools.AndroidDevice.<>c__DisplayClass2c.<InstallPackage>b__2b(Task`1 t)
at System.Threading.Tasks.ContinuationTaskFromResultTask`1.InnerInvoke()
at System.Threading.Tasks.Task.Execute()
To work around this issue, fully uninstall the Android package, either by installing the app from the Android target's GUI, or using adb:
$ adb uninstall @PACKAGE_NAME@
DO NOT USE adb uninstall -k, as this will preserve application data, and thus preserve the conflicting UID on the target device.
Release apps fail to launch on device
Does the Android Debug Log output will contain a message similar to:
D/AndroidRuntime( 1710): Shutting down VM
W/dalvikvm( 1710): threadid=1: thread exiting with uncaught exception (group=0xb412f180)
E/AndroidRuntime( 1710): FATAL EXCEPTION: main
E/AndroidRuntime( 1710): java.lang.UnsatisfiedLinkError: Couldn't load monodroid: findLibrary returned
null
E/AndroidRuntime( 1710):
at java.lang.Runtime.loadLibrary(Runtime.java:365)
If so, there are two possible causes for this:
1. The .apk doesn't provide an ABI that the target device supports. For example, the .apk only contains armeabi-v7a binaries, and the
target device only supports armeabi.
2. An Android bug. If this is the case, uninstall the app, cross your fingers, and reinstall the app.
To fix (1), edit the Project Options/Properties and add support for the required ABI to the list of Supported ABIs. To determine which ABI you
need to add, run the following adb command against your target device:
adb shell getprop ro.product.cpu.abi
adb shell getprop ro.product.cpu.abi2
The output will contain the primary (and optional secondary) ABIs.
$ adb shell getprop | grep ro.product.cpu
[ro.product.cpu.abi2]: [armeabi]
[ro.product.cpu.abi]: [armeabi-v7a]
The OutPath property is not set for project "MyApp.csproj"
This generally means you have an HP computer and the environment variable "Platform" has been set to something like MCD or HPD. This
conflicts with the MSBuild Platform property that is generally set to "Any CPU" or "x86".
You will need to remove this environment variable from your machine before MSBuild can function:
Control Panel > System > Advanced > Environment Variables
Restart Visual Studio or Xamarin Studio and try to rebuild. Things should now work as expected.
java.lang.ClassCastException: mono.android.runtime.JavaObject
cannot be cast to...
Xamarin.Android 4.x doesn't properly marshal nested generic types properly. For example, consider the following C# code
using SimpleExpandableListAdapter:
// BAD CODE; DO NOT USE
var groupData = new List<IDictionary<string, object>> () {
new Dictionary<string, object> {
{ "NAME", "Group 1" },
{ "IS_EVEN", "This group is odd" },
},
};
var childData = new List<IList<IDictionary<string, object>>> () {
new List<IDictionary<string, object>> {
new Dictionary<string, object> {
{ "NAME", "Child 1" },
{ "IS_EVEN", "This group is odd" },
},
},
};
mAdapter = new SimpleExpandableListAdapter (
this,
groupData,
Android.Resource.Layout.SimpleExpandableListItem1,
new string[] { "NAME", "IS_EVEN" },
new int[] { Android.Resource.Id.Text1, Android.Resource.Id.Text2 },
childData,
Android.Resource.Layout.SimpleExpandableListItem2,
new string[] { "NAME", "IS_EVEN" },
new int[] { Android.Resource.Id.Text1, Android.Resource.Id.Text2 }
);
The problem is that Xamarin.Android incorrectly marshals nested generic types. The List<IDictionary<string, object>> is being
marshaled to a java.lang.ArrrayList, but the ArrayList is containing mono.android.runtime.JavaObject instances (which reference
the Dictionary<string, object> instances) instead of something that implements java.util.Map, resulting in the following exception:
E/AndroidRuntime( 2991): FATAL EXCEPTION: main
E/AndroidRuntime( 2991): java.lang.ClassCastException: mono.android.runtime.JavaObject cannot be cast to
java.util.Map
E/AndroidRuntime( 2991):
at
android.widget.SimpleExpandableListAdapter.getGroupView(SimpleExpandableListAdapter.java:278)
E/AndroidRuntime( 2991):
at
android.widget.ExpandableListConnector.getView(ExpandableListConnector.java:446)
E/AndroidRuntime( 2991):
at android.widget.AbsListView.obtainView(AbsListView.java:2271)
E/AndroidRuntime( 2991):
at android.widget.ListView.makeAndAddView(ListView.java:1769)
E/AndroidRuntime( 2991):
at android.widget.ListView.fillDown(ListView.java:672)
E/AndroidRuntime( 2991):
at android.widget.ListView.fillFromTop(ListView.java:733)
E/AndroidRuntime( 2991):
at android.widget.ListView.layoutChildren(ListView.java:1622)
The workaround is to use the provided Java Collection types instead of the System.Collections.Generic types for the "inner" types. This
will result in appropriate Java types when marshaling the instances. (The following code is more complicated than necessary in order to
reduce gref lifetimes. It can be simplified to altering the original code via s/List/JavaList/g and s/Dictionary/JavaDictionary/g if
gref lifetimes aren't a worry.)
// insert good code here
using (var groupData = new JavaList<IDictionary<string, object>> ()) {
using (var groupEntry = new JavaDictionary<string, object> ()) {
groupEntry.Add ("NAME", "Group 1");
groupEntry.Add ("IS_EVEN", "This group is odd");
groupData.Add (groupEntry);
}
using (var childData = new JavaList<IList<IDictionary<string, object>>> ()) {
using (var childEntry = new JavaList<IDictionary<string, object>> ())
using (var childEntryDict = new JavaDictionary<string, object> ()) {
childEntryDict.Add ("NAME", "Child 1");
childEntryDict.Add ("IS_EVEN", "This child is odd.");
childEntry.Add (childEntryDict);
childData.Add (childEntry);
}
mAdapter = new SimpleExpandableListAdapter (
this,
groupData,
Android.Resource.Layout.SimpleExpandableListItem1,
new string[] { "NAME", "IS_EVEN" },
new int[] { Android.Resource.Id.Text1, Android.Resource.Id.Text2 },
childData,
Android.Resource.Layout.SimpleExpandableListItem2,
new string[] { "NAME", "IS_EVEN" },
new int[] { Android.Resource.Id.Text1, Android.Resource.Id.Text2 }
);
}
}
This will be fixed in a future release.
Unexpected NullReferenceExceptions
Occasionally the Android Debug Log will mention NullReferenceExceptions that "cannot happen," or come from Mono for Android runtime
code shortly before the app dies:
E/mono(15202): Unhandled Exception: System.NullReferenceException: Object reference not set to an
instance of an object
E/mono(15202):
at Java.Lang.Object.GetObject (IntPtr handle, System.Type type, Boolean owned)
E/mono(15202):
at Java.Lang.Object._GetObject[IOnTouchListener] (IntPtr handle, Boolean owned)
E/mono(15202):
at Java.Lang.Object.GetObject[IOnTouchListener] (IntPtr handle, Boolean owned)
E/mono(15202):
at
Android.Views.View+IOnTouchListenerAdapter.n_OnTouch_Landroid_view_View_Landroid_view_MotionEvent_(IntPtr
jnienv, IntPtr native__this, IntPtr native_v, IntPtr native_e)
E/mono(15202):
at (wrapper dynamic-method) object:b039cbb0-15e9-4f47-87ce-442060701362
(intptr,intptr,intptr,intptr)
or
E/mono
( 4176): Unhandled Exception:
E/mono
( 4176): System.NullReferenceException: Object reference not set to an instance of an object
E/mono
( 4176): at Android.Runtime.JNIEnv.NewString (string)
E/mono
( 4176): at Android.Util.Log.Info (string,string)
This can happen when the Android runtime decides to abort the process, which can happen for any number of reasons, including hitting the
target's GREF limit or doing something "wrong" with JNI.
To see if this is the case, check the Android Debug Log for a message from your process similar to:
E/dalvikvm(
123): VM aborting
Abort due to Global Reference Exhaustion
The Android runtime's JNI layer only supports a limited number of JNI object references to be valid at any given point in time. When this limit is
exceeded, things break.
The GREF (global reference) limit is 2000 references in the emulator, and ~52000 references on hardware.
You know you're starting to create too many GREFs when you see messages such as this in the Android Debug Log:
D/dalvikvm(
602): GREF has increased to 1801
When you reach the GREF limit, a message such as the following is printed:
D/dalvikvm(
602): GREF has increased to 2001
W/dalvikvm(
602): Last 10 entries in JNI global reference table:
W/dalvikvm(
602):
1991: 0x4057eff8 cls=Landroid/graphics/Point; (20 bytes)
W/dalvikvm(
602):
1992: 0x4057f010 cls=Landroid/graphics/Point; (28 bytes)
W/dalvikvm(
602):
1993: 0x40698e70 cls=Landroid/graphics/Point; (20 bytes)
W/dalvikvm(
602):
1994: 0x40698e88 cls=Landroid/graphics/Point; (20 bytes)
W/dalvikvm(
602):
1995: 0x40698ea0 cls=Landroid/graphics/Point; (28 bytes)
W/dalvikvm(
602):
1996: 0x406981f0 cls=Landroid/graphics/Point; (20 bytes)
W/dalvikvm(
602):
1997: 0x40698208 cls=Landroid/graphics/Point; (20 bytes)
W/dalvikvm(
602):
1998: 0x40698220 cls=Landroid/graphics/Point; (28 bytes)
W/dalvikvm(
602):
1999: 0x406956a8 cls=Landroid/graphics/Point; (20 bytes)
W/dalvikvm(
602):
2000: 0x406956c0 cls=Landroid/graphics/Point; (20 bytes)
W/dalvikvm(
602): JNI global reference table summary (2001 entries):
W/dalvikvm(
602):
51 of Ljava/lang/Class; 164B (41 unique)
W/dalvikvm(
602):
46 of Ljava/lang/Class; 188B (17 unique)
W/dalvikvm(
602):
6 of Ljava/lang/Class; 212B (6 unique)
W/dalvikvm(
602):
11 of Ljava/lang/Class; 236B (7 unique)
W/dalvikvm(
602):
3 of Ljava/lang/Class; 260B (3 unique)
W/dalvikvm(
602):
4 of Ljava/lang/Class; 284B (2 unique)
W/dalvikvm(
602):
8 of Ljava/lang/Class; 308B (6 unique)
W/dalvikvm(
602):
1 of Ljava/lang/Class; 316B
W/dalvikvm(
602):
4 of Ljava/lang/Class; 332B (3 unique)
W/dalvikvm(
602):
1 of Ljava/lang/Class; 356B
W/dalvikvm(
602):
2 of Ljava/lang/Class; 380B (1 unique)
W/dalvikvm(
602):
1 of Ljava/lang/Class; 428B
W/dalvikvm(
602):
1 of Ljava/lang/Class; 452B
W/dalvikvm(
602):
1 of Ljava/lang/Class; 476B
W/dalvikvm(
602):
2 of Ljava/lang/Class; 500B (1 unique)
W/dalvikvm(
602):
1 of Ljava/lang/Class; 548B
W/dalvikvm(
602):
1 of Ljava/lang/Class; 572B
W/dalvikvm(
602):
2 of Ljava/lang/Class; 596B (2 unique)
W/dalvikvm(
602):
1 of Ljava/lang/Class; 692B
W/dalvikvm(
602):
1 of Ljava/lang/Class; 956B
W/dalvikvm(
602):
1 of Ljava/lang/Class; 1004B
W/dalvikvm(
602):
1 of Ljava/lang/Class; 1148B
W/dalvikvm(
602):
2 of Ljava/lang/Class; 1172B (1 unique)
W/dalvikvm(
602):
1 of Ljava/lang/Class; 1316B
W/dalvikvm(
602):
1 of Ljava/lang/Class; 3428B
W/dalvikvm(
602):
1 of Ljava/lang/Class; 3452B
W/dalvikvm(
602):
1 of Ljava/lang/String; 28B
W/dalvikvm(
602):
W/dalvikvm(
602):
2 of Ldalvik/system/VMRuntime; 12B (1 unique)
10 of Ljava/lang/ref/WeakReference; 28B (10 unique)
W/dalvikvm(
602):
W/dalvikvm(
602):
1553 of Landroid/graphics/Point; 20B (1553 unique)
1 of Ldalvik/system/PathClassLoader; 44B
W/dalvikvm(
602):
261 of Landroid/graphics/Point; 28B (261 unique)
W/dalvikvm(
602):
1 of Landroid/view/MotionEvent; 100B
W/dalvikvm(
602):
1 of Landroid/app/ActivityThread$ApplicationThread; 28B
W/dalvikvm(
602):
1 of Landroid/content/ContentProvider$Transport; 28B
W/dalvikvm(
602):
1 of Landroid/view/Surface$CompatibleCanvas; 44B
W/dalvikvm(
602):
1 of
Landroid/view/inputmethod/InputMethodManager$ControlledInputConnectionWrapper; 36B
W/dalvikvm(
602):
1 of Landroid/view/ViewRoot$1; 12B
W/dalvikvm(
602):
1 of Landroid/view/ViewRoot$W; 28B
W/dalvikvm(
602):
1 of Landroid/view/inputmethod/InputMethodManager$1; 28B
W/dalvikvm(
602):
1 of Landroid/view/accessibility/AccessibilityManager$1; 28B
W/dalvikvm(
602):
1 of Landroid/widget/LinearLayout$LayoutParams; 44B
W/dalvikvm(
602):
1 of Landroid/widget/LinearLayout; 332B
W/dalvikvm(
602):
2 of Lorg/apache/harmony/xnet/provider/jsse/TrustManagerImpl; 28B (1 unique)
W/dalvikvm(
602):
1 of Landroid/view/SurfaceView$MyWindow; 36B
W/dalvikvm(
602):
1 of Ltouchtest/RenderThread; 92B
W/dalvikvm(
602):
1 of Landroid/view/SurfaceView$3; 12B
W/dalvikvm(
602):
1 of Ltouchtest/DrawingView; 412B
W/dalvikvm(
602):
1 of Ltouchtest/Activity1; 180B
W/dalvikvm(
602): Memory held directly by tracked refs is 75624 bytes
E/dalvikvm(
602): Excessive JNI global references (2001)
E/dalvikvm(
602): VM aborting
In the above example (which, incidentally, comes from bug 685215) the problem is that too many Android.Graphics.Point instances are being
created; see comment #2 for a list of fixes for this particular bug.
Typically, a useful solution is to find which type has too many instances allocated -- Android.Graphics.Point in the above dump -- then find
where they're created in your source code and dispose of them appropriately (so that their Java-object lifetime is shortened). This is not
always appropriate (#685215 is multithreaded, so the trivial solution avoids the Dispose call), but it's the first thing to consider.
You can enable GREF Logging to see when GREFs are created and how many exist.
Abort due to JNI type mismatch
If you hand-roll JNI code, it's possible that the types won't match correctly, e.g. if you try to invoke java.lang.Runnable.run on a type that
doesn't implement java.lang.Runnable. When this occurs, there will be a message similar to this in the Android Debug Log:
W/dalvikvm( 123): JNI WARNING: can't call Ljava/Type;;.method on instance of Lanother/java/Type;
W/dalvikvm( 123):
in Lmono/java/lang/RunnableImplementor;.n_run:()V (CallVoidMethodA)
...
E/dalvikvm( 123): VM aborting
Dynamic Code Support
Dynamic code does not compile
To use C# dynamic in your application or library, you have to add System.Core.dll, Microsoft.CSharp.dll and Mono.CSharp.dll to your project.
In Release build, MissingMethodException occurs for dynamic code at run time.
It is likely that your application project does not have references to System.Core.dll, Microsoft.CSharp.dll or Mono.CSharp.dll. Make sure
those assemblies are referenced.
Keep in mind that dynamic code always costs. If you need efficient code, consider not using dynamic code.
In the first preview, those assemblies were excluded unless types in each assembly are explicitly used by the application code. See the
following for a workaround: http://lists.ximian.com/pipermail/mo...il/009798.html