I'm trying to increment the value of an integer column in all rows of a SQLite table. Let's say the table name is items and the column name is value. The code looks like this:
SQLiteDatabase db = getDatabase();
db.execSQL("update items set value = (value + 1)");
The code is running in a unit test, and the entire test suite halts completely with the following message:
Test failed to run to completion. Reason: 'Instrumentation run failed
due to 'Native crash''. Check device logcat for details
Here is the entire crash dump from logcat.
I have verified in a SQLite shell that the update statement above does indeed work as written and will increment the value of the column. I've also tried these variations, resulting each time with the same crash:
// variation 1
String sql = "update items set value = ?";
String[] sqlArgs = new String[]{ "(value + 1)" };
db.execSQL(sql, sqlArgs); // crashes
// variation 2
SQLiteStatement statement = db.compileStatement();
statement.execute(); // crashes
// variation 3
// Near as I can tell, below is what execSql does under the hood
SQLiteStatement statement = db.compileStatement();
statement.executeUpdateDelete(); // crashes
Has anyone run into something like this before? How can I execute an update statement like the one above without crashing?
EDIT
This crash appears to happen only within an Android JUnit test. In an actual running application, the execSQL() call with the update statement above executes successfully. I'd still like to know what causes it, but at least production code appears not to be affected by it...
I also faced the same problem with my app.
In my app we have around 30-40 packages and we tested each and every class together.
The test cases are failing in between randomly giving below error:
Test failed to run to completion. Reason: 'Instrumentation run failed due to 'Native crash''. Check device logcat for details
Its a memory Issue while executing the test cases together for all the test classes you create.
So, just override the onTearDown() method in each test class and release the memory by nulling the objects used in that test class.
For Example:
protected void tearDown() throws Exception {
super.tearDown();
mActivity = null;
mInstance = null;
}
where mActivity and mInstance are the Instance variable used by all the test methods.
This overriding tearDown() and relealing object solved my problem.
Related
Edit, probably the better place to have posted this is on the appcenter forums (which I have now done):
https://github.com/microsoft/appcenter-cli/issues/1137
In short, an app I'm working on is built in appcenter and set to run unit tests, the problem I have though is that I'm unable to figure out what is making them fail (they won't fail locally).
I can't share the code that I'm having trouble with here, but to illustrate the problem I'm having, Suppose I defined the following kotlin function:
fun returnFooString() {
return "Foo "
}
and wrote the following test:
#Test
fun test_returnFooString_returns_foo() {
val foo = returnFooString()
assertThat("${foo} is equal to "Foo", "Foo", foo)
}
What I'd like to see is something like:
java.lang.AssertionError: Foo is equal to Foo
Expected: "Foo"
but: was "Foo "
Expected :Foo
Actual :Foo
However the only thing I would see in the appcenter logs for this failing test is:
com.mypackage.name.MyTest > test_returnFooString_returns_foo FAILED
java.lang.AssertionError at MyTest.kt:4
and so I have no clue what just happened. I'm still somewhat of a beginner to android development, and though I've searched google, I haven't been successful in finding something that looks relevant. Is there some setting that can be placed in the build.gradle to not suppress the assertion message, or some environment variable(s) I need to specify in appcenter, or something else to see what was expected and received?
Right now I'm seeing if I can throw exceptions in the test / code to shed some light on the issue but there must be a nicer way (especially since it takes about 10 minutes for a build)
Edit: throwing exceptions doesn't work, if I throw an exception logging out every variable I'm interested in, all I get back is something like:
com.mypackage.name.MyTest > test_returnFooString_returns_foo FAILED
java.lang.Exception at MyTest.kt:4
At this point it seems I either have to abandon the tests or do something crazy like writing 256 tests to figure out the first character my string has at position 0, then 10 minutes later another 256 to figure out the second ...
I turns out that logging can be enabled with the following:
testOptions {
unitTests.all {
testLogging {
showStandardStreams true
}
}
}
Whenever I call getContentResolver().applyBatch(authority,batch), My app crashes on a Asus mobile, while it works fine on other android smartphones.
Logcat
java.lang.NullPointerException: Attempt to get length of null array
at android.content.ContentProvider$Transport.applyBatch(ContentProvider.java:288)
at android.content.ContentProviderClient.applyBatch(ContentProviderClient.java:377)
at android.content.ContentResolver.applyBatch(ContentResolver.java:1244)
How can I solve this problem?
What happens:
You are calling ContentResolver.applyBatch() with a null operations array, this is why you receive a NullPointerException.
This method expects this parameter not to be null, as shown by its signature:
public #NonNull ContentProviderResult[] applyBatch(#NonNull String authority,
#NonNull ArrayList<ContentProviderOperation> operations)
throws RemoteException, OperationApplicationException
You should test the validity of your batch array before calling applyBatch(), and refrain from calling it should batch be null (assuming that having it null means there's no operation to apply).
Why does it work on some cellphones and not on other?
Either because the list of operations to apply depends on the cellphone itself or its configuration (installed apps, Android API, stored data, anything...), which makes it null in the specific case of your Asus ;
or because it works "by accident" on the other cellphones you have tested. This happens sometimes when the code does something wrong but without raising any error due to some permissivity you cannot rely on.
This depends on what your app does.
I'm building an android app using the Android Parse SDK, which gets all data from Parse at initialisation and stores it locally. Later, it will only update those entities (ParseObjects) which need so. I'm not getting any return from some Pin() operations, and similarly no callback when I use PinInBackground() and variants. Same happens with Unpin().
My code is something like the following. I have a list of ControlDate, a ParseObject which contains updated_at and updated_locally_at for each Parse data table. I use it to decide if I should query a given table (reducing number of queries). I iterate over this list when I perform a data update, in an IntentService, like this:
protected void onHandleIntent(Intent intent) {
for(ControlDate d : mUpdateQueue) { // mUpdateQueue is the list of ControlDate
if(d.entityNeedsUpdate()) { // returns true if updated_at > updated_locally_at
updateEntity(d);
}
}
private boolean updateEntity(ControlDate d) {
String tableName = d.getTableName();
Date lastLocalUpdate = d.getLastLocalUpdate();
ParseQuery<ParseObject> qParse = ParseQuery.getQuery(tableName);
qParse.whereGreaterThan("updated_at", lastLocalUpdate);
try {
// update the entities
List<ParseObject> entities = qParse.find();
ParseObject.pinAll(entities); // SOMETIMES GETS STUCK (no return)
// update the associated ControlDate
d.setLastLocalUpdate(new Date()); // updated_locally_at = now
d.pin(); // SOMETIMES GETS STUCK (no return)
}
catch(ParseException e) {
// error
}
}
}
Those operations SOMETIMES do not return. I'm trying to find a pattern but still no luck, apparently it started happening when I added pointer arrays to some of the entities. Thus, I think it may be due to the recursive nature of pin(). However it is strange that it sometimes also gets stuck with ParseObjects which do not reference any others - as it is the case with d.pin().
Things I've tried:
changing the for loop to a ListIterator (as I am changing the list of ControlDates, but I don't think this is necessary);
using the threaded variants (eg.: PinInBackground()) - no callback;
pinning each entity individually (in a loop, doing pin()) - a lot slower, still got stuck;
debugging - the thread just blocks here: http://i.imgur.com/oBDjpCw.png?1
I'm going crazy with this, help would be much appreciated!
PS.: I found this https://github.com/BoltsFramework/Bolts-Android/issues/48
Its an open issue on the bolts library, which is used in the Android SDK and may be causing this (maybe?). Anyway I cannot see how I could overcome my problem even though the cause for the pin() not returning could be an "unobserved exception" leading to a deadlock.
My application uses some complex sql statements so I've gotten in the probably bad habit of using execsql often, even when I could/should probably use something like insert or update for simple things(below).
However, I am wondering why this is not working
String query = "UPDATE OR ABORT " + myTable + " SET " + .... column names and values + WHERE ...
try {
db.execSQL(query);
} catch (SQLiteAbortException e) {
Log.i(TAG, "error in the update");
I've tried this with data that should clearly fail (ie, there is no matching record to update) but I am not hitting the catch. Initially I had used UPDATE OR FAIL and a SQLiteConstraintException but when that was not caught I tried the SQLiteAbortException which specifically states
An exception that indicates that the SQLite program was aborted. This
can happen either through a call to ABORT in a trigger, or as the
result of using the ABORT conflict clause.
What am I missing here?
Update: just adding this for reference on INSERT/UPDATE OR ABORT/FAIL If SQLiteAbortException is not the way, how to catch an update abort/fail?
I just tried to find an explanation for that behavior in the Java source code part of Android API level 19, but the only place where SQLiteAbortException is (re-)thrown is in a static helper class named DatabaseUtils. It gets originally thrown from native code using a method in android_database_SQLiteCommon.cpp. It is thrown when SQLite returned error code 4, which is named SQLITE_ABORT and documented as:
/* Callback routine requested an abort */
I strongly assume a C callback function is meant with that. You can register callbacks with SQLite and they seem to have some level of control. So it appears to me that error code which gets translated into an SQLiteAbortException has little to do with an SQL ABORT clause. in fact, I highly doubt that that exception ever gets thrown, since I don't think that the native part of Android's SQLite database driver hooks callbacks into SQLite that abort requests.
The SQLite documentation of ABORT is also specific which kind of error code to expect:
ABORT
When an applicable constraint violation occurs, the ABORT resolution algorithm aborts
the current SQL statement with an SQLITE_CONSTRAINT error (...snip)
So according to the documentation of SQLite and what the native Android source code actually does, the SQLiteConstraintException is to be expected in that case and apparently Android's documentation of SQLiteAbortException is not entirely correct.
I'm getting an NullPointerException when I insert values into to my SQLite table on Android and I don't understand why. I'm testing ContentValues and the database instance for null.
This is the insertion code:
public void insertOrIgnore(ContentValues values) {
SQLiteDatabase db = this.dbHelper.getWritableDatabase();
try {
//I added these null value checks to stop NPE, but doesn't help.
if (values != null && db != null) {
db.insertWithOnConflict(TABLE, null, values, SQLiteDatabase.CONFLICT_IGNORE);
}
} catch (SQLiteException e) {
} finally {
if (db != null) {
db.close();
}
}
}
where
public static final String TABLE = "albums";
Most of the time this code works with the data added to the database as expected. However, it sometimes and rarely generates the below error. The stack trace is from ACRA and I have not been able to isolate under what conditions this error occurs. I'm looking for pointers as to why this happens and what the conditions are. My knowledge of SQLite is beginner level.
java.lang.NullPointerException
at android.database.sqlite.SQLiteStatement.releaseAndUnlock(SQLiteStatement.java:290)
at android.database.sqlite.SQLiteStatement.executeUpdateDelete(SQLiteStatement.java:96)
at android.database.sqlite.SQLiteDatabase.executeSql(SQLiteDatabase.java:2025)
at android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java:1965)
at android.database.sqlite.SQLiteDatabase.beginTransaction(SQLiteDatabase.java:690)
at android.database.sqlite.SQLiteDatabase.beginTransactionNonExclusive(SQLiteDatabase.java:605)
at android.database.sqlite.SQLiteStatement.acquireAndLock(SQLiteStatement.java:247)
at android.database.sqlite.SQLiteStatement.executeInsert(SQLiteStatement.java:112)
at android.database.sqlite.SQLiteDatabase.insertWithOnConflict(SQLiteDatabase.java:1844)
at com.mydomain.myapp.albums.AlbumsData.insertOrIgnore(AlbumsData.java:89)
Line 89 is the db.insertWithOnConflict(...) call shown above.
I'm not looking for an answer with complete code necessarily but rather a pointer and explanation as to what's going wrong so I can begin to fix it myself.
EDIT:
The stack trace shows the NPE originates from line 290 of SQLiteStatement (v 4.03):
setNativeHandle(mDatabase.mNativeHandle);
So it seems the database instance is null. How can it become null during a transaction when I tested for null at the beginning of the transaction?
As mentioned here SQLiteDatabase close() function causing NullPointerException when multiple threads
The reason for your bug could be that you close the database at some point. Probably concurrently while the task that fails was not finished.
I've followed the stacktrace a bit and this is what roughly happens:
AlbumsData.insertOrIgnore(AlbumsData.java:89)
You call insertWithOnConflict, which builds the resulting sql string ("INSERT OR IGNORE INTO...") then wraps that together with the values from your ContentValues into a SQLiteStatement.
SQLiteDatabase.insertWithOnConflict(SQLiteDatabase.java:1844) - The resulting statement is to be executed now
SQLiteStatement.executeInsert(SQLiteStatement.java:112) - before the actual insert can happen, the database needs to acquire a lock.
SQLiteStatement.acquireAndLock(SQLiteStatement.java:247) - some checks happen here, the database object is as far as I can see not null at that point. Code decides that it has to start a transaction. The database object itself is as far as I can see not locked at that point.
SQLiteDatabase.beginTransactionNonExclusive(SQLiteDatabase.java:605) - just forwarding
SQLiteDatabase.beginTransaction(SQLiteDatabase.java:690) - after some checks (not sure if database has to exist here) it will try to execute execSQL("BEGIN IMMEDIATE;")
SQLiteDatabase.execSQL(SQLiteDatabase.java:1965) - just forward
SQLiteDatabase.executeSql(SQLiteDatabase.java:2025) - builds another SQLiteStatement out of "BEGIN IMMEDIATE;. This one should be executed now
SQLiteStatement.executeUpdateDelete(SQLiteStatement.java:96) - starts with checking the database lock, this seems to be okay and the database should not be null here. The statement is then executed and finally the database is to be unlocked again.
SQLiteStatement.releaseAndUnlock(SQLiteStatement.java:290) - cleans up some stuff and in the end fails with NPE because the database is null.
Line numbers don't match so there are probably vendor modifications / additions in that code.
As you can see, the code crashes before actually using the data you supplied. It was about to do
BEGIN TRANSACTION IMMEDIATE; -- crash
INSERT INTO table (...) VALUES (...);
-- (end transaction)
That makes it in my opinion a framework bug. The database object that is internally handled there should not be able to be null somewhere down the line, especially when it seems that it was not null further up in the stack.
I also think that it is possible that another hidden exception could be the root cause for this. There are a lot of try { /* do stuff */ } finally { /* clean up */ } blocks within the code and the finally part will be executed even if the try part throws an exception. Now the finally block could cause another exception and the result is AFAIK that the original exception is replaced by the new exception from the finally block.
Especially executeUpdateDelete() is like
try {
acquireAndLock(WRITE);
// actual statement execution
} finally {
releaseAndUnlock();
}
if the database is closed at that point, acquireAndLock or any code in the try part could fail and that could leave the database object at null which causes releaseAndUnlock to fail again. You should get the same stacktrace.
Apart from that, don't do empty catch blocks like catch (SQLiteException e) { /* empty */ }. Log them with ACRA if possible / you don't do that already.
This NPE appears to be from a custom ROM as the Android source code is pointing to different Methods than the ones you receive in the LogCat. What I do for such cases is that: if the rate of these exceptions is very rare, I ignore them as it is difficult to know what custom ROM is running on the phone and more difficult to get the source code of this custom ROM to know where the problem is.
Not many users are using custom ROMs, so if you extensively tested your App on different phones with different SDKs and the rate of the Exceptions you get is not that significant, you can ignore them. Otherwise, you can take a shoot in the dark and speculate what can be in this custom ROM that is causing NPE (personally, I think it is not worth the effort).