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 。在 Application
的 attachBaseContext
中替换被 Hook
的 IBinder
对象。
@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
接口两层。