Uploaded image for project: 'Titanium SDK/CLI'
  1. Titanium SDK/CLI
  2. TIMOB-26878

Android: Ti.Database.install() fails if destination directory does not exist

    Details

    • Story Points:
      7
    • Sprint:
      2019 Sprint 6, 2019 Sprint 7, 2019 Sprint 8, 2019 Sprint 9, 2019 Sprint 10

      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:

      1. Create a Classic Titanium app.
      2. Set the "tiapp.xml" property "analytics" to false as shown below.
      3. Copy the below code to the project's "app.js" file.
      4. Copy the Database1.sqlite file to the project's "Resources" directory.
      5. Build and run on Android 6.0.
      6. 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



      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

        1. app.js
          0.1 kB
        2. countries.sqlite
          17 kB
        3. Database1.sqlite
          12 kB
        4. DatabaseInstallTest.js
          0.5 kB
        5. Screenshot 2019-03-05 at 10.47.59.png
          Screenshot 2019-03-05 at 10.47.59.png
          332 kB

          Issue Links

            Activity

              People

              • Assignee:
                jquick Joshua Quick
                Reporter:
                andreas.pingas Andreas Pingas
                Reviewer:
                Gary Mathews
                Tester:
                Keerthi Mahalingam (Inactive)
              • Watchers:
                2 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved:

                  Backbone Issue Sync

                  • Titanium SDK/CLI <> Titanium Mobile
                    Synced with:
                    TIMOB-21077
                    Sync status:
                    PENDING
                    Last received:
                    Last sent:

                    Git Source Code