Fast Locking in Android with Kotlin

Introduction

As I relate in the preface to my most recent book, Addison Wesley’s Android Concurrency, one of my early introductions to advanced concurrent programming was the double checked lock (DCL). A very supportive interviewer guided me into inventing the pattern for myself, during a job interview. The year was probably 1999 and I got the job.

It was less than year later that I stumbled into articles, first by Bill Pugh, then Doug Lea, Josh Bloch and Brian Goetz, all pointing out that the idiom was flawed and would not work, in Java. In fact, the company at which all of this took place was having intermittent trouble with its JSP server pages. That trouble was, eventually, tracked, exactly, to the fact that the pages were guarded with double-check locks. For most of the Oughts, writing a double-checked lock could get you fired.

A new and corrected version of the double-checked lock has become popular since then. In this new version, the variable that is checked twice is a Java volatile. This change makes the new idiom correct.

I was reading some Dagger code, the other day and was amused to notice that Dagger actually has a small, generic DCL wrapper class that it uses to lazily create objects that must be singletons, even in a concurrent environment. It got me to thinking.

The Question

Here is a very simple double-checked lock, similar to the one that Dagger uses:

class DoubleCheckedProvider<a>(private val provider: Provider</a><a>) : Provider</a><a> {
private val lock = Object()
@Volatile private var value: A? = null</a>

override fun get(): A {
if (value == null) {
synchronized(lock) {
if (value == null) {
value = provider.get()
}
}
}
return value!!
}
}

The idiom first checks the protected variable without synchronization. If that check produces a non-null result the variable has been initialized and can be returned immediately. If the value is null, the code synchronizes, to make sure the update is visible and atomic, assigns the new value and returns it. The idea is that, in many cases, this will allow the code to skip the costly synchronization.

Although making the variable value volatile definitely makes this code correct, it is interesting to wonder how it affects idiom performance. The assumption that the code makes is that accessing a volatile variable is significantly faster than synchronizing access to the same variable. Is that true?

On a JVM, accessing a volatile variable and synchronizing access to an analogous variable are somewhat similar operations. Both forms of access require a memory-barrier: an operation that guarantees that, regardless of registers, caches and cores, all accesses appear to refer to a single piece of state. If one thread writes a value to the volatile variable, then that is the value that all other threads see when reading the variable, until some other thread writes something else there.

Note that this is absolutely not the case for unsynchronized access to a non-volatile variable. If some thread writes a value to a variable that is not volatile, without synchronization, it is entirely possible that that value will never be seen by other threads reading from the same variable, even if the other threads do synchronize their accesses and if no other writes take place before they read. This is why the original double-checked lock idiom is broken.

Clearly, because they must synchronize a single piece of state through all of its multiple representations in various caches, memory barriers are moderately expensive things.

In addition, the target platform of interest is Android, not a JVM. The Android runtime has gone through several revisions [see Levin: Dalvik and ART ]. The goals for the platform during those revisions have been significantly different from those of the JVM.

So, the question arises: Does the double check locking idiom actually optimize access to protected state?

The Experiment

The experiment described below attempts to benchmark access times for three types of locks and a reference null lock. In addition to the simply synchronized and double-checked locks, I have also included a spin-lock. This latter lock is used in RxJava, for similar purposes.

For each type of lock the experiment tests the time to access the protected variable in each of the two possible states:

  • it is already initialized and can simply return its current state
  • the internal state must to be updated before it can be returned.

For the rest of this article I will abbreviated these two states: read, compare and return, and read, compare, write and return, as, simply, “read” and “write”

For each of these two cases the experiment tests the access time when the lock is uncontested (that is, there is only one thread attempting to access the lock) and also under various levels of contention (that is, other threads are attempting to access the same lock at the same time).

I ran the entire test suite on three different devices. I would be interested in running similar tests on other devices, especially a couple of the popular Samsung phones.

Benchmarks are notoriously difficult to write and analyze. I’ve tried to be careful to assure that I have tested what I intended to test. None the less, I, absolutely, invite others to re-examine the experiment. The code is available here: here. I would be delighted to have others reproduce or amend my results.

Method

This experiment is meant to compare the various locks in an environment that is as like as possible to that in which they would be used in an actual application.

It is a simple Android application. Its main Activity operates in two modes, either running the test suite once, or running it continuously with a 1 minute delay between runs. I used the first mode only to refine and debug the application until I was confident that it was performing as intended.

I ran the test on three devices:

Device Version CPU Notes
Nexus 4 5.1.1 Snapdragon S4 Pro Test phone: minimal applications
Nexus 6 7.0 Snapdragon 805 Personal phone: many installed apps and, presumably, multiple active periodic processes
Pixel 2 8.1.0 Snapdragon 835 Test phone: minimal applications

All devices were plugged in to power for the duration of the experiment. All were set to stay awake while attached to power and all were in airplane mode.

The results presented below are from approximately 24 hours of running the application, uninterrupted, on each device. On each device I installed the application immediately before starting the experiment in the hope of seeing the effects of ART optimization. The test application remained in foreground throughout the 24 hour test period.

Each run of the test suite produces a single average time for 300000 accesses to each of the two different lock states (read and write), for each of the four types of lock. The four records are, asynchronously, stored in a SQLite database.

I chose 300000 simply because it causes the run of a single iteration to take a few seconds on the slowest of the test devices. This number of accesses is constant, regardless of the number of threads used in the experiment.

For each run of the suite, the harness makes a random choice for the number of threads that will contend for the lock: 1, 5, 10, or 20. In order to maximize contention, all threads wait at a CyclicBarrier at the start of the run. Test threads must also synchronize to record the timing data for each iteration of the test.

The harness also randomizes the order in which the various types of locks are tested, in order to minimize any bias that might be caused by always running one of the tests immediately before or after some other test.

