Et-Setera https://www.setera.org Ramblings of a geek Fri, 15 Nov 2013 00:56:48 +0000 en-US hourly 1 https://wordpress.org/?v=4.5.24 Android Native Libraries In Root Context https://www.setera.org/2013/11/14/android-native-libraries/ Fri, 15 Nov 2013 00:56:48 +0000 https://www.setera.org/?p=733 As usual, I am jumping around from one side project to the next, always looking for the next shiny object. A repeat of a Broadcom networking bug on my new HTC One, lead me to want to be able to dig into the underlying network packets. There are a number of pieces to this project that are completely new to me, including building native code libraries (libpcap) and executing code as a root user on-device to allow libpcap to access the low-level networking stack.

Building libpcap

After a lot of false starts, it turned out to be fairly simple to build the native libpcap library. In my original attempts, I was working to build the entire Cyanogenmod ROM for my device so I could harvest the libpcap so file. While this might have eventually worked out, it was a very difficult path. In the end, the “proper” way to do this was to use the Android NDK to build the Android libpcap native code as part of my project.

Running As Root

Libpcap requires root access in order to access the low-level networking stack. On the surface, this seems pretty simple to do using the support provided by the RootTools project. However, it turns out that the combination of root applications and access to native libraries is a bit tricky.

When using RootTools, launching a root application actually involves multiple processes:

Processes Diagram

Processes Diagram

The initial process is the main application with an Android Activity. This activity interacts with the RootTools support which checks for root ability and, if found, launches a new shell process with root authority. That root shell mediates between the original Activity and root applications launched on behalf of the original activity. For short-running root applications, it is possible to communicate using the STDIN and STDOUT pipes. However, for a long-running service, it makes more sense to use some other communications channel to communicate between the Android activity and the root application. One possibility would be a Unix domain socket provided by the android.net.LocalSocket class.

Native Libraries And Root

While RootTools provides the infrastructure shown above, the problem I ran into was that when launching the root application (process 3), it would not be able to locate the native libraries that the JNI class was dependent on. The RootTools JavaCommandCapture class launches the Java class using a command similar to:

dalvikvm -cp /path/to/anbuild.dex com.android.internal.util.WithFramework com.stericson.RootTools.containers.RootClass my.package.RootCodeClass

This long incantation starts up a new Java Application using the Dalvik VM. The WithFramework class “Binds native framework methods and then invokes a main class with the remaining arguments” and then calls the RootClass class. Finally, the RootClass class invokes the RootCodeClass constructor passing along the remaining command-line arguments. RootTools expects the root functionality to occur as part of the construction of RootCodeClass, however if RootCodeClass has a JNI dependency on a native library the functionality will fail with an UnsatisfiedLinkError exception.

dalvik.system.BaseDexClassLoader

Normally, Java may be started with the “java.library.path” System property to set the location of the native libraries, however that doesn’t appear to work correctly in Android. In addition, the LD_LIBRARY_PATH from Linux won’t work either. It turns out that Android actually pulls the native library path from the Classloader that is used to load the class referring to the native static library.

The dalvik.system.BaseDexClassLoader class acts as both a Java class loader mechanism and a holder of the native library path. The initial classloader started by the Dalvik VM does not contain any references to the static library path leading to the linkage failures. I was able to solve this, by adding yet another layer of indirection:

Classloader Diagram

Classloader Diagram

In this model, the initial RootCodeClass constructor creates a new BaseDexClassLoader instance referencing the native libraries path.

JavaRootClassloader targetLoader = new JavaRootClassloader(
				nativeClasspath, 
				null, 
				nativeLibPath, 
				getClass().getClassLoader());

In this case, the native classpath and native libraries have been passed in as command-line arguments from the originating Activity. The targetLoader must be used to load the target class in order for the target JNI classes to use the provided native libraries. It is important that these classes be kept in separate classloaders to avoid errors in the Dalvik VM about redefinition of classes.

Class<?>targetClass = targetLoader.loadTargetClass(targetClassName); 

The loadTargetClass method is a special Classloader method that uses classloader-first rather than parent-first lookup to avoid using the parent classloader which does not have the native library path defined.

