App not allowed to read or update stored WiFi Ap config

修改Settings 发现的一个问题,记录一下.

问题

代码,使用WifiManager获取Wi-Fi AP 配置:

mWifiConfig = mWifiManager.getWifiApConfiguration();

需要权限:

android.Manifest.permission.ACCESS_WIFI_STATE
android.Manifest.permission.OVERRIDE_WIFI_CONFIG

如果没有声明 OVERRIDE_WIFI_CONFIG 权限 , 则会抛出如下异常:

java.lang.SecurityException: App not allowed to read or update stored WiFi Ap config (uid = 1000)
    at android.os.Parcel.readException(Parcel.java:2004)
    at android.os.Parcel.readException(Parcel.java:1950)
    at android.net.wifi.IWifiManager$Stub$Proxy.getWifiApConfiguration(IWifiManager.java:1769)
    at android.net.wifi.WifiManager.getWifiApConfiguration(WifiManager.java:2221)
    at com.android.settings.TetherSettings.initWifiTethering(TetherSettings.java:205)
    at com.android.settings.TetherSettings.onCreate(TetherSettings.java:171)

分析

如下可以看出 getWifiApConfiguration() 是一个hide 方法,并且是SystemApi ,需要权限 android.Manifest.permission.ACCESS_WIFI_STATE , 另一个权限还不能直接看出

/**
 * Gets the Wi-Fi AP Configuration.
 * @return AP details in WifiConfiguration
 *
 * @hide
 */
@SystemApi
@RequiresPermission(android.Manifest.permission.ACCESS_WIFI_STATE)
public WifiConfiguration getWifiApConfiguration() {
    try {
        return mService.getWifiApConfiguration();
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

mService 是一个 IWifiManager 对象, 在 WifiManager 创建时赋值. 这个 WifiManager 是在注册系统服务时创建的,见 SystemServiceRegistry 的如下注册方法:

registerService(Context.WIFI_SERVICE, WifiManager.class,
        new CachedServiceFetcher() {
    @Override
    public WifiManager createService(ContextImpl ctx) throws ServiceNotFoundException {
        // 获取Wifi系统服务
        IBinder b = ServiceManager.getServiceOrThrow(Context.WIFI_SERVICE);
        // 转换为对应的接口
        IWifiManager service = IWifiManager.Stub.asInterface(b);
        return new WifiManager(ctx.getOuterContext(), service,
                ConnectivityThread.getInstanceLooper());
    }});

可以知道, b 实际上是一个binder代理对象,被代理的是系统服务 WifiService , 更确切的说应该是 WifiServiceImpl . 为什么呢?

查看 SystemServer 的 startOtherServices() 方法, 有如下代码 , 用来启动 WifiService

// Wifi Service must be started first for wifi-related services.
traceBeginAndSlog("StartWifi");
mSystemServiceManager.startService(WIFI_SERVICE_CLASS);
traceEnd();

SystemServiceManage 的startService方法会创建 WifiService ,并调用其 onStart 方法 , 可以发现它发布的binder Service 实际上是 mImpl , 也就是 WifiServiceImpl . 因此, 通过 Context.WIFI_SERVICE 获取的实际是其代理对象 .

final WifiServiceImpl mImpl;
@Override
public void onStart() {
    Log.i(TAG, "Registering " + Context.WIFI_SERVICE);
    publishBinderService(Context.WIFI_SERVICE, mImpl);
}

因此 WifiManager 的 getWifiApConfiguration() 调用,实际上最终调用了WifiServiceImpl 的 getWifiApConfiguration() ,这是一个IPC 过程.

WifiServiceImpl 的 getWifiApConfiguration() 如下, 可以发现, 首先调用 enforceAccessPermission() 方法来确保有android.Manifest.permission.ACCESS_WIFI_STATE 权限, 之后调用checkConfigOverridePermission 方法来检查android.Manifest.permission.OVERRIDE_WIFI_CONFIG 权限 , 可以发现若检查没有权限,则会抛出相关的 SecurityException .

/**
 * see {@link WifiManager#getWifiApConfiguration()}
 * @return soft access point configuration
 * @throws SecurityException if the caller does not have permission to retrieve the softap
 * config
 */
@Override
public WifiConfiguration getWifiApConfiguration() {
    enforceAccessPermission();   // access 权限检查
    int uid = Binder.getCallingUid();
    // only allow Settings UI to get the saved SoftApConfig
    if (!mWifiPermissionsUtil.checkConfigOverridePermission(uid)) {    // override 权限检查
        // random apps should not be allowed to read the user specified config
        throw new SecurityException("App not allowed to read or update stored WiFi Ap config "
                + "(uid = " + uid + ")");
    }
    mLog.trace("getWifiApConfiguration uid=%").c(uid).flush();
    return mWifiStateMachine.syncGetWifiApConfiguration();
}

enforceAccessPermission() 方法如下, 可以看出在检查 ACCESS_WIFI_STATE 权限

private void enforceAccessPermission() {
    mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE,
            "WifiService");
}

WifiPermissionsUtil 的 checkConfigOverridePermission 方法如下,通过WifiPermissionsWrapper.getOverrideWifiConfigPermission 方法 来检查相关权限 :

/**
 * Checks if the app has the permission to override Wi-Fi network configuration or not.
 *
 * @param uid uid of the app.
 * @return true if the app does have the permission, false otherwise.
 */
public boolean checkConfigOverridePermission(int uid) {
    try {
        int permission = mWifiPermissionsWrapper.getOverrideWifiConfigPermission(uid);
        return (permission == PackageManager.PERMISSION_GRANTED);
    } catch (RemoteException e) {
        mLog.err("Error checking for permission: %").r(e.getMessage()).flush();
        return false;
    }
}

WifiPermissionsWrapper.getOverrideWifiConfigPermission 是真正检查 OVERRIDE_WIFI_CONFIG 权限的地方

/**
 * Determines if the caller has the override wifi config permission.
 *
 * @param uid to check the permission for
 * @return int representation of success or denied
 * @throws RemoteException
 */
public int getOverrideWifiConfigPermission(int uid) throws RemoteException {
    return AppGlobals.getPackageManager().checkUidPermission(
            android.Manifest.permission.OVERRIDE_WIFI_CONFIG, uid);
}

OVERRIDE_WIFI_CONFIG权限定义

查看OVERRIDE_WIFI_CONFIG 权限定义的地方( frameworks/base/core/res/AndroidManifest.xml )
这个权限是非 第三方应用 使用的 , 级别是 signature|privileged , 即有平台签名或特权应用

  
   

你可能感兴趣的:(Android)