SlideShare a Scribd company logo
1 of 49
How to recognise that the user
has just uninstalled your Android
app
fb.me/pjakubczyk
+AleksanderPiotrowski
@pelotasplus
Opera Max
The Java way
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>
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)); }
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
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
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
Let’s uninstall our app
and there’s nothing ….
Why ?
OS unregisters listener during removal
What Opera does?
It does not listen for package removal
it does some magic ;-)
… not in Java code
Getting the APK
Getting the APK
● genymotion with
gapps installed
● get app from play store
● be careful with the right ABI
Getting the APK
1.adb shell
2.pm list packages
Getting the APK
3. pm path com.opera.max
4. adb pull
/data/app/com.opera.max.apk
Hacking APK
Apktool
A tool for reverse engineering
Android apk files
Made with <3 in Poland ;-)
Apktool
Easy to use
$ apktool d
com.opera.max.apk
Apktool
● decoded XML files
● smali assembly code
● PNGs, layouts, resources
● id-s mapping
with Opera Max APK
live apktool demo
Opera Findings
Found a clue!
There are *.so files
We can inspect them to see more
Tools: strings, objdump, nm, readelf
rudy$ strings opera/lib/armeabi/libuo.so (II)
...
inotify_init
inotify_add_watch
inotify_rm_watch
/data/data/%s/
%s%s
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.
rudy$ strings opera/lib/armeabi/libuo.so (I)
...
Android
start
android.intent.action.VIEW
--user
...
am command
part of Android system
/system/bin/am
A way to start apps, intents and
whatnot
more details
$ ps
USER PID PPID
u0_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
The scenario
1. Fork the native process
2. Inside the child process use inotify to watch
a file
3. Watcher is woken up on file deletion. Start
another native process
4. The last process run the ‘am’
(ActivityManager) command to run intent.
Setup
JNI
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-sdk
ndk.dir=/Users/alek/android-ndk-r10e
build.gradle
android.defaultConfig {
applicationId "pl.pelotasplus.actionafteruninstall"
ndk {
moduleName "hello-jni"
ldLibs "log", "android"
stl "stlport_static"
}
}
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");
}
}
MainActivity.java calling
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.textView);
textView.setText(stringFromJNI());
observer();
}
project structure
Native code
JNI
Sample by Google
jstring
Java_pl_pelotasplus_actionafteruninstall_MainActivity_stringFro
mJNI
(JNIEnv* env, jobject thiz)
{
return (*env)->NewStringUTF(
env,
"Hello from JNI ! Compiled with ABI foo."
);
}
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hello-jni
LOCAL_SRC_FILES := hello-jni.c
LOCAL_LDFLAGS += -llog -lpthread
include $(BUILD_SHARED_LIBRARY)
Application.mk
APP_ABI := armeabi-v7a
# all
APP_STL := stlport_static
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=%dn", fd);
}
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=%dn", length);
if (length < 0) {
perror("read");
}
inotify on Linux
while (i < length) {
struct inotify_event *event = (struct inotify_event*)&buffer[ i];
printf("Event len %dn", 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 );
inotify on Android (pseudo code)
void observer(void) {
inotify_init();
inotify_add_watch(fd, DIRECTORY, IN_DELETE);
if (event->mask & IN_DELETE) {
startIntent();
}
}
first attempt
void
Java_pl_pelotasplus_actionafteruninstall_MainActivity_observer(JNIEnv* env, jobject
thiz)
{
observer();
}
App blocked as native code blocked app
second attempt, with thread
void
Java_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
third attempt, with fork
void
Java_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 childn");
observer();
}
}
start intent, another fork
void 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");
}
}
Live demo of our app
https://github.com/
pelotasplus/Action
AfterUninstall
Check the dirty source code
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 Hackborn
Android framework engineer
hack...@android.com
http://markmail.org/message/ruqp2t6gvhnhv654

More Related Content

What's hot

Unix Programming with Perl 2
Unix Programming with Perl 2Unix Programming with Perl 2
Unix Programming with Perl 2Kazuho Oku
 
Стажировка 2016-07-27 02 Денис Нелюбин. PostgreSQL и jsonb
Стажировка 2016-07-27 02 Денис Нелюбин. PostgreSQL и jsonbСтажировка 2016-07-27 02 Денис Нелюбин. PostgreSQL и jsonb
Стажировка 2016-07-27 02 Денис Нелюбин. PostgreSQL и jsonbSmartTools
 