A single run of the test produces one data record for each lock type. The record includes the id of the lock mechanism under test, the time at which the test ran, the number of threads in contention, and the two average times, one the read average and the other the write average.

A single test for a given lock tests first the access time for a read access and then a write access, always in that order. The value returned by the test method is saved, without synchronization, into a public harness field. I intend this completely thread-unsafe store to prevent any confounding optimizations.

Testing write access requires a new object for each test. This implies that the timing data may be distorted by occasional garbage collections.

Null Test

The null test always returns the value with which it is initialized, ignoring update requests. Since “read” and “write” operations are identical I expect it take the same time to execute, regardless of how it is accessed. I expect neither the number of threads nor read verses write access to affect its timing.

Synchronized Test

The synchronized test is the simplest possible functional lock. It always synchronizes, updates if necessary, and then returns the current state value. I expect this test to produce very similar times for read and write access. I also expect the times for both read and write access to degrade rapidly as the number of threads increases.

Double Check Test

The double check test is the test that inspired the entire experiment. It determines the necessity of an update with a compare to a volatile value. It synchronizes only if an update is necessary. I expect this lock to perform about the same as the Synchronized Test on writes but much better on reads.

The code I use for the DCL in this experiment is not the exact code that Dagger uses. It is not even the example I showed above. Here are the essentials of the test code:

class DoubleCheckTest(initVal: T) : Test() {
private val lock = Object()
@Volatile
private var value: T = initVal

override fun get(newVal: T): T {
val v1 = value
if (v1 === newVal) {
return v1
}

synchronized(lock) {
val v2 = value
if (v2 === newVal) {
return v2
}
value = newVal
return value
}
}
}

The assignments to the temporary variables v1 and v2 are necessary to prevent Kotlin from complaining (correctly!) that value of the variable newVal might change during the comparison.

The important alteration is that, in order to test both the read and write cases with the same code, the the check comparison is against the method parameter, not a static null.

While I believe this code to be an accurate test of the double check idiom, it will not, as written, guarantee any kind agreement between threads about the value of the protected state.

Spin Test

The spin test algorithm is used in several frameworks, most notably in this context, as mentioned earlier, RxJava (e.g., see ScheduledRunnable). It uses neither volatiles nor explicit synchronization. Instead, it uses Java’s AtomicReference.

It first obtains the value held by the reference (the protected state) and checks to see if it needs updating. The internal workings of the AtomicReference, whether they be synchronization, volatiles, or something else entirely, are completely hidden.

If the value in the reference must be updated the code uses the Reference method compareAndSet, which updates the reference only if its current value is the expected value. For this expected value, the code uses the value that it just obtained from the Reference. In other words, the update happens only if the reference’s value hasn’t changed since it was tested. If the value has changed the spin lock loops back to again fetch and test the value (thus the name “spin lock”).

Again, the test code is not exactly the code that would be used (as Dagger does) to create a lazy singleton. The code for the analog to the DoubleCheckedProvider, shown at the beginning of this article, would look like this:

class SpinProvider<a>(private val provider: Provider</a><a>) : Provider</a><a> {
private val value: AtomicReference</a><a> = AtomicReference()</a>

override fun get(): A {
while (true) {
val v1 = value.get()
if (v1 != null) {
return v1
}
val v2 = provider.get()
if (value.compareAndSet(null, v2)) {
return v2
}
}
}
}

I do not have clear predictions for the behavior of this lock. One might reasonably expect it to perform somewhat worse than the DCL on read but as well or better on write. It seems probably that it will be affected adversely by contention.

Results

After running the experiment I pulled the application databases from each device, converted them to CSV format, and used gnuplot to plot graphs. In a couple of cases I removed a small number of outlying points from the data. Also, on a couple of the graphs, in order to reveal some tightly grouped values, I have set the y-range so that a few points are off the top of the graph.

In the first set of four test graphs below read test points are represented by “+”s and write test points by “x”s. The uncontested tests are purple. Points for contested tests with 5, 10, and 20 threads are drawn in blue, green, and red, respectively.

Null Test

null test

These graphs set the error bars for the other experiments. Since the read and write states for the Null test are exactly the same, any perceived differences are pure error.

For an uncontested lock, the errors are very small. Oddly — and contrary to initial expectations — both the average time to access and the amount of error increase as the number of threads in contention for the lock goes up.

Synchronized Test

sync test

As predicted, simple synchronization degrades rapidly under contention. Against expectations, the times for read and write access spread considerably, as contention rises. Quite surprising, indeed, is that, on the two Nexus devices, it is reading, not writing, that degrades fastest.

Double Check Test

double-check test

This test looks very much as expected. Under contention, write time degrades significantly. Read times degrade much more slowly. On two of the devices, they stay nearly constant.

Spin Test

spin test

The spin idiom, again, degrades under contention. On all except the Pixel 2, however the degradation for read and write access are nearly identical. Even on the Pixel, the degradation for the two different modes is very similar.

In the next set of two comparison graphs, read test points are, again, represented by “+”s and write test points by “x”s. Points for the test types: null, synchronized, double check and spin, are drawn in purple, blue, green, and red, respectively. In this section I present only the graphs for the two extremes, 1 and 20 threads.

Uncontested Access

1 thread test

In an uncontested environment the behaviors of the three locking mechanisms differ very little. The times for read access for two optimized algorithms are somewhat better than the times for simple synchronization. The write times for the optimized algorithms, however, appear to be somewhat worse than simple synchronization.

Contested Access: 20 threads

20 thread test

In a contested access environment, reading any of the optimized locks is faster than reading the simple synchronized lock. The most apparent feature of this test is that writing a double checked lock is very slow: substantially slower than a write with simple synchronization.

Analysis

Nearly as expected, the behaviors of each of the tests degrades as contention increases.

