How to recognise that the user has just uninstalled your android app droidcon.de 2015
-
Upload
przemyslaw-jakubczyk -
Category
Documents
-
view
12 -
download
3
Transcript of How to recognise that the user has just uninstalled your android app droidcon.de 2015
![Page 1: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/1.jpg)
How to recognise that the user has just uninstalled your Android
app
fb.me/pjakubczyk+AleksanderPiotrowski@pelotasplus
![Page 2: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/2.jpg)
Opera Max
![Page 4: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/4.jpg)
The Java way
![Page 5: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/5.jpg)
Read the broadcast
<receiver android:name=".PackageWatcher">
<intent-filter>
<action android:name="android.intent.action.PACKAGE_ADDED"/>
<action
android:name="android.intent.action.PACKAGE_REMOVED"/>
<action
android:name="android.intent.action.PACKAGE_REPLACED"/>
<data android:scheme="package"/>
</intent-filter>
</receiver>
![Page 6: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/6.jpg)
Read the broadcast
void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
Iterator<String> it =
bundle.keySet().iterator;
while (it.hasNext()) {
String key = it.next();
Log.e("DDD", key +"="+bundle.get(key)); }
![Page 7: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/7.jpg)
Usually we see (install)
E/DDD (29199): Dumping Intent start [android.intent.extra.UID=10089] [android.intent.extra.user_handle=0]E/DDD (29199): Dumping Intent end
![Page 8: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/8.jpg)
Usually we see (reinstall)
E/DDD (29199): Dumping Intent start [android.intent.extra.REMOVED_FOR_ALL_USERS=false] [android.intent.extra.UID=10089] [android.intent.extra.DATA_REMOVED=false] [android.intent.extra.REPLACING=true] [android.intent.extra.user_handle=0]E/DDD (29199): Dumping Intent end
![Page 9: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/9.jpg)
Usually we see (uninstall)
E/DDD (29199): Dumping Intent start [android.intent.extra.REMOVED_FOR_ALL_USERS=true] [android.intent.extra.UID=10089] [android.intent.extra.DATA_REMOVED=true] [android.intent.extra.user_handle=0]E/DDD (29199): Dumping Intent end
![Page 10: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/10.jpg)
Let’s uninstall our app
and there’s nothing ….
Why ?
OS unregisters listener during removal
![Page 11: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/11.jpg)
What Opera does?
It does not listen for package removal
it does some magic ;-)
… not in Java code
![Page 12: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/12.jpg)
Getting the APK
![Page 13: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/13.jpg)
Getting the APK
● genymotion withgapps installed
● get app from play store● be careful with the right ABI
![Page 14: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/14.jpg)
Getting the APK
1.adb shell2.pm list packages
![Page 15: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/15.jpg)
Getting the APK
3. pm path com.opera.max4. adb pull /data/app/com.opera.max.apk
![Page 16: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/16.jpg)
Hacking APK
![Page 17: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/17.jpg)
Apktool
A tool for reverse engineering Android apk files
Made with <3 in Poland ;-)
![Page 18: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/18.jpg)
Apktool
Easy to use
$ apktool d com.opera.max.apk
![Page 19: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/19.jpg)
Apktool
● decoded XML files● smali assembly code● PNGs, layouts, resources● id-s mapping
![Page 20: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/20.jpg)
with Opera Max APK
live apktool demo
![Page 21: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/21.jpg)
Opera Findings
![Page 22: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/22.jpg)
Found a clue!
There are *.so files
We can inspect them to see more
Tools: strings, objdump, nm, readelf
![Page 23: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/23.jpg)
rudy$ strings opera/lib/armeabi/libuo.so (II)
...inotify_initinotify_add_watchinotify_rm_watch/data/data/%s/%s%s
![Page 24: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/24.jpg)
inotify framework
http://linux.die.net/man/7/inotify
The inotify API provides a mechanism for monitoring file system events. Inotify can be used to monitor individual files, or to monitor directories.
![Page 25: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/25.jpg)
rudy$ strings opera/lib/armeabi/libuo.so (I)
...Androidstartandroid.intent.action.VIEW--user...
![Page 26: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/26.jpg)
am command
part of Android system/system/bin/am
A way to start apps, intents and whatnot
![Page 27: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/27.jpg)
more details
$ ps
USER PID PPIDu0_a91 24318 20265 246900 27716 ffffffff b6edf5cc S com.opera.max
u0_a91 24337 24318 856 336 c00e4944 b6f72158 S /data/app-lib/com.opera.max-2/libuo.so
![Page 28: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/28.jpg)
The scenario
1. Fork the native process2. Inside the child process use inotify to watch
a file3. Watcher is woken up on file deletion. Start
another native process4. The last process run the ‘am’
(ActivityManager) command to run intent.
![Page 29: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/29.jpg)
Setup
JNI
![Page 30: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/30.jpg)
local.properties
# Location of the SDK. This is only used by Gradle.# For customization when using a Version Control System, please read the
sdk.dir=/Users/alek/android-sdkndk.dir=/Users/alek/android-ndk-r10e
![Page 31: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/31.jpg)
build.gradle
android.defaultConfig { applicationId "pl.pelotasplus.actionafteruninstall"
ndk { moduleName "hello-jni" ldLibs "log", "android" stl "stlport_static" } }
![Page 32: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/32.jpg)
MainActivity.java declaring
public class MainActivity extends AppCompatActivity {
public native String stringFromJNI(); public native void observer();
static { System.loadLibrary("hello-jni"); // System.loadLibrary("/data/data/com.foo.test/lib/liba.so");
}}
![Page 33: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/33.jpg)
MainActivity.java calling
protected void onCreate(Bundle savedInstanceState) { setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.textView);
textView.setText(stringFromJNI());
observer(); }
![Page 34: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/34.jpg)
project structure
![Page 35: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/35.jpg)
Native code
JNI
![Page 36: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/36.jpg)
Sample by Google
jstringJava_pl_pelotasplus_actionafteruninstall_MainActivity_stringFromJNI
(JNIEnv* env, jobject thiz){ return (*env)->NewStringUTF(
env,"Hello from JNI ! Compiled with ABI foo."
);}
![Page 37: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/37.jpg)
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hello-jniLOCAL_SRC_FILES := hello-jni.cLOCAL_LDFLAGS += -llog -lpthreadinclude $(BUILD_SHARED_LIBRARY)
![Page 38: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/38.jpg)
Application.mk
APP_ABI := armeabi-v7a# allAPP_STL := stlport_static
![Page 39: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/39.jpg)
inotify on Linux
int main( int argc, char **argv) { int length, i = 0; int fd; int wd; char buffer[BUF_LEN];
fd = inotify_init(); printf("fd=%d\n", fd);}
![Page 40: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/40.jpg)
inotify on Linux
int main( int argc, char **argv){ [...]
wd = inotify_add_watch(fd, "/var/tmp", IN_MODIFY | IN_CREATE | IN_DELETE); length = read( fd, buffer, BUF_LEN ); printf("length=%d\n", length); if (length < 0) { perror("read"); }
![Page 41: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/41.jpg)
inotify on Linux
while (i < length) {
struct inotify_event *event = (struct inotify_event*)&buffer[ i]; printf("Event len %d\n", event->len); if (event->len) { if (event->mask & IN_DELETE) { if (event->mask & IN_ISDIR) { printf( "The directory %s was deleted.\n", event->name ); } else { printf( "The file %s was deleted.\n", event->name );
![Page 42: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/42.jpg)
inotify on Android (pseudo code)
void observer(void) { inotify_init(); inotify_add_watch(fd, DIRECTORY, IN_DELETE); if (event->mask & IN_DELETE) { startIntent(); }}
![Page 43: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/43.jpg)
first attemptvoidJava_pl_pelotasplus_actionafteruninstall_MainActivity_observer(JNIEnv* env, jobject thiz){
observer();}
App blocked as native code blocked app
![Page 44: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/44.jpg)
second attempt, with threadvoidJava_pl_pelotasplus_actionafteruninstall_MainActivity_observer (JNIEnv* env, jobject thiz){
pthread_attr_init(&attr);pthread_create(&thread, &attr, &observer_thread, NULL);
}
App not blocked but native code stopped when stopping app for uninstalling
![Page 45: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/45.jpg)
third attempt, with forkvoidJava_pl_pelotasplus_actionafteruninstall_MainActivity_observer(JNIEnv* env, jobject thiz){
pid_t pid; pid = fork(); if (pid == 0) { __android_log_print(ANDROID_LOG_INFO, TAG, "Fork child\n"); observer(); }}
![Page 46: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/46.jpg)
start intent, another forkvoid startIntent(void) {
pid_t p = fork(); if (p == 0) { __android_log_print(ANDROID_LOG_INFO, TAG, "startIntent %d", getpid());
system("/system/bin/am start --user 0 -a android.intent.action.VIEW -d http://droidcon.de"); }}
![Page 47: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/47.jpg)
Live demo of our app
![Page 48: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/48.jpg)
https://github.com/pelotasplus/ActionAfterUninstall
Check the dirty source code
![Page 49: How to recognise that the user has just uninstalled your android app droidcon.de 2015](https://reader035.fdocuments.in/reader035/viewer/2022062308/55d239e1bb61eb9f1c8b45f8/html5/thumbnails/49.jpg)
Moral> What happens when I call fork() in JNI code? Will this totally break the> Activity lifecycle model in Android?
Don't do this. Just don't.
-- Dianne HackbornAndroid framework [email protected]
http://markmail.org/message/ruqp2t6gvhnhv654