主要涉及怎样使用 WifiManager 进行 wifi 相关操作;通过怎么获取 WifiManageraddNetwork 的调用过程来学习 ADIL RPC 通信,但不涉及 Binder IPC 通信。

Wifi

WifiManager

简介

  • public class WifiManager extends Object
  • Android N 之前的版本(即 android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.N )应该是使用 application context 获取该类的对象而不应该使用其子类,以避免调用过程中的内存泄漏。至于原因可以参考这篇博客
  • Context 对象可以通过两种方式获取该类的实例:
    1. public final T getSystemService(Class<T> serviceClass) WifiManager wifiManager = getApplicationContext().getSystemService(WifiManager.class);
    2. public abstract Object getSystemService(String name) WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
  • 该类主要作用:
    • 管理已配置的 Wifi 连接列表,可以查看和更新该列表并可以修改各个条目的属性;
    • 控制当前连接的 Wifi,可以断开或连接 Wifi,并且可以查看当前连接的 Wifi 的网络状态的动态信息;
    • 获取周围可连接 Wifi 扫描结果,获取各个 Wifi 热点的信息并决定连接到那个 Wifi;
    • 定义了 Wifi 状态改变时各广播 Intent 的动作名称;
    • 当前类用来执行 Wifi 的特定操作,要执行网络连接相关的操作请使用 ConnectivityManager

API

该类的详细 API 我就不列出来了,具体可参见 Android 官方 API,如果连不上可以使用Android 官方 API 中国版.

例子

