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

How to recognise that the user has just uninstalled your android app droidcon.de 2015

Aug 18, 2015

Download

Documents

Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: How to recognise that the user has just uninstalled your android app   droidcon.de 2015

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

Opera Max

Page 4: How to recognise that the user has just uninstalled your android app   droidcon.de 2015

The Java way

Page 5: How to recognise that the user has just uninstalled your android app   droidcon.de 2015

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

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

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

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

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

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

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

Getting the APK

Page 13: How to recognise that the user has just uninstalled your android app   droidcon.de 2015

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

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

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

Hacking APK

Page 17: How to recognise that the user has just uninstalled your android app   droidcon.de 2015

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

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

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

with Opera Max APK

live apktool demo

Page 21: How to recognise that the user has just uninstalled your android app   droidcon.de 2015

Opera Findings

Page 22: How to recognise that the user has just uninstalled your android app   droidcon.de 2015

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

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

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

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

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

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

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

Setup

JNI

Page 30: How to recognise that the user has just uninstalled your android app   droidcon.de 2015

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

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

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

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

project structure

Page 35: How to recognise that the user has just uninstalled your android app   droidcon.de 2015

Native code

JNI

Page 36: How to recognise that the user has just uninstalled your android app   droidcon.de 2015

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

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

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

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

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

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

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

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

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

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

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

Live demo of our app

Page 48: How to recognise that the user has just uninstalled your android app   droidcon.de 2015

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

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