The results for read and write Null tests — actually identical reads of a final variable — are reasonably consistent. An examination of the byte code provides an explanation for the consistency with which the read times are slower than the write times. The test harness code that runs a test looks like this:

fun runOnce() {
val newVal = Object()
val tRead = measureNanoTime { value = readTest.get(initVal) }
val tWrite = measureNanoTime { value = writeTest.get(newVal) }
update(tRead, tWrite)
}

An examination of the corresponding byte code provides some insight. Although the reference to newVal is already in a register, the reference to initVal has to be loaded from a field. The two branches are not identical.

The read test looks like this:

iget-object v6, p0, Llocktest/TestOne;
->readTest:Llocktest/Test;
iget-object v7, p0, Llocktest/TestOne;
->initVal:Ljava/lang/Object;
invoke-virtual {v6, v7}, Llocktest/Test;
->get(Ljava/lang/Object;)Ljava/lang/Object;

whereas the write test looks like this:

iget-object v7, p0, Llocktest/TestOne;
->writeTest:Llocktest/Test;
invoke-virtual {v7, v0}, Llocktest/Test;
->get(Ljava/lang/Object;)Ljava/lang/Object;

I am less able to explain the degradation of the Null test as contention increases. I originally suspected a hidden synchronization, perhaps in getElapsedTimeNanos. Reading the code for that function, however, I can find no such synchronization. Instead, perhaps the degradation is an artifact of scheduling: there are more threads than there are cores on any of the devices.

The baseline standard deviations for all Null write tests, for the three devices are 5.99ms, 17.70ms, and 1.09ms, respectively, for the Nexus 4, the Nexus 6 and Pixel 2.

It is interesting to observe the rate of degradation of the Null test, across devices. On the older, Nexus devices the degradation is nearly exponential. On the Pixel, however, it appears to be nearly logarithmic. It would be interesting to conduct further tests in this area.

The behavior of the simple synchronization test is the most surprising result in the entire experiment. I admit to revisiting the code, both in the application and in the analysis tools, several times, to be sure that I had not reversed the results.

Because the behavior does not appear in other tests, I not am inclined not to suspect the harness. Examining the byte code for the test does not seem to provide any useful insights either:

.method public get(Ljava/lang/Object;)Ljava/lang/Object;
iget-object v0, p0, Llocktest/SynchronizedTest;
->lock:Ljava/lang/Object;

monitor-enter v0
const/4 v1, 0x0

.local v1, "$i$a$1$synchronized":I
:try_start_0
iget-object v2, p0, Llocktest/SynchronizedTest;
->value:Ljava/lang/Object;
if-eq v2, p1, :cond_0
iput-object p1, p0, Llocktest/SynchronizedTest;
->value:Ljava/lang/Object;
:try_end_0
.catchall {:try_start_0 .. :try_end_0} :catchall_0

:cond_0
nop
.end local v1 # "$i$a$1$synchronized":I
monitor-exit v0

return-object p1
// …
.end method

For the single case of a simple synchronization lock on the Nexus 4, I created an alternative version of the experiment (branch: rand-test) that randomly re-orders the read and write tests, and moves the initialization value to a local variable (register) in the harness. The results from running this test are different — times are closer together — but not dramatically so.

Note that the Pixel’s behavior on the simple synchronization test is dramatically better and much more what I expected: write time degrades as the lock is contested. This might be because the Pixel is the most modern of the three devices and has twice the number of cores. Alternatively, perhaps there has been a significant improvement in either ART’s or the CPU’s handling of memory barriers.

The double check algorithm performs very much as billed. Both read and write access times degrade as lock contention increases but, unlike the simple synchronization test, read access degrades much more slowly than write access.

Note that the times for write case of the double check idiom are not the same as the write times for the simple synchronization test. This is a bit surprising, since the source code for the double-check write case is, almost identical to the source code for simple synchronization.

The byte code for the double-check idiom, however, is significantly different from the simple synchronization bytecode. The label cond-1 marks the beginning of the write branch. It contains a second read from the protected variable:

.method public get(Ljava/lang/Object;)Ljava/lang/Object;
iget-object v0, p0, Llocktest/DoubleCheckTest;
->value:Ljava/lang/Object;
.local v0, "v1":Ljava/lang/Object;
if-ne v0, p1, :cond_0
return-object v0

:cond_0
iget-object v1, p0, Llocktest/DoubleCheckTest;
->lock:Ljava/lang/Object;
monitor-enter v1
const/4 v2, 0x0
.local v2, "$i$a$1$synchronized":I

:try_start_0
iget-object v3, p0, Llocktest/DoubleCheckTest;
->value:Ljava/lang/Object;
:try_end_0
.catchall {:try_start_0 .. :try_end_0} :catchall_0

.local v3, "v2":Ljava/lang/Object;
if-ne v0, p1, :cond_1
nop

.end local v2 # "$i$a$1$synchronized":I
.end local v3 # "v2":Ljava/lang/Object;
monitor-exit v1

return-object v3

.restart local v2 # "$i$a$1$synchronized":I
.restart local v3 # "v2":Ljava/lang/Object;

:cond_1
:try_start_1
iput-object p1, p0, Llocktest/DoubleCheckTest;
->value:Ljava/lang/Object;
iget-object v2, p0, Llocktest/DoubleCheckTest;
->value:Ljava/lang/Object;
:try_end_1
.catchall {:try_start_1 .. :try_end_1} :catchall_0

.end local v2 # "$i$a$1$synchronized":I
.end local v3 # "v2":Ljava/lang/Object;
monitor-exit v1

return-object v2
// ...
.end method

Access times for the Spin algorithm degrade, nearly identically for both read and write access. But wait! Perhaps this isn’t a bad thing! Let’s compare the algorithms head to head.

Uncontested Read

uncontested read

While both optimized algorithms outperform simple synchronization on an uncontested read, the improvement is barely significant: no more than a millisecond. The difference is well within the error-bars.