/**
	 * Load the specified class, making sure to *not* do a parent-first load
	 * as we will end up with the wrong classloader.
	 * 
	 * @param targetClassName
	 * @return
	 * @throws ClassNotFoundException 
	 */
	public Class<?> loadTargetClass(String targetClassName) 
		throws ClassNotFoundException 
	{
        Class<?> clazz = findLoadedClass(targetClassName);

        if (clazz == null) {
        	// Look locally first for our target class
        	clazz = findClass(targetClassName);
        }

        return clazz;
	}

In the current implementation, all of the information necessary to launch the final targetted class with native library path properly set is provided by the originating Activity. Remaining command-line arguments are captured by the “launcher” class and provided as the arguments to the main method of the target class.

DEX Files

The default RootTools approach for creating Java classes that can be loaded in the root context is by adding the com.stericson.RootTools.containers.RootClass.Candidate annotation to the root classes and then processing with the com.stericson.RootTools.containers.RootClass class. The result of this process it to create an Android DEX file called anbuild.dex. I struggled to get this all to play nicely and get all of the proper classes into the proper DEX files. As mentioned, loading the same class in different classloaders can cause Dalvik VM errors that look like the following:

Class ref in pre-verified class resolved to unexpected implementation

In the end, I ended up with three separate DEX files:

  • Standard application DEX file
    This file is automatically built and handled by the Android tools and the runtime. This file contains the code for the main Activity and associated logic
  • Root Launcher DEX file
    This file contains just necessary classes to be loaded by RootTools and to create the special Classloader instance that can load the real root functionality while specifying the native libraries path. This DEX file is generated as rootlauncher.dex into the res/raw folder
  • Root functionality DEX file
    This DEX file contains the Java functionality that will run in a root context that will have access to the native libraries necessary to interact with the system. This DEX file is generated as root.dex into the res/raw folder

Building The DEX Files

Because of this added complexity in creating the multiple DEX files, I had to take more control over the build process. Taking advantage of Eclipse’s ability to call out to an Ant build.xml as part of the build process. For instance, the build.xml file for generating the DEX files would look something like:

    <target name="build_root_dexs">  	
    	<property name="dx.path" value="${user.home}/software/unzipped/android-sdk-macosx-personal/build-tools/${build-tools-version}/dx" />
    	
    	<!-- Build the root launcher -->
    	<unzip src="libs/RootTools-3.3.jar" dest="bin/classes-launcher">
    		<patternset>
    			<include name="com/stericson/RootTools/containers/*.class"/>
    		</patternset>
    	</unzip>

    	<echo message="Building rootlauncher.dex" />
    	<exec executable="${dx.path}">
    		<arg value="--dex" />
    		<arg value="--output=res/raw/rootlauncher.dex" />
    		<arg value="--positions=lines" />
    		<arg value="bin/classes-launcher" />
    	</exec>
    	
    	<!-- Build the code that will run within the root container -->
    	<echo message="Building root.dex" />
    	<exec executable="${dx.path}">
    		<arg value="--dex" />
    		<arg value="--output=res/raw/root.dex" />
    		<arg value="--positions=lines" />
    		<arg value="bin/classes-root" />
    	</exec>
  </target>

An Ant build can be added to the build file via the Project properties:

Eclipse Builders

Eclipse Builders

Add a new Ant Builder:

Eclipse Builder Type

Eclipse Builder Type

Choose your Ant file:

Ant Build File

Ant Build File

And save the resulting build launch configuration:

Build Configuration

Build Configuration

Caveats

While this approach is working fine for Android 4.0+, there are a lot of pieces of this puzzle that are private/internal to the Android implementation. For that reason, many of these internals have the chance of changing over time. In particular:

  • The com.android.internal.util.WithFramework is clearly marked as an internal class
  • The dalvik.system.BaseDexClassLoader is yet another internal class that may disappear or change
  • Even the Dalvik VM will likely go away in the future and be replaced by the new Android ART runtime
]]>
Debugging Titanium Android Native Modules https://www.setera.org/2013/08/08/debugging-titanium-android-native-modules/ Thu, 08 Aug 2013 11:24:04 +0000 https://www.setera.org/?p=710 Recently, I’ve been playing a bit with the Appcelerator Titanium Platform. In particular, I’ve been working on a native Android module for Titanium. In their documentation, they state:

The best way to debug your Android modules right now is a bit old fashioned. When there is a problem or unexpected behavior in your module, use log statements to trace through your code’s execution.


However, the functionality I was working on was complicated enough that I needed the comfort of Eclipse step-debugging to truly feel like I was able to see what was going on inside my code. With that in mind, I dug around and figured out a way to debug these native modules and discovered some cool functionality in the Android Debug Bridge (adb) that I was previously unaware of.

Native Module Creation

The module creation and implementation steps are no different than the standard steps documented by Appcelerator. Once that is complete and it is time to do some debugging, I found the following to work to allow for step-wise debugging of the module. (NOTE: This has only been attempted on-device, although I expect it should work on top of the Android emulator).

Setting Up Module Debugging

After making testable changes, execute the “install” target of the build.xml file for your module to get the module properly installed on the device. At this point, it is necessary to enable debugging of your module’s example application if it has not already been handled via the Android manifest file. The basic command looks like:

adb shell am set-debug-app -w –persistent my.package.name

Where the two options can be used dependent on your needs:

  • -w
    Wait for debugger at start. Use this if you need to debug something that starts early in the module’s startup routines
  • –persistent
    Remember that this application should be debuggable across reinstalls.

With a debuggable application, it is actually possible to use the application’s process identifier to connect up a local port to the application’s JDWP agent. For instance, if you look at the output of “ps” from the shell, you will see something like the following:

USER PID PPID VSIZE RSS WCHAN PC NAME
…..
u0_a48 1471 795 215984 29516 ffffffff b7e62157 S com.seterasoft.sync.scheduler
…..

With this knowledge, adb can be used to forward host traffic from TCP port 9999 to the JDWP agent for this particular process using this command:

adb forward tcp:9999 jdwp:1471

Given my infinite laziness, I prefer to do this linkage with a script to avoid manual steps as much as possible. Thus, I created this simple Groovy script to query for “my.package.name” and link it to local TCP port 9999.

#!/usr/bin/env groovy

def ps = "adb shell ps".execute().text
def reader = new StringReader(ps)

def found = false
reader.eachLine { line ->
    if (line =~ /my\.package\.name/) {
    	found = true
        def pid = line.split()[1]
        println "Forwarding tcp:9999 => jdwp:${pid}"
        println "adb forward tcp:9999 jdwp:${pid}".execute().text
    }
}

if (!found) {
	println "Did not find application process.  Is it running?"
}

It is important to understand that this linkage must be re-established each time that the application is rebuilt and/or redeployed. This will result in a new process being started and a new ADB forward must then be configured.

Debug with Eclipse Remote Debugger

With debugging enabled for the application and a JDWP forwarding set up via ADB, it is just a matter of using the standard Eclipse remote debugging configuration. Assuming the previously documented forwarding set up, Eclipse remote debugging can be configured to debug via local port 9999 and ADB will proxy those requests to the running (or waiting) application.

Screen Shot 2013-08-06 at 2.46.49 PM

While this requires a bit more setup than some standard debugging and only works for Android, I’ve still found it well worth the time and effort while working on native modules for Android in Titanium.

]]>
Ubuntu 12.10 Screen Brightness on Sony VAIO T15 https://www.setera.org/2013/03/03/ubuntu-12-10-screen-brightness-on-sony-vaio-t15/ Mon, 04 Mar 2013 01:44:00 +0000 https://www.setera.org/?p=691 I recently picked up a new Sony VAIO T15 ultrabook laptop. A really nicely designed laptop for a good price. After repartitioning, I was able to install Ubuntu 12.10 in a dual-boot arrangement fairly easily and Ubuntu worked well out of the box. However, screen brightness controls using Gnome power manager did not work out of the box and I had to to some hacking to get at least a bit of control.

Background

Normally, the backlight brightness is controlled via the /sys/class/backlight/acpi_video0 ACPI interface. However, the Intel video driver installs its controls as /sys/class/backlight/intel_backlight. This mismatch causes Gnome power management to fail to operate on this laptop.

Short-term Solution