展示如何使用该类及其常用方法。 这是我做的一个扫码自动连接指定到 wifi 并通过 Socket 连接到指定 PC 的应用的部分代码节选,该源码的Github 地址

  • 获取 WifiManager 对象:

    1
    2
    3
    4
    5
    
    private WifiManagerUtils(Context context) {
        mContext = context;
        mWifiManager = (WifiManager) context.getApplicationContext()
            .getSystemService(Context.WIFI_SERVICE);
    }

    注意参数传入的是 Activiy Context ,要转换成 Application Context 来获取 WifiManager 对象,以避免内存泄漏。

  • 判断 Wifi 是否开启:

    1
    2
    3
    4
    
    public boolean isWifiEnabled() {
        Log.d(TAG, "isWifiEnabled():" + mWifiManager.isWifiEnabled());
        return mWifiManager.isWifiEnabled();
    }
  • 开启 Wifi:

    1
    2
    3
    
    public void openWifi() {
        mWifiManager.setWifiEnabled(true);
    }
  • 获取指定 wifi 加密类型:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    
    private int getType(@NonNull String ssid) {
    
        List<ScanResult> mScanResultList = mWifiManager.getScanResults();
    
        for (ScanResult scanResult : mScanResultList) {
            if (ssid.equals(scanResult.SSID)) {
                if (scanResult.capabilities.contains("WPA")) {
                    return WIFICIPHER_WPA;
                } else if (scanResult.capabilities.contains("WEP")) {
                    return WIFICIPHER_WEP;
                } else {
                    return WIFICIPHER_NOPASS;
                }
            } else {
                Log.d(TAG, ssid + "isn't discover.");
            }
        }
    
        return WIFICIPHER_WPA;
    }
  • 构建指定的 WifiConfiguration 对象:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    
    private WifiConfiguration createWifiConfig(String ssid, String password, int type) {
        //初始化  WifiConfiguration
        WifiConfiguration config = new WifiConfiguration();
        config.allowedAuthAlgorithms.clear();
        config.allowedGroupCiphers.clear();
        config.allowedKeyManagement.clear();
        config.allowedPairwiseCiphers.clear();
        config.allowedProtocols.clear();
    
        //指定对应的  SSID
        config.SSID = "\"" + ssid + "\"";
    
        //不需要密码的场景
        if (type == WIFICIPHER_NOPASS) {
            config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
            //以  WEP 加密的场景
        } else if (type == WIFICIPHER_WEP) {
            config.hiddenSSID = true;
            config.wepKeys[0] = "\"" + password + "\"";
            config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
            config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED);
            config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE);
            config.wepTxKeyIndex = 0;
            //以  WPA 加密的场景,自己测试时,发现热点以  WPA2 建立时,同样可以用这种配置连接
        } else if (type == WIFICIPHER_WPA) {
            config.preSharedKey = "\"" + password + "\"";
            config.hiddenSSID = true;
            config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
            config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
            config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
            config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
            config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
            config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
            config.status = WifiConfiguration.Status.ENABLED;
        }
        return config;
    }
  • 通过 SSID 和密码连接到指定 wifi:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    
    public boolean connectWifi(@NonNull String ssid, String password) {
        Log.d(TAG, "SSID:" + ssid + " password:" + password);
    
        //如果之前有类似的配置
        WifiConfiguration tempConfig = isExist(ssid);
        if (tempConfig != null) {
            //清除旧有配置;注意权限问题,不能先删除再添加,删除操作会检查当前包名是否和添加时的应用包名一致
            int netId = mWifiManager.updateNetwork(
                                                   createWifiConfig(ssid, password, getType(ssid), tempConfig.networkId));
            Log.d(TAG, "netId1:" + netId);
            return mWifiManager.enableNetwork(netId, true);
        } else {
            int netId = mWifiManager.addNetwork(createWifiConfig(ssid, password, getType(ssid)));
            Log.d(TAG, "netId2:" + netId);
            return mWifiManager.enableNetwork(netId, true);
        }
    }

    由于权限限制,你只能删除当前应用创建的 wifi 配置。

  • 判断当前 Wifi 是否曾经连接过:

    遍历已保存的 wifi 列表,查看当前 SSID 是否在该列表中。

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    
    private WifiConfiguration isExist(String ssid) {
        List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
    
        for (WifiConfiguration config : configs) {
            if (config.SSID.equals("\"" + ssid + "\"")) {
                return config;
            }
        }
        return null;
    }
  • 判断是否连接上指定 wifi:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    
    public boolean isWifiConnected(String ssid) {
        ConnectivityManager connectivityManager = (ConnectivityManager) mContext.getSystemService(
                                                                                                  Context.CONNECTIVITY_SERVICE);
        NetworkInfo activeNetInfo = connectivityManager.getActiveNetworkInfo();
        if (activeNetInfo != null && activeNetInfo.getType() == ConnectivityManager.TYPE_WIFI
            && activeNetInfo.isConnected()) {
            Log.d(TAG, activeNetInfo.toString());
            Log.d(TAG, "isWifiConnected():" + ('"' + ssid + '"').equals(activeNetInfo.getExtraInfo()));
            return ('"' + ssid + '"').equals(activeNetInfo.getExtraInfo());
        }
        Log.d(TAG, "isWifiConnected():false");
        return false;
    }

    使用 Connectivity 对象获取网络连接信息而不是使用 WifiManager,但此处有误应该和上面获取 WifiManage 对象一样使用 Application Context 而不应该使用 Activity Context

  • 至于断开连接、重新连接、关闭 wifi、获取 wifi 信息等,可以参照上面的代码和官方 API 使用。

WifiService

我们平时使用的都是 WifiManager 对象,但最终工作交由 WifiService 来完成的,哪它们是怎样建立通讯的呢?

  • 涉及文件:
    • frameworks/base/core/java/android/content/Context.java
    • frameworks/base/core/java/android/app/ContextImpl.java
    • frameworks/base/core/java/android/app/SystemServiceRegistry.java
    • frameworks/base/core/java/android/os/Binder.java
    • frameworks/base/wifi/java/android/net/wifi/IWifiManager.aidl
    • out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/wifi/java/android/net/wifi/IWifiManager.java
    • frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiServiceImpl.java
    • frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiService.java
    • frameworks/base/services/core/java/com/android/server/SystemService.java
    • frameworks/base/services/core/java/com/android/server/SystemServiceManager.java