Uncontested Write

uncontested write

The unexpected speed of a synchronized write make the results of this comparison surprising. In this environment, simple synchronization always beats double-check locking; on some devices by several milliseconds.

The spin lock is comparable with the double-check lock, beating it only on the Nexus 4. Even there, though, it does not out-perform simple synchronization.

Note that, as in the uncontested read test, the differences between the tests scores do not exceed the null test error.

Contested Read

contested read

In a contested read environment the optimized algorithms clearly demonstrate their advantage. Times for the two optimized algorithms are within the margin of error of each other and both are significantly better (> 100ms on two of the three devices) than simple synchronization.

Contested Write

contested write

In this experiment, in a contested write environment, the double-check lock is the worst performer. It is never better than simple synchronization; on the two Nexus devices it is significantly worse. The spin lock outperforms not only the DCL, but also simple synchronization

Conclusions

This experiment does not demonstrate ART optimization. This is probably because even the experimental Activity’s onPause was never called during data collection. It would be interesting to stop the app, wait a while, and then run it again. It would also be interesting to have a look at its .oat file.

The answer to the question posed at the beginning of this experiment: “Is the DCL performant” is mixed. Regardless of the device or the Android version, the DCL definitely does provides significant optimization for contested reads.

In other environments, it does not fare so well. In this experiment, in an uncontested environment, it did not significantly outperform simple synchronization. In this experiment, in a contested write environment, it performed very poorly: worse than simple synchronization on some devices/Android pairs.

The big winner here, is the spin lock. In nearly every test it performs as at least as well as the DCL and in most, much better. Especially in a contested write environment, it outperformed the DCL by a substantial margin.

Summary

I undertook this experiment because I was curious. I hope it will stimulate discussion. Regardless of how that discussion goes, I think I have demonstrated the following:

  • If you are going to attempt to optimize concurrent code, be very careful. Even if there are flaws in this experiment, the timings are absolutely real. If the experiment is flawed, then your code may be flawed and non-performant as well.

  • If a lock is not contested, even on Android, optimizing it may, simply, not be important. A simple synchronized block may be entirely sufficient.

  • If access to the lock is contested, it may well be worth optimizing access. In this case a double-checked lock may be an effective optimization

  • When optimizing a lock, consider a spin lock. Especially if the protected state must be updated frequently, spin locks seems to be quite performant.

Again, the code, data and tools are here

Android SQLite for the DBA

As mobile devices become more and more important in the enterprise, you, as an enterprise database architect, may find yourself asked to participate in the design of the persistent data store in an Android application. Before you wade in, there are a couple of things you should know.

Introduction to SQLite

Android uses the open source database engine, SQLite. It is a small, server-less library and has features that are pretty attractive in the mobile environment. Data stored in SQLite databases is persistent across processes, power-cycling, and, usually, across upgrades and re-installs of the system software.

SQLite is an independent, self-sustaining OSS project. Originally developed in 2000 by D. Richard Hipp, it was quickly and broadly adopted as a way for applications to manage their persistent, structured data. A group of dedicated developers supports the large user community. SQLite is embedded in high-profile projects like Apple Mail, the Firefox Web Browser and Intuit’s TurboTax.

Reliability is a key feature of SQLite. More than half of the project code is devoted to testing and each release of SQLite is tested very carefully, especially under failure conditions. The library is designed to handle many different failures modes gracefully, including low memory, disk errors, and power outages. This is very important on a mobile platform where life is just way less predictable than it is on a device confined to a server room. If something goes wrong – the user removes the battery or a buggy app hogs all available memory – SQLite managed databases are unlikely to be corrupted and any user data is likely safe and recoverable.

There is comprehensive and detailed documentation about SQLite at the project website:

http://www.sqlite.org/docs.html.

On the downside, however SQLite is really not an RDBMS. Although you talk to it using SQL, many of the key features that you’d expect from a relational system are completely missing. As built for Android, SQLite does support transactions but it does not support either referential integrity or strong typing. It’s own documentation suggests that one should think of SQLite “not as a replacement for Oracle, but as a replacement for fopen()”

Datatypes in SQLite

Consider, for instance, the following interaction:

sqlite> create table test (
...> c1 biginteger, c2 smalldatetime, c3 float(9, 3));
sqlite> insert into test values("la", "la", "la");
sqlite> select * from test;
la|la|la
sqlite>

Although SQLite syntax supports a wide variety of data types — TINYINT, BIGINT, FLOAT(7, 3), LONGVARCHAR, SMALLDATETIME and so on — the column type is really no more than a hint to help SQLite choose an efficient internal representation for the data stored in the column. SQLite determines the internal storage for a column using a handful of simple rules that regulate “type affinity”. These rules are very nearly invisible when inserting or recovering data from the database. They appear to affect only the amount of space that a given dataset occupies on disk. There are full details for type affinity at:

http://www.sqlite.org/datatype3.html#affinity

In practice, many developers just restrict themselves to four primitive internal storage types used by SQLite: integer, real, text, and blob, and explicitly represent booleans as integers and timestamps as text. Especially the latter, representing timestamps as text, can be tricky. There are details here:

http://www.sqlite.org/lang_datefunc.html

Primary Keys SQLite

One of the most important concepts in relational databases is the primary key. No, no… don’t worry: SQLite does support primary keys! It even supports composite (multi-column) primary keys. Beware, though, of primary keys that are not integer typed. In addition to implying that a column is UNIQUE the primary key constraint should also imply that it is NOT NULL. Unfortunately, because of an oversight in its early versions, perpetuated for backwards compatibility, SQLite allows any primary key type other than integer to contain NULL values. As shown below — because each NULL is a distinct value different from any other NULL — SQLite permits a primary key column to contain multiple NULLs and thus multiple rows that cannot be distinguished by their primary key. If your table needs a primary key, consider making it an integer primary key.