While there are a number of different potential solutions on the internet, I was unable to get any of those to work as-is. The closest I came was with the solution list here. However, the keyboard shortcuts didn’t seem to work. Using those scripts, I was able to roll my own solution.

Scripts

Based on the solution listed above, I created two script files.

~/bin/brightdown.sh

#!/bin/bash

curr=`cat /sys/class/backlight/intel_backlight/actual_brightness`
if [ $curr -gt 0 ]; then
curr=$((curr-610));
echo $curr > /sys/class/backlight/intel_backlight/brightness;
fi

~/bin/brightdown.sh

#!/bin/bash

curr=`cat /sys/class/backlight/intel_backlight/actual_brightness`
if [ $curr -lt 4882 ]; then
curr=$((curr+610));
echo $curr > /sys/class/backlight/intel_backlight/brightness;
fi

Note that I placed these scripts in my personal bin folder rather than /etc/acpi. Each of the scripts must also be made executable.

Root Access When Necessary

Writing to the ACPI interface in the /sys folder requires root access. In order to avoid having to use su or sudo with a password in order to invoke these commands, the sudoers file can be configured to allow root execution without password for just these commands.

Using the visudo command, alter the sudo file as follows:


username ALL=NOPASSWD: /home/username/bin/brightdown.sh
username ALL=NOPASSWD: /home/username/bin/brightup.sh

where username is the name of the user to be given root access without a password to those commands.

Keyboard Shortcuts

As I was unable to get the standard keyboard shortcuts to work correctly with any of the suggested, I chose instead to create my own keyboard shortcuts. After installing, autokey, I was able to create my own shortcuts for decreasing and increasing the brightness using the above scripts. In my case, I chose Ctrl+Shift+- to decrease the brightness and Ctrl+Shift++ to increase the brightness.

Using the autokey application, choose New -> Script. Enter the name “Brightness Down”. Enter the command:

system.exec_command("sudo /home/username/bin/brightdown.sh")

and set the Hotkey to Ctrl+Shift+-.

Decrease Brightness

Autokey set up to decrease brightness

Do the same for increase the brightness, using the other script file.

Longer Term Solution

There is some hope according to Ubuntu Bug 954661 that this problem will be fixed via a kernel fix in the upcoming 13.04 Ubuntu release. If that happens, I will be able to remove these simple workaround. For the short-term though this works reasonably well. The primary missing feature is auto-dimming the screen for power savings.

]]>
Pinpointing Android LocationManagerService Battery Drain https://www.setera.org/2012/09/10/pinpointing-android-locationmanagerservice-battery-drain/ Tue, 11 Sep 2012 02:16:30 +0000 https://www.setera.org/?p=675 Recently, I was seeing severe battery drain on my Samsung Galaxy SII. Using the most awesome BetterBatteryStats application I was able to see that my phone was not being able to go into deep sleep due to WakeLocks from the LocationManagerService. Android’s LocationManagerService, is responsible for managing LocationProviders and issues location updates and alerts. If applications are requesting location updates too frequently, the LocationManagerService may be forced to keep the phone awake to provide those updates.

It is possible using the dumpsys command via the adb shell to find out which applications are currently requesting location updates. For instance:

adb shell dumpsys > /path/to/dumpsys.txt

will collect the output of the dumpsys command run on the connected device into the specified file. Looking in the output from dumpsys the LocationManagerService dumps into a section

DUMP OF SERVICE location:

Within that section, there are a number of LocationListeners that look something like

Receiver{419e7ad0 Listener android.os.BinderProxy@41b8abd0}mUpdateRecords: {passive=UpdateRecord{421e75a0 mProvider: passive mUid: 10084}}:
passive:
UpdateRecord{421e75a0 mProvider: passive mUid: 10084}
mProvider=passive mReceiver=Receiver{419e7ad0 Listener android.os.BinderProxy@41b8abd0}mUpdateRecords: {passive=UpdateRecord{421e75a0 mProvider: passive mUid: 10084}}
mMinTime=0 mMinDistance=0.0
mSingleShot=false
mUid=10084
mLastFixBroadcast:
mProvider=network mTime=1346849822124
mLatitude=44.0836108 mLongitude=-92.5067299
mHasAltitude=false mAltitude=0.0
mHasSpeed=false mSpeed=0.0
mHasBearing=false mBearing=0.0
mHasAccuracy=true mAccuracy=20.0
mExtras=Bundle[mParcelledData.dataSize=148]
mLastStatusBroadcast=0

