A presentation done spontaneously during Droidcon.de 2015.
Shows the trick Opera did - open a web page after uninstalling the binary. Raw meat, C code, included.
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
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
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 );
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");
}
}
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