主要涉及怎样使用 WifiManager
进行 wifi 相关操作;通过怎么获取 WifiManager
及 addNetwork
的调用过程来学习 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
对象可以通过两种方式获取该类的实例:public final T getSystemService(Class<T> serviceClass)
WifiManager wifiManager = getApplicationContext().getSystemService(WifiManager.class);
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()
获取WifiService
的IBinder
对象,如果当前进程是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
WifiManager
的mService
是IWifiManager.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; } ... } }
时序图