This UpdateRecord is particularly bad because it is requesting constant updates:

mMinTime=0 mMinDistance=0.0

The mUid specifies the process identifier requesting the updates. The processes are dumped within the same output and can be found in the section beginning:

ACTIVITY MANAGER RUNNING PROCESSES (dumpsys activity processes)

Each application is listed separately by process identifier:

*APP* UID 10084 ProcessRecord{41af23e8 13037:com.google.android.apps.maps:LocationFriendService/10084}
class=com.google.googlenav.android.AndroidGmmApplication
dir=/data/app/com.google.android.apps.maps-1.apk publicDir=/data/app/com.google.android.apps.maps-1.apk data=/data/data/com.google.android.apps.maps
packageList=[com.google.android.apps.maps]
compat={240dpi always-compat}
thread=android.app.ApplicationThreadProxy@42457df0 curReceiver=null
pid=13037 starting=false lastPss=0
lastActivityTime=-6m23s226ms lruWeight=-50901 serviceb=false keeping=false hidden=true empty=true
oom: max=15 hidden=12 curRaw=12 setRaw=12 cur=12 set=12
curSchedGroup=1 setSchedGroup=1 systemNoUi=false trimMemoryLevel=0
hasShownUi=false pendingUiClean=false hasAboveClient=false
setIsForeground=false foregroundServices=false forcingToForeground=null
persistent=false removed=false
adjSeq=3891 lruSeq=535
lastWakeTime=0 time used=0
lastCpuTime=20 time used=+20ms
lastRequestedGc=-6m28s504ms lastLowMemory=-6m28s504ms reportLowMemory=false
conProviders={ContentProviderRecord{418add48 com.android.providers.settings.SettingsProvider}=1}
receivers=[ReceiverList{41a84148 13037 com.google.android.apps.maps:LocationFriendService/10084 remote:41a83f70}]

With this information we have our culprit. Process identifier 10084 is Google’s LocationFriendService (Latitude). This process is requesting constant location updates and causing severe battery drain. In this particular case, I was able to go through the Latitude settings and disable everything related to location updates. With those settings disabled and a quick restart, my battery drain went back to normal again. Hopefully this information may be helpful to others having battery drain issues related to location updated.

]]>
EclipseME Lives! https://www.setera.org/2012/07/01/eclipseme-lives/ Sun, 01 Jul 2012 19:58:18 +0000 https://www.setera.org/?p=663 When I started hacking on EclipseME way back in 2001, I never would have guessed that it would still be going in 2012 in use in the form of the Eclipse Mobile Tools for Java (MTJ) project and a shipping product. A few days ago, Gorkem Ercan of Nokia announced that the latest version of Nokia SDK for Java is now based on Eclipse MTJ. Even though I don’t really spend any time on the MTJ project these days, it is very cool to see the software still being put to good use.

]]>
Android Analog Clock Collection https://www.setera.org/2012/05/28/android-analog-clock-collection/ Mon, 28 May 2012 13:59:09 +0000 https://www.setera.org/?p=664 While I haven’t entirely given up on my Android Clock Widget project, it has definitely stalled out for the time being. I have some potential ideas on how to move that project forward, but between work and coaching soccer I just don’t have much time at the moment to play around. In the meantime, I wanted a nice analog clock on my phone’s homescreen. While looking around the Google Play store, I came across the awesome Analog Clock Collection. For anyone looking for an analog clock widget, I’d recommend taking a look.

]]>
Still Deadlocked https://www.setera.org/2012/03/11/still-deadlocked/ Sun, 11 Mar 2012 21:19:16 +0000 https://www.setera.org/?p=649 Wow… three months since my last post about my Android Clock Widget Project. While I’ve failed to bring stability to the clock selector during that time, I have figured out that the problem is not actually due to a deadlock. Instead, it appears that my project is tickling a bug in the Dalvik VM’s garbage collector.