Unix Programming with Perl
Unix Programming with PerlUnix Programming with Perl
Unix Programming with PerlKazuho Oku
 
Continuous testing In PHP
Continuous testing In PHPContinuous testing In PHP
Continuous testing In PHPEric Hogue
 
Introduction to puppet - Hands on Session at HPI Potsdam
Introduction to puppet - Hands on Session at HPI PotsdamIntroduction to puppet - Hands on Session at HPI Potsdam
Introduction to puppet - Hands on Session at HPI PotsdamChristoph Oelmüller
 
Perl web app 테스트전략
Perl web app 테스트전략Perl web app 테스트전략
Perl web app 테스트전략Jeen Lee
 
Using the Power to Prove
Using the Power to ProveUsing the Power to Prove
Using the Power to ProveKazuho Oku
 
Firefox OS learnings & visions, WebAPIs - budapest.mobile
Firefox OS learnings & visions, WebAPIs - budapest.mobileFirefox OS learnings & visions, WebAPIs - budapest.mobile
Firefox OS learnings & visions, WebAPIs - budapest.mobileRobert Nyman
 
Guarding Your Code Against Bugs with Continuous Testing
Guarding Your Code Against Bugs with Continuous TestingGuarding Your Code Against Bugs with Continuous Testing
Guarding Your Code Against Bugs with Continuous TestingEric Hogue
 
Commencer avec le TDD
Commencer avec le TDDCommencer avec le TDD
Commencer avec le TDDEric Hogue
 
Reactive Web - Servlet & Async, Non-blocking I/O
Reactive Web - Servlet & Async, Non-blocking I/OReactive Web - Servlet & Async, Non-blocking I/O
Reactive Web - Servlet & Async, Non-blocking I/OArawn Park
 
NodeJs
NodeJsNodeJs
NodeJsdizabl
 
The Art Of Application Logging PHPNW12
The Art Of Application Logging PHPNW12The Art Of Application Logging PHPNW12
The Art Of Application Logging PHPNW12benwaine
 
Debian 5 Hardening Tips
Debian 5 Hardening TipsDebian 5 Hardening Tips
Debian 5 Hardening Tipss3m1llon
 
Docker for data science
Docker for data scienceDocker for data science
Docker for data scienceCalvin Giles
 
Puppet Module Reusability - What I Learned from Shipping to the Forge
Puppet Module Reusability - What I Learned from Shipping to the ForgePuppet Module Reusability - What I Learned from Shipping to the Forge
Puppet Module Reusability - What I Learned from Shipping to the ForgePuppet
 

What's hot (20)

Unix Programming with Perl 2
Unix Programming with Perl 2Unix Programming with Perl 2
Unix Programming with Perl 2
 
Стажировка 2016-07-27 02 Денис Нелюбин. PostgreSQL и jsonb
Стажировка 2016-07-27 02 Денис Нелюбин. PostgreSQL и jsonbСтажировка 2016-07-27 02 Денис Нелюбин. PostgreSQL и jsonb
Стажировка 2016-07-27 02 Денис Нелюбин. PostgreSQL и jsonb
 
Unix Programming with Perl
Unix Programming with PerlUnix Programming with Perl
Unix Programming with Perl
 
Continuous testing In PHP
Continuous testing In PHPContinuous testing In PHP
Continuous testing In PHP
 
Introduction to puppet - Hands on Session at HPI Potsdam
Introduction to puppet - Hands on Session at HPI PotsdamIntroduction to puppet - Hands on Session at HPI Potsdam
Introduction to puppet - Hands on Session at HPI Potsdam
 
Perl web app 테스트전략
Perl web app 테스트전략Perl web app 테스트전략
Perl web app 테스트전략
 
Intro django
Intro djangoIntro django
Intro django
 
Using the Power to Prove
Using the Power to ProveUsing the Power to Prove
Using the Power to Prove
 
Firefox OS learnings & visions, WebAPIs - budapest.mobile
Firefox OS learnings & visions, WebAPIs - budapest.mobileFirefox OS learnings & visions, WebAPIs - budapest.mobile
Firefox OS learnings & visions, WebAPIs - budapest.mobile
 
Guarding Your Code Against Bugs with Continuous Testing
Guarding Your Code Against Bugs with Continuous TestingGuarding Your Code Against Bugs with Continuous Testing
Guarding Your Code Against Bugs with Continuous Testing
 
