[TIMOB-26878] Android: Ti.Database.install() fails if destination directory does not exist
GitHub Issue | n/a |
---|---|
Type | Bug |
Priority | High |
Status | Closed |
Resolution | Fixed |
Resolution Date | 2019-05-16T22:54:02.000+0000 |
Affected Version/s | Release 7.5.0 |
Fix Version/s | Release 8.1.0 |
Components | Android |
Labels | android, database, engSchedule, install |
Reporter | Andreas Pingas |
Assignee | Joshua Quick |
Created | 2019-02-26T15:03:32.000+0000 |
Updated | 2019-05-16T22:54:02.000+0000 |
Description
*Summary:*
As of Titanium 7.5.0, the
Ti.Database.install()
function will throw a FileNotFoundException
on an Android 6.0 device if analytics is disabled and the database was never installed on that device before. This issue only happens if the destination directory does not exist, which seems to happen on Android 6.0 but not newer OS versions.
Note that you need to disable "analytics" in the "tiapp.xml" since it will create the "databases" directory before the "app.js" has a chance to load, which skirts the issue.
*Steps to reproduce:*
Create a Classic Titanium app.
Set the "tiapp.xml" property "analytics" to false as shown below.
Copy the below code to the project's "app.js" file.
Copy the [^Database1.sqlite] file to the project's "Resources" directory.
Build and run on Android 6.0.
Notice the app crashes on startup.
tiapp.xml
<?xml version="1.0" encoding="UTF-8"?>
<ti:app xmlns:ti="http://ti.appcelerator.org">
<analytics>false</analytics>
</ti:app>
app.js
var dbConnection = Ti.Database.install("Database1.sqlite", "Database1");
var resultSet = dbConnection.execute("SELECT key, value FROM properties");
Ti.API.info("@@@ Database Table 'properties' row count: " + (resultSet ? resultSet.rowCount : "<null>"));
if (resultSet) {
for (; resultSet.isValidRow(); resultSet.next()) {
Ti.API.info("- Key: '" + resultSet.field(0) + "', Value: '" + resultSet.field(1) + "'");
}
}
dbConnection.execute("INSERT OR REPLACE INTO properties(key, value) VALUES (?, ?)", "LastLaunchTime", new Date());
dbConnection.close();
*Recommended Solution:*
Add a mkdirs()
call to create the destination directory tree (if missing) to our DatabaseModule.java
class' install() method below.
[DatabaseModule.java#L85](https://github.com/appcelerator/titanium_mobile/blob/master/android/modules/database/src/java/ti/modules/titanium/database/DatabaseModule.java#L85)
\\
----
var db = Ti.Database.install('/src/countries.sqlite', 'countries');
[ERROR] : TiDatabase: (main) [1023,1023] Error installing database: countries msg=/data/user/0/com.test.a/databases/countries: open failed: ENOENT (No such file or directory)
[ERROR] : TiDatabase: java.io.FileNotFoundException: /data/user/0/com.test.a/databases/countries: open failed: ENOENT (No such file or directory)
[ERROR] : TiDatabase: at libcore.io.IoBridge.open(IoBridge.java:497)
[ERROR] : TiDatabase: at java.io.FileOutputStream.<init>(FileOutputStream.java:87)
[ERROR] : TiDatabase: at java.io.FileOutputStream.<init>(FileOutputStream.java:72)
[ERROR] : TiDatabase: at ti.modules.titanium.database.DatabaseModule.install(DatabaseModule.java:124)
[ERROR] : TiDatabase: at org.appcelerator.kroll.runtime.v8.V8Runtime.nativeRunModule(Native Method)
[ERROR] : TiDatabase: at org.appcelerator.kroll.runtime.v8.V8Runtime.doRunModule(V8Runtime.java:162)
[ERROR] : TiDatabase: at org.appcelerator.kroll.KrollRuntime.runModule(KrollRuntime.java:207)
[ERROR] : TiDatabase: at org.appcelerator.titanium.TiLaunchActivity.loadScript(TiLaunchActivity.java:97)
[ERROR] : TiDatabase: at org.appcelerator.titanium.TiRootActivity.loadScript(TiRootActivity.java:414)
[ERROR] : TiDatabase: at org.appcelerator.titanium.TiLaunchActivity.windowCreated(TiLaunchActivity.java:174)
[ERROR] : TiDatabase: at org.appcelerator.titanium.TiRootActivity.windowCreated(TiRootActivity.java:283)
[ERROR] : TiDatabase: at org.appcelerator.titanium.TiBaseActivity.onCreate(TiBaseActivity.java:767)
[ERROR] : TiDatabase: at org.appcelerator.titanium.TiLaunchActivity.onCreate(TiLaunchActivity.java:167)
[ERROR] : TiDatabase: at org.appcelerator.titanium.TiRootActivity.onCreate(TiRootActivity.java:260)
[ERROR] : TiDatabase: at android.app.Activity.performCreate(Activity.java:6309)
[ERROR] : TiDatabase: at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1113)
[ERROR] : TiDatabase: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2519)
[ERROR] : TiDatabase: at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2654)
[ERROR] : TiDatabase: at android.app.ActivityThread.access$900(ActivityThread.java:175)
[ERROR] : TiDatabase: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1488)
[ERROR] : TiDatabase: at android.os.Handler.dispatchMessage(Handler.java:111)
[ERROR] : TiDatabase: at android.os.Looper.loop(Looper.java:207)
[ERROR] : TiDatabase: at android.app.ActivityThread.main(ActivityThread.java:5728)
[ERROR] : TiDatabase: at java.lang.reflect.Method.invoke(Native Method)
[ERROR] : TiDatabase: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:789)
[ERROR] : TiDatabase: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:679)
[ERROR] : TiDatabase: Caused by: android.system.ErrnoException: open failed: ENOENT (No such file or directory)
[ERROR] : TiDatabase: at libcore.io.Posix.open(Native Method)
[ERROR] : TiDatabase: at libcore.io.BlockGuardOs.open(BlockGuardOs.java:186)
[ERROR] : TiDatabase: at libcore.io.IoBridge.open(IoBridge.java:483)
[ERROR] : TiDatabase: ... 25 more
[ERROR] : TiExceptionHandler: (main) [15,1038] ti:/invoker.js:105
[ERROR] : TiExceptionHandler: return delegate.apply(invoker.__thisObj__, args);
[ERROR] : TiExceptionHandler: ^
[ERROR] : TiExceptionHandler: Error: /data/user/0/com.test.a/databases/countries: open failed: ENOENT (No such file or directory)
[ERROR] : TiExceptionHandler: at SandboxAPI.invoker [as install] (ti:/invoker.js:105:19)
[ERROR] : TiExceptionHandler: at /src/lib/phone_code.js:5:20
[ERROR] : TiExceptionHandler: at Module._runScript (ti:/module.js:612:9)
[ERROR] : TiExceptionHandler: at Module.load (ti:/module.js:108:7)
[ERROR] : TiExceptionHandler: at Module.loadJavascriptText (ti:/module.js:457:9)
[ERROR] : TiExceptionHandler: at Module.loadAsFile (ti:/module.js:512:15)
[ERROR] : TiExceptionHandler: at Module.loadAsFileOrDirectory (ti:/module.js:429:20)
[ERROR] : TiExceptionHandler: at Module.require (ti:/module.js:262:17)
[ERROR] : TiExceptionHandler: at Module.global.Module.require (/ti.internal/extensions/binding.js:33:76)
[ERROR] : TiExceptionHandler: at require (ti:/module.js:570:15)
[ERROR] : TiExceptionHandler:
[ERROR] : TiExceptionHandler: libcore.io.IoBridge.open(IoBridge.java:497)
[ERROR] : TiExceptionHandler: java.io.FileOutputStream.<init>(FileOutputStream.java:87)
[ERROR] : TiExceptionHandler: java.io.FileOutputStream.<init>(FileOutputStream.java:72)
[ERROR] : TiExceptionHandler: ti.modules.titanium.database.DatabaseModule.install(DatabaseModule.java:124)
[ERROR] : TiExceptionHandler: org.appcelerator.kroll.runtime.v8.V8Runtime.nativeRunModule(Native Method)
[ERROR] : TiExceptionHandler: org.appcelerator.kroll.runtime.v8.V8Runtime.doRunModule(V8Runtime.java:162)
[ERROR] : TiExceptionHandler: org.appcelerator.kroll.KrollRuntime.runModule(KrollRuntime.java:207)
[ERROR] : TiExceptionHandler: org.appcelerator.titanium.TiLaunchActivity.loadScript(TiLaunchActivity.java:97)
[ERROR] : TiExceptionHandler: org.appcelerator.titanium.TiRootActivity.loadScript(TiRootActivity.java:414)
[ERROR] : TiExceptionHandler: org.appcelerator.titanium.TiLaunchActivity.windowCreated(TiLaunchActivity.java:174)
[INFO] : I/[MALI][Gralloc]: [+]r_hnd(0xb46ff060), client(26), share_fd(25)
[ERROR] : V8Exception: Exception occurred at ti:/invoker.js:105: Uncaught Error: /data/user/0/com.test.a/databases/countries: open failed: ENOENT (No such file or directory)
Attachments
File | Date | Size |
---|---|---|
app.js | 2019-02-27T21:29:44.000+0000 | 66 |
countries.sqlite | 2019-02-27T21:29:54.000+0000 | 17408 |
Database1.sqlite | 2019-03-12T02:06:36.000+0000 | 12288 |
DatabaseInstallTest.js | 2019-03-12T02:08:16.000+0000 | 557 |
Screenshot 2019-03-05 at 10.47.59.png | 2019-03-05T09:32:19.000+0000 | 340122 |
Hello, please provide a full standalone sample project for us to test the issue on our end. Thanks.
I think i Have found the issue: 1. Create a New classic project 2. Copy app.js, countries.sqlite 3. Disable
I can't reproduce the issue. The
Ti.Database.install()
method is correctly installing the bundled sqlite database. I've built it with Titanium 8.0.0 and ran it on a physical Android 9.0 device. I've tested it with the below code which outputs all table names within the installed database. I can see that the database contains a "countries" table name.The issue appears at Android 6.0 5.0 and 4,4 devices. At 9.0 works properly.
Hello [~andreas.pingas], I have tested the issue with [~jquick]'s sample code provided above with your database. I have tested on Android 6.0.1 physical device(Galaxy j2 Prime), 4.4.4 emulator and 6.0.0 emulator with SDK 7.5.1.GA. I was able to get the expected result in the console. What are the devices you are testing on? Provide the model.
Thank you.
Environment Titanium SDK: 7.5.0.GA OR 7.5.1.GA OR 8_0_X 8.0.0.v20190228092226 Device: Samsung Galaxy S6 (Android 5.0 OR 6.0) *
Unfortunately, we're still unable to reproduce the issue. From looking at the stack trace you've posted, it looks like it's failing to create/write the file. If I were to "guess" what's wrong, I would think the issue is that the directory
/data/data/com.test/databases
doesn't exist on your Galaxy S6 (note that this directory path will be different on different devices too). As a quick *+test+*, try create the "databases" directory on your Galaxy S6 before installing the database. Note that the below isn't a work-around and won't work on any other device. It's merely a test to see if the real issue is that it that the "databases" subdirectory is missing on your device. Also note the "com.test" is your test app's package name, so, make sure your app's package name and subdirectory match here.Yes it works when the Database installs later it runs properly. To find the bug the following has to be valid: 1) Analytics to be disabled - false. If you run the app and it was true and then you disable it, it work as the Database has been installed properly since the first time. In a situation like this you have to delete all the data of the app from CLEAR DATA setting. 2) The issue applies to all devices both physical as well as simulator that run android 6.0 or below.
bq. Analytics to be disabled - false. If you run the app and it was true and then you disable it, it work as the Database has been installed properly since the first time. In a situation like this you have to delete all the data of the app from CLEAR DATA setting. I've tried this, but I still can't reproduce the issue. The database under the "Resources" directory still installs fine for me. bq. Yes it works when the Database installs later it runs properly. What do you mean? Did it work when you called
createDirectory()
that I showed you above? If that works, then we can attempt a "blind" fix and see about creating the directory tree before installing the database file. But note that this would be a complete guess on our end since we're still unable to reproduce the issue you are seeing.The bug does not get fixed even after Ti.Filesystem.getFile("{/data/data/com.test/databases").createDirectory(true); The bug exists on simulators as well as physical devices. The only way to resolve the issue is analytics - true. Then eveything runs properly. At this point, i will disable analytics in order for the app to work properly, as the issue has to be somewhere there. You can see the results for a TEST app that i have created just yesterday and i have only run it a few times in an Android Device. !Screenshot 2019-03-05 at 10.47.59.png|thumbnail!
We can't reproduce the issue when setting analytics
false
. We've already tried that. But I still think this is an issue with the app's "databases" subdirectory not existing. The analytics system will automatically create that directory tree if it doesn't exist.Okay. I'm able to reproduce the issue now. I've updated the ticket summary to provide more details. Thanks.
PR (master): https://github.com/appcelerator/titanium_mobile/pull/10770
FR passed. PR merged
Verified the fix on sdk 8.1.0.v20190516120244.Works as expected. Test information found under the PR https://github.com/appcelerator/titanium_mobile/pull/10770