我们先从怎样获取 WifiManager 对象说起

  • Context.getSystemService

    该方法有两个重载 Context 类的抽象方法一般都由 ContextImpl 子类实现。

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    
    @SuppressWarnings("unchecked")
    public final @Nullable <T> T getSystemService(@NonNull Class<T> serviceClass) {
        // Because subclasses may override getSystemService(String) we cannot
        // perform a lookup by class alone.  We must first map the class to its
        // service name then invoke the string-based method.
        // 通过服务类名获 =Context= 中的服务名,该方法未抽象方法,具体实现后面会分析
        String serviceName = getSystemServiceName(serviceClass);
        // 调用另一种重载方法
        return serviceName != null ? (T)getSystemService(serviceName) : null;
    }
    
    @Override
    public String getSystemServiceName(Class<?> serviceClass) {
        return SystemServiceRegistry.getSystemServiceName(serviceClass);
    }
    
    @Override
    public Object getSystemService(String name) {
        return SystemServiceRegistry.getSystemService(this, name);
    }
  • SystemServiceRegistry.getSystemServiceName()

    1
    2
    3
    4
    5
    6
    
    private static final HashMap<Class<?>, String> SYSTEM_SERVICE_NAMES =
        new HashMap<Class<?>, String>();
    
    public static String getSystemServiceName(Class<?> serviceClass) {
        return SYSTEM_SERVICE_NAMES.get(serviceClass);
    }
  • SystemServiceRegistry.getSystemService()

    1
    2
    3
    4
    5
    6
    7
    
    private static final HashMap<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =
        new HashMap<String, ServiceFetcher<?>>();
    
    public static Object getSystemService(ContextImpl ctx, String name) {
        ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
        return fetcher != null ? fetcher.getService(ctx) : null;
    }
  • SystemServiceRegistry.ServiceFetcher<T>.getService(ContextImpl ctx)

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    
    static abstract class CachedServiceFetcher<T> implements ServiceFetcher<T> {
        private final int mCacheIndex;
    
        CachedServiceFetcher() {
            // Note this class must be instantiated only by the static initializer of the
            // outer class (SystemServiceRegistry), which already does the synchronization,
            // so bare access to sServiceCacheSize is okay here.
            mCacheIndex = sServiceCacheSize++;
        }
    
        @Override
        @SuppressWarnings("unchecked")
        public final T getService(ContextImpl ctx) {
            final Object[] cache = ctx.mServiceCache;
            final int[] gates = ctx.mServiceInitializationStateArray;
    
            for (;;) {
                boolean doInitialize = false;
                synchronized (cache) {
                    // Return it if we already have a cached instance.
                    T service = (T) cache[mCacheIndex];
                    if (service != null || gates[mCacheIndex] == ContextImpl.STATE_NOT_FOUND) {
                        return service;
                    }
    
                    ...
    
                        }
    
                ...
    
                    // The other threads will wait for the first thread to call notifyAll(),
                    // and go back to the top and retry.
                    synchronized (cache) {
                        while (gates[mCacheIndex] < ContextImpl.STATE_READY) {
                            try {
                                cache.wait();
                            } catch (InterruptedException e) {
                                Log.w(TAG, "getService() interrupted");
                                Thread.currentThread().interrupt();
                                return null;
                            }
                        }
                    }
            }
        }
    
        public abstract T createService(ContextImpl ctx) throws ServiceNotFoundException;
    }
  • SystemServiceRegistry.registerService

    ```java

    /**

    • Statically registers a system service with the context.
    • This method must be called during static initialization only. */ private static void registerService(String serviceName, Class serviceClass, ServiceFetcher serviceFetcher) { SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName); SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher); }

    static { // 常见系统服务都是在这里注册的 …

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    
    registerService(Context.WIFI_SERVICE, WifiManager.class,
                    new CachedServiceFetcher<WifiManager>() {
        @Override
        public WifiManager createService(ContextImpl ctx) throws ServiceNotFoundException {
            // IBinder、IWifiManager 暂且不管,往下看
            IBinder b = ServiceManager.getServiceOrThrow(Context.WIFI_SERVICE);
            IWifiManager service = IWifiManager.Stub.asInterface(b);
            // 终于看到了  WifiManager 了
            return new WifiManager(ctx.getOuterContext(), service,
                                   ConnectivityThread.getInstanceLooper());
        }});
    
    ...
        }

    ```

    终于看到 WifiManager 对象创建了

  • 时序图