EC2
EC2EC2
EC2
 
Commencer avec le TDD
Commencer avec le TDDCommencer avec le TDD
Commencer avec le TDD
 
Reactive Web - Servlet & Async, Non-blocking I/O
Reactive Web - Servlet & Async, Non-blocking I/OReactive Web - Servlet & Async, Non-blocking I/O
Reactive Web - Servlet & Async, Non-blocking I/O
 
NodeJs
NodeJsNodeJs
NodeJs
 
The Art Of Application Logging PHPNW12
The Art Of Application Logging PHPNW12The Art Of Application Logging PHPNW12
The Art Of Application Logging PHPNW12
 
Debian 5 Hardening Tips
Debian 5 Hardening TipsDebian 5 Hardening Tips
Debian 5 Hardening Tips
 
Docker for data science
Docker for data scienceDocker for data science
Docker for data science
 
Puppet Module Reusability - What I Learned from Shipping to the Forge
Puppet Module Reusability - What I Learned from Shipping to the ForgePuppet Module Reusability - What I Learned from Shipping to the Forge
Puppet Module Reusability - What I Learned from Shipping to the Forge
 
Introduction to JavaFX 2
Introduction to JavaFX 2Introduction to JavaFX 2
Introduction to JavaFX 2
 
General fraction
General fractionGeneral fraction
General fraction
 

Viewers also liked

Android 5.0 internals and inferiority complex droidcon.de 2015
Android 5.0 internals and inferiority complex droidcon.de 2015Android 5.0 internals and inferiority complex droidcon.de 2015
Android 5.0 internals and inferiority complex droidcon.de 2015Aleksander Piotrowski
 
Black Burlap Portfolio 2015
Black Burlap Portfolio 2015Black Burlap Portfolio 2015
Black Burlap Portfolio 2015Shannya Preeya
 
Xamarin for (not only) Android developers
Xamarin for (not only) Android developersXamarin for (not only) Android developers
Xamarin for (not only) Android developersAleksander Piotrowski
 
lettre mensuelle BKB du mois d’Octobre 2010
lettre mensuelle BKB du mois d’Octobre 2010lettre mensuelle BKB du mois d’Octobre 2010
lettre mensuelle BKB du mois d’Octobre 2010www.bourse-maroc.org
 
Livre la-joie-de-l echec-de-faysal-hafidi
Livre la-joie-de-l echec-de-faysal-hafidiLivre la-joie-de-l echec-de-faysal-hafidi
Livre la-joie-de-l echec-de-faysal-hafidiwww.bourse-maroc.org
 
oh montgomery portfolio
oh montgomery portfoliooh montgomery portfolio
oh montgomery portfolioShannya Preeya
 
Good Stuff Cakes Portfolio
Good Stuff Cakes PortfolioGood Stuff Cakes Portfolio
Good Stuff Cakes PortfolioShannya Preeya
 

Viewers also liked (11)

Android 5.0 internals and inferiority complex droidcon.de 2015
Android 5.0 internals and inferiority complex droidcon.de 2015Android 5.0 internals and inferiority complex droidcon.de 2015
Android 5.0 internals and inferiority complex droidcon.de 2015
 
Business resume
Business resumeBusiness resume
Business resume
 
Uninstall opera
Uninstall operaUninstall opera
Uninstall opera
 
Black Burlap Portfolio 2015
Black Burlap Portfolio 2015Black Burlap Portfolio 2015
Black Burlap Portfolio 2015
 
It's always your fault
It's always your faultIt's always your fault
It's always your fault
 
Xamarin for (not only) Android developers
Xamarin for (not only) Android developersXamarin for (not only) Android developers
Xamarin for (not only) Android developers
 
RoboSpock Poznań ADG 2016
RoboSpock Poznań ADG 2016RoboSpock Poznań ADG 2016
RoboSpock Poznań ADG 2016
 
lettre mensuelle BKB du mois d’Octobre 2010
lettre mensuelle BKB du mois d’Octobre 2010lettre mensuelle BKB du mois d’Octobre 2010
lettre mensuelle BKB du mois d’Octobre 2010
 
Livre la-joie-de-l echec-de-faysal-hafidi
Livre la-joie-de-l echec-de-faysal-hafidiLivre la-joie-de-l echec-de-faysal-hafidi
Livre la-joie-de-l echec-de-faysal-hafidi
 