Depending on the device and operating system level, there are subtle changes in behavior. In most cases, there is a crash log written to the /data/tombstones folder. The most revealing tombstone file has come from a Samsung Captivate running a version of the AOKP ICS ROM.

Build fingerprint: 'samsung/SGH-I897/SGH-I897:2.3.5/GINGERBREAD/UCKK4:user/release-keys'
pid: 1758, tid: 1777  >>> com.seterasoft.mclock <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr deadbaad
 r0 deadbaad  r1 00000001  r2 40000000  r3 00000000
 r4 00000000  r5 00000027  r6 50c53b40  r7 00000064
 r8 41338018  r9 00000024  10 50c53a6c  fp 50c53ab0
 ip ffffffff  sp 50c53a30  lr 400fdf79  pc 400fa694  cpsr 60000030
 d0  0000000000000000  d1  0000000000000000
 d2  0000000000000000  d3  0000000000000000
 d4  0000000000000000  d5  0000000000000000
 d6  0000000000000000  d7  0000000000000000
 d8  0000000000000000  d9  0000000000000000
 d10 0000000000000000  d11 0000000000000000
 d12 0000000000000000  d13 0000000000000000
 d14 0000000000000000  d15 0000000000000000
 d16 0000000000000000  d17 0000000000000000
 d18 0000000000000000  d19 0000000000000000
 d20 0000000000000000  d21 0000000000000000
 d22 0000000000000000  d23 0000000000000000
 d24 0000000000000000  d25 0000000000000000
 d26 0000000000000000  d27 0000000000000000
 d28 0100010001000100  d29 0100010001000100
 d30 0000000000000000  d31 3ff0000000000000
 scr 2800001b

         #00  pc 00017694  /system/lib/libc.so
         #01  pc 00007bb0  /system/lib/libcutils.so (mspace_merge_objects)
         #02  pc 0007b6c8  /system/lib/libdvm.so (_Z21dvmHeapSourceFreeListjPPv)
         #03  pc 00042ce0  /system/lib/libdvm.so
         #04  pc 00032f94  /system/lib/libdvm.so (_Z22dvmHeapBitmapSweepWalkPK10HeapBitmapS1_jjPFvjPPvS2_ES2_)
         #05  pc 00042c9c  /system/lib/libdvm.so (_Z27dvmHeapSweepUnmarkedObjectsbbPjS_)
         #06  pc 000337c0  /system/lib/libdvm.so (_Z25dvmCollectGarbageInternalPK6GcSpec)
         #07  pc 0005ff6c  /system/lib/libdvm.so (_Z17dvmCollectGarbagev)
         #08  pc 00072a8e  /system/lib/libdvm.so
         #09  pc 00030a8c  /system/lib/libdvm.so
         #10  pc 00034248  /system/lib/libdvm.so (_Z12dvmInterpretP6ThreadPK6MethodP6JValue)
         #11  pc 0006c692  /system/lib/libdvm.so (_Z14dvmCallMethodVP6ThreadPK6MethodP6ObjectbP6JValueSt9__va_list)
         #12  pc 0006c6b4  /system/lib/libdvm.so (_Z13dvmCallMethodP6ThreadPK6MethodP6ObjectP6JValuez)
         #13  pc 0005f7c0  /system/lib/libdvm.so
         #14  pc 00012c14  /system/lib/libc.so (__thread_entry)
         #15  pc 00012744  /system/lib/libc.so (pthread_create)

The failing function appears to be implemented in dlmalloc.c in the Android source, but I really don't have any good idea about what might be causing the crash. I also don't appear to be the only one, as there are other references on the web that look similar.

To this point, I've tried a variety of things to try to track down the problem. I've gone so far as to try to build my own version of the Cyanogenmod with the idea that I might be able to add more logging output. So far, I've not had any luck with this approach. I generally have no problem walking away from hobby projects when I lose interest. However, this has turned into a competition of me versus the computer and I'm not quite ready to give up.

]]>
Deadlocked https://www.setera.org/2011/12/27/deadlocked/ Wed, 28 Dec 2011 01:26:58 +0000 https://www.setera.org/?p=628 I recently started spending more time on my Android Clock Widget Project. I’ve implemented some much needed caching of the SVG definitions, speeding performance of clock rendering substantially. In addition, I’ve been working on building a nice graphical clock selector. Unfortunately, this selector is causing me lots of frustration due to a race condition that keeps deadlocking the application’s UI thread.