获取 IBinder 对象

  • ServiceManager.getServiceOrThrow()

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    public static IBinder getServiceOrThrow(String name) throws ServiceNotFoundException {
        //这里  name=Context.WIFI_SERVICE="wifi"
        final IBinder binder = getService(name);
        if (binder != null) {
            return binder;
        } else {
            throw new ServiceNotFoundException(name);
        }
    }

    这里调用 ServiceManager.getService() 得到 IBinder 对象; ServiceManager 怎样管理 Services 这里不深入讨论,把它当作一个 Map<IBinder> 即可,通过 getService() 方法获取 IBinder 对象,通过 addService() 方法存储 IBinder 对象,接下来看看 IWifiManager 对象是怎样存储到 SericeManager 中的。

  • SystemServer 启动

    ```java /**

    • The main entry point from zygote. */ public static void main(String[] args) { new SystemServer().run(); }

    private void run() { … startOtherServices(); … mSystemServiceManager = new SystemServiceManager(mSystemContext); … }

    private void startOtherServices() { … // 支持 Wifi 功能就启动 Wifi Service if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI)) { // WIFI_SERVICE_CLASS = “com.android.server.wifi.WifiService”; mSystemServiceManager.startService(WIFI_SERVICE_CLASS); } … } ```

  • SystemServiceManager.starService()

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    
    public SystemService startService(String className) {
        final Class<SystemService> serviceClass;
        ...
            return startService(serviceClass);
    }
    
    public <T extends SystemService> T startService(Class<T> serviceClass) {
        ...
        // 通过反射获取类对象
        final T service;
        Constructor<T> constructor = serviceClass.getConstructor(Context.class);
        service = constructor.newInstance(mContext);
        ...
            startService(service);
            return service;
    }
    
    public void startService(@NonNull final SystemService service) {
        ...
        // WifiService.onStart()
        service.onStart();
        ...
            }
  • WifiService.onStart()

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    
    public WifiService(Context context) {
        super(context);
        mImpl = new WifiServiceImpl(context, new WifiInjector(context), new WifiAsyncChannel(TAG));
    }
    
    @Override
    public void onStart() {
        publishBinderService(Context.WIFI_SERVICE, mImpl);
    }
    
    protected final void publishBinderService(String name, IBinder service, boolean allowIsolated) {
        publishBinderService(name, service, allowIsolated, DUMP_FLAG_PRIORITY_DEFAULT);
    }
    
    protected final void publishBinderService(String name, IBinder service,
                                              boolean allowIsolated, int dumpPriority) {
        // 存储到  ServiceManager 的  IBinder 是  WifiServiceImpl 类对象
        ServiceManager.addService(name, service, allowIsolated, dumpPriority);
    }

    到此我们可知 ServiceManager.addService() 存储的是 IBinder 子类 WifiManagerImpl 的对象。接下来看看怎样通过 WifiManagerImpl 获取 IWifiManager 对象。

