14

I'd like to monitor changes to another applications SQLite database. Since the Android doesn't allow me to access another application's internal data, I need a root application which is exactly what mine is.

Is there a way I could monitor changes to a file on the system and trigger an event in my application?

I've Googled around and seen people recommend using FileObserver class but this wouldn't work for protected files. Any other suggestions?

--

I've been looking for answer for this but I haven't found any. I've tried these two sei-promising techniques but I couldn't get them to work.

  1. All the files in an application's data directory are owned by that application's user and group. FileObserver respects Linux permissions and therefore I can't seem to use it to monitor a database/file in another application's data directory.

I'm wondering if this was possible if I could somehow elevate my application's Linux process to run as root. This isn't easy either as it would mean toying with the setuid, setguid mechanism which I don't have much idea about.

  1. I tried creating a symbolic link from the other application's database file into my application's data directory. I added all permissions on the symbolic link and then used FileObserver to monitor it but this didn't work either. Maybe I did something wrong but my best guess that in Linux, symbolic-link permissions are useless. The permissions on a symbolic link that are respected are that of the target file/directory.

There might be way using JNI and the inotify.h files but I'm not sure about how to go about this.

I don't want to poll the database from my application. I'd like to have an event trigger mechanism.

Community
  • 1
  • 1
Mridang Agarwalla
  • 43,201
  • 71
  • 221
  • 382
  • Can you add trigger to the table in question? – David Jashi Jul 03 '13 at 08:29
  • There's underlying mechanism under `FileObserver`, called `inotify`. You can try to use it. – SpongeBobFan Jul 03 '13 at 10:46
  • @SpongeBobFan, do you know if I can use `FileObserver` if I have root access in order to monitor another system file? – Mridang Agarwalla Jul 15 '13 at 10:12
  • @DavidJashi, I could do that. Would you elaborate on how I could accomplish what I'm looking for using database triggers? Thanks. – Mridang Agarwalla Jul 23 '13 at 08:21
  • @MridangAgarwalla I'm not a an expert in Android SQLite, but when I want to keep custom audit trail on RDBMS, I put triggers on tables in question and update one audit table with tracing records. If SQLite allows simultaneous access from two applications (as most of RDBMSes do), you could poll record count once a second and request last record if it changes, i.e. put polling on DB level, rather then filesystem. – David Jashi Jul 23 '13 at 13:21
  • As it is mentioned here http://stackoverflow.com/questions/10801119/concurrent-access-to-a-sqlite-database-in-android-db-already-closed , it looks like concurrent access is supported, so you might give it a try. – David Jashi Jul 23 '13 at 13:24

4 Answers4

7

You can't access it from Java.

One way is poll: to run ls -l /data/data/com.target.app/databases/data.db and get time-stamp periodically.

Or perhaps use watch or tail commands.

May be a background service can run this and issue a local broadcast.

Other way is to ship SQLite3 binary with your app, start process as root, and supply commands to it. I think many apps like titanium etc, do this.

Update: Here's an SQLite3 project: http://code.google.com/p/sqlite3-android/

Community
  • 1
  • 1
S.D.
  • 29,290
  • 3
  • 79
  • 130
  • He has a root access, which means he also has BusyBox in all likelihood. Meaning, watch and tail are available. – Joel Bodega Jul 03 '13 at 08:57
  • @JoelBodega True, so that's an option. But If he's able to ship his own sqlite3, and get an active sqlite shell (as root) to run commands on, then this would be the better choice of the two, because he gets database like access as well. – S.D. Jul 03 '13 at 09:02
  • @S.D., this is not an option as it requires polling. I'm interested in an event e.g. something like `FileObserver` or `inotify` – Mridang Agarwalla Jul 23 '13 at 08:07
  • @S.D., I forgot to mention that I have the `sqlite3` binary bundle with my application and I'm using this execute commands against the database in question and read the output. While this works, I need to know when to query the database. I want to do this only when the database has been written to and therefore my question. – Mridang Agarwalla Jul 23 '13 at 08:17
  • Yes, a watch script running with root privilege could update a readable file that can be monitored from java FileObserver – Anthony Palmer Jul 23 '13 at 10:38
  • @AnthonyPalmer, how is that different from me simply polling the file myself in Java without the hassle of extra scripts and `watch`? If I did have to poll it, I could simply use a Java library like `Roottools` to execute commands and check the file at regular intervals. Doesn't this whole method bring us back to the circle of polling which is something I've mentioned trying to avoid. – Mridang Agarwalla Jul 23 '13 at 10:44
  • @MridangAgarwalla On Linux, `Inotify` is the proper module for monitoring file-system changes. But I don't think its available on android. – S.D. Jul 23 '13 at 11:45
  • 1
    @S.D. It's a way of circumventing not being able to watch a file directly. i.e. monitor one that you can. Agreed its not pretty, but you are doing something that isnt exactly standard, and remember that none of us are fully aware of your exact requirements, environment, constraints or capability. We are somewhat shooting out options that might at least give you a nudge in the right direction! – Anthony Palmer Jul 24 '13 at 11:58
4

One option would be to encapsulate your database with a content provider, and then the other application can subscribe for changes in the tables/URIs with the ContentObserver class

Thomas
  • 2,751
  • 5
  • 31
  • 52
  • This would require access to the source of the other application, wouldn't it? That's something I can't do. – Mridang Agarwalla Jul 23 '13 at 08:23
  • I think that either the application would need to implement a content provider (can you check if they do?) or you would need to be able to connect/open their db (I'm not sure if you can do that even as root) and implement a content provider yourself. – Thomas Jul 23 '13 at 08:27
  • 1
    No, you don't need the source of the other application to use its `ContentProvider` if it exprots one. However, you do need enough documentation to be able to provide the correct parameters to a `ContentResolver`. The preferred pattern is that the other application provides a "contract" class which provides the constants necessary to interact with an exported `ContentProvider`. – Code-Apprentice Jul 29 '13 at 22:18
3

Iff you have root access, why not update file permissions to allow group read access to the file in question? i.e.

  • Create a new group if needed e.g. SQLLiteGroup
  • Update group ownership of SQLLite db file to SQLLiteGroup
  • Set file permissions for group read for SQLLite db file
  • App2 add user to group SQLLiteGroup

App2 user should now have read access to file, FileObserver will work.

FYI symbolic links mirror (i.e. respect) the permissions of the file that is being pointed to.

Anthony Palmer
  • 944
  • 10
  • 15
1

inotify is the way to go here but you'll need something like the command-line inotifywait utility from inotify-tools, so that you can elevate it with su.

You can either write your own (it's super easy) or use an existing port.

Then, you run it elevated, in a separate thread, and either wait for it to tell you there's a change or to close down (depending on whether you run inotifywatch or inotifywait).

P.S. This will likely fail miserably on 4.3 onwards with the SELinux contexts and whatnot.

Delyan
  • 8,881
  • 4
  • 37
  • 42