Parsing and rendering the various SVG layers that make up each clock is a relatively expensive operation. Locking up the user interface while doing these operations is bad design and leads the user to believe that the application may not working correctly. What I’m attempting to do seems pretty simple on the surface. The following screen capture shows the (partially working) goal:

Clock Skin Selector

The selector consists of two columns, an image of the clock on the left and the name of the clock on the right. Using the standard ListActivity support, the goal is to show an indeterminate progress image in the left column until the layers have been loaded and rendered. At that point, the animated progress image is hidden and the clock image is displayed.

The implementation is simple in concept. The list adapter subclasses the standard BaseAdapter implementation to provide an implementation of the getView method. The getView method delegates loading of the clock’s image to an asynchronous task, keeping the user interface alive. When the asynchronous task completes, it signals the adapter by calling notifyDataSetChanged. The next call to getView will hide the progress animation and display the rendered image.

While this is mostly working, I’m hitting a random deadlock condition that locks up the UI thread, usually resulting in an “Application Not Responding” (ANR) error message to the user. All of my attempts to diagnose and resolve this issue have ended with nothing but frustration. So far, I’ve tried all of the “standard” approaches to diagnose this:

  • Analyzed the traces.txt file generated by the ANR.
    Unfortunately, the process never shows up in the log file.
  • Force-generated a traces.txt file using kill SIGQUIT pid while the application was still running.
    Again, the process doesn’t seem to show up. Instead, I see “W/dalvikvm(19144): threadid=4: spin on suspend #1 threadid=9 (pcf=0)” whenever attempting this.
  • Attempted to use the standard Eclipse debugger to suspend the UI thread once it is locked up.
    No big surprise that it did not work.
  • Added lots of Log output trying to pinpoint the hang.
    At least from that logging, it doesn’t appear to be a hang anywhere directly in my code.
  • I even tried to use method tracing to see if I could figure anything out.

At this point, I’ve run out of good ideas on how to track down and fix this problem on my own. I’ve gone ahead and joined the Google android-developers group and asked for ideas on solving this. I’m still waiting for my question to clear moderation to see if anyone else can offer any insights. If anyone reading this has any ideas, I’d love to hear them. Until then, this project is officially deadlocked.

]]>
Relinking Android Market Applications https://www.setera.org/2011/11/02/relinking-android-market-applications/ Wed, 02 Nov 2011 23:00:59 +0000 https://www.setera.org/?p=595 When I initially set up my Samsung Captivate, I used my work email as the primary email address for the device. This caused my Android Market applications to be associated with my work email. When Google started allowing multiple accounts, I added my personal GMail account to the device and managed to get a confusing mix of installed applications associated with each account. After being frustrated with this for a while, I decided I needed to fix this.


The internet offered no examples of how I might go about doing this, so I went spelunking on my own. For those that may need to do something similar, I decided to capture the steps I used to relink my Android Market applications with a single GMail address. Before I go any further, let me offer some warnings:

  • I AM NOT LIABLE IF YOU BREAK YOUR PHONE BY TRYING THIS.
    IF YOU DON’T KNOW WHAT YOU ARE DOING, DO NOT ATTEMPT THESE CHANGES.
  • My steps include a few things to hopefully avoid major breakage, however I’d urge caution. Be careful.
  • Your device must be rooted in order to make the necessary changes.
  • These steps only work for free applications. Paid applications are associated to a particular Google account using DRM.
  • CONSIDER YOURSELF WARNED

November 13, 2011 Update

While this appears to work in the short term, I’m noticing applications slowly migrating back to the original accounts. I’m not entirely sure where those values are being stored or how to fix this permanently.

The Market Assets Database

As of this writing, Android Market (implemented by the com.android.vending package) stores the linkage between an Android application package and the associated Android Market account in the file:

/data/data/com.android.vending/databases/market_assets.db

The ASSETS table within that SQLITE database contains the mappings as seen in this screenshot.

Market Assets DB