oh montgomery portfolio
oh montgomery portfoliooh montgomery portfolio
oh montgomery portfolio
 
Good Stuff Cakes Portfolio
Good Stuff Cakes PortfolioGood Stuff Cakes Portfolio
Good Stuff Cakes Portfolio
 

Similar to 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 app
How to recognise that the user has just uninstalled your appHow to recognise that the user has just uninstalled your app
How to recognise that the user has just uninstalled your appAleksander Piotrowski
 
An inconvenient truth: Evading the Ransomware Protection in windows 10 @ LeHack
An inconvenient truth: Evading the Ransomware Protection in windows 10 @ LeHackAn inconvenient truth: Evading the Ransomware Protection in windows 10 @ LeHack
An inconvenient truth: Evading the Ransomware Protection in windows 10 @ LeHackSoya Aoyama
 
Jakob Holderbaum - Managing Shared secrets using basic Unix tools
Jakob Holderbaum - Managing Shared secrets using basic Unix toolsJakob Holderbaum - Managing Shared secrets using basic Unix tools
Jakob Holderbaum - Managing Shared secrets using basic Unix toolsDevSecCon
 
Gdg san diego android 11 meetups what's new in android - ui and dev tools
Gdg san diego android 11 meetups  what's new in android  - ui and dev toolsGdg san diego android 11 meetups  what's new in android  - ui and dev tools
Gdg san diego android 11 meetups what's new in android - ui and dev toolsSvetlin Stanchev
 
Node.js basics
Node.js basicsNode.js basics
Node.js basicsBen Lin
 
Information track presentation_final
Information track presentation_finalInformation track presentation_final
Information track presentation_finalKazuki Omo
 
Linux Security APIs and the Chromium Sandbox
Linux Security APIs and the Chromium SandboxLinux Security APIs and the Chromium Sandbox
Linux Security APIs and the Chromium SandboxPatricia Aas
 
Gimli: Server Process Monitoring and Fault Analysis
Gimli: Server Process Monitoring and Fault AnalysisGimli: Server Process Monitoring and Fault Analysis
Gimli: Server Process Monitoring and Fault AnalysisWez Furlong
 
Virus Bulletin 2015: Exposing Gatekeeper
Virus Bulletin 2015: Exposing GatekeeperVirus Bulletin 2015: Exposing Gatekeeper
Virus Bulletin 2015: Exposing GatekeeperSynack
 
MacOS forensics and anti-forensics (DC Lviv 2019) presentation
MacOS forensics and anti-forensics (DC Lviv 2019) presentationMacOS forensics and anti-forensics (DC Lviv 2019) presentation
MacOS forensics and anti-forensics (DC Lviv 2019) presentationOlehLevytskyi1
 
Grâce aux tags Varnish, j'ai switché ma prod sur Raspberry Pi
Grâce aux tags Varnish, j'ai switché ma prod sur Raspberry PiGrâce aux tags Varnish, j'ai switché ma prod sur Raspberry Pi
Grâce aux tags Varnish, j'ai switché ma prod sur Raspberry PiJérémy Derussé
 
PHP Backdoor: The rise of the vuln
PHP Backdoor: The rise of the vulnPHP Backdoor: The rise of the vuln
PHP Backdoor: The rise of the vulnSandro Zaccarini
 
FRIDA 101 Android
FRIDA 101 AndroidFRIDA 101 Android
FRIDA 101 AndroidTony Thomas
 
Permission enforcement s in android new (1)
Permission   enforcement s  in android new (1)Permission   enforcement s  in android new (1)
Permission enforcement s in android new (1)Siddhartha Kakarla
 
Installing odoo v8 from github
Installing odoo v8 from githubInstalling odoo v8 from github
Installing odoo v8 from githubAntony Gitomeh
 

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

How to recognise that the user has just uninstalled your app
How to recognise that the user has just uninstalled your appHow to recognise that the user has just uninstalled your app
How to recognise that the user has just uninstalled your app
 
Iwatch tech 1
Iwatch tech 1Iwatch tech 1
Iwatch tech 1
 
An inconvenient truth: Evading the Ransomware Protection in windows 10 @ LeHack
An inconvenient truth: Evading the Ransomware Protection in windows 10 @ LeHackAn inconvenient truth: Evading the Ransomware Protection in windows 10 @ LeHack
An inconvenient truth: Evading the Ransomware Protection in windows 10 @ LeHack
 
