1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.wifi.mockwifi;
18 
19 import static android.os.UserHandle.CURRENT;
20 
21 import android.annotation.IntDef;
22 import android.content.ComponentName;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.ServiceConnection;
26 import android.net.wifi.nl80211.WifiNl80211Manager;
27 import android.os.IBinder;
28 import android.util.Log;
29 
30 import com.android.server.wifi.WifiMonitor;
31 
32 import java.lang.annotation.Retention;
33 import java.lang.annotation.RetentionPolicy;
34 
35 /** This class provides wrapper APIs for binding interfaces to mock service. */
36 public class MockWifiServiceUtil {
37     private static final String TAG = "MockWifiModemUtil";
38     private static final String BIND_NL80211 = "android.wifi.mockwifimodem.nl80211";
39     private static final String BIND_SUPPLICANT = "android.wifi.mockwifimodem.supplicant";
40 
41     @IntDef({MOCK_NL80211_SERVICE, MOCK_SUPPLICANT_SERVICE})
42     @Retention(RetentionPolicy.SOURCE)
43     public @interface MockServiceType {}
44 
45     public static final int MOCK_NL80211_SERVICE = 0;
46     public static final int MOCK_SUPPLICANT_SERVICE = 1;
47     public static final int MIN_SERVICE_IDX = MOCK_NL80211_SERVICE;
48     public static final int NUM_SERVICES = 2;
49     public static final int BINDER_RETRY_MILLIS = 3 * 100;
50     public static final int BINDER_MAX_RETRY = 3;
51 
52     public static final String METHOD_SEPARATOR = ",";
53     public static final String CLASS_IDENTIFIER = "-";
54     public static final String AIDL_METHOD_IDENTIFIER = "#";
55 
56     private static final String TAG_MOCK_NL80211 = "WifiNL80211ManagerImp";
57     private static final String TAG_MOCK_SUPPLICANT = "ISupplicantImp";
58 
59     private Context mContext;
60     private WifiMonitor mWifiMonitor;
61     private String mServiceName;
62     private String mPackageName;
63     private MockWifiNl80211Manager mMockWifiNl80211Manager;
64     private MockSupplicantManager mMockSupplicantManager;
65     private IBinder mMockNl80211Binder;
66     private ServiceConnection mMockNl80211ServiceConnection;
67     private IBinder mMockSupplicantBinder;
68     private ServiceConnection mMockSupplicantServiceConnection;
69 
MockWifiServiceUtil(Context context, String serviceName, WifiMonitor wifiMonitor)70     public MockWifiServiceUtil(Context context, String serviceName, WifiMonitor wifiMonitor) {
71         mContext = context.createContextAsUser(CURRENT, 0);
72         mWifiMonitor = wifiMonitor;
73         String[] componentInfo = serviceName.split("/", 2);
74         mPackageName = componentInfo[0];
75         mServiceName = componentInfo[1];
76     }
77 
78     private class MockModemConnection implements ServiceConnection {
79         private int mService;
80 
MockModemConnection(int module)81         MockModemConnection(int module) {
82             mService = module;
83         }
84 
85         @Override
onServiceConnected(ComponentName name, IBinder binder)86         public void onServiceConnected(ComponentName name, IBinder binder) {
87             Log.d(TAG, "Wifi mock Service " + getModuleName(mService) + "  - onServiceConnected");
88             if (mService == MOCK_NL80211_SERVICE) {
89                 mMockNl80211Binder = binder;
90                 mMockWifiNl80211Manager = new MockWifiNl80211Manager(mMockNl80211Binder, mContext,
91                         mWifiMonitor);
92             }
93             if (mService == MOCK_SUPPLICANT_SERVICE) {
94                 mMockSupplicantBinder = binder;
95                 mMockSupplicantManager = new MockSupplicantManager(mMockSupplicantBinder,
96                         mWifiMonitor);
97             }
98 
99         }
100 
101         @Override
onServiceDisconnected(ComponentName name)102         public void onServiceDisconnected(ComponentName name) {
103             Log.d(TAG, "Wifi mock Service " + getModuleName(mService)
104                     + "  - onServiceDisconnected");
105             if (mService == MOCK_NL80211_SERVICE) {
106                 mMockNl80211Binder = null;
107                 mMockWifiNl80211Manager = null;
108             }
109             if (mService == MOCK_SUPPLICANT_SERVICE) {
110                 mMockSupplicantBinder = null;
111                 mMockSupplicantManager = null;
112             }
113         }
114     }
115 
bindModuleToMockModemService( String actionName, ServiceConnection serviceConnection)116     private boolean bindModuleToMockModemService(
117             String actionName, ServiceConnection serviceConnection) {
118         boolean status = false;
119 
120         Intent intent = new Intent();
121         intent.setComponent(new ComponentName(mPackageName, mServiceName));
122         intent.setAction(actionName);
123 
124         status = mContext.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
125         return status;
126     }
127 
128     /**
129      * Unbind of the provided service.
130      */
unbindMockModemService()131     public void unbindMockModemService() {
132         mContext.unbindService(mMockNl80211ServiceConnection);
133         mContext.unbindService(mMockSupplicantServiceConnection);
134     }
135 
136     /** waitForBinder */
getServiceBinder(@ockServiceType int service)137     public IBinder getServiceBinder(@MockServiceType int service) {
138         switch (service) {
139             case MOCK_NL80211_SERVICE:
140                 return mMockNl80211Binder;
141             case MOCK_SUPPLICANT_SERVICE:
142                 return mMockSupplicantBinder;
143             default:
144                 return null;
145         }
146     }
147 
148     /** Binding interfaces with mock modem service */
bindAllMockModemService()149     public void bindAllMockModemService() {
150         for (int service = MIN_SERVICE_IDX; service < NUM_SERVICES; service++) {
151             bindToMockModemService(service);
152         }
153     }
154 
155     /** bindToMockModemService */
bindToMockModemService(@ockServiceType int service)156     public void bindToMockModemService(@MockServiceType int service) {
157         // Based on {@code service} to get each mocked HAL binder
158         if (service == MOCK_NL80211_SERVICE) {
159             mMockNl80211ServiceConnection = new MockModemConnection(MOCK_NL80211_SERVICE);
160 
161             boolean status =
162                     bindModuleToMockModemService(BIND_NL80211, mMockNl80211ServiceConnection);
163             if (!status) {
164                 Log.d(TAG, getModuleName(service) + " bind fail");
165                 mMockNl80211ServiceConnection = null;
166             }
167         }
168         if (service == MOCK_SUPPLICANT_SERVICE) {
169             mMockSupplicantServiceConnection = new MockModemConnection(MOCK_SUPPLICANT_SERVICE);
170             boolean status =
171                     bindModuleToMockModemService(BIND_SUPPLICANT, mMockSupplicantServiceConnection);
172             if (!status) {
173                 Log.d(TAG, getModuleName(service) + " bind fail");
174                 mMockSupplicantServiceConnection = null;
175             }
176         }
177     }
178 
getServiceName()179     public String getServiceName() {
180         return mServiceName;
181     }
182 
getServiceConnection(@ockServiceType int service)183     private ServiceConnection getServiceConnection(@MockServiceType int service) {
184         switch (service) {
185             case MOCK_NL80211_SERVICE:
186                 return mMockNl80211ServiceConnection;
187             case MOCK_SUPPLICANT_SERVICE:
188                 return mMockSupplicantServiceConnection;
189             default:
190                 return null;
191         }
192     }
193 
194     /**
195      * Returns name of the provided service.
196      */
getModuleName(@ockServiceType int service)197     public String getModuleName(@MockServiceType int service) {
198         switch (service) {
199             case MOCK_NL80211_SERVICE:
200                 return "nl80211";
201             case MOCK_SUPPLICANT_SERVICE:
202                 return "supplicant";
203             default:
204                 return "none";
205         }
206     }
207 
208     /**
209      * set mocked methods.
210      *
211      * @param methods mocked methods with format HAL-method, ...
212      */
setMockedMethods(String methods)213     public boolean setMockedMethods(String methods) {
214         Log.i(TAG, "setMockedMethods - " + methods);
215         if (methods == null) {
216             return false;
217         }
218         if (mMockWifiNl80211Manager != null) {
219             mMockWifiNl80211Manager.resetMockedMethods();
220         }
221         if (mMockSupplicantManager != null) {
222             mMockSupplicantManager.resetMockedMethods();
223         }
224         String[] mockedMethods = methods.split(METHOD_SEPARATOR);
225         for (String mockedMethod : mockedMethods) {
226             String[] mockedMethodInfo = mockedMethod.split(CLASS_IDENTIFIER);
227             if (mockedMethodInfo.length != 2) {
228                 return false;
229             }
230             String mockedClassName = mockedMethodInfo[0];
231             String mockedMethodName = mockedMethodInfo[1];
232             if (TAG_MOCK_NL80211.equals(mockedClassName) && mMockWifiNl80211Manager != null) {
233                 mMockWifiNl80211Manager.addMockedMethod(mockedMethodName);
234             }
235             if (TAG_MOCK_SUPPLICANT.equals(mockedClassName) && mMockSupplicantManager != null) {
236                 mMockSupplicantManager.addMockedMethod(mockedMethodName);
237             }
238         }
239         return true;
240     }
241 
getMockSupplicantManager()242     public MockSupplicantManager getMockSupplicantManager() {
243         return mMockSupplicantManager;
244     }
245 
getMockWifiNl80211Manager()246     public MockWifiNl80211Manager getMockWifiNl80211Manager() {
247         return mMockWifiNl80211Manager;
248     }
249 
getWifiNl80211Manager()250     public WifiNl80211Manager getWifiNl80211Manager() {
251         return mMockWifiNl80211Manager == null
252                 ? null : mMockWifiNl80211Manager.getWifiNl80211Manager();
253     }
254 
255     /**
256      * Get method configured status based on service.
257      */
isMethodConfigured(@ockServiceType int service, String methodName)258     public boolean isMethodConfigured(@MockServiceType int service, String methodName) {
259         switch (service) {
260             case MOCK_NL80211_SERVICE:
261                 return getWifiNl80211Manager() != null
262                         && getMockWifiNl80211Manager().isMethodConfigured(methodName);
263             case MOCK_SUPPLICANT_SERVICE:
264                 return mMockSupplicantManager != null
265                         && getMockSupplicantManager().isMethodConfigured(methodName);
266             default:
267                 return false;
268         }
269     }
270 }
271