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.hal;
18 
19 import android.annotation.NonNull;
20 import android.hardware.wifi.V1_0.WifiStatus;
21 import android.hardware.wifi.V1_0.WifiStatusCode;
22 import android.net.MacAddress;
23 import android.os.RemoteException;
24 import android.util.Log;
25 
26 import com.android.server.wifi.util.GeneralUtil;
27 
28 import java.util.ArrayList;
29 import java.util.List;
30 import java.util.function.Supplier;
31 
32 /**
33  * HIDL implementation of the IWifiApIface interface.
34  */
35 public class WifiApIfaceHidlImpl implements IWifiApIface {
36     private static final String TAG = "WifiApIfaceHidlImpl";
37     private android.hardware.wifi.V1_0.IWifiApIface mWifiApIface;
38     private String mIfaceName;
39 
WifiApIfaceHidlImpl(@onNull android.hardware.wifi.V1_0.IWifiApIface apIface)40     public WifiApIfaceHidlImpl(@NonNull android.hardware.wifi.V1_0.IWifiApIface apIface) {
41         mWifiApIface = apIface;
42     }
43 
44     /**
45      * See comments for {@link IWifiApIface#getName()}
46      */
getName()47     public String getName() {
48         final String methodStr = "getName";
49         return validateAndCall(methodStr, null,
50                 () -> getNameInternal(methodStr));
51     }
52 
53     /**
54      * See comments for {@link IWifiApIface#getBridgedInstances()}
55      */
getBridgedInstances()56     public List<String> getBridgedInstances() {
57         final String methodStr = "getBridgedInstances";
58         return validateAndCall(methodStr, null,
59                 () -> getBridgedInstancesInternal(methodStr));
60     }
61 
62     /**
63      * See comments for {@link IWifiApIface#getFactoryMacAddress()}
64      */
getFactoryMacAddress()65     public MacAddress getFactoryMacAddress() {
66         final String methodStr = "getFactoryMacAddress";
67         return validateAndCall(methodStr, null,
68                 () -> getFactoryMacAddressInternal(methodStr));
69     }
70 
71     /**
72      * See comments for {@link IWifiApIface#setCountryCode(byte[])}
73      */
setCountryCode(byte[] countryCode)74     public boolean setCountryCode(byte[] countryCode) {
75         final String methodStr = "setCountryCode";
76         return validateAndCall(methodStr, false,
77                 () -> setCountryCodeInternal(methodStr, countryCode));
78     }
79 
80     /**
81      * See comments for {@link IWifiApIface#resetToFactoryMacAddress()}
82      *
83      * Note: If HAL < 1.5, will only reset the MAC address for this interface.
84      */
resetToFactoryMacAddress()85     public boolean resetToFactoryMacAddress() {
86         final String methodStr = "resetToFactoryMacAddress";
87         return validateAndCall(methodStr, false,
88                 () -> resetToFactoryMacAddressInternal(methodStr));
89     }
90 
91     /**
92      * See comments for {@link IWifiApIface#isSetMacAddressSupported()}
93      */
isSetMacAddressSupported()94     public boolean isSetMacAddressSupported() {
95         if (mWifiApIface == null) return false;
96         return getWifiApIfaceV1_4Mockable() != null;
97     }
98 
99     /**
100      * See comments for {@link IWifiApIface#setMacAddress(MacAddress)}
101      */
setMacAddress(MacAddress mac)102     public boolean setMacAddress(MacAddress mac) {
103         final String methodStr = "setMacAddress";
104         return validateAndCall(methodStr, false,
105                 () -> setMacAddressInternal(methodStr, mac));
106     }
107 
108 
109     // Internal Implementations
110 
getNameInternal(String methodStr)111     private String getNameInternal(String methodStr) {
112         if (mIfaceName != null) return mIfaceName;
113         GeneralUtil.Mutable<String> nameResp = new GeneralUtil.Mutable<>();
114         try {
115             mWifiApIface.getName((WifiStatus status, String name) -> {
116                 if (isOk(status, methodStr)) {
117                     nameResp.value = name;
118                     mIfaceName = name;
119                 }
120             });
121         } catch (RemoteException e) {
122             handleRemoteException(e, methodStr);
123         }
124         return nameResp.value;
125     }
126 
getBridgedInstancesInternal(String methodStr)127     private List<String> getBridgedInstancesInternal(String methodStr) {
128         GeneralUtil.Mutable<List<String>> instancesResp = new GeneralUtil.Mutable<>();
129         try {
130             android.hardware.wifi.V1_5.IWifiApIface ap15 = getWifiApIfaceV1_5Mockable();
131             if (ap15 == null) return null;
132             ap15.getBridgedInstances((status, instances) -> {
133                 if (isOk(status, methodStr)) {
134                     instancesResp.value = new ArrayList<>(instances);
135                 }
136             });
137         } catch (RemoteException e) {
138             handleRemoteException(e, methodStr);
139         }
140         return instancesResp.value;
141     }
142 
getFactoryMacAddressInternal(String methodStr)143     private MacAddress getFactoryMacAddressInternal(String methodStr) {
144         GeneralUtil.Mutable<MacAddress> macResp = new GeneralUtil.Mutable<>();
145         try {
146             android.hardware.wifi.V1_4.IWifiApIface ap14 = getWifiApIfaceV1_4Mockable();
147             if (ap14 == null) return null;
148             ap14.getFactoryMacAddress((status, macBytes) -> {
149                 if (isOk(status, methodStr)) {
150                     macResp.value = MacAddress.fromBytes(macBytes);
151                 }
152             });
153         } catch (RemoteException e) {
154             handleRemoteException(e, methodStr);
155         }
156         return macResp.value;
157     }
158 
setCountryCodeInternal(String methodStr, byte[] countryCode)159     private boolean setCountryCodeInternal(String methodStr, byte[] countryCode) {
160         try {
161             WifiStatus status = mWifiApIface.setCountryCode(countryCode);
162             return isOk(status, methodStr);
163         } catch (RemoteException e) {
164             handleRemoteException(e, methodStr);
165             return false;
166         }
167     }
168 
resetToFactoryMacAddressInternal(String methodStr)169     private boolean resetToFactoryMacAddressInternal(String methodStr) {
170         try {
171             android.hardware.wifi.V1_5.IWifiApIface ap15 = getWifiApIfaceV1_5Mockable();
172             if (ap15 == null) {
173                 MacAddress mac = getFactoryMacAddress();
174                 return mac != null && setMacAddress(mac);
175             }
176             WifiStatus status = ap15.resetToFactoryMacAddress();
177             return isOk(status, methodStr);
178         } catch (RemoteException e) {
179             handleRemoteException(e, methodStr);
180             return false;
181         }
182     }
183 
setMacAddressInternal(String methodStr, MacAddress mac)184     private boolean setMacAddressInternal(String methodStr, MacAddress mac) {
185         try {
186             android.hardware.wifi.V1_4.IWifiApIface ap14 = getWifiApIfaceV1_4Mockable();
187             if (ap14 == null) return false;
188             WifiStatus status = ap14.setMacAddress(mac.toByteArray());
189             return isOk(status, methodStr);
190         } catch (RemoteException e) {
191             handleRemoteException(e, methodStr);
192             return false;
193         }
194     }
195 
196 
197     // Helper Functions
198 
getWifiApIfaceV1_4Mockable()199     protected android.hardware.wifi.V1_4.IWifiApIface getWifiApIfaceV1_4Mockable() {
200         return android.hardware.wifi.V1_4.IWifiApIface.castFrom(mWifiApIface);
201     }
202 
getWifiApIfaceV1_5Mockable()203     protected android.hardware.wifi.V1_5.IWifiApIface getWifiApIfaceV1_5Mockable() {
204         return android.hardware.wifi.V1_5.IWifiApIface.castFrom(mWifiApIface);
205     }
206 
isOk(WifiStatus status, String methodStr)207     private boolean isOk(WifiStatus status, String methodStr) {
208         if (status.code == WifiStatusCode.SUCCESS) return true;
209         Log.e(TAG, methodStr + " failed with status: " + status);
210         return false;
211     }
212 
handleRemoteException(RemoteException e, String methodStr)213     private void handleRemoteException(RemoteException e, String methodStr) {
214         Log.e(TAG, methodStr + " failed with remote exception: " + e);
215         mWifiApIface = null;
216     }
217 
validateAndCall(String methodStr, T defaultVal, @NonNull Supplier<T> supplier)218     private <T> T validateAndCall(String methodStr, T defaultVal, @NonNull Supplier<T> supplier) {
219         if (mWifiApIface == null) {
220             Log.wtf(TAG, "Cannot call " + methodStr + " because mWifiApIface is null");
221             return defaultVal;
222         }
223         return supplier.get();
224     }
225 }
226