Jakob Holderbaum - Managing Shared secrets using basic Unix tools
Jakob Holderbaum - Managing Shared secrets using basic Unix toolsJakob Holderbaum - Managing Shared secrets using basic Unix tools
Jakob Holderbaum - Managing Shared secrets using basic Unix tools
 
Gdg san diego android 11 meetups what's new in android - ui and dev tools
Gdg san diego android 11 meetups  what's new in android  - ui and dev toolsGdg san diego android 11 meetups  what's new in android  - ui and dev tools
Gdg san diego android 11 meetups what's new in android - ui and dev tools
 
Android
AndroidAndroid
Android
 
Node.js basics
Node.js basicsNode.js basics
Node.js basics
 
test
testtest
test
 
Information track presentation_final
Information track presentation_finalInformation track presentation_final
Information track presentation_final
 
Linux Security APIs and the Chromium Sandbox
Linux Security APIs and the Chromium SandboxLinux Security APIs and the Chromium Sandbox
Linux Security APIs and the Chromium Sandbox
 
Gimli: Server Process Monitoring and Fault Analysis
Gimli: Server Process Monitoring and Fault AnalysisGimli: Server Process Monitoring and Fault Analysis
Gimli: Server Process Monitoring and Fault Analysis
 
Virus Bulletin 2015: Exposing Gatekeeper
Virus Bulletin 2015: Exposing GatekeeperVirus Bulletin 2015: Exposing Gatekeeper
Virus Bulletin 2015: Exposing Gatekeeper
 
MacOS forensics and anti-forensics (DC Lviv 2019) presentation
MacOS forensics and anti-forensics (DC Lviv 2019) presentationMacOS forensics and anti-forensics (DC Lviv 2019) presentation
MacOS forensics and anti-forensics (DC Lviv 2019) presentation
 
Grâce aux tags Varnish, j'ai switché ma prod sur Raspberry Pi
Grâce aux tags Varnish, j'ai switché ma prod sur Raspberry PiGrâce aux tags Varnish, j'ai switché ma prod sur Raspberry Pi
Grâce aux tags Varnish, j'ai switché ma prod sur Raspberry Pi
 
PHP Backdoor: The rise of the vuln
PHP Backdoor: The rise of the vulnPHP Backdoor: The rise of the vuln
PHP Backdoor: The rise of the vuln
 
Android dev
Android devAndroid dev
Android dev
 
FRIDA 101 Android
FRIDA 101 AndroidFRIDA 101 Android
FRIDA 101 Android
 
My name is Trinidad
My name is TrinidadMy name is Trinidad
My name is Trinidad
 
Permission enforcement s in android new (1)
Permission   enforcement s  in android new (1)Permission   enforcement s  in android new (1)
Permission enforcement s in android new (1)
 
Installing odoo v8 from github
Installing odoo v8 from githubInstalling odoo v8 from github
Installing odoo v8 from github
 

More from Przemek Jakubczyk

Android Auto instrumentation
Android Auto instrumentationAndroid Auto instrumentation
Android Auto instrumentationPrzemek Jakubczyk
 
Droidcon Berlin Barcamp 2016
Droidcon Berlin Barcamp 2016Droidcon Berlin Barcamp 2016
Droidcon Berlin Barcamp 2016Przemek Jakubczyk
 
It's always your fault. Poznań ADG 2016
It's always your fault. Poznań ADG 2016It's always your fault. Poznań ADG 2016
It's always your fault. Poznań ADG 2016Przemek Jakubczyk
 
How to recognise that the user has just uninstalled your android app
How to recognise that the user has just uninstalled your android appHow to recognise that the user has just uninstalled your android app
How to recognise that the user has just uninstalled your android appPrzemek Jakubczyk
 

More from Przemek Jakubczyk (7)

Android Auto instrumentation
Android Auto instrumentationAndroid Auto instrumentation
Android Auto instrumentation
 
Droidcon Berlin Barcamp 2016
Droidcon Berlin Barcamp 2016Droidcon Berlin Barcamp 2016
Droidcon Berlin Barcamp 2016
 
It's always your fault. Poznań ADG 2016
It's always your fault. Poznań ADG 2016It's always your fault. Poznań ADG 2016
It's always your fault. Poznań ADG 2016
 
RoboSpock
RoboSpockRoboSpock
RoboSpock
 