Relinking applications is a matter of properly updating this table. The prerequisites for this process are:

  • Rooted device
  • Android Debug Tools (adb) installed and working

Relinking Process

Start by making sure that Market application has been stopped:

  1. Navigate to Settings -> Applications -> Manage Applications
  2. Locate and select the Market application in the list
  3. Press the Force Stop button

Make sure that your device is attached with USB Debugging enabled:

$ -> adb devices
List of devices attached 
3231174E43AA00EC	device

Open a shell on the device and navigate to the database directory:

$ -> adb shell
# cd /data/data/com.android.vending/databases
# ls -l
-rw-rw----    1 app_57   app_57       34816 Oct 29 11:55 market_assets.db

Backup the current file:

# cp market_assets.db market_assets.db.save
# ls -l
-rw-rw----    1 app_57   app_57       34816 Oct 29 11:55 market_assets.db
-rw-rw----    1 root     root         31744 Oct 29 11:44 market_assets.db.save

Update the database file:

# sqlite3 market_asset.db
sqlite> update ASSETS set ACCOUNT = 'new.email@gmail.com' 
   ...> where ACCOUNT = 'old.email@gmail.com';
sqlite> .exit
# exit

At this point, reboot your phone. If all went correctly, your free applications should now be associated with new.email@gmail.com.

Updating Paid Applications

As I mentioned earlier, this process can’t be used to relink paid applications due to DRM that is tied to your account. If you want to do this, most application developers will offer a refund if you purchase on a new account and send them the order details for both the old and new accounts. Once you’ve purchased on the new account, you can uninstall for the old account and reinstall from the new. This is a lot of effort, but can help if you need to switch market accounts.

]]>
Oops I Did It Again… https://www.setera.org/2011/10/29/oops-i-did-it-again/ Sat, 29 Oct 2011 19:29:22 +0000 https://www.setera.org/?p=617 One of these days I may actually learn my lesson when it comes to installing new software. Lately I’ve been busy with work and recovering from some surgery, so I haven’t really had the energy to focus on any of my personal programming projects. Instead, I’ve been doing a lot of home network administration and software updates. In a multiple cases, I’m reminded of why being on the leading (bleeding?) edge of software may not always be the easiest place to be.

Ubuntu 11.10

I have long used a dual-interface Linux machine at the edge of my network to provide firewall, file server and other interesting services to the network. My old machine was getting pretty noisy and I was sure something was going to die and leave me in a bad situation. I bought a cheap new HP tower machine to replace the old machine and was tripped up on multiple things:

  • I didn’t think about the fact that my old network card would no longer fit in the machine due to bus changes. I was further surprised to find out that it was impossible to find a PCIExpress networking card without going online and waiting for delivery.
  • The latest Ubuntu installer guessed that the HP machine was using UEFI for bootloading and failed to boot Ubuntu. With lots of great help from the Ubuntu forums I was able to diagnose the issue and get grub-pc installed and the machine working.

This machine is up and running pretty well now after the false starts. I wish I could say the same for my Dell laptop. Every time a new version of Ubuntu comes out, I tell myself I’m not going to update for at least a month and that I should really wait a bit longer for the issues to shake out. Every time, I lose the battle to wait and end up regretting it after the fact. While Ubuntu 11.10 has some pretty nice new features, I ran up against new regressions that I had to work through.

Thanks to Canonical engineer Kamal Mostafa, I have a patched kernel to fix the backlight issue. Unfortunately, I’m still struggling with the wireless issue that kills my wireless router from time to time.

Cyanogen Mod 7.1

I was excited to see Cyanogen Mod 7.1 come out with support for my Samsung Captivate. I’m a fan of Android, but not a big fan of the crap-tacular software loaded on AT&T devices by default. The idea of installing a new ROM that was cleaner and faster was enticing. While the transition has been relatively smooth, I’m seeing some strange behavior with my external 32G SD card. I’m also having a hard time figuring out if the battery life is as good as it had been on the stock firmware. I need to do more digging to figure that out.

In the end, I don’t expect my habit of installing new software will likely change very soon. I usually try to avoid upgrading too early for mission critical hardware such as my work laptop. Admittedly half of the fun of installing new software is that you can usually dig yourself out of a hole if something goes wrong.

]]>