sqlite> create table test (key text primary key, val text);
sqlite> insert into test(val) values("foo");
sqlite> insert into test(val) values("bar");
sqlite> select * from test where key is not null;
sqlite> select * from test where key is null;
|foo
|bar
sqlite>

A related issue arises from a common use of of SQLite databases in Android. The typical way of viewing a dataset in Android employs a Cursor, the standard class that an application uses to get data from a table, combined with a ListAdapter, a class that relates each row in a cursor to its representation in a cell on the screen. The implementation of ListAdapter requires a column named “_id” that uniquely identifies each row in the cursor: essentially a primary key. This is not a requirement that every table contain a primary key column named “_id”. It is necessary only that every join/projection viewed through a ListAdapter have such a column.

There are several ways to do this. If the table contains a primary key whose name is “_id” no further work is required. Not only that, but naming the row “_id” gives future developers a pretty good hint about the way the table is being used.

Another possibility, though, is that a primary key with another name can be renamed to “_id” in the query:

select part_num _id, supplier, price from parts;

This works and may allow db columns with more descriptive names.

One other possibility come from the fact that every SQLite table has an implicit column named “rowid”. This column — unless it is explicitly redefined at table creation — contains a 64 bit integer that identifies the corresponding row: an implicit integer primary key. That provides another way of fulfilling the need for an _id column:

select rowid _id, supplier, price from parts;

Foreign Keys in SQLite

SQLite doesn’t support the FOREIGN KEY constraint at all, as demonstrated here:

sqlite> create table people (
...> name text, address integer references addresses(id));
sqlite> create table addresses (id integer primary key, street text);
sqlite> insert into people values("blake", 99);
sqlite> insert into addresses(street) values ("harpst");
sqlite> select * from people;
blake|99
sqlite> select * from addresses;
1|harpst
sqlite> select * from people, addresses where address = id;
sqlite>

In a database engine that supported referential integrity, the first insert statement would fail with a foreign key constraint violation. In fact, the attempt to create the table in the first create table statement would fail for the same reason.

There is good news here. Android programs must create their databases programatically. The method onCreate and onUpdate in the SQLiteOpenHelper class are responsible for running the DDL necessary to create any database objects required by the application. The process of creating and deleting tables is much less likely to cause errors if the error checking is neither incremental nor part of the database system. The code that creates the database can — and probably should — verify the schema in its entirely, once it is complete.

Because SQLite doesn’t support referential integrity, code using the database must be prepared to handle error cases. For example, when designing a schema for an Android application it may well make sense to replace the standard practice of defining dimension tables — tables that enumerate the values legal in the column of some other table — with checks in code.

Data safety in SQLite

Finally, it is well to remember that data stored in a SQLite database is not automatically encrypted. The Android data sandboxing mechanism is a pretty good first line of defense. Data that belong to one application is protected by Unix file permissions from access by all other non-root applications. For truly sensitive data, though — data that must be protected even if a device is lost or stolen — you might consider encrypting the data as it is inserted. If encrypting seems advisable, have a look at the SQLCipher project: http://sqlcipher.net/

In conclusion…

As a tool embedded on portable devices, SQLite is simply not an RDBMS. Many of the features that make a true relational system useful are completely absent: strong typing, reliable primary keys, and referential integrity. Even as simple repositories for structured data, however, SQLite databases systems can benefit from the skills that an experienced DBA brings to the table. Good organization and reasonable normalization can be a big help in creating an application that isn’t already painted into a corner as it expands to support new features.

AnDevCon III

Had a really great time speaking at AnDevCon III, yesterday!  The audience was awesome and turned what I expected to be a 40 minute talk into 70+ minutes.

All the materials from the talk are on GitHub, here:

https://github.com/bmeike/AnDevCon.git

Singletons in Android

There was a surprisingly acrimonious discussion about this, in the Android Developer’s Google Group, recently. Apparently the topic can be confusing.

The issue is that developers occasionally find themselves in need of a singleton. As a pattern, I would say that use of singletons has pretty well been discredited (see, e.g., WhySingletonsAreControversial ). Still, in Android, in a muli-activity application, it is entirely likely that there will be shared data and the desire to store that shared data in some place that is accessible to all application activities.

The problem with Singletons is that they really don’t exist. An instance of some kind of state is only a singleton within some context. A “singleton” on your phone is, clearly, not the same as the instance of the same singleton on my phone. It is even possible that the instance of the singleton on my phone this morning isn’t the same as the instance that was there last night, before I rebooted the phone. This only becomes a problem if the number or lifespan of the singleton surprises someone.

Before Java 5, the typical definition of a singleton, in Java, looked like this:

public final class Singleton {
    private static final Singleton instance = new Singleton();
    public static Singleton getInstance() { return instance; }

    private Singleton() {}
    // ...
}

After Java 5, the recommended implementation of a singleton looked like this:

public enum Singleton {
    SINGLETON;

    // ....
}

The idea is that there is only a single instance of the definition of a class (or enum) so we make that single class instance hold and return the singleton instance of the class. There are tricky extensions of this — usually ways to make it initialize lazily — but this is the gist.

In the Java community, the surprises typically showed up in applications that used multiple ClassLoaders. ClassLoaders are the things that read class definitions from, usually, the file system, and convert them into running code. The surprise comes when a developer doesn’t realize that a class definition is unique per ClassLoader (an object of which they may never even have heard) not per application. The Tomcat application server, for instance, loads webapps (.war files) each in its own ClassLoader. If you make changes to an app and reload it, it gets loaded in a new ClassLoader. If the previous version of the application hasn’t terminated yet it is entirely possible to have two distinct copies of the “same” singleton, one in each ClassLoader. …and that’s surprising.