获取 IWifiManager 对象

  • 类图

  • BinderProxy

    通过 ServiceManager.getServiceOrThrow() 获取 WifiServiceIBinder 对象,如果当前进程是 system_server (即和 WfiService 同进程)获取到是 Binder 对象,否则获取到是 Binder 对象在当前进程的代理 BinderProxy 对象,显然我们一般都是跨进程访问获取到是后者。这里涉及到 Binder 跨进程调用,暂略过。

  • IWifiManager

    我们会发现找不到 IWifiManager 这个类,只有 IWifiManager.aidl ;它是用来生成 IWifiManager.java 文件的,编译时生成在 out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/wifi/java/android/net/wifi/IWifiManager.java ,也可以在源码根目录执行: prebuilts/sdk/tools/linux/bin/aidl -Iframeworks/base/wifi/java -Iframeworks/base/core/java frameworks/base/wifi/java/android/net/wifi/IWifiManager.aidl 命令在下 frameworks/base/wifi/java/android/net/wifi 目录下生成。IWifiManager.java 源码

    • IWifiManager.Stub.asInterface()

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      
      public static android.net.wifi.IWifiManager asInterface(android.os.IBinder obj)
      {
          if ((obj==null)) {
              return null;
          }
          // 这里  obj 是  BinderProxy 对象
          android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
          if (((iin!=null)&&(iin instanceof android.net.wifi.IWifiManager))) {
              return ((android.net.wifi.IWifiManager)iin);
          }
          // 这里返回
          return new android.net.wifi.IWifiManager.Stub.Proxy(obj);
      }
    • queryLocalInterface

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      
      // IWifiManager.Stub.class
      private static final java.lang.String DESCRIPTOR = "android.net.wifi.IWifiManager";
      /** Construct the stub at attach it to the interface. */
      public Stub()
      {
          this.attachInterface(this, DESCRIPTOR);
      }
      
      // Binder.class
      public void attachInterface(@Nullable IInterface owner, @Nullable String descriptor) {
          mOwner = owner;
          mDescriptor = descriptor;
      }
      
      public @Nullable IInterface queryLocalInterface(@NonNull String descriptor) {
          if (mDescriptor != null && mDescriptor.equals(descriptor)) {
              return mOwner;
          }
          return null;
      }
      
      // BinderProxy.class
      public IInterface queryLocalInterface(String descriptor) {
          return null;
      }

      这里是 BinderProxy.queryLocalInterface 返回 null

    • IWifiManager.Stub.Proxy

      1
      2
      3
      4
      5
      6
      7
      8
      9
      
      private static class Proxy implements android.net.wifi.IWifiManager
      {
          private android.os.IBinder mRemote;
          Proxy(android.os.IBinder remote)
          {
              mRemote = remote;
          }
          ...
      }

