how to recognise that the user has just uninstalled your android app

49
How to recognise that the user has just uninstalled your Android app fb.me/pjakubczyk +AleksanderPiotrowsk @pelotasplus

Upload: przemyslaw-jakubczyk

Post on 15-Aug-2015

21 views

Category:

Mobile


5 download

TRANSCRIPT

Page 1: How to recognise that the user has just uninstalled your android app

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

Opera Max

Page 4: How to recognise that the user has just uninstalled your android app

The Java way

Page 5: How to recognise that the user has just uninstalled your android app

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

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

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

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

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

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

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

Getting the APK

Page 13: How to recognise that the user has just uninstalled your android app

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

Getting the APK

1.adb shell2.pm list packages

Page 15: How to recognise that the user has just uninstalled your android app

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

Hacking APK

Page 17: How to recognise that the user has just uninstalled your android app

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

Apktool

Easy to use

$ apktool d com.opera.max.apk

Page 19: How to recognise that the user has just uninstalled your android app

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

with Opera Max APK

live apktool demo

Page 21: How to recognise that the user has just uninstalled your android app

Opera Findings

Page 22: How to recognise that the user has just uninstalled your android app

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

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

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

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

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

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

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

Setup

JNI

Page 30: How to recognise that the user has just uninstalled your android app

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

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

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

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

project structure

Page 35: How to recognise that the user has just uninstalled your android app

Native code

JNI

Page 36: How to recognise that the user has just uninstalled your android app

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

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

Application.mk

APP_ABI := armeabi-v7a# allAPP_STL := stlport_static

Page 39: How to recognise that the user has just uninstalled your android app

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

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

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

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

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

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

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

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

Live demo of our app

Page 48: How to recognise that the user has just uninstalled your android app

https://github.com/pelotasplus/ActionAfterUninstall

Check the dirty source code

Page 49: How to recognise that the user has just uninstalled your android app

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