It is entirely possible to for the same thing to happen, in Android. Android’s similarity to Java absolutely extends to its definition of classes as unique per ClassLoader. Multiple ClassLoaders: multiple instances of your singleton. You can demonstrate this with an app of about 10 lines. At least at this point, though, most Android applications don’t make use of ClassLoader magic and so most developers aren’t getting this particular surprise.

When Android developers want a singleton — perhaps the DAO or a place to remember a running AsyncTask — they might consider keeping the reference to it in a custom subclass of Application. If you read the official documentation for the Application class, though, you’ll find this comment, barred for emphasis:

There is normally no need to subclass Application. In most situation, static singletons can provide the same functionality in a more modular way. If your singleton needs a global context (for example to register broadcast receivers), the function to retrieve it can be given a Context which internally uses Context.getApplicationContext() when first constructing the singleton.

This is all fine, so far. But here comes a surprise. The Android OS may completely terminate your application and then recreate it. When the new process is created, your classes are loaded and initialized. Exactly how to describe this terminate/reload event was the source of significant heat in the Google Groups discussion. I’ll resist the urge to poke fun at the guys that insisted that this was not a suprise because the reload happens in a new process [The classes are not reloaded! Rather there is a new “process”. What is a “process”? It is an undetectable entity that makes it appear that your classes have been reloaded…] because they are exactly right. An Android application will, frequently, span several processes. This is not something that is common in, say, the desktop world. It may be surprising.

The point is that you cannot put program state into class data members and expect it to stay there. Frequently, this isn’t a problem. If you use a class data member to store a reference to something idempotent, e.g., your DAO, you don’t care which specific instance you happen to use. That is, this code works just fine:

public class MyApplication extends Application {
   private static final MyDAO db = new MyDAO();
   public static MyDAO getDB() { return db; }

   // ...
}

This code, however, won’t work:

public class MyApplication extends Application {
    private static long lastUpdate;
    public static void setLastUpdate(long udate) { lastUpdate = udate; }
    public static long getLastUpdate() { return lastUpdate; }

    // ...
}

… or, at least, you may be surprised to find that getLastUpdate returns 0, even though the code has called setLastUpdate() at some point. Suppose an Activity in the application looks like this:

// ...
setContentView(R.layout.main);
((TextView) findViewById(R.id.myText))
    .setText(String.valueOf(getLastUpdate()));
((Button) findViewById(R.id.myButton)).setOnClickListener(
    new Button.OnClickListener() {
        @Override public void onClick(View v) {
            MyApplication.setLastUpdate(System.currentTimeMillis());
        } } );
// ...

If I push the button, then the Home key and then run a bunch of other apps (on my Nexus S, about a dozen), when I return to this app, the text view will read 0, despite the fact that I definitely pushed the button.

I don’t think anyone is claiming that this is a bug. …and it certainly helps to understand why it happens. As my colleagues point out, it happens because the application survives process boundaries. It is definitely surprising, though, and it puts that quote from the documentation, cited above, in a new light.  Neither the application object nor a static singleton can be expected to hold persistent state for the life of the application! It just won’t work.

What might be a bug is that it is hard to tell when a process ends (thus my jibe about processes being undetectable). I have empirically determined that Application.onTerminate() is not always called, and I have from an authority I respect, that it is, actually, never called (documentation to the contrary). It is probably best to design so that you don’t depend on knowing, anyway. To do that, your static fields must appear to have a value that is constant as of creation. Making them final is a good start.

In some ways, this is the opposite of the problem in Tomcat.  Whereas, in affected web apps, a single object might, at some point in its lifetime, have references to multiple, inconsistent copies a given singleton, in Android a single object, over its lifetime, can’t get a reference to even one instance that stays consistent.  So, don’t be surprised.  It is really easy to create an application in which an Activity, for instance, retains some state for much longer than fields in the Application object, or its own static fields. Nothing new: we’ve all initialized apps from the file system or from a database, before. Usually, though, we do it at “startup” and we have some definite ideas about when “startup” happens.. That’s not how Android works. Serialize your state into a Bundle or Sqlite, if you need to keep it around.

Multi-Platform Fragments, the Webcast

I’m going to be presenting the Multi-platform Fragments topics that I blogged about, here, previously, in two webcasts.  The first is part of the AT&T Developer program on Aug 25, 10AM PDT.

I’ll be presenting some of the same material one more time on Friday, Sept 9 as part of the O’Reilly Webcasts series.

Stop by and ask questions.

 

 

It’s in the stores!

The new book is out!  You can get your copy here!

The combination of perspectives from the 4 authors have, I believe, built something way better than might have happened if we’d each written our own.  Obviously, I’m prejudiced.  Check it out for yourself.

Multi-platform fragments, Part II

In Part I I describe a pretty well-known way of using resources to make an application look good on a variety of devices.  It works pretty well as far as it goes, but 20% of Android users out there are still running Eclair, and some of them are using HVGA screens.  For them we’ll need, reluctantly, to back away from fragments.  It turns out that that isn’t so bad either.

First move the existing layout directories, from Part I, “layout” and “layout-port” so that they apply only to large screens.  Rename them “layout-large” and “layout-large-port”.  The application will continue to behave as it did in Part 1, as long as the device screen qualifies as “large”.   BTW, here’s some handy code that will let you know what kind of screen Android thinks it is dealing with:

Configuration config = getResources().getConfiguration();

Log.d(TAG, "Orientation: " + config.orientation);

