安卓WifiManager
是系统服务之一,应用程序是通过上下文对象Context
进行跨进程通信来获取的。 这里我们来看一下,如何修改应用程序内的WifiManager
的功能,也就是替换WifiManager
。
切入点
在开发过程中,一般是通过上下文对象Context
来获取WifiManager
,代码如下:
WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
我们顺藤摸瓜,来研究下WifiManager
这个类,看看它针对wifi模块的功能到底是由谁实现的。我们选择一个方法getWifiState
来看一下源码:
/**
* Gets the Wi-Fi enabled state.
* @return One of {@link #WIFI_STATE_DISABLED},
* {@link #WIFI_STATE_DISABLING}, {@link #WIFI_STATE_ENABLED},
* {@link #WIFI_STATE_ENABLING}, {@link #WIFI_STATE_UNKNOWN}
* @see #isWifiEnabled()
*/
public int getWifiState() {
try {
return mService.getWifiEnabledState();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
可以看到最终是调用的mService.getWifiEnabledState()
方法,也就是说具体实现是由mService
来完成的。
@UnsupportedAppUsage
IWifiManager mService;
是一个系统层面的IWifiManager
类型变量。这里可能是一个突破口,因为在安卓世界中,类名以I
开头的类大概率是一个接口,只要IWifiManager
是一个接口,我们就可以使用动态代理来替换掉这个成员变量。看下源码:
frameworks/base/wifi/java/android/net/wifi/IWifiManager.aidl
,aidl文件,编译完后也就是一个接口文件。看下文件内容:
/**
* Interface that allows controlling and querying Wi-Fi connectivity.
*
* {@hide}
*/
interface IWifiManager
{
......
boolean setWifiEnabled(String packageName, boolean enable);
int getWifiEnabledState();
......
}
可以看到,是定义了一些接口方法,其中就有getWifiEnabledState
,到此,我们已经可以确定IWifiManager
就是一个很好的hook切入点。剩下的,我们需要确认的是:WifiManager
是何时被系统初始化的?是否是单例的?是否跟系统组件绑定的?
这时候,我们需要研究下ContextImpl
类,为什么呢?因为Context
最终实现基本都在ContextImpl
中。
我们看下ContextImpl
的getSystemService
方法:
@Override
public Object getSystemService(String name) {
return SystemServiceRegistry.getSystemService(this, name);
}
最终调用的是SystemServiceRegistry
的一个静态方法getSystemService
。
/**
* Gets a system service from a given context.
*/
public static Object getSystemService(ContextImpl ctx, String name) {
ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
return fetcher != null ? fetcher.getService(ctx) : null;
}