如何获取系统服务?

1.AlarmManager系统服务

AlarmManager是一个典型的系统服务,意为“警告”,会定时执行动作。典型用法为

    void set(int type, long triggerAtMillis, PendingIntent operation)

到达设定时间后服务会发出广播,执行PendingIntent中定义的动作。动作完成后系统重启后alarm会被清除。如果期间设备进入休眠了,动作将保持等待设备苏醒。

AlarmManager也可以在广播执行期间持有唤醒锁,保证设备不被关闭。广播执行完成后再释放唤醒锁。

AlarmManager可以以精确时间执行

setExact(int, long, PendingIntent) 

也可以指定一个时间窗口,由系统OS调整调整执行的精确时间

setWindow(int, long, long, PendingIntent)

还可以重复执行动作

void setRepeating(int type, long triggerAtMillis,
        long intervalMillis, PendingIntent operation)

使用 AlarmManager 的优势是比Hanlder更方便和效率,能够重复执行,且 AlarmManager 的执行不用保持 AP,相比之下,Timer 的执行则依赖 AP,因此更为耗电,应该避免使用 Timer。

2.如何启动系统服务?

AlarmManager服务的获取方式如下

AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);

2.1从缓存中读取服务获取器

context的实现类是ContextImpl

@Override
public Object getSystemService(String name) {
    return SystemServiceRegistry.getSystemService(this, name);
} 

SystemServiceRegistry类是系统服务的注册管理类,其内部有两个字典记录缓存服务

//1.记录服务类与名称的键值对
HashMap, String> SYSTEM_SERVICE_NAMES
//2.记录ServiceFetcher与服务类名称的键值对
HashMap> SYSTEM_SERVICE_FETCHERS 

SystemServiceRegistry类读取服务就是从集合中读取ServiceFetcher,进而获取服务类AlarmManager

public static Object getSystemService(ContextImpl ctx, String name) {
    ServiceFetcher fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
    return fetcher != null ? fetcher.getService(ctx) : null;
}

ServiceFetcher是一个接口,只有一个方法用于获取具体服务

static abstract interface ServiceFetcher {
    T getService(ContextImpl ctx);
}

ServiceFetcher的实现类是CachedServiceFetcher该类是获取服务的核心类,ServiceFetcher 实现了对服务的缓存,如果没有则使用createService()方法创建服务。这种设计是因为缓存机制是通用的,而具体服务是独特的。

@Override
@SuppressWarnings("unchecked")
public final T getService(ContextImpl ctx) {
    final Object[] cache = ctx.mServiceCache;
    synchronized (cache) {
        // Fetch or create the service.
        Object service = cache[mCacheIndex];
        if (service == null) {
            service = createService(ctx);
            cache[mCacheIndex] = service;
        }
        return (T)service;
    }
}

SystemServiceRegistry类中的静态代码块完成系统服务的注册,填充两个集合。