Log.d("TAG, "Size: " + (config.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK));

Here’s a new version of the main layout.  Put it in “layout”, the default for normal (and small) platforms:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout

xmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="vertical"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

>

 

<ListView

android:id="@+id/contacts"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:layout_weight="2"

/>

</LinearLayout>

The trick is that this version is completely missing the FrameLayout that the previous versions used to position the fragment. Here’s a new version of onCreate that determines whether to use fragments, or not:

@Override

public void onCreate(Bundle state) {

super.onCreate(state);

 

setContentView(R.layout.main);

 

final boolean useFrag

= null != findViewById(R.id.contact_detail);

 

if (useFrag) { installFragment(); }

 

//...

}

It only installs the visible fragment showing the contact details if there is a place to put it.  On small screens, then, no fragment will get created.

There’s just one more piece: what to do when there’s a click in the list of contacts.  In the old version we created a new fragment and put it on the stack.  In this version, though, we either stack a fragment or a new activity, depending on whether there’s a place to put the fragment or not.  The activity’s onClickHandler calls launchDetails to navigate to the contact details, how ever they are represented in the UI.  It looks like this:

void launchDetails(int pos, boolean useFrag) {

//... get the name and id from a cursor

 

if (useFrag) { stackFragment(id, name); }

else { stackActivity(id, name); }

}


private void stackFragment(String id, String name) {

FragmentTransaction xact

= getSupportFragmentManager().beginTransaction();


xact.replace(

R.id.contact_detail,

ContactDetailFragment.newInstance(id, name),

FRAG_TAG);

xact.addToBackStack(null);

xact.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);

xact.commit();

}


private void stackActivity(String id, String name) {

Intent intent = new Intent();

intent.setClass(this, ContactDetailActivity.class);

intent.putExtra(ContactDetails.TAG_ID, id);

intent.putExtra(ContactDetails.TAG_CONTACT, name);

startActivity(intent);

}

That’s it!  When this application runs on a small screen, it will launch a new activity into the back-stack, instead of a new fragment.  It looks like this:

No frags1 No frags2

This idea comes from one of Diane Hackborne’s posts on the Android Developer’s blog.  It’s so tasty, though that it bears repeating.  The rest of the docs for fragments are here.

There are a couple of other things about this app that are worthy of note.  First, as is, it will treat an xlarge screen like a small or a normal one.  That’s probably not right.  Also, I suppose, how it is that the demo has an Activity and a Fragment with the same behavior could use a little explanation.

You can find all the code for this demo application here.

Multi-platform fragments, Part I

This is going to be a bit long.  I’ve been away from Android for a while, mostly looking at embedded Linux and Meego… but that’s another story. I’ve been meaning to write about some clever tricks for building applications that can work on a wide variety of platforms.  I’ll do it in two posts.

The advent of tablets/slates/pads, brings the problem of making an application’s UI look good on a wide variety of devices to a whole new level.  Until Honeycomb, with device independent pixels and a couple of fine tuned bitmaps, you could probably cover most of the devices out there.  Now that Fragments have arrived, an app may actually have substantially different behaviours on different platforms.  On a small screen it may show only a single window at a time and use the back button for navigation.  On a larger screen, however, it might work need multiple windows to make use of the space.  Sounds like a nightmare…

It turns out that it isn’t so bad.  A little experimentation and a close read of the docs reveal couple of cute tricks will contain the whole issue in just a few lines of code.

First off, use the ACL (Android Compatibility Library).  An app that is based on Fragments, without the ACL cannot run on pre-Honeycomb Android.  Game over.  In order to support a wide variety of platforms, you’ve got to code to the ACL.

To use it, you just copy it from its home:

$ANDROID_SDK/extras/android/compatibility/v4/android-support-v4.jar

… to a directory named “lib” in your project 9and add it to your Eclipse build path).

Consider an example app that displays information about your Contacts. It uses fragments and is meant for a tablet in landscape orientation Here’s its layout, the file “main.xml” in the directory “res/layout”.

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout

xmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="horizontal"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

>

<ListView

android:id="@+id/contacts"

android:layout_width="0dp"

android:layout_height="fill_parent"

android:layout_weight="1"

/>

<FrameLayout

android:id="@+id/contact_detail"

android:layout_width="0dp"

android:layout_height="fill_parent"

android:layout_weight="2"

android:background="@color/blue"

/>

 </LinearLayout>

The FrameLayout will be replaced by a fragment, in the code.  That looks like this:

