h1. RestoreApplicationInternalData {{toc}} h2. /!\ Warning: Draft This article is in draft form and is being written: * Everybody is welcome to contribute * Some things might not be accurate yet, so beware before using the information contained in it. h2. Introduction In some case, it is useful to be able to restore internal applications data: * You may want to move the data of an application from a device to another * If some files like /data/system/packages.xml or /data/system/appops.xml get corrupted, applications can loose access to their data. This can make the launcher and other applications crash. h2. Howto This howto will explain how to move silence data from a device to another. TODO: * Explain that we assume that the data partition isn't encrypted * Explain why we need the uid/gid * Explain why the ls -ld gives the application uid/gid * Point to how to get root * Explain how to handle a corrupted /data/system/packages.xml and /data/system/appops.xml * Explain how to mount a full backup, and why not to restore full backup completely * Explain how and why create a tarball of the application data Once we have a tarball backup of the application data we need to reboot in the recovery to avoid any writes to the data filesystem. Once this is done you need to mount the data partition. For the Galaxy SIII (GT-I9300), this can be done from your computer with this command:
$ adb shell "mount /dev/block/platform/dw_mmc/by-name/USERDATA /data"
Then we need to get a root shell inside the recovery. This can be done with the @adb shell@ command:
$ adb shell
Then we assume that you are in /data/data to simplify this tutorial. You will need to remember adjust all other commands if you are not in this directory. To go in /data/data, you can use the following command:
root@m0:/ # cd /data/data/                                                     
root@m0:/data/data # 
As applications are sandboxed, and that as part of that sandboxing, they have their own usersname, we need to retrieve this username. To do that we can just use @ls -ld@ on the directory holding the application internal data. The directory has the internal name of the application. Here are some well known name correspondances: | Internal name | Application | | org.smssecure.smssecure | Silence | | com.android.dialer | Dialer (Android's stock dialer application) | For pakcages comming from f-droid, the f-droid website can find the correspondance. For instance the "Silence page":https://f-droid.org/en/packages/org.smssecure.smssecure/ has @org.smssecure.smssecure@ in its URL and inside the page. So with @ls -ld@ we can find the application username in this way:
root@m0:/data/data # ls -ld org.smssecure.smssecure
__bionic_open_tzdata: couldn't find any tzdata when looking for localtime!
__bionic_open_tzdata: couldn't find any tzdata when looking for GMT!
__bionic_open_tzdata: couldn't find any tzdata when looking for posixrules!
drwxr-x--x 2 u0_a61 u0_a61 4096 2012-01-01 00:01 org.smssecure.smssecure
Here the users and groups are @u0_a61@. We will then need this information later on to restore the silence data from the other device: If we restore that data as-is it will most likely have wrong permissions: when the the silence application was installed on the older device, it was assigned an username. As this username depends on the number of applications that were installed before it, we cannot expect it to always be the same between the two devices. It's also best to move or delete the data we don't want:
root@m0:/data/data # mv org.smssecure.smssecure org.smssecure.smssecure.delme
Moving it has several advantages: * We can still verify the username later on to see if it matches with the backup we restored. * We can interrupt this tutorial more easily if something goes wrong. Here we need to verify that the archive will extract its files in the @org.smssecure.smssecure@ directory and not in the current directory which is @/data/data@:
root@m0:/data/data # tar tf /org.smssecure.smssecure.tar
./org.smssecure.smssecure/
./org.smssecure.smssecure/lib -> /data/app/org.smssecure.smssecure-1/lib/arm
[...]
Here we see that everything starts with @./org.smssecure.smssecure/@ (or @org.smssecure.smssecure/@) so it's good. TODO: move this part earlier If we had something like that instead:
root@m0:/data/data # tar tf /org.smssecure.smssecure.tar
./lib -> /data/app/org.smssecure.smssecure-1/lib/arm
[...]
Then it's best to recreate the archive. If you need more time you could also move back org.smssecure.smsecure.delme to org.smssecure.smssecure if needed. We can then proceed to extract the application data (with the username from the old device):
root@m0:/data/data # tar xpf /org.smssecure.smssecure.tar --numeric-owner
Here we can see that the username differs from the one we need:
root@m0:/data/data # ls -ld org.smssecure.smssecure 
__bionic_open_tzdata: couldn't find any tzdata when looking for localtime!
__bionic_open_tzdata: couldn't find any tzdata when looking for GMT!
__bionic_open_tzdata: couldn't find any tzdata when looking for posixrules!
drwxr-x--x 9 u0_a63 u0_a63 4096 2012-01-01 00:21 org.smssecure.smssecure
We have @u0_a63@ instead of @u0_a61@. So we need to fix it. This can be done with the @chown@ command, like that:
root@m0:/data/data # chown u0_a61:u0_a61 -R org.smssecure.smssecure            
root@m0:/data/data # 
At this point, we don't need the @org.smssecure.smssecure.delme@ directory anymore, and it's best to remove it not to create any issues later on. This can be done with the following command:
root@m0:/data/data # rm -rf org.smssecure.smssecure.delme
root@m0:/data/data # 
In addition to the standard unix permissions, Android also uses selinux, so we also need to fixup the selinux permissions. The restorecon command can be used for that. Here's its help:
root@m0:/data/data # restorecon                                                
usage: restorecon [-D] [-F] [-R] [-n] [-v] FILE...

Restores the default security contexts for the given files.

-D	apply to /data/data too
-F	force reset
-R	recurse into directories
-n	don't make any changes; useful with -v to see what would change
-v	verbose: show any changes

restorecon: Needs 1 argument
So to use it to fixup the selinux permissions, we can use the following command:
root@m0:/data/data # restorecon -D -F -R -v /data/
The order of the arguments (-D, -F, etc) seem to be important here as the wrong order might result in nothing being done. Without the @-v@ argument and with the wrong order of argument, it might make you think that it did its job while it did nothing. It will then print something that looks like that:
SELinux: Loaded file_contexts contexts from /file_contexts.
[...]
SELinux:  Relabeling /data/data/org.smssecure.smssecure from u:object_r:system_data_file:s0 to u:object_r:app_data_file:s0:c512,c768.
SELinux:  Relabeling /data/data/org.smssecure.smssecure/lib from u:object_r:system_data_file:s0 to u:object_r:app_data_file:s0:c512,c768.
[...]
The premissions fixing is now done. So we can then umount the data partition and reboot. To do that first we need to go outside of data, else the mount will fail:
root@m0:/data/data # cd /
root@m0:/ # 
Then we can simply unmount it with this command:
root@m0:/ # umount  /data/                                                     
root@m0:/ # 
Then it's a good practice to make sure that everything is written to the data partition before rebooting. We can do that with the @sync@ command:
root@m0:/ # sync
And we can finally reboot:
root@m0:/ # reboot
After rebooting, silence still refused to start. So I looked at the logs from my laptop with this command:
$ adb logcat -b main
I waited until no more new logs were printed. I then press enter multiple times to create a separation with many new lines to be able to get back to the begining of the new logs easily. Then I launched silence and started pressing enter multiple times again to mark the end of the silence related logs. I then had that in these new logs:
01-01 01:27:48.260  4126  4126 D AndroidRuntime: Shutting down VM
01-01 01:27:48.265  4126  4126 E AndroidRuntime: FATAL EXCEPTION: main
01-01 01:27:48.265  4126  4126 E AndroidRuntime: Process: org.smssecure.smssecure, PID: 4126
01-01 01:27:48.265  4126  4126 E AndroidRuntime: Theme: themes:{}
01-01 01:27:48.265  4126  4126 E AndroidRuntime: java.lang.RuntimeException: Unable to create application org.smssecure.smssecure.ApplicationContext: java.lang.SecurityException: getActiveSubscriptionInfoList: Neither user 10061 nor current process has android.permission.READ_PHONE_STATE.
01-01 01:27:48.265  4126  4126 E AndroidRuntime: 	at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4754)
[...]
So to fix it I went in @Settings->Apps->Silence->Permissions@ and gave it all the permissions it needed. I had this issue because I didn't even launch silence after installing it, so it cound't ask me for the permissions it needed. And the silence of the former device probably wrote in its data that it already asked the permissions.