com_android_server_wifi_WifiNative.cpp revision f8a283f4fc2f103fdf68062a50e516141d1e881d
1/*
2 * Copyright 2008, 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#define LOG_TAG "wifi"
18
19#include <ctype.h>
20#include <stdlib.h>
21#include <sys/klog.h>
22#include <sys/socket.h>
23/* We need linux/if_arp.h for ARPHRD_ETHER.  Sadly, it forward declares
24   struct sockaddr and must be included after sys/socket.h. */
25#include <linux/if_arp.h>
26
27#include <algorithm>
28#include <limits>
29#include <vector>
30
31#include <hardware_legacy/rtt.h>
32#include <hardware_legacy/wifi.h>
33#include <hardware_legacy/wifi_hal.h>
34#include <log/log.h>
35#include <nativehelper/JniConstants.h>
36#include <nativehelper/ScopedBytes.h>
37#include <nativehelper/ScopedUtfChars.h>
38#include <nativehelper/jni.h>
39#include <utils/String16.h>
40#include <utils/misc.h>
41#include <wifi_system/wifi.h>
42
43#include "jni_helper.h"
44#include "wifi_hal_stub.h"
45#define REPLY_BUF_SIZE (4096 + 1)         // wpa_supplicant's maximum size + 1 for nul
46#define EVENT_BUF_SIZE 2048
47#define WAKE_REASON_TYPE_MAX 10
48
49namespace android {
50
51extern "C"
52jint Java_com_android_server_wifi_WifiNative_registerNanNatives(JNIEnv* env, jclass clazz);
53
54static jint DBG = false;
55
56//Please put all HAL function call here and call from the function table instead of directly call
57wifi_hal_fn hal_fn;
58static bool doCommand(JNIEnv* env, jstring javaCommand,
59                      char* reply, size_t reply_len) {
60    ScopedUtfChars command(env, javaCommand);
61    if (command.c_str() == NULL) {
62        return false; // ScopedUtfChars already threw on error.
63    }
64
65    if (DBG) {
66        ALOGD("doCommand: %s", command.c_str());
67    }
68
69    --reply_len; // Ensure we have room to add NUL termination.
70    if (::wifi_command(command.c_str(), reply, &reply_len) != 0) {
71        return false;
72    }
73
74    // Strip off trailing newline.
75    if (reply_len > 0 && reply[reply_len-1] == '\n') {
76        reply[reply_len-1] = '\0';
77    } else {
78        reply[reply_len] = '\0';
79    }
80    return true;
81}
82
83static jint doIntCommand(JNIEnv* env, jstring javaCommand) {
84    char reply[REPLY_BUF_SIZE];
85    if (!doCommand(env, javaCommand, reply, sizeof(reply))) {
86        return -1;
87    }
88    return static_cast<jint>(atoi(reply));
89}
90
91static jboolean doBooleanCommand(JNIEnv* env, jstring javaCommand) {
92    char reply[REPLY_BUF_SIZE];
93    if (!doCommand(env, javaCommand, reply, sizeof(reply))) {
94        return JNI_FALSE;
95    }
96    jboolean result = (strcmp(reply, "OK") == 0);
97    if (!result) {
98        ScopedUtfChars command(env, javaCommand);
99        ALOGI("command '%s' returned '%s", command.c_str(), reply);
100    }
101    return result;
102}
103
104// Send a command to the supplicant, and return the reply as a String.
105static jstring doStringCommand(JNIEnv* env, jstring javaCommand) {
106    char reply[REPLY_BUF_SIZE];
107    if (!doCommand(env, javaCommand, reply, sizeof(reply))) {
108        return NULL;
109    }
110    return env->NewStringUTF(reply);
111}
112
113static jboolean android_net_wifi_isDriverLoaded(JNIEnv* env, jclass)
114{
115    return (::is_wifi_driver_loaded() == 1);
116}
117
118static jboolean android_net_wifi_loadDriver(JNIEnv* env, jclass)
119{
120    return (::wifi_load_driver() == 0);
121}
122
123static jboolean android_net_wifi_unloadDriver(JNIEnv* env, jclass)
124{
125    return (::wifi_unload_driver() == 0);
126}
127
128static jboolean android_net_wifi_startSupplicant(JNIEnv* env, jclass, jboolean p2pSupported)
129{
130    return (::wifi_start_supplicant(p2pSupported) == 0);
131}
132
133static jboolean android_net_wifi_killSupplicant(JNIEnv* env, jclass, jboolean p2pSupported)
134{
135    return (::wifi_stop_supplicant(p2pSupported) == 0);
136}
137
138static jboolean android_net_wifi_connectToSupplicant(JNIEnv* env, jclass)
139{
140    return (::wifi_connect_to_supplicant() == 0);
141}
142
143static void android_net_wifi_closeSupplicantConnection(JNIEnv* env, jclass)
144{
145    ::wifi_close_supplicant_connection();
146}
147
148static jstring android_net_wifi_waitForEvent(JNIEnv* env, jclass)
149{
150    char buf[EVENT_BUF_SIZE];
151    int nread = ::wifi_wait_for_event(buf, sizeof buf);
152    if (nread > 0) {
153        return env->NewStringUTF(buf);
154    } else {
155        return NULL;
156    }
157}
158
159static jboolean android_net_wifi_doBooleanCommand(JNIEnv* env, jclass, jstring javaCommand) {
160    return doBooleanCommand(env, javaCommand);
161}
162
163static jint android_net_wifi_doIntCommand(JNIEnv* env, jclass, jstring javaCommand) {
164    return doIntCommand(env, javaCommand);
165}
166
167static jstring android_net_wifi_doStringCommand(JNIEnv* env, jclass, jstring javaCommand) {
168    return doStringCommand(env,javaCommand);
169}
170
171/* wifi_hal <==> WifiNative bridge */
172
173static jclass mCls;                             /* saved WifiNative object */
174static JavaVM *mVM;                             /* saved JVM pointer */
175
176static const char *WifiHandleVarName = "sWifiHalHandle";
177static const char *WifiIfaceHandleVarName = "sWifiIfaceHandles";
178
179wifi_handle getWifiHandle(JNIHelper &helper, jclass cls) {
180    return (wifi_handle) helper.getStaticLongField(cls, WifiHandleVarName);
181}
182
183wifi_interface_handle getIfaceHandle(JNIHelper &helper, jclass cls, jint index) {
184    return (wifi_interface_handle) helper.getStaticLongArrayField(cls, WifiIfaceHandleVarName, index);
185}
186
187jboolean setSSIDField(JNIHelper helper, jobject scanResult, const char *rawSsid) {
188
189    int len = strlen(rawSsid);
190
191    if (len > 0) {
192        JNIObject<jbyteArray> ssidBytes = helper.newByteArray(len);
193        helper.setByteArrayRegion(ssidBytes, 0, len, (jbyte *) rawSsid);
194        jboolean ret = helper.callStaticMethod(mCls,
195                "setSsid", "([BLandroid/net/wifi/ScanResult;)Z", ssidBytes.get(), scanResult);
196        return ret;
197    } else {
198        //empty SSID or SSID start with \0
199        return true;
200    }
201}
202static JNIObject<jobject> createScanResult(JNIHelper &helper, wifi_scan_result *result,
203        bool fill_ie) {
204    // ALOGD("creating scan result");
205    JNIObject<jobject> scanResult = helper.createObject("android/net/wifi/ScanResult");
206    if (scanResult == NULL) {
207        ALOGE("Error in creating scan result");
208        return JNIObject<jobject>(helper, NULL);
209    }
210
211    ALOGV("setting SSID to %s", result->ssid);
212
213    if (!setSSIDField(helper, scanResult, result->ssid)) {
214        ALOGE("Error on set SSID");
215        return JNIObject<jobject>(helper, NULL);
216    }
217
218    char bssid[32];
219    snprintf(bssid, sizeof(bssid), "%02x:%02x:%02x:%02x:%02x:%02x",
220             result->bssid[0], result->bssid[1], result->bssid[2],
221             result->bssid[3], result->bssid[4], result->bssid[5]);
222
223    helper.setStringField(scanResult, "BSSID", bssid);
224
225    helper.setIntField(scanResult, "level", result->rssi);
226    helper.setIntField(scanResult, "frequency", result->channel);
227    helper.setLongField(scanResult, "timestamp", result->ts);
228
229    if (fill_ie) {
230        JNIObject<jbyteArray> elements = helper.newByteArray(result->ie_length);
231        if (elements == NULL) {
232            ALOGE("Error in allocating elements array, length=%d", result->ie_length);
233            return JNIObject<jobject>(helper, NULL);
234        }
235        jbyte * bytes = (jbyte *)&(result->ie_data[0]);
236        helper.setByteArrayRegion(elements, 0, result->ie_length, bytes);
237        helper.setObjectField(scanResult, "bytes", "[B", elements);
238    }
239
240    return scanResult;
241}
242
243int set_iface_flags(const char *ifname, bool dev_up) {
244    struct ifreq ifr;
245    int ret;
246    int sock = socket(PF_INET, SOCK_DGRAM, 0);
247    if (sock < 0) {
248        ALOGD("Bad socket: %d\n", sock);
249        return -errno;
250    }
251
252    //ALOGD("setting interface %s flags (%s)\n", ifname, dev_up ? "UP" : "DOWN");
253
254    memset(&ifr, 0, sizeof(ifr));
255    strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
256
257    //ALOGD("reading old value\n");
258
259    if (ioctl(sock, SIOCGIFFLAGS, &ifr) != 0) {
260      ret = errno ? -errno : -999;
261      ALOGE("Could not read interface %s flags: %d\n", ifname, errno);
262      close(sock);
263      return ret;
264    } else {
265      //ALOGD("writing new value\n");
266    }
267
268    if (dev_up) {
269      if (ifr.ifr_flags & IFF_UP) {
270        // ALOGD("interface %s is already up\n", ifname);
271        close(sock);
272        return 0;
273      }
274      ifr.ifr_flags |= IFF_UP;
275    } else {
276      if (!(ifr.ifr_flags & IFF_UP)) {
277        // ALOGD("interface %s is already down\n", ifname);
278        close(sock);
279        return 0;
280      }
281      ifr.ifr_flags &= ~IFF_UP;
282    }
283
284    if (ioctl(sock, SIOCSIFFLAGS, &ifr) != 0) {
285      ALOGE("Could not set interface %s flags: %d\n", ifname, errno);
286      ret = errno ? -errno : -999;
287      close(sock);
288      return ret;
289    } else {
290      ALOGD("set interface %s flags (%s)\n", ifname, dev_up ? "UP" : "DOWN");
291    }
292    close(sock);
293    return 0;
294}
295
296static jboolean android_net_wifi_set_interface_up(JNIEnv* env, jclass cls, jboolean up) {
297    return (set_iface_flags("wlan0", (bool)up) == 0);
298}
299
300static jboolean android_net_wifi_startHal(JNIEnv* env, jclass cls) {
301    JNIHelper helper(env);
302    wifi_handle halHandle = getWifiHandle(helper, cls);
303    if (halHandle == NULL) {
304
305        if(init_wifi_stub_hal_func_table(&hal_fn) != 0 ) {
306            ALOGE("Can not initialize the basic function pointer table");
307            return false;
308        }
309
310        wifi_error res = init_wifi_vendor_hal_func_table(&hal_fn);
311        if (res != WIFI_SUCCESS) {
312            ALOGE("Can not initialize the vendor function pointer table");
313	    return false;
314        }
315
316        int ret = set_iface_flags("wlan0", true);
317        if(ret != 0) {
318            return false;
319        }
320
321        res = hal_fn.wifi_initialize(&halHandle);
322        if (res == WIFI_SUCCESS) {
323            helper.setStaticLongField(cls, WifiHandleVarName, (jlong)halHandle);
324            ALOGD("Did set static halHandle = %p", halHandle);
325        }
326        env->GetJavaVM(&mVM);
327        mCls = (jclass) env->NewGlobalRef(cls);
328        ALOGD("halHandle = %p, mVM = %p, mCls = %p", halHandle, mVM, mCls);
329        return res == WIFI_SUCCESS;
330    } else {
331        return (set_iface_flags("wlan0", true) == 0);
332    }
333}
334
335void android_net_wifi_hal_cleaned_up_handler(wifi_handle handle) {
336    ALOGD("In wifi cleaned up handler");
337
338    JNIHelper helper(mVM);
339    helper.setStaticLongField(mCls, WifiHandleVarName, 0);
340
341    helper.deleteGlobalRef(mCls);
342    mCls = NULL;
343    mVM  = NULL;
344}
345
346static void android_net_wifi_stopHal(JNIEnv* env, jclass cls) {
347    ALOGD("In wifi stop Hal");
348
349    JNIHelper helper(env);
350    wifi_handle halHandle = getWifiHandle(helper, cls);
351    if (halHandle == NULL)
352        return;
353
354    ALOGD("halHandle = %p, mVM = %p, mCls = %p", halHandle, mVM, mCls);
355    hal_fn.wifi_cleanup(halHandle, android_net_wifi_hal_cleaned_up_handler);
356}
357
358static void android_net_wifi_waitForHalEvents(JNIEnv* env, jclass cls) {
359
360    ALOGD("waitForHalEvents called, vm = %p, obj = %p, env = %p", mVM, mCls, env);
361
362    JNIHelper helper(env);
363    wifi_handle halHandle = getWifiHandle(helper, cls);
364    hal_fn.wifi_event_loop(halHandle);
365    set_iface_flags("wlan0", false);
366}
367
368static int android_net_wifi_getInterfaces(JNIEnv *env, jclass cls) {
369    int n = 0;
370
371    JNIHelper helper(env);
372
373    wifi_handle halHandle = getWifiHandle(helper, cls);
374    wifi_interface_handle *ifaceHandles = NULL;
375    int result = hal_fn.wifi_get_ifaces(halHandle, &n, &ifaceHandles);
376    if (result < 0) {
377        return result;
378    }
379
380    if (n < 0) {
381        THROW(helper,"android_net_wifi_getInterfaces no interfaces");
382        return 0;
383    }
384
385    if (ifaceHandles == NULL) {
386       THROW(helper,"android_net_wifi_getInterfaces null interface array");
387       return 0;
388    }
389
390    if (n > 8) {
391        THROW(helper,"Too many interfaces");
392        return 0;
393    }
394
395    jlongArray array = (env)->NewLongArray(n);
396    if (array == NULL) {
397        THROW(helper,"Error in accessing array");
398        return 0;
399    }
400
401    jlong elems[8];
402    for (int i = 0; i < n; i++) {
403        elems[i] = reinterpret_cast<jlong>(ifaceHandles[i]);
404    }
405
406    helper.setLongArrayRegion(array, 0, n, elems);
407    helper.setStaticLongArrayField(cls, WifiIfaceHandleVarName, array);
408
409    return (result < 0) ? result : n;
410}
411
412static jstring android_net_wifi_getInterfaceName(JNIEnv *env, jclass cls, jint i) {
413
414    char buf[EVENT_BUF_SIZE];
415
416    JNIHelper helper(env);
417
418    jlong value = helper.getStaticLongArrayField(cls, WifiIfaceHandleVarName, i);
419    wifi_interface_handle handle = (wifi_interface_handle) value;
420    int result = hal_fn.wifi_get_iface_name(handle, buf, sizeof(buf));
421    if (result < 0) {
422        return NULL;
423    } else {
424        JNIObject<jstring> name = helper.newStringUTF(buf);
425        return name.detach();
426    }
427}
428
429
430static void onScanEvent(wifi_request_id id, wifi_scan_event event) {
431
432    JNIHelper helper(mVM);
433
434    // ALOGD("onScanStatus called, vm = %p, obj = %p, env = %p", mVM, mCls, env);
435
436    helper.reportEvent(mCls, "onScanStatus", "(II)V", id, event);
437}
438
439static void onFullScanResult(wifi_request_id id, wifi_scan_result *result,
440        unsigned buckets_scanned) {
441
442    JNIHelper helper(mVM);
443
444    //ALOGD("onFullScanResult called, vm = %p, obj = %p, env = %p", mVM, mCls, env);
445
446    JNIObject<jobject> scanResult = createScanResult(helper, result, true);
447
448    if (scanResult == NULL) {
449        return;
450    }
451
452    helper.reportEvent(mCls, "onFullScanResult", "(ILandroid/net/wifi/ScanResult;II)V", id,
453            scanResult.get(), buckets_scanned, (jint) result->capability);
454}
455
456static jboolean android_net_wifi_startScan(
457        JNIEnv *env, jclass cls, jint iface, jint id, jobject settings) {
458
459    JNIHelper helper(env);
460    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
461    // ALOGD("starting scan on interface[%d] = %p", iface, handle);
462
463    wifi_scan_cmd_params params;
464    memset(&params, 0, sizeof(params));
465
466    params.base_period = helper.getIntField(settings, "base_period_ms");
467    params.max_ap_per_scan = helper.getIntField(settings, "max_ap_per_scan");
468    params.report_threshold_percent = helper.getIntField(settings, "report_threshold_percent");
469    params.report_threshold_num_scans = helper.getIntField(settings, "report_threshold_num_scans");
470
471    ALOGD("Initialized common fields %d, %d, %d, %d", params.base_period, params.max_ap_per_scan,
472            params.report_threshold_percent, params.report_threshold_num_scans);
473
474    const char *bucket_array_type = "[Lcom/android/server/wifi/WifiNative$BucketSettings;";
475    const char *channel_array_type = "[Lcom/android/server/wifi/WifiNative$ChannelSettings;";
476
477    params.num_buckets = helper.getIntField(settings, "num_buckets");
478
479    // ALOGD("Initialized num_buckets to %d", params.num_buckets);
480
481    for (int i = 0; i < params.num_buckets; i++) {
482        JNIObject<jobject> bucket = helper.getObjectArrayField(
483                settings, "buckets", bucket_array_type, i);
484
485        params.buckets[i].bucket = helper.getIntField(bucket, "bucket");
486        params.buckets[i].band = (wifi_band) helper.getIntField(bucket, "band");
487        params.buckets[i].period = helper.getIntField(bucket, "period_ms");
488        params.buckets[i].max_period = helper.getIntField(bucket, "max_period_ms");
489        // Although HAL API allows configurable base value for the truncated
490        // exponential back off scan. Native API and above support only
491        // truncated binary exponential back off scan.
492        // Hard code value of base to 2 here.
493        params.buckets[i].base = 2;
494        params.buckets[i].step_count = helper.getIntField(bucket, "step_count");
495
496        int report_events = helper.getIntField(bucket, "report_events");
497        params.buckets[i].report_events = report_events;
498
499        if (DBG) {
500            ALOGD("bucket[%d] = %d:%d:%d:%d:%d:%d:%d", i, params.buckets[i].bucket,
501                    params.buckets[i].band, params.buckets[i].period,
502                    params.buckets[i].max_period, params.buckets[i].base,
503                    params.buckets[i].step_count, report_events);
504        }
505
506        params.buckets[i].num_channels = helper.getIntField(bucket, "num_channels");
507        // ALOGD("Initialized num_channels to %d", params.buckets[i].num_channels);
508
509        for (int j = 0; j < params.buckets[i].num_channels; j++) {
510            JNIObject<jobject> channel = helper.getObjectArrayField(
511                    bucket, "channels", channel_array_type, j);
512
513            params.buckets[i].channels[j].channel = helper.getIntField(channel, "frequency");
514            params.buckets[i].channels[j].dwellTimeMs = helper.getIntField(channel, "dwell_time_ms");
515
516            bool passive = helper.getBoolField(channel, "passive");
517            params.buckets[i].channels[j].passive = (passive ? 1 : 0);
518
519            // ALOGD("Initialized channel %d", params.buckets[i].channels[j].channel);
520        }
521    }
522
523    // ALOGD("Initialized all fields");
524
525    wifi_scan_result_handler handler;
526    memset(&handler, 0, sizeof(handler));
527    handler.on_full_scan_result = &onFullScanResult;
528    handler.on_scan_event = &onScanEvent;
529
530    return hal_fn.wifi_start_gscan(id, handle, params, handler) == WIFI_SUCCESS;
531}
532
533static jboolean android_net_wifi_stopScan(JNIEnv *env, jclass cls, jint iface, jint id) {
534
535    JNIHelper helper(env);
536    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
537    // ALOGD("stopping scan on interface[%d] = %p", iface, handle);
538
539    return hal_fn.wifi_stop_gscan(id, handle)  == WIFI_SUCCESS;
540}
541
542static int compare_scan_result_timestamp(const void *v1, const void *v2) {
543    const wifi_scan_result *result1 = static_cast<const wifi_scan_result *>(v1);
544    const wifi_scan_result *result2 = static_cast<const wifi_scan_result *>(v2);
545    return result1->ts - result2->ts;
546}
547
548static jobject android_net_wifi_getScanResults(
549        JNIEnv *env, jclass cls, jint iface, jboolean flush)  {
550
551    JNIHelper helper(env);
552    wifi_cached_scan_results scan_data[64];
553    int num_scan_data = 64;
554
555    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
556    // ALOGD("getting scan results on interface[%d] = %p", iface, handle);
557
558    byte b = flush ? 0xFF : 0;
559    int result = hal_fn.wifi_get_cached_gscan_results(handle, b, num_scan_data, scan_data, &num_scan_data);
560    if (result == WIFI_SUCCESS) {
561        JNIObject<jobjectArray> scanData = helper.createObjectArray(
562                "android/net/wifi/WifiScanner$ScanData", num_scan_data);
563        if (scanData == NULL) {
564            ALOGE("Error in allocating array of scanData for getScanResults, length=%d",
565                  num_scan_data);
566            return NULL;
567        }
568
569        for (int i = 0; i < num_scan_data; i++) {
570
571            JNIObject<jobject> data = helper.createObject("android/net/wifi/WifiScanner$ScanData");
572            if (data == NULL) {
573                ALOGE("Error in allocating scanData for getScanResults");
574                return NULL;
575            }
576
577            helper.setIntField(data, "mId", scan_data[i].scan_id);
578            helper.setIntField(data, "mFlags", scan_data[i].flags);
579            helper.setIntField(data, "mBucketsScanned", scan_data[i].buckets_scanned);
580
581            /* sort all scan results by timestamp */
582            qsort(scan_data[i].results, scan_data[i].num_results,
583                    sizeof(wifi_scan_result), compare_scan_result_timestamp);
584
585            JNIObject<jobjectArray> scanResults = helper.createObjectArray(
586                    "android/net/wifi/ScanResult", scan_data[i].num_results);
587            if (scanResults == NULL) {
588                ALOGE("Error in allocating scanResult array for getScanResults, length=%d",
589                      scan_data[i].num_results);
590                return NULL;
591            }
592
593            wifi_scan_result *results = scan_data[i].results;
594            for (int j = 0; j < scan_data[i].num_results; j++) {
595
596                JNIObject<jobject> scanResult = createScanResult(helper, &results[j], false);
597                if (scanResult == NULL) {
598                    ALOGE("Error in creating scan result for getScanResults");
599                    return NULL;
600                }
601
602                helper.setObjectArrayElement(scanResults, j, scanResult);
603            }
604
605            helper.setObjectField(data, "mResults", "[Landroid/net/wifi/ScanResult;", scanResults);
606            helper.setObjectArrayElement(scanData, i, data);
607        }
608
609        // ALOGD("retrieved %d scan data from interface[%d] = %p", num_scan_data, iface, handle);
610        return scanData.detach();
611    } else {
612        return NULL;
613    }
614}
615
616
617static jboolean android_net_wifi_getScanCapabilities(
618        JNIEnv *env, jclass cls, jint iface, jobject capabilities) {
619
620    JNIHelper helper(env);
621    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
622    // ALOGD("getting scan capabilities on interface[%d] = %p", iface, handle);
623
624    wifi_gscan_capabilities c;
625    memset(&c, 0, sizeof(c));
626    int result = hal_fn.wifi_get_gscan_capabilities(handle, &c);
627    if (result != WIFI_SUCCESS) {
628        ALOGD("failed to get capabilities : %d", result);
629        return JNI_FALSE;
630    }
631
632    helper.setIntField(capabilities, "max_scan_cache_size", c.max_scan_cache_size);
633    helper.setIntField(capabilities, "max_scan_buckets", c.max_scan_buckets);
634    helper.setIntField(capabilities, "max_ap_cache_per_scan", c.max_ap_cache_per_scan);
635    helper.setIntField(capabilities, "max_rssi_sample_size", c.max_rssi_sample_size);
636    helper.setIntField(capabilities, "max_scan_reporting_threshold", c.max_scan_reporting_threshold);
637    helper.setIntField(capabilities, "max_hotlist_bssids", c.max_hotlist_bssids);
638    helper.setIntField(capabilities, "max_significant_wifi_change_aps",
639            c.max_significant_wifi_change_aps);
640    helper.setIntField(capabilities, "max_bssid_history_entries", c.max_bssid_history_entries);
641    helper.setIntField(capabilities, "max_number_epno_networks", c.max_number_epno_networks);
642    helper.setIntField(capabilities, "max_number_epno_networks_by_ssid",
643            c.max_number_epno_networks_by_ssid);
644    helper.setIntField(capabilities, "max_number_of_white_listed_ssid",
645            c.max_number_of_white_listed_ssid);
646
647    return JNI_TRUE;
648}
649
650
651static byte parseHexChar(char ch) {
652    if (isdigit(ch))
653        return ch - '0';
654    else if ('A' <= ch && ch <= 'F')
655        return ch - 'A' + 10;
656    else if ('a' <= ch && ch <= 'f')
657        return ch - 'a' + 10;
658    else {
659        ALOGE("invalid character in bssid %c", ch);
660        return 0;
661    }
662}
663
664static byte parseHexByte(const char * &str) {
665    if (str[0] == '\0') {
666        ALOGE("Passed an empty string");
667        return 0;
668    }
669    byte b = parseHexChar(str[0]);
670    if (str[1] == '\0' || str[1] == ':') {
671        str ++;
672    } else {
673        b = b << 4 | parseHexChar(str[1]);
674        str += 2;
675    }
676
677    // Skip trailing delimiter if not at the end of the string.
678    if (str[0] != '\0') {
679        str++;
680    }
681    return b;
682}
683
684static void parseMacAddress(const char *str, mac_addr addr) {
685    addr[0] = parseHexByte(str);
686    addr[1] = parseHexByte(str);
687    addr[2] = parseHexByte(str);
688    addr[3] = parseHexByte(str);
689    addr[4] = parseHexByte(str);
690    addr[5] = parseHexByte(str);
691}
692
693static bool parseMacAddress(JNIEnv *env, jobject obj, mac_addr addr) {
694    JNIHelper helper(env);
695    JNIObject<jstring> macAddrString = helper.getStringField(obj, "bssid");
696    if (macAddrString == NULL) {
697        ALOGE("Error getting bssid field");
698        return false;
699    }
700
701    ScopedUtfChars chars(env, macAddrString);
702    const char *bssid = chars.c_str();
703    if (bssid == NULL) {
704        ALOGE("Error getting bssid");
705        return false;
706    }
707
708    parseMacAddress(bssid, addr);
709    return true;
710}
711
712static void onHotlistApFound(wifi_request_id id,
713        unsigned num_results, wifi_scan_result *results) {
714
715    JNIHelper helper(mVM);
716    ALOGD("onHotlistApFound called, vm = %p, obj = %p, num_results = %d", mVM, mCls, num_results);
717
718    JNIObject<jobjectArray> scanResults = helper.newObjectArray(num_results,
719            "android/net/wifi/ScanResult", NULL);
720    if (scanResults == NULL) {
721        ALOGE("Error in allocating ScanResult array in onHotlistApFound, length=%d", num_results);
722        return;
723    }
724
725    for (unsigned i = 0; i < num_results; i++) {
726
727        JNIObject<jobject> scanResult = createScanResult(helper, &results[i], false);
728        if (scanResult == NULL) {
729            ALOGE("Error in creating scan result in onHotlistApFound");
730            return;
731        }
732
733        helper.setObjectArrayElement(scanResults, i, scanResult);
734
735        ALOGD("Found AP %32s", results[i].ssid);
736    }
737
738    helper.reportEvent(mCls, "onHotlistApFound", "(I[Landroid/net/wifi/ScanResult;)V",
739        id, scanResults.get());
740}
741
742static void onHotlistApLost(wifi_request_id id,
743        unsigned num_results, wifi_scan_result *results) {
744
745    JNIHelper helper(mVM);
746    ALOGD("onHotlistApLost called, vm = %p, obj = %p, num_results = %d", mVM, mCls, num_results);
747
748    JNIObject<jobjectArray> scanResults = helper.newObjectArray(num_results,
749            "android/net/wifi/ScanResult", NULL);
750    if (scanResults == NULL) {
751        ALOGE("Error in allocating ScanResult array onHotlistApLost, length=%d", num_results);
752        return;
753    }
754
755    for (unsigned i = 0; i < num_results; i++) {
756
757        JNIObject<jobject> scanResult = createScanResult(helper, &results[i], false);
758        if (scanResult == NULL) {
759            ALOGE("Error in creating scan result in onHotlistApLost");
760            return;
761        }
762
763        helper.setObjectArrayElement(scanResults, i, scanResult);
764
765        ALOGD("Lost AP %32s", results[i].ssid);
766    }
767
768    helper.reportEvent(mCls, "onHotlistApLost", "(I[Landroid/net/wifi/ScanResult;)V",
769        id, scanResults.get());
770}
771
772
773static jboolean android_net_wifi_setHotlist(
774        JNIEnv *env, jclass cls, jint iface, jint id, jobject ap)  {
775
776    JNIHelper helper(env);
777    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
778    ALOGD("setting hotlist on interface[%d] = %p", iface, handle);
779
780    wifi_bssid_hotlist_params params;
781    memset(&params, 0, sizeof(params));
782
783    params.lost_ap_sample_size = helper.getIntField(ap, "apLostThreshold");
784
785    JNIObject<jobjectArray> array = helper.getArrayField(
786            ap, "bssidInfos", "[Landroid/net/wifi/WifiScanner$BssidInfo;");
787    params.num_bssid = helper.getArrayLength(array);
788
789    if (params.num_bssid == 0) {
790        ALOGE("setHotlist array length was 0");
791        return false;
792    }
793
794    for (int i = 0; i < params.num_bssid; i++) {
795        JNIObject<jobject> objAp = helper.getObjectArrayElement(array, i);
796
797        JNIObject<jstring> macAddrString = helper.getStringField(objAp, "bssid");
798        if (macAddrString == NULL) {
799            ALOGE("Error getting bssid field");
800            return false;
801        }
802
803        ScopedUtfChars chars(env, macAddrString);
804        const char *bssid = chars.c_str();
805        if (bssid == NULL) {
806            ALOGE("Error getting bssid");
807            return false;
808        }
809        parseMacAddress(bssid, params.ap[i].bssid);
810
811        mac_addr addr;
812        memcpy(addr, params.ap[i].bssid, sizeof(mac_addr));
813
814        char bssidOut[32];
815        snprintf(bssidOut, sizeof(bssidOut), "%0x:%0x:%0x:%0x:%0x:%0x", addr[0],
816                 addr[1], addr[2], addr[3], addr[4], addr[5]);
817
818        ALOGD("Added bssid %s", bssidOut);
819
820        params.ap[i].low = helper.getIntField(objAp, "low");
821        params.ap[i].high = helper.getIntField(objAp, "high");
822    }
823
824    wifi_hotlist_ap_found_handler handler;
825    memset(&handler, 0, sizeof(handler));
826
827    handler.on_hotlist_ap_found = &onHotlistApFound;
828    handler.on_hotlist_ap_lost  = &onHotlistApLost;
829    return hal_fn.wifi_set_bssid_hotlist(id, handle, params, handler) == WIFI_SUCCESS;
830}
831
832static jboolean android_net_wifi_resetHotlist(JNIEnv *env, jclass cls, jint iface, jint id)  {
833
834    JNIHelper helper(env);
835    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
836    ALOGD("resetting hotlist on interface[%d] = %p", iface, handle);
837
838    return hal_fn.wifi_reset_bssid_hotlist(id, handle) == WIFI_SUCCESS;
839}
840
841void onSignificantWifiChange(wifi_request_id id,
842        unsigned num_results, wifi_significant_change_result **results) {
843
844    JNIHelper helper(mVM);
845
846    ALOGD("onSignificantWifiChange called, vm = %p, obj = %p", mVM, mCls);
847
848    JNIObject<jobjectArray> scanResults = helper.newObjectArray(
849            num_results, "android/net/wifi/ScanResult", NULL);
850    if (scanResults == NULL) {
851        ALOGE("Error in allocating ScanResult array in onSignificantWifiChange, length=%d",
852              num_results);
853        return;
854    }
855
856    for (unsigned i = 0; i < num_results; i++) {
857
858        wifi_significant_change_result &result = *(results[i]);
859
860        JNIObject<jobject> scanResult = helper.createObject("android/net/wifi/ScanResult");
861        if (scanResult == NULL) {
862            ALOGE("Error in creating scan result in onSignificantWifiChange");
863            return;
864        }
865
866        // helper.setStringField(scanResult, "SSID", results[i].ssid);
867
868        char bssid[32];
869        snprintf(bssid, sizeof(bssid), "%02x:%02x:%02x:%02x:%02x:%02x",
870                 result.bssid[0], result.bssid[1], result.bssid[2],
871                 result.bssid[3], result.bssid[4], result.bssid[5]);
872
873        helper.setStringField(scanResult, "BSSID", bssid);
874
875        helper.setIntField(scanResult, "level", result.rssi[0]);
876        helper.setIntField(scanResult, "frequency", result.channel);
877        // helper.setLongField(scanResult, "timestamp", result.ts);
878
879        helper.setObjectArrayElement(scanResults, i, scanResult);
880    }
881
882    helper.reportEvent(mCls, "onSignificantWifiChange", "(I[Landroid/net/wifi/ScanResult;)V",
883        id, scanResults.get());
884
885}
886
887static jboolean android_net_wifi_trackSignificantWifiChange(
888        JNIEnv *env, jclass cls, jint iface, jint id, jobject settings)  {
889
890    JNIHelper helper(env);
891    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
892    ALOGD("tracking significant wifi change on interface[%d] = %p", iface, handle);
893
894    wifi_significant_change_params params;
895    memset(&params, 0, sizeof(params));
896
897    params.rssi_sample_size = helper.getIntField(settings, "rssiSampleSize");
898    params.lost_ap_sample_size = helper.getIntField(settings, "lostApSampleSize");
899    params.min_breaching = helper.getIntField(settings, "minApsBreachingThreshold");
900
901    const char *bssid_info_array_type = "[Landroid/net/wifi/WifiScanner$BssidInfo;";
902    JNIObject<jobjectArray> bssids = helper.getArrayField(
903            settings, "bssidInfos", bssid_info_array_type);
904    params.num_bssid = helper.getArrayLength(bssids);
905
906    if (params.num_bssid == 0) {
907        ALOGE("BssidInfo array length was 0");
908        return false;
909    }
910
911    ALOGD("Initialized common fields %d, %d, %d, %d", params.rssi_sample_size,
912            params.lost_ap_sample_size, params.min_breaching, params.num_bssid);
913
914    for (int i = 0; i < params.num_bssid; i++) {
915        JNIObject<jobject> objAp = helper.getObjectArrayElement(bssids, i);
916
917        JNIObject<jstring> macAddrString = helper.getStringField(objAp, "bssid");
918        if (macAddrString == NULL) {
919            ALOGE("Error getting bssid field");
920            return false;
921        }
922
923        ScopedUtfChars chars(env, macAddrString.get());
924        const char *bssid = chars.c_str();
925        if (bssid == NULL) {
926            ALOGE("Error getting bssid");
927            return false;
928        }
929
930        mac_addr addr;
931        parseMacAddress(bssid, addr);
932        memcpy(params.ap[i].bssid, addr, sizeof(mac_addr));
933
934        char bssidOut[32];
935        snprintf(bssidOut, sizeof(bssidOut), "%02x:%02x:%02x:%02x:%02x:%02x",
936                 addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
937
938        params.ap[i].low = helper.getIntField(objAp, "low");
939        params.ap[i].high = helper.getIntField(objAp, "high");
940
941        ALOGD("Added bssid %s, [%04d, %04d]", bssidOut, params.ap[i].low, params.ap[i].high);
942    }
943
944    ALOGD("Added %d bssids", params.num_bssid);
945
946    wifi_significant_change_handler handler;
947    memset(&handler, 0, sizeof(handler));
948
949    handler.on_significant_change = &onSignificantWifiChange;
950    return hal_fn.wifi_set_significant_change_handler(id, handle, params, handler) == WIFI_SUCCESS;
951}
952
953static jboolean android_net_wifi_untrackSignificantWifiChange(
954        JNIEnv *env, jclass cls, jint iface, jint id)  {
955
956    JNIHelper helper(env);
957    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
958    ALOGD("resetting significant wifi change on interface[%d] = %p", iface, handle);
959
960    return hal_fn.wifi_reset_significant_change_handler(id, handle) == WIFI_SUCCESS;
961}
962
963wifi_iface_stat link_stat;
964wifi_radio_stat radio_stat; // L release has support for only one radio
965u32 *tx_time_per_level_arr = 0;
966// Let's cache the supported feature set to avoid unnecessary HAL invocations.
967feature_set cached_feature_set = 0;
968
969bool isTxLevelStatsPresent(wifi_radio_stat *radio_stats) {
970    if (IS_SUPPORTED_FEATURE(WIFI_FEATURE_TX_TRANSMIT_POWER, cached_feature_set)) {
971        if(radio_stats->tx_time_per_levels != 0 && radio_stats->num_tx_levels > 0) {
972            return true;
973        } else {
974            ALOGE("Ignoring invalid tx_level info in radio_stats");
975        }
976    }
977    return false;
978}
979
980void onLinkStatsResults(wifi_request_id id, wifi_iface_stat *iface_stat,
981         int num_radios, wifi_radio_stat *radio_stats)
982{
983    if (iface_stat != 0) {
984        memcpy(&link_stat, iface_stat, sizeof(wifi_iface_stat));
985    } else {
986        memset(&link_stat, 0, sizeof(wifi_iface_stat));
987    }
988
989    if (num_radios > 0 && radio_stats != 0) {
990        memcpy(&radio_stat, radio_stats, sizeof(wifi_radio_stat));
991        if (isTxLevelStatsPresent(radio_stats)) {
992            // This realloc should be a no-op after the first allocation because for a given
993            // device, the number of power levels should not change.
994            u32 arr_size = sizeof(u32) * radio_stats->num_tx_levels;
995            tx_time_per_level_arr = (u32 *)realloc(tx_time_per_level_arr, arr_size);
996            memcpy(tx_time_per_level_arr, radio_stats->tx_time_per_levels, arr_size);
997            radio_stat.tx_time_per_levels = tx_time_per_level_arr;
998        } else {
999            radio_stat.num_tx_levels = 0;
1000            radio_stat.tx_time_per_levels = 0;
1001        }
1002    } else {
1003        memset(&radio_stat, 0, sizeof(wifi_radio_stat));
1004    }
1005}
1006
1007static void android_net_wifi_setLinkLayerStats (JNIEnv *env, jclass cls, jint iface, int enable)  {
1008    JNIHelper helper(env);
1009    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
1010
1011    wifi_link_layer_params params;
1012    params.aggressive_statistics_gathering = enable;
1013    params.mpdu_size_threshold = 128;
1014
1015    ALOGD("android_net_wifi_setLinkLayerStats: %u\n", enable);
1016
1017    hal_fn.wifi_set_link_stats(handle, params);
1018}
1019
1020static jobject android_net_wifi_getLinkLayerStats (JNIEnv *env, jclass cls, jint iface)  {
1021
1022    JNIHelper helper(env);
1023    wifi_stats_result_handler handler;
1024    memset(&handler, 0, sizeof(handler));
1025    handler.on_link_stats_results = &onLinkStatsResults;
1026    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
1027    int result;
1028    // Cache the features supported by the device to determine if tx level stats are present or not
1029    if (cached_feature_set == 0) {
1030        result = hal_fn.wifi_get_supported_feature_set(handle, &cached_feature_set);
1031        if (result != WIFI_SUCCESS) {
1032            cached_feature_set = 0;
1033        }
1034    }
1035
1036    result = hal_fn.wifi_get_link_stats(0, handle, handler);
1037    if (result < 0) {
1038        ALOGE("android_net_wifi_getLinkLayerStats: failed to get link statistics\n");
1039        return NULL;
1040    }
1041
1042    JNIObject<jobject> wifiLinkLayerStats = helper.createObject(
1043            "android/net/wifi/WifiLinkLayerStats");
1044    if (wifiLinkLayerStats == NULL) {
1045       ALOGE("Error in allocating wifiLinkLayerStats");
1046       return NULL;
1047    }
1048
1049    JNIObject<jintArray> tx_time_per_level = helper.newIntArray(radio_stat.num_tx_levels);
1050    if (tx_time_per_level == NULL) {
1051        ALOGE("Error in allocating wifiLinkLayerStats");
1052        return NULL;
1053    }
1054
1055    helper.setIntField(wifiLinkLayerStats, "beacon_rx", link_stat.beacon_rx);
1056    helper.setIntField(wifiLinkLayerStats, "rssi_mgmt", link_stat.rssi_mgmt);
1057    helper.setLongField(wifiLinkLayerStats, "rxmpdu_be", link_stat.ac[WIFI_AC_BE].rx_mpdu);
1058    helper.setLongField(wifiLinkLayerStats, "rxmpdu_bk", link_stat.ac[WIFI_AC_BK].rx_mpdu);
1059    helper.setLongField(wifiLinkLayerStats, "rxmpdu_vi", link_stat.ac[WIFI_AC_VI].rx_mpdu);
1060    helper.setLongField(wifiLinkLayerStats, "rxmpdu_vo", link_stat.ac[WIFI_AC_VO].rx_mpdu);
1061    helper.setLongField(wifiLinkLayerStats, "txmpdu_be", link_stat.ac[WIFI_AC_BE].tx_mpdu);
1062    helper.setLongField(wifiLinkLayerStats, "txmpdu_bk", link_stat.ac[WIFI_AC_BK].tx_mpdu);
1063    helper.setLongField(wifiLinkLayerStats, "txmpdu_vi", link_stat.ac[WIFI_AC_VI].tx_mpdu);
1064    helper.setLongField(wifiLinkLayerStats, "txmpdu_vo", link_stat.ac[WIFI_AC_VO].tx_mpdu);
1065    helper.setLongField(wifiLinkLayerStats, "lostmpdu_be", link_stat.ac[WIFI_AC_BE].mpdu_lost);
1066    helper.setLongField(wifiLinkLayerStats, "lostmpdu_bk", link_stat.ac[WIFI_AC_BK].mpdu_lost);
1067    helper.setLongField(wifiLinkLayerStats, "lostmpdu_vi",  link_stat.ac[WIFI_AC_VI].mpdu_lost);
1068    helper.setLongField(wifiLinkLayerStats, "lostmpdu_vo", link_stat.ac[WIFI_AC_VO].mpdu_lost);
1069    helper.setLongField(wifiLinkLayerStats, "retries_be", link_stat.ac[WIFI_AC_BE].retries);
1070    helper.setLongField(wifiLinkLayerStats, "retries_bk", link_stat.ac[WIFI_AC_BK].retries);
1071    helper.setLongField(wifiLinkLayerStats, "retries_vi", link_stat.ac[WIFI_AC_VI].retries);
1072    helper.setLongField(wifiLinkLayerStats, "retries_vo", link_stat.ac[WIFI_AC_VO].retries);
1073
1074    helper.setIntField(wifiLinkLayerStats, "on_time", radio_stat.on_time);
1075    helper.setIntField(wifiLinkLayerStats, "tx_time", radio_stat.tx_time);
1076    helper.setIntField(wifiLinkLayerStats, "rx_time", radio_stat.rx_time);
1077    helper.setIntField(wifiLinkLayerStats, "on_time_scan", radio_stat.on_time_scan);
1078    if (radio_stat.tx_time_per_levels != 0) {
1079        helper.setIntArrayRegion(tx_time_per_level, 0, radio_stat.num_tx_levels,
1080                (jint *)radio_stat.tx_time_per_levels);
1081    }
1082    helper.setObjectField(wifiLinkLayerStats, "tx_time_per_level", "[I", tx_time_per_level);
1083
1084
1085    return wifiLinkLayerStats.detach();
1086}
1087
1088static jint android_net_wifi_getSupportedFeatures(JNIEnv *env, jclass cls, jint iface) {
1089
1090    JNIHelper helper(env);
1091    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
1092    feature_set set = 0;
1093
1094    wifi_error result = WIFI_SUCCESS;
1095    /*
1096    set = WIFI_FEATURE_INFRA
1097        | WIFI_FEATURE_INFRA_5G
1098        | WIFI_FEATURE_HOTSPOT
1099        | WIFI_FEATURE_P2P
1100        | WIFI_FEATURE_SOFT_AP
1101        | WIFI_FEATURE_GSCAN
1102        | WIFI_FEATURE_PNO
1103        | WIFI_FEATURE_TDLS
1104        | WIFI_FEATURE_EPR;
1105    */
1106
1107    result = hal_fn.wifi_get_supported_feature_set(handle, &set);
1108    if (result == WIFI_SUCCESS) {
1109        // ALOGD("wifi_get_supported_feature_set returned set = 0x%x", set);
1110        return set;
1111    } else {
1112        ALOGE("wifi_get_supported_feature_set returned error = 0x%x", result);
1113        return 0;
1114    }
1115}
1116
1117static void onRttResults(wifi_request_id id, unsigned num_results, wifi_rtt_result* results[]) {
1118
1119    JNIHelper helper(mVM);
1120
1121    ALOGD("onRttResults called, vm = %p, obj = %p", mVM, mCls);
1122
1123    JNIObject<jobjectArray> rttResults = helper.newObjectArray(
1124            num_results, "android/net/wifi/RttManager$RttResult", NULL);
1125    if (rttResults == NULL) {
1126        ALOGE("Error in allocating RttResult array in onRttResults, length=%d", num_results);
1127        return;
1128    }
1129
1130    for (unsigned i = 0; i < num_results; i++) {
1131
1132        wifi_rtt_result *result = results[i];
1133
1134        JNIObject<jobject> rttResult = helper.createObject("android/net/wifi/RttManager$RttResult");
1135        if (rttResult == NULL) {
1136            ALOGE("Error in creating rtt result in onRttResults");
1137            return;
1138        }
1139
1140        char bssid[32];
1141        snprintf(bssid, sizeof(bssid), "%02x:%02x:%02x:%02x:%02x:%02x",
1142                 result->addr[0], result->addr[1], result->addr[2],
1143                 result->addr[3], result->addr[4], result->addr[5]);
1144
1145        helper.setStringField(rttResult, "bssid", bssid);
1146        helper.setIntField( rttResult, "burstNumber",              result->burst_num);
1147        helper.setIntField( rttResult, "measurementFrameNumber",   result->measurement_number);
1148        helper.setIntField( rttResult, "successMeasurementFrameNumber",   result->success_number);
1149        helper.setIntField(rttResult, "frameNumberPerBurstPeer",   result->number_per_burst_peer);
1150        helper.setIntField( rttResult, "status",                   result->status);
1151        helper.setIntField( rttResult, "measurementType",          result->type);
1152        helper.setIntField(rttResult, "retryAfterDuration",       result->retry_after_duration);
1153        helper.setLongField(rttResult, "ts",                       result->ts);
1154        helper.setIntField( rttResult, "rssi",                     result->rssi);
1155        helper.setIntField( rttResult, "rssiSpread",               result->rssi_spread);
1156        helper.setIntField( rttResult, "txRate",                   result->tx_rate.bitrate);
1157        helper.setIntField( rttResult, "rxRate",                   result->rx_rate.bitrate);
1158        helper.setLongField(rttResult, "rtt",                      result->rtt);
1159        helper.setLongField(rttResult, "rttStandardDeviation",     result->rtt_sd);
1160        helper.setIntField( rttResult, "distance",                 result->distance_mm / 10);
1161        helper.setIntField( rttResult, "distanceStandardDeviation", result->distance_sd_mm / 10);
1162        helper.setIntField( rttResult, "distanceSpread",           result->distance_spread_mm / 10);
1163        helper.setIntField( rttResult, "burstDuration",             result->burst_duration);
1164        helper.setIntField( rttResult, "negotiatedBurstNum",      result->negotiated_burst_num);
1165
1166        JNIObject<jobject> LCI = helper.createObject(
1167                "android/net/wifi/RttManager$WifiInformationElement");
1168        if (result->LCI != NULL && result->LCI->len > 0) {
1169            ALOGD("Add LCI in result");
1170            helper.setByteField(LCI, "id", result->LCI->id);
1171            JNIObject<jbyteArray> elements = helper.newByteArray(result->LCI->len);
1172            jbyte *bytes = (jbyte *)&(result->LCI->data[0]);
1173            helper.setByteArrayRegion(elements, 0, result->LCI->len, bytes);
1174            helper.setObjectField(LCI, "data", "[B", elements);
1175        } else {
1176            ALOGD("No LCI in result");
1177            helper.setByteField(LCI, "id", (byte)(0xff));
1178        }
1179        helper.setObjectField(rttResult, "LCI",
1180            "Landroid/net/wifi/RttManager$WifiInformationElement;", LCI);
1181
1182        JNIObject<jobject> LCR = helper.createObject(
1183                "android/net/wifi/RttManager$WifiInformationElement");
1184        if (result->LCR != NULL && result->LCR->len > 0) {
1185            ALOGD("Add LCR in result");
1186            helper.setByteField(LCR, "id",           result->LCR->id);
1187            JNIObject<jbyteArray> elements = helper.newByteArray(result->LCI->len);
1188            jbyte *bytes = (jbyte *)&(result->LCR->data[0]);
1189            helper.setByteArrayRegion(elements, 0, result->LCI->len, bytes);
1190            helper.setObjectField(LCR, "data", "[B", elements);
1191        } else {
1192            ALOGD("No LCR in result");
1193            helper.setByteField(LCR, "id", (byte)(0xff));
1194        }
1195        helper.setObjectField(rttResult, "LCR",
1196            "Landroid/net/wifi/RttManager$WifiInformationElement;", LCR);
1197
1198        helper.setObjectArrayElement(rttResults, i, rttResult);
1199    }
1200
1201    helper.reportEvent(mCls, "onRttResults", "(I[Landroid/net/wifi/RttManager$RttResult;)V",
1202        id, rttResults.get());
1203}
1204
1205const int MaxRttConfigs = 16;
1206
1207static jboolean android_net_wifi_requestRange(
1208        JNIEnv *env, jclass cls, jint iface, jint id, jobject params)  {
1209
1210    JNIHelper helper(env);
1211
1212    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
1213    ALOGD("sending rtt request [%d] = %p", id, handle);
1214    if (params == NULL) {
1215        ALOGE("ranging params are empty");
1216        return false;
1217    }
1218
1219    wifi_rtt_config configs[MaxRttConfigs];
1220    memset(&configs, 0, sizeof(configs));
1221
1222    int len = helper.getArrayLength((jobjectArray)params);
1223    if (len > MaxRttConfigs) {
1224        return false;
1225    }
1226
1227    for (int i = 0; i < len; i++) {
1228
1229        JNIObject<jobject> param = helper.getObjectArrayElement((jobjectArray)params, i);
1230        if (param == NULL) {
1231            ALOGD("could not get element %d", i);
1232            continue;
1233        }
1234
1235        wifi_rtt_config &config = configs[i];
1236
1237        parseMacAddress(env, param, config.addr);
1238        config.type = (wifi_rtt_type)helper.getIntField(param, "requestType");
1239        config.peer = (rtt_peer_type)helper.getIntField(param, "deviceType");
1240        config.channel.center_freq = helper.getIntField(param, "frequency");
1241        config.channel.width = (wifi_channel_width) helper.getIntField(param, "channelWidth");
1242        config.channel.center_freq0 = helper.getIntField(param, "centerFreq0");
1243        config.channel.center_freq1 = helper.getIntField(param, "centerFreq1");
1244
1245        config.num_burst = helper.getIntField(param, "numberBurst");
1246        config.burst_period = (unsigned) helper.getIntField(param, "interval");
1247        config.num_frames_per_burst = (unsigned) helper.getIntField(param, "numSamplesPerBurst");
1248        config.num_retries_per_rtt_frame = (unsigned) helper.getIntField(param,
1249                "numRetriesPerMeasurementFrame");
1250        config.num_retries_per_ftmr = (unsigned) helper.getIntField(param, "numRetriesPerFTMR");
1251        config.LCI_request = helper.getBoolField(param, "LCIRequest") ? 1 : 0;
1252        config.LCR_request = helper.getBoolField(param, "LCRRequest") ? 1 : 0;
1253        config.burst_duration = (unsigned) helper.getIntField(param, "burstTimeout");
1254        config.preamble = (wifi_rtt_preamble) helper.getIntField(param, "preamble");
1255        config.bw = (wifi_rtt_bw) helper.getIntField(param, "bandwidth");
1256
1257        ALOGD("RTT request destination %d: type is %d, peer is %d, bw is %d, center_freq is %d ", i,
1258                config.type,config.peer, config.channel.width,  config.channel.center_freq);
1259        ALOGD("center_freq0 is %d, center_freq1 is %d, num_burst is %d,interval is %d",
1260                config.channel.center_freq0, config.channel.center_freq1, config.num_burst,
1261                config.burst_period);
1262        ALOGD("frames_per_burst is %d, retries of measurement frame is %d, retries_per_ftmr is %d",
1263                config.num_frames_per_burst, config.num_retries_per_rtt_frame,
1264                config.num_retries_per_ftmr);
1265        ALOGD("LCI_requestis %d, LCR_request is %d,  burst_timeout is %d, preamble is %d, bw is %d",
1266                config.LCI_request, config.LCR_request, config.burst_duration, config.preamble,
1267                config.bw);
1268    }
1269
1270    wifi_rtt_event_handler handler;
1271    handler.on_rtt_results = &onRttResults;
1272
1273    return hal_fn.wifi_rtt_range_request(id, handle, len, configs, handler) == WIFI_SUCCESS;
1274}
1275
1276static jboolean android_net_wifi_cancelRange(
1277        JNIEnv *env, jclass cls, jint iface, jint id, jobject params)  {
1278
1279    JNIHelper helper(env);
1280    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
1281    ALOGD("cancelling rtt request [%d] = %p", id, handle);
1282
1283    if (params == NULL) {
1284        ALOGE("ranging params are empty");
1285        return false;
1286    }
1287
1288    mac_addr addrs[MaxRttConfigs];
1289    memset(&addrs, 0, sizeof(addrs));
1290
1291    int len = helper.getArrayLength((jobjectArray)params);
1292    if (len > MaxRttConfigs) {
1293        return false;
1294    }
1295
1296    for (int i = 0; i < len; i++) {
1297
1298        JNIObject<jobject> param = helper.getObjectArrayElement(params, i);
1299        if (param == NULL) {
1300            ALOGD("could not get element %d", i);
1301            continue;
1302        }
1303
1304        parseMacAddress(env, param, addrs[i]);
1305    }
1306
1307    return hal_fn.wifi_rtt_range_cancel(id, handle, len, addrs) == WIFI_SUCCESS;
1308}
1309
1310static jobject android_net_wifi_enableResponder(
1311        JNIEnv *env, jclass cls, jint iface, jint id, jint timeout_seconds, jobject channel_hint) {
1312    JNIHelper helper(env);
1313    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
1314    if (DBG) ALOGD("enabling responder request [%d] = %p", id, handle);
1315    wifi_channel_info channel;
1316    // Get channel information from HAL if it's not provided by caller.
1317    if (channel_hint == NULL) {
1318        wifi_rtt_responder responder_info_hint;
1319        bool status = hal_fn.wifi_rtt_get_responder_info(handle, &responder_info_hint);
1320        if (status != WIFI_SUCCESS) {
1321            ALOGE("could not get available channel for responder");
1322            return NULL;
1323        }
1324        channel = responder_info_hint.channel;
1325    } else {
1326        channel.center_freq = helper.getIntField(channel_hint, "mPrimaryFrequency");
1327        channel.center_freq0 = helper.getIntField(channel_hint, "mCenterFrequency0");
1328        channel.center_freq1 = helper.getIntField(channel_hint, "mCenterFrequency1");
1329        channel.width = (wifi_channel_width)helper.getIntField(channel_hint, "mChannelWidth");
1330    }
1331
1332    if (DBG) {
1333        ALOGD("wifi_channel_width: %d, center_freq: %d, center_freq0: %d",
1334              channel.width, channel.center_freq, channel.center_freq0);
1335    }
1336
1337    wifi_rtt_responder responder_info_used;
1338    bool status = hal_fn.wifi_enable_responder(id, handle, channel, timeout_seconds,
1339            &responder_info_used);
1340    if (status != WIFI_SUCCESS) {
1341        ALOGE("enabling responder mode failed");
1342        return NULL;
1343    }
1344    wifi_channel_info channel_used = responder_info_used.channel;
1345    if (DBG) {
1346        ALOGD("wifi_channel_width: %d, center_freq: %d, center_freq0: %d",
1347              channel_used.width, channel_used.center_freq, channel_used.center_freq0);
1348    }
1349    JNIObject<jobject> responderConfig =
1350        helper.createObject("android/net/wifi/RttManager$ResponderConfig");
1351    if (responderConfig == NULL) return NULL;
1352    helper.setIntField(responderConfig, "frequency", channel_used.center_freq);
1353    helper.setIntField(responderConfig, "centerFreq0", channel_used.center_freq0);
1354    helper.setIntField(responderConfig, "centerFreq1", channel_used.center_freq1);
1355    helper.setIntField(responderConfig, "channelWidth", channel_used.width);
1356    helper.setIntField(responderConfig, "preamble", responder_info_used.preamble);
1357    return responderConfig.detach();
1358}
1359
1360static jboolean android_net_wifi_disableResponder(
1361        JNIEnv *env, jclass cls, jint iface, jint id)  {
1362    JNIHelper helper(env);
1363    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
1364    if (DBG) ALOGD("disabling responder request [%d] = %p", id, handle);
1365    return hal_fn.wifi_disable_responder(id, handle) == WIFI_SUCCESS;
1366}
1367
1368
1369static jboolean android_net_wifi_setScanningMacOui(JNIEnv *env, jclass cls,
1370        jint iface, jbyteArray param)  {
1371
1372    JNIHelper helper(env);
1373    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
1374    ALOGD("setting scan oui %p", handle);
1375
1376    static const unsigned oui_len = 3;          /* OUI is upper 3 bytes of mac_address */
1377    int len = helper.getArrayLength(param);
1378    if (len != oui_len) {
1379        ALOGE("invalid oui length %d", len);
1380        return false;
1381    }
1382
1383    ScopedBytesRW paramBytes(env, param);
1384    jbyte* bytes = paramBytes.get();
1385    if (bytes == NULL) {
1386        ALOGE("failed to get setScanningMacOui param array");
1387        return false;
1388    }
1389
1390    return hal_fn.wifi_set_scanning_mac_oui(handle, (byte *)bytes) == WIFI_SUCCESS;
1391}
1392
1393static jboolean android_net_wifi_is_get_channels_for_band_supported(JNIEnv *env, jclass cls){
1394    return (hal_fn.wifi_get_valid_channels == wifi_get_valid_channels_stub);
1395}
1396
1397static jintArray android_net_wifi_getValidChannels(JNIEnv *env, jclass cls,
1398        jint iface, jint band)  {
1399
1400    JNIHelper helper(env);
1401    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
1402    ALOGV("getting valid channels %p", handle);
1403
1404    static const int MaxChannels = 64;
1405    wifi_channel channels[64];
1406    int num_channels = 0;
1407    wifi_error result = hal_fn.wifi_get_valid_channels(handle, band, MaxChannels,
1408            channels, &num_channels);
1409
1410    if (result == WIFI_SUCCESS) {
1411        JNIObject<jintArray> channelArray = helper.newIntArray(num_channels);
1412        if (channelArray == NULL) {
1413            ALOGE("failed to allocate channel list, num_channels=%d", num_channels);
1414            return NULL;
1415        }
1416
1417        helper.setIntArrayRegion(channelArray, 0, num_channels, channels);
1418        return channelArray.detach();
1419    } else {
1420        ALOGE("failed to get channel list : %d", result);
1421        return NULL;
1422    }
1423}
1424
1425static jboolean android_net_wifi_setDfsFlag(JNIEnv *env, jclass cls, jint iface, jboolean dfs) {
1426
1427    JNIHelper helper(env);
1428    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
1429    ALOGD("setting dfs flag to %s, %p", dfs ? "true" : "false", handle);
1430
1431    u32 nodfs = dfs ? 0 : 1;
1432    wifi_error result = hal_fn.wifi_set_nodfs_flag(handle, nodfs);
1433    return result == WIFI_SUCCESS;
1434}
1435
1436static jobject android_net_wifi_get_rtt_capabilities(JNIEnv *env, jclass cls, jint iface) {
1437
1438    JNIHelper helper(env);
1439    wifi_rtt_capabilities rtt_capabilities;
1440    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
1441    wifi_error ret = hal_fn.wifi_get_rtt_capabilities(handle, &rtt_capabilities);
1442
1443    if(WIFI_SUCCESS == ret) {
1444         JNIObject<jobject> capabilities = helper.createObject(
1445                "android/net/wifi/RttManager$RttCapabilities");
1446         helper.setBooleanField(capabilities, "oneSidedRttSupported",
1447                 rtt_capabilities.rtt_one_sided_supported == 1);
1448         helper.setBooleanField(capabilities, "twoSided11McRttSupported",
1449                 rtt_capabilities.rtt_ftm_supported == 1);
1450         helper.setBooleanField(capabilities, "lciSupported",
1451                 rtt_capabilities.lci_support);
1452         helper.setBooleanField(capabilities, "lcrSupported",
1453                 rtt_capabilities.lcr_support);
1454         helper.setIntField(capabilities, "preambleSupported",
1455                 rtt_capabilities.preamble_support);
1456         helper.setIntField(capabilities, "bwSupported",
1457                 rtt_capabilities.bw_support);
1458         helper.setBooleanField(capabilities, "responderSupported",
1459                 rtt_capabilities.responder_supported == 1);
1460         if (DBG) {
1461             ALOGD("One side RTT is %s", rtt_capabilities.rtt_one_sided_supported == 1 ?
1462                "supported" : "not supported");
1463             ALOGD("Two side RTT is %s", rtt_capabilities.rtt_ftm_supported == 1 ?
1464                "supported" : "not supported");
1465             ALOGD("LCR is %s", rtt_capabilities.lcr_support == 1 ? "supported" : "not supported");
1466             ALOGD("LCI is %s", rtt_capabilities.lci_support == 1 ? "supported" : "not supported");
1467             ALOGD("Supported preamble is %d", rtt_capabilities.preamble_support);
1468             ALOGD("Supported bandwidth is %d", rtt_capabilities.bw_support);
1469             ALOGD("Sta responder is %s",
1470                 rtt_capabilities.responder_supported == 1 ? "supported" : "not supported");
1471         }
1472         return capabilities.detach();
1473    } else {
1474        return NULL;
1475    }
1476}
1477
1478static jobject android_net_wifi_get_apf_capabilities(JNIEnv *env, jclass cls,
1479        jint iface) {
1480
1481    JNIHelper helper(env);
1482    u32 version = 0, max_len = 0;
1483    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
1484    wifi_error ret = hal_fn.wifi_get_packet_filter_capabilities(handle, &version, &max_len);
1485
1486    if (WIFI_SUCCESS == ret) {
1487        // Cannot just use createObject() because members are final and initializer values must be
1488        // passed via ApfCapabilities().
1489        JNIObject<jclass> apf_cls(helper, env->FindClass("android/net/apf/ApfCapabilities"));
1490        if (apf_cls == NULL) {
1491            ALOGE("Error in finding class android/net/apf/ApfCapabilities");
1492            return NULL;
1493        }
1494        jmethodID constructor = env->GetMethodID(apf_cls, "<init>", "(III)V");
1495        if (constructor == 0) {
1496            ALOGE("Error in constructor ID for android/net/apf/ApfCapabilities");
1497            return NULL;
1498        }
1499        JNIObject<jobject> capabilities(helper, env->NewObject(apf_cls, constructor, version,
1500                max_len, ARPHRD_ETHER));
1501        if (capabilities == NULL) {
1502            ALOGE("Could not create new object of android/net/apf/ApfCapabilities");
1503            return NULL;
1504        }
1505        ALOGD("APF version supported: %d", version);
1506        ALOGD("Maximum APF program size: %d", max_len);
1507        return capabilities.detach();
1508    } else {
1509        return NULL;
1510    }
1511}
1512
1513static jboolean android_net_wifi_install_packet_filter(JNIEnv *env, jclass cls, jint iface,
1514        jbyteArray jfilter) {
1515
1516    JNIHelper helper(env);
1517    const u8* filter = (uint8_t*)env->GetByteArrayElements(jfilter, NULL);
1518    const u32 filter_len = env->GetArrayLength(jfilter);
1519    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
1520    wifi_error ret = hal_fn.wifi_set_packet_filter(handle, filter, filter_len);
1521    env->ReleaseByteArrayElements(jfilter, (jbyte*)filter, JNI_ABORT);
1522    return WIFI_SUCCESS == ret;
1523}
1524
1525static jboolean android_net_wifi_set_Country_Code_Hal(JNIEnv *env,jclass cls, jint iface,
1526        jstring country_code) {
1527
1528    JNIHelper helper(env);
1529    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
1530
1531    ScopedUtfChars chars(env, country_code);
1532    const char *country = chars.c_str();
1533
1534    ALOGD("set country code: %s", country);
1535    wifi_error res = hal_fn.wifi_set_country_code(handle, country);
1536    return res == WIFI_SUCCESS;
1537}
1538
1539static jboolean android_net_wifi_enable_disable_tdls(JNIEnv *env,jclass cls, jint iface,
1540        jboolean enable, jstring addr) {
1541
1542    JNIHelper helper(env);
1543    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
1544
1545    mac_addr address;
1546    parseMacAddress(env, addr, address);
1547    wifi_tdls_handler tdls_handler;
1548    //tdls_handler.on_tdls_state_changed = &on_tdls_state_changed;
1549
1550    if(enable) {
1551        return (hal_fn.wifi_enable_tdls(handle, address, NULL, tdls_handler) == WIFI_SUCCESS);
1552    } else {
1553        return (hal_fn.wifi_disable_tdls(handle, address) == WIFI_SUCCESS);
1554    }
1555}
1556
1557static void on_tdls_state_changed(mac_addr addr, wifi_tdls_status status) {
1558
1559    JNIHelper helper(mVM);
1560
1561    ALOGD("on_tdls_state_changed is called: vm = %p, obj = %p", mVM, mCls);
1562
1563    char mac[32];
1564    snprintf(mac, sizeof(mac), "%02x:%02x:%02x:%02x:%02x:%02x", addr[0],
1565             addr[1], addr[2], addr[3], addr[4], addr[5]);
1566
1567    JNIObject<jstring> mac_address = helper.newStringUTF(mac);
1568    helper.reportEvent(mCls, "onTdlsStatus", "(Ljava/lang/StringII;)V",
1569        mac_address.get(), status.state, status.reason);
1570
1571}
1572
1573static jobject android_net_wifi_get_tdls_status(JNIEnv *env,jclass cls, jint iface,jstring addr) {
1574
1575    JNIHelper helper(env);
1576    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
1577
1578    mac_addr address;
1579    parseMacAddress(env, addr, address);
1580
1581    wifi_tdls_status status;
1582
1583    wifi_error ret;
1584    ret = hal_fn.wifi_get_tdls_status(handle, address, &status );
1585
1586    if (ret != WIFI_SUCCESS) {
1587        return NULL;
1588    } else {
1589        JNIObject<jobject> tdls_status = helper.createObject(
1590                "com/android/server/wifi/WifiNative$TdlsStatus");
1591        helper.setIntField(tdls_status, "channel", status.channel);
1592        helper.setIntField(tdls_status, "global_operating_class", status.global_operating_class);
1593        helper.setIntField(tdls_status, "state", status.state);
1594        helper.setIntField(tdls_status, "reason", status.reason);
1595        return tdls_status.detach();
1596    }
1597}
1598
1599static jobject android_net_wifi_get_tdls_capabilities(JNIEnv *env, jclass cls, jint iface) {
1600
1601    JNIHelper helper(env);
1602    wifi_tdls_capabilities tdls_capabilities;
1603    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
1604    wifi_error ret = hal_fn.wifi_get_tdls_capabilities(handle, &tdls_capabilities);
1605
1606    if (WIFI_SUCCESS == ret) {
1607         JNIObject<jobject> capabilities = helper.createObject(
1608                 "com/android/server/wifi/WifiNative$TdlsCapabilities");
1609         helper.setIntField(capabilities, "maxConcurrentTdlsSessionNumber",
1610                 tdls_capabilities.max_concurrent_tdls_session_num);
1611         helper.setBooleanField(capabilities, "isGlobalTdlsSupported",
1612                 tdls_capabilities.is_global_tdls_supported == 1);
1613         helper.setBooleanField(capabilities, "isPerMacTdlsSupported",
1614                 tdls_capabilities.is_per_mac_tdls_supported == 1);
1615         helper.setBooleanField(capabilities, "isOffChannelTdlsSupported",
1616                 tdls_capabilities.is_off_channel_tdls_supported);
1617
1618         ALOGD("TDLS Max Concurrent Tdls Session Number is: %d",
1619                 tdls_capabilities.max_concurrent_tdls_session_num);
1620         ALOGD("Global Tdls is: %s", tdls_capabilities.is_global_tdls_supported == 1 ? "support" :
1621                 "not support");
1622         ALOGD("Per Mac Tdls is: %s", tdls_capabilities.is_per_mac_tdls_supported == 1 ? "support" :
1623                 "not support");
1624         ALOGD("Off Channel Tdls is: %s", tdls_capabilities.is_off_channel_tdls_supported == 1 ?
1625                 "support" : "not support");
1626
1627         return capabilities.detach();
1628    } else {
1629        return NULL;
1630    }
1631}
1632
1633// ----------------------------------------------------------------------------
1634// Debug framework
1635// ----------------------------------------------------------------------------
1636static jint android_net_wifi_get_supported_logger_feature(JNIEnv *env, jclass cls, jint iface){
1637    //Not implemented yet
1638    return -1;
1639}
1640
1641static jobject android_net_wifi_get_driver_version(JNIEnv *env, jclass cls, jint iface) {
1642     //Need to be fixed. The memory should be allocated from lower layer
1643    //char *buffer = NULL;
1644    JNIHelper helper(env);
1645    int buffer_length =  256;
1646    char *buffer = (char *)malloc(buffer_length);
1647    if (!buffer) return NULL;
1648    memset(buffer, 0, buffer_length);
1649    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
1650
1651    ALOGD("android_net_wifi_get_driver_version = %p", handle);
1652
1653    if (handle == 0) {
1654        free(buffer);
1655        return NULL;
1656    }
1657
1658    wifi_error result = hal_fn.wifi_get_driver_version(handle, buffer, buffer_length);
1659
1660    if (result == WIFI_SUCCESS) {
1661        ALOGD("buffer is %p, length is %d", buffer, buffer_length);
1662        JNIObject<jstring> driver_version = helper.newStringUTF(buffer);
1663        free(buffer);
1664        return driver_version.detach();
1665    } else {
1666        ALOGE("Fail to get driver version");
1667        free(buffer);
1668        return NULL;
1669    }
1670}
1671
1672static jobject android_net_wifi_get_firmware_version(JNIEnv *env, jclass cls, jint iface) {
1673
1674    //char *buffer = NULL;
1675    JNIHelper helper(env);
1676    int buffer_length = 256;
1677    char *buffer = (char *)malloc(buffer_length);
1678    if (!buffer) return NULL;
1679    memset(buffer, 0, buffer_length);
1680    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
1681
1682    ALOGD("android_net_wifi_get_firmware_version = %p", handle);
1683
1684    if (handle == 0) {
1685        free(buffer);
1686        return NULL;
1687    }
1688
1689    wifi_error result = hal_fn.wifi_get_firmware_version(handle, buffer, buffer_length);
1690
1691    if (result == WIFI_SUCCESS) {
1692        ALOGD("buffer is %p, length is %d", buffer, buffer_length);
1693        JNIObject<jstring> firmware_version = helper.newStringUTF(buffer);
1694        free(buffer);
1695        return firmware_version.detach();
1696    } else {
1697        ALOGE("Fail to get Firmware version");
1698        free(buffer);
1699        return NULL;
1700    }
1701}
1702
1703static jobject android_net_wifi_get_ring_buffer_status (JNIEnv *env, jclass cls, jint iface) {
1704
1705    JNIHelper helper(env);
1706    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
1707
1708    ALOGD("android_net_wifi_get_ring_buffer_status = %p", handle);
1709
1710    if (handle == 0) {
1711        return NULL;
1712    }
1713
1714    //wifi_ring_buffer_status *status = NULL;
1715    u32 num_rings = 10;
1716    wifi_ring_buffer_status *status =
1717        (wifi_ring_buffer_status *)malloc(sizeof(wifi_ring_buffer_status) * num_rings);
1718    if (!status) return NULL;
1719    memset(status, 0, sizeof(wifi_ring_buffer_status) * num_rings);
1720    wifi_error result = hal_fn.wifi_get_ring_buffers_status(handle, &num_rings, status);
1721    if (result == WIFI_SUCCESS) {
1722        ALOGD("status is %p, number is %d", status, num_rings);
1723
1724        JNIObject<jobjectArray> ringBuffersStatus = helper.newObjectArray(
1725            num_rings, "com/android/server/wifi/WifiNative$RingBufferStatus", NULL);
1726
1727        wifi_ring_buffer_status *tmp = status;
1728
1729        for(u32 i = 0; i < num_rings; i++, tmp++) {
1730
1731            JNIObject<jobject> ringStatus = helper.createObject(
1732                    "com/android/server/wifi/WifiNative$RingBufferStatus");
1733
1734            if (ringStatus == NULL) {
1735                ALOGE("Error in creating ringBufferStatus");
1736                free(status);
1737                return NULL;
1738            }
1739
1740            char name[32];
1741            for(int j = 0; j < 32; j++) {
1742                name[j] = tmp->name[j];
1743            }
1744
1745            helper.setStringField(ringStatus, "name", name);
1746            helper.setIntField(ringStatus, "flag", tmp->flags);
1747            helper.setIntField(ringStatus, "ringBufferId", tmp->ring_id);
1748            helper.setIntField(ringStatus, "ringBufferByteSize", tmp->ring_buffer_byte_size);
1749            helper.setIntField(ringStatus, "verboseLevel", tmp->verbose_level);
1750            helper.setIntField(ringStatus, "writtenBytes", tmp->written_bytes);
1751            helper.setIntField(ringStatus, "readBytes", tmp->read_bytes);
1752            helper.setIntField(ringStatus, "writtenRecords", tmp->written_records);
1753
1754            helper.setObjectArrayElement(ringBuffersStatus, i, ringStatus);
1755        }
1756
1757        free(status);
1758        return ringBuffersStatus.detach();
1759    } else {
1760        free(status);
1761        return NULL;
1762    }
1763}
1764
1765static void on_ring_buffer_data(char *ring_name, char *buffer, int buffer_size,
1766        wifi_ring_buffer_status *status) {
1767
1768    if (!ring_name || !buffer || !status ||
1769            (unsigned int)buffer_size <= sizeof(wifi_ring_buffer_entry)) {
1770        ALOGE("Error input for on_ring_buffer_data!");
1771        return;
1772    }
1773
1774
1775    JNIHelper helper(mVM);
1776    /* ALOGD("on_ring_buffer_data called, vm = %p, obj = %p, env = %p buffer size = %d", mVM,
1777            mCls, env, buffer_size); */
1778
1779    JNIObject<jobject> ringStatus = helper.createObject(
1780                    "com/android/server/wifi/WifiNative$RingBufferStatus");
1781    if (status == NULL) {
1782        ALOGE("Error in creating ringBufferStatus");
1783        return;
1784    }
1785
1786    helper.setStringField(ringStatus, "name", ring_name);
1787    helper.setIntField(ringStatus, "flag", status->flags);
1788    helper.setIntField(ringStatus, "ringBufferId", status->ring_id);
1789    helper.setIntField(ringStatus, "ringBufferByteSize", status->ring_buffer_byte_size);
1790    helper.setIntField(ringStatus, "verboseLevel", status->verbose_level);
1791    helper.setIntField(ringStatus, "writtenBytes", status->written_bytes);
1792    helper.setIntField(ringStatus, "readBytes", status->read_bytes);
1793    helper.setIntField(ringStatus, "writtenRecords", status->written_records);
1794
1795    JNIObject<jbyteArray> bytes = helper.newByteArray(buffer_size);
1796    helper.setByteArrayRegion(bytes, 0, buffer_size, (jbyte*)buffer);
1797
1798    helper.reportEvent(mCls,"onRingBufferData",
1799            "(Lcom/android/server/wifi/WifiNative$RingBufferStatus;[B)V",
1800            ringStatus.get(), bytes.get());
1801}
1802
1803static void on_alert_data(wifi_request_id id, char *buffer, int buffer_size, int err_code){
1804
1805    JNIHelper helper(mVM);
1806    ALOGD("on_alert_data called, vm = %p, obj = %p, buffer_size = %d, error code = %d"
1807            , mVM, mCls, buffer_size, err_code);
1808
1809    if (buffer_size > 0) {
1810        JNIObject<jbyteArray> records = helper.newByteArray(buffer_size);
1811        jbyte *bytes = (jbyte *) buffer;
1812        helper.setByteArrayRegion(records, 0,buffer_size, bytes);
1813        helper.reportEvent(mCls,"onWifiAlert","([BI)V", records.get(), err_code);
1814    } else {
1815        helper.reportEvent(mCls,"onWifiAlert","([BI)V", NULL, err_code);
1816    }
1817}
1818
1819
1820static jboolean android_net_wifi_start_logging_ring_buffer(JNIEnv *env, jclass cls, jint iface,
1821        jint verbose_level,jint flags, jint max_interval,jint min_data_size, jstring ring_name) {
1822
1823    JNIHelper helper(env);
1824    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
1825
1826    ALOGD("android_net_wifi_start_logging_ring_buffer = %p", handle);
1827
1828    if (handle == 0) {
1829        return false;
1830    }
1831
1832    ScopedUtfChars chars(env, ring_name);
1833    const char* ring_name_const_char = chars.c_str();
1834    int ret = hal_fn.wifi_start_logging(handle, verbose_level,
1835            flags, max_interval, min_data_size, const_cast<char *>(ring_name_const_char));
1836
1837    if (ret != WIFI_SUCCESS) {
1838        ALOGE("Fail to start logging for ring %s", ring_name_const_char);
1839    } else {
1840        ALOGD("start logging for ring %s", ring_name_const_char);
1841    }
1842
1843    return ret == WIFI_SUCCESS;
1844}
1845
1846static jboolean android_net_wifi_get_ring_buffer_data(JNIEnv *env, jclass cls, jint iface,
1847        jstring ring_name) {
1848
1849    JNIHelper helper(env);
1850    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
1851    // ALOGD("android_net_wifi_get_ring_buffer_data = %p", handle);
1852
1853    ScopedUtfChars chars(env, ring_name);
1854    const char* ring_name_const_char = chars.c_str();
1855    int result = hal_fn.wifi_get_ring_data(handle, const_cast<char *>(ring_name_const_char));
1856    return result == WIFI_SUCCESS;
1857}
1858
1859
1860static void on_firmware_memory_dump(char *buffer, int buffer_size) {
1861
1862    JNIHelper helper(mVM);
1863    /* ALOGD("on_firmware_memory_dump called, vm = %p, obj = %p, env = %p buffer_size = %d"
1864            , mVM, mCls, env, buffer_size); */
1865
1866    if (buffer_size > 0) {
1867        JNIObject<jbyteArray> dump = helper.newByteArray(buffer_size);
1868        jbyte *bytes = (jbyte *) (buffer);
1869        helper.setByteArrayRegion(dump, 0, buffer_size, bytes);
1870        helper.reportEvent(mCls,"onWifiFwMemoryAvailable","([B)V", dump.get());
1871    }
1872}
1873
1874static jboolean android_net_wifi_get_fw_memory_dump(JNIEnv *env, jclass cls, jint iface){
1875
1876    JNIHelper helper(env);
1877    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
1878    // ALOGD("android_net_wifi_get_fw_memory_dump = %p", handle);
1879
1880    if (handle == NULL) {
1881        ALOGE("Can not get wifi_interface_handle");
1882        return false;
1883    }
1884
1885    wifi_firmware_memory_dump_handler fw_dump_handle;
1886    fw_dump_handle.on_firmware_memory_dump = on_firmware_memory_dump;
1887    int result = hal_fn.wifi_get_firmware_memory_dump(handle, fw_dump_handle);
1888    return result == WIFI_SUCCESS;
1889
1890}
1891
1892std::vector<jbyte>* driver_state_dump_buffer_for_callback = nullptr;
1893
1894static void on_driver_state_dump(char *buffer, int buffer_size);
1895static wifi_driver_memory_dump_callbacks driver_state_dump_callbacks = {
1896    on_driver_state_dump
1897};
1898
1899static void on_driver_state_dump(char *buffer, int buffer_size) {
1900
1901    if (!driver_state_dump_buffer_for_callback) {
1902        ALOGE("Unexpected call from HAL implementation, into %s", __func__);
1903        return;
1904    }
1905
1906    if (buffer_size > 0) {
1907        driver_state_dump_buffer_for_callback->insert(
1908            driver_state_dump_buffer_for_callback->end(), buffer, buffer + buffer_size);
1909    }
1910}
1911
1912// TODO(quiche): Add unit tests. b/28072392
1913static jbyteArray android_net_wifi_get_driver_state_dump(JNIEnv *env, jclass cls, jint iface){
1914
1915    JNIHelper helper(env);
1916    wifi_interface_handle interface_handle = getIfaceHandle(helper, cls, iface);
1917
1918    if (!interface_handle) {
1919        return nullptr;
1920    }
1921
1922    int result;
1923    std::vector<jbyte> state_dump_buffer_local;
1924    driver_state_dump_buffer_for_callback = &state_dump_buffer_local;
1925    result = hal_fn.wifi_get_driver_memory_dump(interface_handle, driver_state_dump_callbacks);
1926    driver_state_dump_buffer_for_callback = nullptr;
1927
1928    if (result != WIFI_SUCCESS) {
1929        ALOGW("HAL's wifi_get_driver_memory_dump returned %d", result);
1930        return nullptr;
1931    }
1932
1933    if (state_dump_buffer_local.empty()) {
1934        ALOGW("HAL's wifi_get_driver_memory_dump provided zero bytes");
1935        return nullptr;
1936    }
1937
1938    const size_t dump_size = state_dump_buffer_local.size();
1939    JNIObject<jbyteArray> driver_dump_java = helper.newByteArray(dump_size);
1940    if (!driver_dump_java)  {
1941        ALOGW("Failed to allocate Java buffer for driver state dump");
1942        return nullptr;
1943    }
1944
1945    helper.setByteArrayRegion(driver_dump_java, 0, dump_size, state_dump_buffer_local.data());
1946    return driver_dump_java.detach();
1947}
1948
1949static jboolean android_net_wifi_set_log_handler(JNIEnv *env, jclass cls, jint iface, jint id) {
1950
1951    JNIHelper helper(env);
1952    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
1953    ALOGD("android_net_wifi_set_log_handler = %p", handle);
1954
1955    //initialize the handler on first time
1956    wifi_ring_buffer_data_handler handler;
1957    handler.on_ring_buffer_data = &on_ring_buffer_data;
1958    int result = hal_fn.wifi_set_log_handler(id, handle, handler);
1959    if (result != WIFI_SUCCESS) {
1960        ALOGE("Fail to set logging handler");
1961        return false;
1962    }
1963
1964    //set alter handler This will start alert too
1965    wifi_alert_handler alert_handler;
1966    alert_handler.on_alert = &on_alert_data;
1967    result = hal_fn.wifi_set_alert_handler(id, handle, alert_handler);
1968    if (result != WIFI_SUCCESS) {
1969        ALOGE(" Fail to set alert handler");
1970        return false;
1971    }
1972
1973    return true;
1974}
1975
1976static jboolean android_net_wifi_reset_log_handler(JNIEnv *env, jclass cls, jint iface, jint id) {
1977
1978    JNIHelper helper(env);
1979    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
1980
1981    //reset alter handler
1982    ALOGD("android_net_wifi_reset_alert_handler = %p", handle);
1983    int result = hal_fn.wifi_reset_alert_handler(id, handle);
1984    if (result != WIFI_SUCCESS) {
1985        ALOGE(" Fail to reset alert handler");
1986        return false;
1987    }
1988
1989    //reset log handler
1990    ALOGD("android_net_wifi_reset_log_handler = %p", handle);
1991    result = hal_fn.wifi_reset_log_handler(id, handle);
1992    if (result != WIFI_SUCCESS) {
1993        ALOGE("Fail to reset logging handler");
1994        return false;
1995    }
1996
1997    return true;
1998}
1999
2000static jint android_net_wifi_start_pkt_fate_monitoring(JNIEnv *env, jclass cls, jint iface) {
2001
2002    JNIHelper helper(env);
2003    return hal_fn.wifi_start_pkt_fate_monitoring(
2004        getIfaceHandle(helper, cls, iface));
2005}
2006
2007// Helper for make_default_fate().
2008template<typename T> void set_to_max(T* value) {
2009    if (!value) {
2010        return;
2011    }
2012    *value = std::numeric_limits<T>::max();
2013}
2014
2015// make_default_fate() has two purposes:
2016// 1) Minimize the chances of data leakage. In case the HAL gives us an overlong long |frame_len|,
2017//    for example, we want to return zeros, rather than other data from this process.
2018// 2) Make it obvious when the HAL doesn't set a field. We accomplish this by setting fields
2019//    to "impossible" values, where possible.
2020// Normally, such work would be done in a ctor. However, doing so would make the HAL API
2021// incompatible with C. So we use a free-standing function instead.
2022//
2023// TODO(quiche): Add unit test for this function. b/27726696
2024template<typename FateReportT> FateReportT make_default_fate() {
2025
2026    FateReportT fate_report;
2027    set_to_max(&fate_report.fate);
2028    std::fill(std::begin(fate_report.md5_prefix), std::end(fate_report.md5_prefix), 0);
2029    set_to_max(&fate_report.frame_inf.payload_type);
2030    fate_report.frame_inf.frame_len = 0;
2031    fate_report.frame_inf.driver_timestamp_usec = 0;
2032    fate_report.frame_inf.firmware_timestamp_usec = 0;
2033    std::fill(std::begin(fate_report.frame_inf.frame_content.ieee_80211_mgmt_bytes),
2034        std::end(fate_report.frame_inf.frame_content.ieee_80211_mgmt_bytes), 0);
2035    return fate_report;
2036}
2037
2038// TODO(quiche): Add unit test for this function. b/27726696
2039template<typename FateReportT, typename HalFateFetcherT> wifi_error get_pkt_fates(
2040    HalFateFetcherT fate_fetcher_func, const char *java_fate_type,
2041    JNIEnv *env, jclass cls, jint iface, jobjectArray reports) {
2042
2043    JNIHelper helper(env);
2044    const size_t n_reports_wanted =
2045        std::min(helper.getArrayLength(reports), MAX_FATE_LOG_LEN);
2046
2047    std::vector<FateReportT> report_bufs(n_reports_wanted, make_default_fate<FateReportT>());
2048    size_t n_reports_provided = 0;
2049    wifi_error result = fate_fetcher_func(
2050        getIfaceHandle(helper, cls, iface),
2051        report_bufs.data(),
2052        n_reports_wanted,
2053        &n_reports_provided);
2054    if (result != WIFI_SUCCESS) {
2055        return result;
2056    }
2057
2058    if (n_reports_provided > n_reports_wanted) {
2059        LOG_ALWAYS_FATAL(
2060            "HAL data exceeds request; memory may be corrupt (provided: %zu, requested: %zu)",
2061            n_reports_provided, n_reports_wanted);
2062    }
2063
2064    for (size_t i = 0; i < n_reports_provided; ++i) {
2065        const FateReportT& report(report_bufs[i]);
2066
2067        const char *frame_bytes_native = nullptr;
2068        size_t max_frame_len;
2069        switch (report.frame_inf.payload_type) {
2070            case FRAME_TYPE_UNKNOWN:
2071            case FRAME_TYPE_ETHERNET_II:
2072                max_frame_len = MAX_FRAME_LEN_ETHERNET;
2073                frame_bytes_native = report.frame_inf.frame_content.ethernet_ii_bytes;
2074                break;
2075            case FRAME_TYPE_80211_MGMT:
2076                max_frame_len = MAX_FRAME_LEN_80211_MGMT;
2077                frame_bytes_native = report.frame_inf.frame_content.ieee_80211_mgmt_bytes;
2078                break;
2079            default:
2080                max_frame_len = 0;
2081                frame_bytes_native = 0;
2082        }
2083
2084        size_t copy_len = report.frame_inf.frame_len;
2085        if (copy_len > max_frame_len) {
2086            ALOGW("Overly long frame (len: %zu, max: %zu)", copy_len, max_frame_len);
2087            copy_len = max_frame_len;
2088        }
2089
2090        JNIObject<jbyteArray> frame_bytes_java = helper.newByteArray(copy_len);
2091        if (frame_bytes_java.isNull()) {
2092            ALOGE("Failed to allocate frame data buffer");
2093            return WIFI_ERROR_OUT_OF_MEMORY;
2094        }
2095        helper.setByteArrayRegion(frame_bytes_java, 0, copy_len,
2096            reinterpret_cast<const jbyte *>(frame_bytes_native));
2097
2098        JNIObject<jobject> fate_report = helper.createObjectWithArgs(
2099            java_fate_type,
2100            "(BJB[B)V",  // byte, long, byte, byte array
2101            static_cast<jbyte>(report.fate),
2102            static_cast<jlong>(report.frame_inf.driver_timestamp_usec),
2103            static_cast<jbyte>(report.frame_inf.payload_type),
2104            frame_bytes_java.get());
2105        if (fate_report.isNull()) {
2106            ALOGE("Failed to create %s", java_fate_type);
2107            return WIFI_ERROR_OUT_OF_MEMORY;
2108        }
2109        helper.setObjectArrayElement(reports, i, fate_report);
2110    }
2111
2112    return result;
2113}
2114
2115static jint android_net_wifi_get_tx_pkt_fates(JNIEnv *env, jclass cls, jint iface,
2116    jobjectArray reports) {
2117
2118    return get_pkt_fates<wifi_tx_report>(
2119        hal_fn.wifi_get_tx_pkt_fates, "com/android/server/wifi/WifiNative$TxFateReport",
2120        env, cls, iface, reports);
2121}
2122
2123static jint android_net_wifi_get_rx_pkt_fates(JNIEnv *env, jclass cls, jint iface,
2124    jobjectArray reports) {
2125
2126    return get_pkt_fates<wifi_rx_report>(
2127        hal_fn.wifi_get_rx_pkt_fates, "com/android/server/wifi/WifiNative$RxFateReport",
2128        env, cls, iface, reports);
2129}
2130
2131// ----------------------------------------------------------------------------
2132// ePno framework
2133// ----------------------------------------------------------------------------
2134
2135
2136static void onPnoNetworkFound(wifi_request_id id,
2137                                          unsigned num_results, wifi_scan_result *results) {
2138    JNIHelper helper(mVM);
2139    ALOGD("onPnoNetworkFound called, vm = %p, obj = %p, num_results %u", mVM, mCls, num_results);
2140
2141    if (results == NULL || num_results == 0) {
2142       ALOGE("onPnoNetworkFound: Error no results");
2143       return;
2144    }
2145
2146    JNIObject<jobjectArray> scanResults = helper.newObjectArray(num_results,
2147            "android/net/wifi/ScanResult", NULL);
2148    if (scanResults == NULL) {
2149        ALOGE("onpnoNetworkFound: Error in allocating scanResults array");
2150        return;
2151    }
2152
2153    JNIObject<jintArray> beaconCaps = helper.newIntArray(num_results);
2154    if (beaconCaps == NULL) {
2155        ALOGE("onpnoNetworkFound: Error in allocating beaconCaps array");
2156        return;
2157    }
2158
2159    for (unsigned i=0; i<num_results; i++) {
2160
2161        JNIObject<jobject> scanResult = createScanResult(helper, &results[i], true);
2162        if (scanResult == NULL) {
2163            ALOGE("Error in creating scan result");
2164            return;
2165        }
2166
2167        helper.setObjectArrayElement(scanResults, i, scanResult);
2168        helper.setIntArrayRegion(beaconCaps, i, 1, (jint *)&(results[i].capability));
2169
2170        if (DBG) {
2171            ALOGD("ScanResult: IE length %d, i %u, <%s> rssi=%d %02x:%02x:%02x:%02x:%02x:%02x",
2172                    results->ie_length, i, results[i].ssid, results[i].rssi,
2173                    results[i].bssid[0], results[i].bssid[1],results[i].bssid[2],
2174                    results[i].bssid[3], results[i].bssid[4], results[i].bssid[5]);
2175        }
2176    }
2177
2178    helper.reportEvent(mCls, "onPnoNetworkFound", "(I[Landroid/net/wifi/ScanResult;[I)V", id,
2179               scanResults.get(), beaconCaps.get());
2180}
2181
2182static jboolean android_net_wifi_setPnoListNative(
2183        JNIEnv *env, jclass cls, jint iface, jint id, jobject settings)  {
2184
2185    JNIHelper helper(env);
2186    wifi_epno_handler handler;
2187    handler.on_network_found = &onPnoNetworkFound;
2188
2189    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
2190    ALOGD("configure ePno list request [%d] = %p", id, handle);
2191
2192    if (settings == NULL) {
2193        return false;
2194    }
2195
2196    JNIObject<jobjectArray> list = helper.getArrayField(settings, "networkList",
2197            "[Lcom/android/server/wifi/WifiNative$PnoNetwork;");
2198    if (list == NULL) {
2199        return false;
2200    }
2201
2202    size_t len = helper.getArrayLength(list);
2203    if (len > (size_t)MAX_EPNO_NETWORKS) {
2204        return false;
2205    }
2206
2207    wifi_epno_params params;
2208    memset(&params, 0, sizeof(params));
2209
2210    for (unsigned int i = 0; i < len; i++) {
2211
2212        JNIObject<jobject> pno_net = helper.getObjectArrayElement(list, i);
2213        if (pno_net == NULL) {
2214            ALOGE("setPnoListNative: could not get element %d", i);
2215            continue;
2216        }
2217
2218        JNIObject<jstring> sssid = helper.getStringField(pno_net, "ssid");
2219        if (sssid == NULL) {
2220              ALOGE("Error setPnoListNative: getting ssid field");
2221              return false;
2222        }
2223
2224        ScopedUtfChars chars(env, (jstring)sssid.get());
2225        const char *ssid = chars.c_str();
2226        if (ssid == NULL) {
2227             ALOGE("Error setPnoListNative: getting ssid");
2228             return false;
2229        }
2230        int ssid_len = strnlen((const char*)ssid, 33);
2231        if (ssid_len > 32) {
2232           ALOGE("Error setPnoListNative: long ssid %zu", strnlen((const char*)ssid, 256));
2233           return false;
2234        }
2235
2236        if (ssid_len > 1 && ssid[0] == '"' && ssid[ssid_len-1] == '"')
2237        {
2238            // strip leading and trailing '"'
2239            ssid++;
2240            ssid_len-=2;
2241        }
2242        if (ssid_len == 0) {
2243            ALOGE("Error setPnoListNative: zero length ssid, skip it");
2244            continue;
2245        }
2246        memcpy(params.networks[i].ssid, ssid, ssid_len);
2247
2248        params.networks[i].auth_bit_field = helper.getByteField(pno_net, "auth_bit_field");
2249        params.networks[i].flags = helper.getByteField(pno_net, "flags");
2250        ALOGD(" setPnoListNative: idx %u auth %x flags %x [%s]", i,
2251                params.networks[i].auth_bit_field, params.networks[i].flags,
2252                params.networks[i].ssid);
2253    }
2254    params.min5GHz_rssi = helper.getIntField(settings, "min5GHzRssi");
2255    params.min24GHz_rssi = helper.getIntField(settings, "min24GHzRssi");
2256    params.initial_score_max = helper.getIntField(settings, "initialScoreMax");
2257    params.current_connection_bonus = helper.getIntField(settings, "currentConnectionBonus");
2258    params.same_network_bonus = helper.getIntField(settings, "sameNetworkBonus");
2259    params.secure_bonus = helper.getIntField(settings, "secureBonus");
2260    params.band5GHz_bonus = helper.getIntField(settings, "band5GHzBonus");
2261    params.num_networks = len;
2262
2263    int result = hal_fn.wifi_set_epno_list(id, handle, &params, handler);
2264    ALOGD(" setPnoListNative: result %d", result);
2265
2266    return result >= 0;
2267}
2268
2269static jboolean android_net_wifi_resetPnoListNative(
2270        JNIEnv *env, jclass cls, jint iface, jint id)  {
2271
2272    JNIHelper helper(env);
2273
2274    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
2275    ALOGD("reset ePno list request [%d] = %p", id, handle);
2276
2277    // stop pno
2278    int result = hal_fn.wifi_reset_epno_list(id, handle);
2279    ALOGD(" ressetPnoListNative: result = %d", result);
2280    return result >= 0;
2281}
2282
2283static jboolean android_net_wifi_setBssidBlacklist(
2284        JNIEnv *env, jclass cls, jint iface, jint id, jobject list)  {
2285
2286    JNIHelper helper(env);
2287    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
2288    ALOGD("configure BSSID black list request [%d] = %p", id, handle);
2289
2290    wifi_bssid_params params;
2291    memset(&params, 0, sizeof(params));
2292
2293    if (list != NULL) {
2294        size_t len = helper.getArrayLength((jobjectArray)list);
2295        if (len > (size_t)MAX_BLACKLIST_BSSID) {
2296            return false;
2297        }
2298        for (unsigned int i = 0; i < len; i++) {
2299
2300            JNIObject<jobject> jbssid = helper.getObjectArrayElement(list, i);
2301            if (jbssid == NULL) {
2302                ALOGE("configure BSSID blacklist: could not get element %d", i);
2303                continue;
2304            }
2305
2306            ScopedUtfChars chars(env, (jstring)jbssid.get());
2307            const char *bssid = chars.c_str();
2308            if (bssid == NULL) {
2309                ALOGE("Error getting bssid");
2310                return false;
2311            }
2312
2313            mac_addr addr;
2314            parseMacAddress(bssid, addr);
2315            memcpy(params.bssids[i], addr, sizeof(mac_addr));
2316
2317            char bssidOut[32];
2318            snprintf(bssidOut, sizeof(bssidOut), "%0x:%0x:%0x:%0x:%0x:%0x",
2319                     addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
2320
2321            ALOGD("BSSID blacklist: added bssid %s", bssidOut);
2322
2323            params.num_bssid++;
2324        }
2325    }
2326
2327    ALOGD("Added %d bssids", params.num_bssid);
2328    return hal_fn.wifi_set_bssid_blacklist(id, handle, params) == WIFI_SUCCESS;
2329}
2330
2331static jint android_net_wifi_start_sending_offloaded_packet(JNIEnv *env, jclass cls, jint iface,
2332                    jint idx, jbyteArray srcMac, jbyteArray dstMac, jbyteArray pkt, jint period)  {
2333    JNIHelper helper(env);
2334    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
2335    ALOGD("Start packet offload [%d] = %p", idx, handle);
2336    wifi_error ret;
2337    wifi_request_id id = idx;
2338
2339    ScopedBytesRO pktBytes(env, pkt), srcMacBytes(env, srcMac), dstMacBytes(env, dstMac);
2340
2341    byte * pkt_data = (byte*) pktBytes.get();
2342    unsigned short pkt_len = env->GetArrayLength(pkt);
2343    byte* src_mac_addr = (byte*) srcMacBytes.get();
2344    byte* dst_mac_addr = (byte*) dstMacBytes.get();
2345    int i;
2346    char macAddr[32];
2347    snprintf(macAddr, sizeof(macAddr), "%0x:%0x:%0x:%0x:%0x:%0x",
2348             src_mac_addr[0], src_mac_addr[1], src_mac_addr[2], src_mac_addr[3],
2349             src_mac_addr[4], src_mac_addr[5]);
2350    ALOGD("src_mac_addr %s", macAddr);
2351    snprintf(macAddr, sizeof(macAddr), "%0x:%0x:%0x:%0x:%0x:%0x",
2352             dst_mac_addr[0], dst_mac_addr[1], dst_mac_addr[2], dst_mac_addr[3],
2353             dst_mac_addr[4], dst_mac_addr[5]);
2354    ALOGD("dst_mac_addr %s", macAddr);
2355    ALOGD("pkt_len %d\n", pkt_len);
2356    ALOGD("Pkt data : ");
2357    for(i = 0; i < pkt_len; i++) {
2358        ALOGD(" %x ", pkt_data[i]);
2359    }
2360    ALOGD("\n");
2361    ret =  hal_fn.wifi_start_sending_offloaded_packet(id, handle, pkt_data, pkt_len,
2362                src_mac_addr, dst_mac_addr, period);
2363    ALOGD("ret= %d\n", ret);
2364    return ret;
2365}
2366
2367static jint android_net_wifi_stop_sending_offloaded_packet(JNIEnv *env, jclass cls,
2368                    jint iface, jint idx) {
2369    int ret;
2370    JNIHelper helper(env);
2371    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
2372    ALOGD("Stop packet offload [%d] = %p", idx, handle);
2373    ret =  hal_fn.wifi_stop_sending_offloaded_packet(idx, handle);
2374    ALOGD("ret= %d\n", ret);
2375    return ret;
2376}
2377
2378static void onRssiThresholdbreached(wifi_request_id id, u8 *cur_bssid, s8 cur_rssi) {
2379
2380    ALOGD("RSSI threshold breached, cur RSSI - %d!!\n", cur_rssi);
2381    ALOGD("BSSID %02x:%02x:%02x:%02x:%02x:%02x\n",
2382            cur_bssid[0], cur_bssid[1], cur_bssid[2],
2383            cur_bssid[3], cur_bssid[4], cur_bssid[5]);
2384    JNIHelper helper(mVM);
2385    //ALOGD("onRssiThresholdbreached called, vm = %p, obj = %p, env = %p", mVM, mCls, env);
2386    helper.reportEvent(mCls, "onRssiThresholdBreached", "(IB)V", id, cur_rssi);
2387}
2388
2389static jint android_net_wifi_start_rssi_monitoring_native(JNIEnv *env, jclass cls, jint iface,
2390        jint idx, jbyte maxRssi, jbyte minRssi) {
2391
2392    JNIHelper helper(env);
2393    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
2394    ALOGD("Start Rssi monitoring = %p", handle);
2395    ALOGD("MinRssi %d MaxRssi %d", minRssi, maxRssi);
2396    wifi_error ret;
2397    wifi_request_id id = idx;
2398    wifi_rssi_event_handler eh;
2399    eh.on_rssi_threshold_breached = onRssiThresholdbreached;
2400    ret = hal_fn.wifi_start_rssi_monitoring(id, handle, maxRssi, minRssi, eh);
2401    return ret;
2402}
2403
2404static jint android_net_wifi_stop_rssi_monitoring_native(JNIEnv *env, jclass cls,
2405        jint iface, jint idx) {
2406    JNIHelper helper(env);
2407    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
2408    ALOGD("Stop Rssi monitoring = %p", handle);
2409    wifi_error ret;
2410    wifi_request_id id = idx;
2411    ret = hal_fn.wifi_stop_rssi_monitoring(id, handle);
2412    return ret;
2413}
2414
2415static jobject android_net_wifi_get_wlan_wake_reason_count(JNIEnv *env, jclass cls, jint iface) {
2416
2417    JNIHelper helper(env);
2418    WLAN_DRIVER_WAKE_REASON_CNT wake_reason_cnt;
2419    int cmd_event_wake_cnt_array[WAKE_REASON_TYPE_MAX];
2420    int driver_fw_local_wake_cnt_array[WAKE_REASON_TYPE_MAX];
2421    wifi_interface_handle handle = getIfaceHandle(helper, cls, iface);
2422    wifi_error ret;
2423
2424    wake_reason_cnt.cmd_event_wake_cnt = cmd_event_wake_cnt_array;
2425    wake_reason_cnt.cmd_event_wake_cnt_sz = WAKE_REASON_TYPE_MAX;
2426    wake_reason_cnt.cmd_event_wake_cnt_used = 0;
2427
2428    wake_reason_cnt.driver_fw_local_wake_cnt = driver_fw_local_wake_cnt_array;
2429    wake_reason_cnt.driver_fw_local_wake_cnt_sz = WAKE_REASON_TYPE_MAX;
2430    wake_reason_cnt.driver_fw_local_wake_cnt_used = 0;
2431
2432    ret = hal_fn.wifi_get_wake_reason_stats(handle, &wake_reason_cnt);
2433
2434    if (ret != WIFI_SUCCESS) {
2435        ALOGE("android_net_wifi_get_wlan_wake_reason_count: failed to get wake reason count\n");
2436        return NULL;
2437    }
2438
2439    JNIObject<jobject> stats = helper.createObject( "android/net/wifi/WifiWakeReasonAndCounts");
2440    if (stats == NULL) {
2441        ALOGE("android_net_wifi_get_wlan_wake_reason_count: error allocating object\n");
2442        return NULL;
2443    }
2444    JNIObject<jintArray> cmd_wake_arr =
2445            helper.newIntArray(wake_reason_cnt.cmd_event_wake_cnt_used);
2446    if (cmd_wake_arr == NULL) {
2447        ALOGE("android_net_wifi_get_wlan_wake_reason_count: error allocating array object\n");
2448        return NULL;
2449    }
2450    JNIObject<jintArray> local_wake_arr =
2451            helper.newIntArray(wake_reason_cnt.driver_fw_local_wake_cnt_used);
2452    if (local_wake_arr == NULL) {
2453        ALOGE("android_net_wifi_get_wlan_wake_reason_count: error allocating array object\n");
2454        return NULL;
2455    }
2456
2457    helper.setIntField(stats, "totalCmdEventWake", wake_reason_cnt.total_cmd_event_wake);
2458    helper.setIntField(stats, "totalDriverFwLocalWake", wake_reason_cnt.total_driver_fw_local_wake);
2459    helper.setIntField(stats, "totalRxDataWake", wake_reason_cnt.total_rx_data_wake);
2460    helper.setIntField(stats, "rxUnicast", wake_reason_cnt.rx_wake_details.rx_unicast_cnt);
2461    helper.setIntField(stats, "rxMulticast", wake_reason_cnt.rx_wake_details.rx_multicast_cnt);
2462    helper.setIntField(stats, "rxBroadcast", wake_reason_cnt.rx_wake_details.rx_broadcast_cnt);
2463    helper.setIntField(stats, "icmp", wake_reason_cnt.rx_wake_pkt_classification_info.icmp_pkt);
2464    helper.setIntField(stats, "icmp6", wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_pkt);
2465    helper.setIntField(stats, "icmp6Ra", wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_ra);
2466    helper.setIntField(stats, "icmp6Na", wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_na);
2467    helper.setIntField(stats, "icmp6Ns", wake_reason_cnt.rx_wake_pkt_classification_info.icmp6_ns);
2468    helper.setIntField(stats, "ipv4RxMulticast",
2469            wake_reason_cnt.rx_multicast_wake_pkt_info.ipv4_rx_multicast_addr_cnt);
2470    helper.setIntField(stats, "ipv6Multicast",
2471            wake_reason_cnt.rx_multicast_wake_pkt_info.ipv6_rx_multicast_addr_cnt);
2472    helper.setIntField(stats, "otherRxMulticast",
2473            wake_reason_cnt.rx_multicast_wake_pkt_info.other_rx_multicast_addr_cnt);
2474    helper.setIntArrayRegion(cmd_wake_arr, 0, wake_reason_cnt.cmd_event_wake_cnt_used,
2475            wake_reason_cnt.cmd_event_wake_cnt);
2476    helper.setIntArrayRegion(local_wake_arr, 0, wake_reason_cnt.driver_fw_local_wake_cnt_used,
2477            wake_reason_cnt.driver_fw_local_wake_cnt);
2478    helper.setObjectField(stats, "cmdEventWakeCntArray", "[I", cmd_wake_arr);
2479    helper.setObjectField(stats, "driverFWLocalWakeCntArray", "[I", local_wake_arr);
2480    return stats.detach();
2481}
2482
2483static jbyteArray android_net_wifi_readKernelLog(JNIEnv *env, jclass cls) {
2484    JNIHelper helper(env);
2485    ALOGV("Reading kernel logs");
2486
2487    int size = klogctl(/* SYSLOG_ACTION_SIZE_BUFFER */ 10, 0, 0);
2488    if (size < 1) {
2489        ALOGD("no kernel logs");
2490        return helper.newByteArray(0).detach();
2491    }
2492
2493    char *buf = (char *)malloc(size);
2494    if (buf == NULL) {
2495        ALOGD("can't allocate temporary storage");
2496        return helper.newByteArray(0).detach();
2497    }
2498
2499    int read = klogctl(/* SYSLOG_ACTION_READ_ALL */ 3, buf, size);
2500    if (read < 0) {
2501        ALOGD("can't read logs - %d", read);
2502        free(buf);
2503        return helper.newByteArray(0).detach();
2504    } else {
2505        ALOGV("read %d bytes", read);
2506    }
2507
2508    if (read != size) {
2509        ALOGV("read %d bytes, expecting %d", read, size);
2510    }
2511
2512    JNIObject<jbyteArray> result = helper.newByteArray(read);
2513    if (result.isNull()) {
2514        ALOGD("can't allocate array");
2515        free(buf);
2516        return result.detach();
2517    }
2518
2519    helper.setByteArrayRegion(result, 0, read, (jbyte*)buf);
2520    free(buf);
2521    return result.detach();
2522}
2523
2524static jint android_net_wifi_configure_nd_offload(JNIEnv *env, jclass cls,
2525        jint iface, jboolean enable) {
2526    JNIHelper helper(env);
2527    return hal_fn.wifi_configure_nd_offload(
2528            getIfaceHandle(helper, cls, iface),
2529            static_cast<int>(enable));
2530}
2531
2532
2533// ----------------------------------------------------------------------------
2534
2535/*
2536 * JNI registration.
2537 */
2538static JNINativeMethod gWifiMethods[] = {
2539    /* name, signature, funcPtr */
2540
2541    { "loadDriverNative", "()Z",  (void *)android_net_wifi_loadDriver },
2542    { "isDriverLoadedNative", "()Z",  (void *)android_net_wifi_isDriverLoaded },
2543    { "unloadDriverNative", "()Z",  (void *)android_net_wifi_unloadDriver },
2544    { "startSupplicantNative", "(Z)Z",  (void *)android_net_wifi_startSupplicant },
2545    { "killSupplicantNative", "(Z)Z",  (void *)android_net_wifi_killSupplicant },
2546    { "connectToSupplicantNative", "()Z", (void *)android_net_wifi_connectToSupplicant },
2547    { "closeSupplicantConnectionNative", "()V",
2548            (void *)android_net_wifi_closeSupplicantConnection },
2549    { "waitForEventNative", "()Ljava/lang/String;", (void*)android_net_wifi_waitForEvent },
2550    { "doBooleanCommandNative", "(Ljava/lang/String;)Z", (void*)android_net_wifi_doBooleanCommand },
2551    { "doIntCommandNative", "(Ljava/lang/String;)I", (void*)android_net_wifi_doIntCommand },
2552    { "doStringCommandNative", "(Ljava/lang/String;)Ljava/lang/String;",
2553            (void*) android_net_wifi_doStringCommand },
2554    { "startHalNative", "()Z", (void*) android_net_wifi_startHal },
2555    { "stopHalNative", "()V", (void*) android_net_wifi_stopHal },
2556    { "waitForHalEventNative", "()V", (void*) android_net_wifi_waitForHalEvents },
2557    { "getInterfacesNative", "()I", (void*) android_net_wifi_getInterfaces},
2558    { "getInterfaceNameNative", "(I)Ljava/lang/String;", (void*) android_net_wifi_getInterfaceName},
2559    { "getScanCapabilitiesNative", "(ILcom/android/server/wifi/WifiNative$ScanCapabilities;)Z",
2560            (void *) android_net_wifi_getScanCapabilities},
2561    { "startScanNative", "(IILcom/android/server/wifi/WifiNative$ScanSettings;)Z",
2562            (void*) android_net_wifi_startScan},
2563    { "stopScanNative", "(II)Z", (void*) android_net_wifi_stopScan},
2564    { "getScanResultsNative", "(IZ)[Landroid/net/wifi/WifiScanner$ScanData;",
2565            (void *) android_net_wifi_getScanResults},
2566    { "setHotlistNative", "(IILandroid/net/wifi/WifiScanner$HotlistSettings;)Z",
2567            (void*) android_net_wifi_setHotlist},
2568    { "resetHotlistNative", "(II)Z", (void*) android_net_wifi_resetHotlist},
2569    { "trackSignificantWifiChangeNative", "(IILandroid/net/wifi/WifiScanner$WifiChangeSettings;)Z",
2570            (void*) android_net_wifi_trackSignificantWifiChange},
2571    { "untrackSignificantWifiChangeNative", "(II)Z",
2572            (void*) android_net_wifi_untrackSignificantWifiChange},
2573    { "getWifiLinkLayerStatsNative", "(I)Landroid/net/wifi/WifiLinkLayerStats;",
2574            (void*) android_net_wifi_getLinkLayerStats},
2575    { "setWifiLinkLayerStatsNative", "(II)V",
2576            (void*) android_net_wifi_setLinkLayerStats},
2577    { "getSupportedFeatureSetNative", "(I)I",
2578            (void*) android_net_wifi_getSupportedFeatures},
2579    { "requestRangeNative", "(II[Landroid/net/wifi/RttManager$RttParams;)Z",
2580            (void*) android_net_wifi_requestRange},
2581    { "cancelRangeRequestNative", "(II[Landroid/net/wifi/RttManager$RttParams;)Z",
2582            (void*) android_net_wifi_cancelRange},
2583    { "enableRttResponderNative",
2584        "(IIILcom/android/server/wifi/WifiNative$WifiChannelInfo;)Landroid/net/wifi/RttManager$ResponderConfig;",
2585            (void*) android_net_wifi_enableResponder},
2586    { "disableRttResponderNative", "(II)Z",
2587            (void*) android_net_wifi_disableResponder},
2588
2589    { "setScanningMacOuiNative", "(I[B)Z",  (void*) android_net_wifi_setScanningMacOui},
2590    { "getChannelsForBandNative", "(II)[I", (void*) android_net_wifi_getValidChannels},
2591    { "setDfsFlagNative",         "(IZ)Z",  (void*) android_net_wifi_setDfsFlag},
2592    { "setInterfaceUpNative", "(Z)Z",  (void*) android_net_wifi_set_interface_up},
2593    { "getRttCapabilitiesNative", "(I)Landroid/net/wifi/RttManager$RttCapabilities;",
2594            (void*) android_net_wifi_get_rtt_capabilities},
2595    { "getApfCapabilitiesNative", "(I)Landroid/net/apf/ApfCapabilities;",
2596            (void*) android_net_wifi_get_apf_capabilities},
2597    { "installPacketFilterNative", "(I[B)Z", (void*) android_net_wifi_install_packet_filter},
2598    {"setCountryCodeHalNative", "(ILjava/lang/String;)Z",
2599            (void*) android_net_wifi_set_Country_Code_Hal},
2600    { "setPnoListNative", "(IILcom/android/server/wifi/WifiNative$PnoSettings;)Z",
2601            (void*) android_net_wifi_setPnoListNative},
2602    { "resetPnoListNative", "(II)Z", (void*) android_net_wifi_resetPnoListNative},
2603    {"enableDisableTdlsNative", "(IZLjava/lang/String;)Z",
2604            (void*) android_net_wifi_enable_disable_tdls},
2605    {"getTdlsStatusNative", "(ILjava/lang/String;)Lcom/android/server/wifi/WifiNative$TdlsStatus;",
2606            (void*) android_net_wifi_get_tdls_status},
2607    {"getTdlsCapabilitiesNative", "(I)Lcom/android/server/wifi/WifiNative$TdlsCapabilities;",
2608            (void*) android_net_wifi_get_tdls_capabilities},
2609    {"getSupportedLoggerFeatureSetNative","(I)I",
2610            (void*) android_net_wifi_get_supported_logger_feature},
2611    {"getDriverVersionNative", "(I)Ljava/lang/String;",
2612            (void*) android_net_wifi_get_driver_version},
2613    {"getFirmwareVersionNative", "(I)Ljava/lang/String;",
2614            (void*) android_net_wifi_get_firmware_version},
2615    {"getRingBufferStatusNative", "(I)[Lcom/android/server/wifi/WifiNative$RingBufferStatus;",
2616            (void*) android_net_wifi_get_ring_buffer_status},
2617    {"startLoggingRingBufferNative", "(IIIIILjava/lang/String;)Z",
2618            (void*) android_net_wifi_start_logging_ring_buffer},
2619    {"getRingBufferDataNative", "(ILjava/lang/String;)Z",
2620            (void*) android_net_wifi_get_ring_buffer_data},
2621    {"getFwMemoryDumpNative","(I)Z", (void*) android_net_wifi_get_fw_memory_dump},
2622    {"getDriverStateDumpNative","(I)[B", (void*) android_net_wifi_get_driver_state_dump},
2623    { "setBssidBlacklistNative", "(II[Ljava/lang/String;)Z",
2624            (void*)android_net_wifi_setBssidBlacklist},
2625    {"setLoggingEventHandlerNative", "(II)Z", (void *) android_net_wifi_set_log_handler},
2626    {"resetLogHandlerNative", "(II)Z", (void *) android_net_wifi_reset_log_handler},
2627    {"startPktFateMonitoringNative", "(I)I", (void*) android_net_wifi_start_pkt_fate_monitoring},
2628    {"getTxPktFatesNative", "(I[Lcom/android/server/wifi/WifiNative$TxFateReport;)I",
2629            (void*) android_net_wifi_get_tx_pkt_fates},
2630    {"getRxPktFatesNative", "(I[Lcom/android/server/wifi/WifiNative$RxFateReport;)I",
2631            (void*) android_net_wifi_get_rx_pkt_fates},
2632    { "startSendingOffloadedPacketNative", "(II[B[B[BI)I",
2633             (void*)android_net_wifi_start_sending_offloaded_packet},
2634    { "stopSendingOffloadedPacketNative", "(II)I",
2635             (void*)android_net_wifi_stop_sending_offloaded_packet},
2636    {"startRssiMonitoringNative", "(IIBB)I",
2637            (void*)android_net_wifi_start_rssi_monitoring_native},
2638    {"stopRssiMonitoringNative", "(II)I",
2639            (void*)android_net_wifi_stop_rssi_monitoring_native},
2640    { "getWlanWakeReasonCountNative", "(I)Landroid/net/wifi/WifiWakeReasonAndCounts;",
2641            (void*) android_net_wifi_get_wlan_wake_reason_count},
2642    {"isGetChannelsForBandSupportedNative", "()Z",
2643            (void*)android_net_wifi_is_get_channels_for_band_supported},
2644    {"readKernelLogNative", "()[B", (void*)android_net_wifi_readKernelLog},
2645    {"configureNeighborDiscoveryOffload", "(IZ)I", (void*)android_net_wifi_configure_nd_offload},
2646};
2647
2648/* User to register native functions */
2649extern "C"
2650jint Java_com_android_server_wifi_WifiNative_registerNatives(JNIEnv* env, jclass clazz) {
2651    // initialization needed for unit test APK
2652    JniConstants::init(env);
2653
2654    return jniRegisterNativeMethods(env,
2655            "com/android/server/wifi/WifiNative", gWifiMethods, NELEM(gWifiMethods));
2656}
2657
2658}; // namespace android
2659