public class ContactViewer extends FragmentActivity {

private static final String FRAG_TAG

= ContactViewer.class.getCanonicalName() + ".fragment";

public void onCreate(Bundle state) {

super.onCreate(state);


setContentView(R.layout.main);

 

installFragment();

 

// ...

}


private void installFragment() {

FragmentManager fragMgr = getSupportFragmentManager();

 

if (null != fragMgr.findFragmentByTag(FRAG_TAG)) { return; }

  FragmentTransaction xact = fragMgr.beginTransaction();

xact.add(

R.id.contact_detail,

ContactDetailFragment.newInstance(null, null),

FRAG_TAG);

xact.commit();

}

Pretty straighforward fragment code.  ContactDetailFragment is the fragment class and R.id.contact_detail is where it goes, the FrameLayout.  I’ve mentioned, previously, using fragment’s tagging facility to prevent leaking them.

If you run this on a tablet, landscape WXGA, it looks pretty good:

Landscape

Running it on a phone, in portrait WVGA800, is another story:

Smooshed landscape

The screen is acutually still big enough to support two windows but the proportions have to be different and they have to be layed out vertically.  This turns out to be dead simple.  In the “res” directory, create a new sub-directory named “layout-port”, next to the original “layout”.  Copy “main.xml” into it and reorient it for the smaller portrait screen:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout

xmlns:android="http://schemas.android.com/apk/res/android"

android:orientation="vertical"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

>

<ListView

android:id="@+id/contacts"

android:layout_width="fill_parent"

android:layout_height="0dp"

android:layout_weight="2"

/>

 

<FrameLayout

android:id="@+id/contact_detail"

android:layout_width="fill_parent"

android:layout_height="0dp"

android:layout_weight="1"

android:background="@color/blue"

/>

</LinearLayout>

We might copy “contact_detail.xml” over as well and tweak font sizes and such a little so that everything looks nice.  With no code changes the app UI will now look pretty good on a wide variety of screens — including the Honeycomb tablet rotated to portrait.

Portrait

The Android system allows you to group resources according to the configuration of the runtime device screen.  The documentation has the details of how this works.  Basically, Android will prefer resources from a subdirectory of “res” the that most closely corresponds to the device on which your app is running.  It is all covered here:

http://developer.android.com/guide/practices/screens_support.html

All of this was introduced back in the Eclair days.  In Part II, though, I have a neat trick that’s buried in the Honeycomb docs that makes this same code compatible with even older and smaller phones.

Programmatic and Layout fragments

I finished a deep dive into the new Fragments feature in Honeycomb.  It’s an interesting feature — combining the UI of a View with the lifecycle of an Activity — and it has a few interesting complexities.

I’m getting a kick out of the two senses of the word “fragment” evident in articles like this one, that talk about the release of the ACL (Android Compatibility Library).  The ACL allows Android releases as far back as Donut to use fragments.  The point seems to be that back-fitting Fragments into older releases reduces Android’s perceived version fragmentation problem…

I came across one issue, using Fragments, that qualifies as a “gottcha”.  I don’t think I’d call it a bug but it certainly can be a surprise.

Consider the canonical fragment demo: an application that presents a list view and then a fragment that shows content based on the selection in the list.  You might imagine an RSS reader or a mail application, or something like that.  You might expect to set up a screen layout that looks something like this:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ListView
            android:id="@+id/list"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1" />
    <fragment android:name="net.callmeike.android.example.FragmentationBomb"
            android:id="@+id/fragment"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="2" />
</LinearLayout>

That seems like a perfectly reasonable approach, based on the documentation.  It’s a static definition for a page consisting of the list and the fragment that you want visible when your applications starts up.  Presuming this layout lives in a file named “main.xml”, you’d make it visible like this:

@Override
public void onCreate(Bundle state) {
   super.onCreate(state);
   setContentView(R.layout.main);
   // ...

There’s already something to be careful about.  The fragment class, net.callmeike.android.example.FragmentationBomb, will be instantiated during that call to setContentView.  That means that the fragment cannot count on there being a selection in the list from which it can determine the content it should display.  It had better be able to handle an empty selection.

There’s another issue, though that is much more subtile.  A key feature of a fragment is that it can be put on the back stack.  This is nice because it makes multi-pane applications navigate just like their single-pane cousins.  When using an Android app on a small screened device, a user navigates forward onto a new screen — perhaps by selecting something — but then pops back to the previous screen simply by pushing the back button.

On a device with a larger screen, an app like this one should behave analogously. If the user selects the second item in the list, then the fifth, and then pushes the back button, you’d hope that the screen looks exactly as it did when they originally selected the second item.  The back button should back out actions, exactly as it does on a small screen (or in a web browser, for that matter).

Fragment transactions enable exactly that behavior:

FragmentTransaction xact = getFragmentManager().beginTransaction();
xact.replace(R.id.fragment, FragmentationBomb.newInstance(selection));
xact.addToBackStack(null);
xact.commit();

This bit of code puts the current fragment on the back stack and replaces it with a new fragment instance — presumably based on a new selection in the list view.  When the user pushes the back button, the back stack is popped and the previous list selection and the fragment that contains its contents are restored.  Perfect!

Well, almost.  An application implemented as described above will fail and crash with a fairly inscrutable message like this:

java.lang.IllegalStateException: Fragment did not create a view.
    at android.app.Activity.onCreateView(Activity.java:4095)

It turns out that fragments created in a layout and fragments created programmatically are very different animals and have very different lifecycles.  Replacing one with the other is bound to cause failures.  You can drive the bug by running the transaction code, once, so that there is a programmatically created fragment visible, and then rotating the screen from portrait to landscape.

A fragment that is created as part of a layout has its onCreateView method called when it leaves the Fragment.INITIALIZING state.  If the fragment is created programmatically its onCreateView method isn’t called until it leaves the Fragment.CREATED state.  When Activity.onCreate is called, the fragment is still in the Fragment.CREATED state: it’s onCreateView method has not been called and it has no view.  The moral appears to be: “Never mix layout and programmatic fragments”.

While the code could be changed so that the layout fragment reloads its content when the list view selection changes, that defeats the whole point of the fragment transaction: the back stack.  A better solution uses only programmatically created fragments.  Use a layout like this:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
   <ListView
            android:id="@+id/list"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1" />
    <FrameLayout
            android:id="@+id/fragment"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="2" />
</LinearLayout>

…and create all of your fragments programmatically,  installing them in the view like this:

FragmentManager fragMgr = getFragmentManager();
FragmentTransaction xact = fragMgr.beginTransaction();
if (null == fragMgr.findFragmentByTag(FRAG_TAG)) {
    xact.add(R.id.fragment, FragmentationBomb.newInstance(selection), FRAG_TAG);
}

The fragment will be occupy the space created for it by the FrameLayout item.  The FRAG_TAG is just a unique identifier to make sure you don’t add that fragment more than once.  Once you’ve tagged the fragment in the layout, you can recover that exact fragment with the findFragmentByTag call.  If the fragment already exists, adding it again would leak fragments.  Using the tag guarantees that you will only create add the fragment once and can subsequently replace it.

It turns out that there’s a really slick way to handle multiple devices, using layouts and fragments.  I’ll describe that later.

AIDL and Fragments

Catherine is out of town, so it’s just me and the cat.  I’m trying to catch up on Fragments, AIDL and the Android Security model.

AIDL bumps into some serious problems when combined with design for inheritance.  I think the best idea is an abstract base class whose unmarshaller, the reference stored in the public CREATOR member, is a factory for all of the subtypes.

I suppose you could do it like JDBC did: each subclass registers, in a static initializer, with the base class.  Nah… that’s a bad idea.