android监听app启动

前言

有时候你会遇到一些比较邪恶的需求,比如某些游戏加速软件,在游戏开始运行的时候,执行以下内存清理。这个就需要监听游戏的启动了。如何实现这个需求呢?

原理

在android.app.ActivityManagerNative类里面定义了一个setActivityController(IActivityController watcher)方法,该方法通过参数IAcitivityController设置一个监听器,用来监听系统启动某个Activity。当系统启动某个Activity时,会调用IAcitivityController的回调方法。

在工程中可以通过获取ActivityManagerNative对象并生成一个IActivityController实例作为setActivityController()的参数传递过去,从而达到在工程中监听到系统Activity的启动。 既然如此,那还不简单,直接调用方法就可以了,但是。现实是残酷的。因为这个方法是隐藏方法。

package android.app;
/** {@hide} */
public abstract class ActivityManagerNative extends Binder implements IActivityManager{
    /**
     * Retrieve the system's default/global activity manager.
     */
    static public IActivityManager getDefault() {
        return gDefault.get();
  }

  public void setActivityController(IActivityController watcher) throws RemoteException{}
}

package android.app;
import android.content.Intent;
/**
 * Testing interface to monitor what is happening in the activity manager
 * while tests are running.  Not for normal application development.
 * {@hide}
 */
interface IActivityController

可以看到,都有hide标签。因此在api里面是找不到这个方法的。也找不到IActivityController这个接口。怎么办?

解决方案

方法一

从手机里面提取framework.jar。将android.app.ActivityManagerNative.class和其内部类都提取出来,将android.app.IActivityController和其内部类都提取出来。替换掉当前开发环境中的sdk的platform的android.jar里面相应的class。刷新一下工程,就可以调用这两个隐藏的内容了。

方法二

如果觉得方法一太复杂了,则可以使用反射来调用隐藏方法。此处摘自pierce0young的专栏

解决方案:把系统内的IActivityController.aidl文件在我们自己的工程里按照同样的包结构创建一份,在程序中继承该接口,在调用setActivityController时传入该实例即可。

1、拷贝系统内IActivityController.aidl到工程中,与系统内该文件包结构保持一致:

app

这里提供一下aidl的传送门

2、程序中实现该接口:

    private class ActivityController extends IActivityController.Stub {

    public boolean activityStarting(Intent intent, String pkg) {
        return true;
    }

    public boolean activityResuming(String pkg) {
        return true;
    }

    public int appEarlyNotResponding(String processName, int pid,
            String annotation) {
        return 0;
    }

    public boolean appCrashed(String processName, int pid, String shortMsg,
            String longMsg, long timeMillis, String stackTrace) {
        return false;
    }

    public int appNotResponding(String processName, int pid,
            String processStats) {
        return 0;
    }
}

3、通过反射获取ActivityManagerNative对象并调用方法setActivityController进行监听器设置:

    private void setActivityController() {
    try {
        Class<?> cActivityManagerNative = Class
                .forName("android.app.ActivityManagerNative");
        Method mGetDefault = cActivityManagerNative.getMethod("getDefault",
                null);
        Object oActivityManagerNative = mGetDefault.invoke(null, null);
        Class<?> i = Class.forName("android.app.IActivityController$Stub");

        Method mSetActivityController = cActivityManagerNative.getMethod(
                "setActivityController",
                Class.forName("android.app.IActivityController"));
        mSetActivityController.invoke(oActivityManagerNative,
                new ActivityController());
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    }
}

至此。就实现了监听任意app启动了。当任意app启动时都会触发activityStarting方法。在这个方法里面写上你的逻辑处理即可。如果你想中断此app的启动:

public boolean activityStarting(Intent intent, String pkg) {
        return false;//即可中断app启动
    }

其他几个回调方法请自行发掘,这里就不多讲述了。

小球球

继续阅读此作者的更多文章

深圳