WifiManager.addNetwork() 的调用链

  • WifiManager 的构造方法

    1
    2
    3
    4
    5
    6
    7
    
    public WifiManager(Context context, IWifiManager service, Looper looper) {
        mContext = context;
        // IWifiManager.Stub.Proxy 对象
        mService = service;
        mLooper = looper;
        mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
    }
  • 我们来看看它的 addNetwork 方法:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    
    public int addNetwork(WifiConfiguration config) {
        if (config == null) {
            return -1;
        }
        config.networkId = -1;
        return addOrUpdateNetwork(config);
    }
    
    private int addOrUpdateNetwork(WifiConfiguration config) {
        try {
            return mService.addOrUpdateNetwork(config, mContext.getOpPackageName());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    观察其它方法可以看到 WifiManager 类是目标类 IWifiManager 的代理类,而目标类对象 mServic 由构造导入。

  • addOrUpdateNetwork

    WifiManagermServiceIWifiManager.Stub.Proxy ,调用它的 addOrUpdateNetwork 方法

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    
    static final int TRANSACTION_addOrUpdateNetwork = (android.os.IBinder.FIRST_CALL_TRANSACTION + 8);
    @Override public int addOrUpdateNetwork(android.net.wifi.WifiConfiguration config, java.lang.String packageName) throws android.os.RemoteException
    {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        int _result;
        try {
            _data.writeInterfaceToken(DESCRIPTOR);
            if ((config!=null)) {
                _data.writeInt(1);
                config.writeToParcel(_data, 0);
            }
            else {
                _data.writeInt(0);
            }
            _data.writeString(packageName);
            // mRemote 是  BinderProxy 的对象
            mRemote.transact(Stub.TRANSACTION_addOrUpdateNetwork, _data, _reply, 0);
            _reply.readException();
            _result = _reply.readInt();
        }
        finally {
            _reply.recycle();
            _data.recycle();
        }
        return _result;
    }
  • BinderProxy.transact()

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    
    public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
        Binder.checkParcel(this, code, data, "Unreasonably large binder buffer");
        // FLAG_ONEWAY 是异步的
        if (mWarnOnBlocking && ((flags & FLAG_ONEWAY) == 0)) {
            // For now, avoid spamming the log by disabling after we've logged
            // about this interface at least once
            mWarnOnBlocking = false;
            Log.w(Binder.TAG, "Outgoing transactions from this process must be FLAG_ONEWAY",
                  new Throwable());
        }
    
        final boolean tracingEnabled = Binder.isTracingEnabled();
        if (tracingEnabled) {
            final Throwable tr = new Throwable();
            Binder.getTransactionTracker().addTrace(tr);
            StackTraceElement stackTraceElement = tr.getStackTrace()[1];
            Trace.traceBegin(Trace.TRACE_TAG_ALWAYS,
                             stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName());
        }
        try {
            // Binder RPC 通讯最终会调用到  Binder.transact()
            return transactNative(code, data, reply, flags);
        } finally {
            if (tracingEnabled) {
                Trace.traceEnd(Trace.TRACE_TAG_ALWAYS);
            }
        }
    }
  • Binder.transact()

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    
    public final boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply,
                                  int flags) throws RemoteException {
        if (false) Log.v("Binder", "Transact: " + code + " to " + this);
    
        if (data != null) {
            data.setDataPosition(0);
        }
        boolean r = onTransact(code, data, reply, flags);
        if (reply != null) {
            reply.setDataPosition(0);
        }
        return r;
    }
  • IWifiManager.Stub.onTransact()

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    
    @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
    {
        java.lang.String descriptor = DESCRIPTOR;
        switch (code)
            {
                ...
    
            case TRANSACTION_addOrUpdateNetwork:
                {
                    data.enforceInterface(descriptor);
                    android.net.wifi.WifiConfiguration _arg0;
                    if ((0!=data.readInt())) {
                        _arg0 = android.net.wifi.WifiConfiguration.CREATOR.createFromParcel(data);
                    }
                    else {
                        _arg0 = null;
                    }
                    java.lang.String _arg1;
                    _arg1 = data.readString();
                    int _result = this.addOrUpdateNetwork(_arg0, _arg1);
                    reply.writeNoException();
                    reply.writeInt(_result);
                    return true;
                }
                ...
                    }
    }
  • IWifiManager.Stub.addOrUpdateNetwork()

    public int addOrUpdateNetwork(android.net.wifi.WifiConfiguration config, java.lang.String packageName) throws android.os.RemoteException;

  • WifiServiceImpl.addOrUpdateNetwork

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    
    public class WifiServiceImpl extends IWifiManager.Stub {
        ...
        @Override
        public int addOrUpdateNetwork(WifiConfiguration config, String packageName) {
            if (enforceChangePermission(packageName) != MODE_ALLOWED) {
                return -1;
            }
            mLog.info("addOrUpdateNetwork uid=%").c(Binder.getCallingUid()).flush();
    
            // Previously, this API is overloaded for installing Passpoint profiles.  Now
            // that we have a dedicated API for doing it, redirect the call to the dedicated API.
            if (config.isPasspoint()) {
                PasspointConfiguration passpointConfig =
                    PasspointProvider.convertFromWifiConfig(config);
                if (passpointConfig.getCredential() == null) {
                    Slog.e(TAG, "Missing credential for Passpoint profile");
                    return -1;
                }
                // Copy over certificates and keys.
                passpointConfig.getCredential().setCaCertificate(
                                                                 config.enterpriseConfig.getCaCertificate());
                passpointConfig.getCredential().setClientCertificateChain(
                                                                          config.enterpriseConfig.getClientCertificateChain());
                passpointConfig.getCredential().setClientPrivateKey(
                                                                    config.enterpriseConfig.getClientPrivateKey());
                if (!addOrUpdatePasspointConfiguration(passpointConfig, packageName)) {
                    Slog.e(TAG, "Failed to add Passpoint profile");
                    return -1;
                }
                // There is no network ID associated with a Passpoint profile.
                return 0;
            }
    
            if (config != null) {
                //TODO: pass the Uid the WifiStateMachine as a message parameter
                Slog.i("addOrUpdateNetwork", " uid = " + Integer.toString(Binder.getCallingUid())
                       + " SSID " + config.SSID
                       + " nid=" + Integer.toString(config.networkId));
                if (config.networkId == WifiConfiguration.INVALID_NETWORK_ID) {
                    config.creatorUid = Binder.getCallingUid();
                } else {
                    config.lastUpdateUid = Binder.getCallingUid();
                }
                if (mWifiStateMachineChannel != null) {
                    return mWifiStateMachine.syncAddOrUpdateNetwork(mWifiStateMachineChannel, config);
                } else {
                    Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
                    return -1;
                }
            } else {
                Slog.e(TAG, "bad network configuration");
                return -1;
            }
            ...
                }
    }
  • 时序图