static{
    ...
    registerService(Context.ALARM_SERVICE, AlarmManager.class,CachedServiceFetcher
}    

registerService方法会将某个服务的相关信息写入到内部集合中。

private static  void registerService(String serviceName, Class serviceClass, ServiceFetcher serviceFetcher) {
    SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
    SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
}

2.3系统服务的创建

到目前为止 ServiceFetcher 还仅仅是一层包装,服务还没有真正创建,CachedServiceFetcher类负责创建服务,其实现如下,主要定义如何创建系统服务类的实例

public abstract T createService(ContextImpl ctx);

    return new CachedServiceFetcher() {

      @Override
          public AlarmManager createService(ContextImpl ctx) {
        IBinder b = ServiceManager.getService(Context.ALARM_SERVICE);
        IAlarmManager service = IAlarmManager.Stub.asInterface(b);
        return new AlarmManager(service, ctx);
      }
};

可见AlarmManager类的创建依靠从ServiceManager获取的IBinder 对象,这个IBinder对象是Alarm服务所使用的Binder接口,而后将被下转型为业务接口 IAlarmManager 。

ServiceManager本身就是一个服务类,负责管理系统服务。它的内部有一个IServiceManager 对象,负责从远端获取各种服务的Binder对象,定义如下

public interface IServiceManager extends IInterface{
    public IBinder getService(String name);
}

ServiceManager使用这个IServiceManager 对象获取具体服务,如AlarmManager

HashMap sCache;
public static IBinder getService(String name) {

    IBinder service = sCache.get(name);
    if (service != null) {
        return service;
    } else {
        return iServiceManager.getService(name);
    }
}

可见ServiceManager内部还有一个集合缓存所获取的各种 Binder 对象,如果没有就使用IServiceManager 对象获取服务所需的Binder接口。

IServiceManager 对象本身就是一个远程Binder对象

public final class ServiceManager {
    private static IServiceManager sServiceManager;
    private static IServiceManager getIServiceManager() {
        sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
        return sServiceManager;
    }
}

其中BinderInternal.getContextObject()返回一个全局Context类,该对象同时是一个IBinder类,即IServiceManager,由其构建ServiceManager服务。

ServiceManagerNative是其服务端实现,定义如下

class ServiceManagerNative extends Binder implements IServiceManager

本地实际使用的是远端的代理类ServiceManagerProxy,获取服务的方法为

public IBinder getService(String name) throws RemoteException {
    Parcel data = Parcel.obtain();
    Parcel reply = Parcel.obtain();
    data.writeInterfaceToken(IServiceManager.descriptor);
    data.writeString(name);
    mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
    IBinder binder = reply.readStrongBinder();
    reply.recycle();
    data.recycle();
    return binder;
}

远端的onTransact方法响应如下

switch (code) {
    case IServiceManager.GET_SERVICE_TRANSACTION: {
        data.enforceInterface(IServiceManager.descriptor);
        String name = data.readString();
        IBinder service = getService(name);
        reply.writeStrongBinder(service);
        return true;
    }
}

3.结论与扩展

总结一下加载系统服务的过程ServiceManager类通过问答式机制(即Binder机制)获取到某个服务的 IBinder 对象,而后将其下转型为服务特定接口,最后构建服务对象。在此过程中,存在一些缓存行为以提高性能

使用 Hook 技术可以替换和伪造系统服务 AlarmManager 。在 ApplicationattachBaseContext 中替换被 HookIBinder 对象。

@Override
protected void attachBaseContext(Context base) {
    super.attachBaseContext(base);
    Class serviceManagerClass = Class.forName("android.os.ServiceManager");
    Method getServiceMethod = serviceManagerClass.getDeclaredMethod("getService", String.class);
    IBinder rawBinder = (IBinder) getServiceMethod.invoke(null, Context.ALARM_SERVICE);

    IBinder hookedBinder = (IBinder) Proxy.newProxyInstance(serviceManagerClass.getClassLoader(),
            new Class[] { IBinder.class },
            new BinderInvocationHandler(rawBinder));

    Field cacheField = serviceManagerClass.getDeclaredField("sCache");
    cacheField.setAccessible(true);
    Map cache = (Map) cacheField.get(null);
    cache.put(Context.ALARM_SERVICE, hookedBinder);
}

我们往serviceManager的缓存列表中加入 Hook 过的的 IBinder 对象,这样等于阉割了其 getService方法,使得该方法只能从缓存中获取对象,而不能自己创建对象。

但只 Hook 掉 IBinder 对象没有意义,我们需要继续 Hook 掉其下转型的具体接口 IAlarmManager ,这样才能改变服务的功能。为此需要改写 IBinder 对象的 queryLocalInterface 方法,使其返回一个 Hook 过的IAlarmManager对象。

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    if ("queryLocalInterface".equals(method.getName())) {
        Class iAlarmManager = Class.forName("android.app.IAlarmManager");
        Class stub = Class.forName("android.app.IAlarmManager$Stub");
        return Proxy.newProxyInstance(proxy.getClass().getClassLoader(), new Class[]{IBinder.class, IInterface.class, iAlarmManager},new BinderHookInvocationHandler(iBinder, stub));
    }
    return  method.invoke(iBinder, args);
}

BinderHookInvocationHandler类中可以改写服务的各种方法实现。注意这里需要使用Stub类的asInterface向下转型为IAlarmManager接口。

private class IAlarmManagerHookHandler implements InvocationHandler{

    IBinder iBinder;

    Object iAlarmManager;

    public IAlarmManagerHookHandler(IBinder rawBinder) {
        this.iBinder = rawBinder;
        Class stubClass = Class.forName("android.app.IAlarmManager$Stub");
        Method asInterfaceMethod = stubClass.getDeclaredMethod("asInterface",IBinder.class);
        iAlarmManager = asInterfaceMethod.invoke(null, rawBinder);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if("getNextAlarmClock".equals(method.getName())){
            Log.i(TAG, "new getNextAlarmClock: " + method.toString());
        }
        return method.invoke(iAlarmManager, args);
    }
}

总结一下 Hook 系统服务就意味着 Hook 服务的 Binder 对象,包括 IBinder 接口和 IAlarmManager接口两层。

你可能感兴趣的:(如何获取系统服务?)