How to recognise that the user has just uninstalled your android app
How to recognise that the user has just uninstalled your android appHow to recognise that the user has just uninstalled your android app
How to recognise that the user has just uninstalled your android app
 
Android accounts & sync
Android accounts & syncAndroid accounts & sync
Android accounts & sync
 
Robospock droidcon '14
Robospock   droidcon '14Robospock   droidcon '14
Robospock droidcon '14
 

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

  • 1. How to recognise that the user has just uninstalled your Android app fb.me/pjakubczyk +AleksanderPiotrowski @pelotasplus
  • 3.
  • 5. 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>
  • 6. 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)); }
  • 7. 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
  • 8. 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
  • 9. 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
  • 10. Let’s uninstall our app and there’s nothing …. Why ? OS unregisters listener during removal
  • 11. What Opera does? It does not listen for package removal it does some magic ;-) … not in Java code
  • 13. Getting the APK ● genymotion with gapps installed ● get app from play store ● be careful with the right ABI
  • 14. Getting the APK 1.adb shell 2.pm list packages
  • 15. Getting the APK 3. pm path com.opera.max 4. adb pull /data/app/com.opera.max.apk
  • 17. Apktool A tool for reverse engineering Android apk files Made with <3 in Poland ;-)
  • 18. Apktool Easy to use $ apktool d com.opera.max.apk
  • 19. Apktool ● decoded XML files ● smali assembly code ● PNGs, layouts, resources ● id-s mapping
  • 20. with Opera Max APK live apktool demo
  • 22. Found a clue! There are *.so files We can inspect them to see more Tools: strings, objdump, nm, readelf
  • 23. rudy$ strings opera/lib/armeabi/libuo.so (II) ... inotify_init inotify_add_watch inotify_rm_watch /data/data/%s/ %s%s
  • 24. 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.
  • 25. rudy$ strings opera/lib/armeabi/libuo.so (I) ... Android start android.intent.action.VIEW --user ...
  • 26. am command part of Android system /system/bin/am A way to start apps, intents and whatnot
  • 27. more details $ ps USER PID PPID u0_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
  • 28. The scenario 1. Fork the native process 2. Inside the child process use inotify to watch a file 3. Watcher is woken up on file deletion. Start another native process 4. The last process run the ‘am’ (ActivityManager) command to run intent.
  • 30. 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-sdk ndk.dir=/Users/alek/android-ndk-r10e
  • 31. build.gradle android.defaultConfig { applicationId "pl.pelotasplus.actionafteruninstall" ndk { moduleName "hello-jni" ldLibs "log", "android" stl "stlport_static" } }
  • 32. 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"); } }
  • 33. MainActivity.java calling protected void onCreate(Bundle savedInstanceState) { setContentView(R.layout.activity_main); textView = (TextView) findViewById(R.id.textView); textView.setText(stringFromJNI()); observer(); }
  • 36. Sample by Google jstring Java_pl_pelotasplus_actionafteruninstall_MainActivity_stringFro mJNI (JNIEnv* env, jobject thiz) { return (*env)->NewStringUTF( env, "Hello from JNI ! Compiled with ABI foo." ); }
  • 37. Android.mk LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := hello-jni LOCAL_SRC_FILES := hello-jni.c LOCAL_LDFLAGS += -llog -lpthread include $(BUILD_SHARED_LIBRARY)
  • 38. Application.mk APP_ABI := armeabi-v7a # all APP_STL := stlport_static
  • 39. 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=%dn", fd); }
  • 40. 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=%dn", length); if (length < 0) { perror("read"); }
  • 41. inotify on Linux while (i < length) { struct inotify_event *event = (struct inotify_event*)&buffer[ i]; printf("Event len %dn", 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 );
  • 42. inotify on Android (pseudo code) void observer(void) { inotify_init(); inotify_add_watch(fd, DIRECTORY, IN_DELETE); if (event->mask & IN_DELETE) { startIntent(); } }
  • 43. first attempt void Java_pl_pelotasplus_actionafteruninstall_MainActivity_observer(JNIEnv* env, jobject thiz) { observer(); } App blocked as native code blocked app
  • 44. second attempt, with thread void Java_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
  • 45. third attempt, with fork void Java_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 childn"); observer(); } }
  • 46. start intent, another fork void 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"); } }
  • 47. Live demo of our app
  • 49. 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 Hackborn Android framework engineer hack...@android.com http://markmail.org/message/ruqp2t6gvhnhv654