1/*
2 * Copyright (C) 2015 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
17package com.android.server.wifi;
18
19import android.os.Bundle;
20import android.util.Log;
21
22import com.android.server.wifi.WifiNative;
23
24import org.json.JSONArray;
25import org.json.JSONException;
26import org.json.JSONObject;
27
28import java.lang.reflect.Field;
29import java.util.Iterator;
30
31public class HalMockUtils {
32    private static final String TAG = "HalMockUtils";
33    private static final boolean DBG = true;
34    private static final boolean VDBG = true;
35
36    private static native int initHalMock();
37
38    public static native void setHalMockObject(Object obj);
39
40    static {
41        System.loadLibrary("wifi-hal-mock");
42    }
43
44    public static void initHalMockLibrary() throws Exception {
45        /*
46         * Setting the Wi-Fi HAL handle and interface (array) to dummy
47         * values. Required to fake the init checking code to think that
48         * the HAL actually started.
49         *
50         * Note that values are not important since they are only used by
51         * the real HAL - which is mocked-out in this use-case.
52         */
53        Field field = WifiNative.class.getDeclaredField("sWifiHalHandle");
54        field.setAccessible(true);
55        long currentWifiHalHandle = field.getLong(null);
56        if (DBG) Log.d(TAG, "currentWifiHalHandle=" + currentWifiHalHandle);
57        if (currentWifiHalHandle == 0) {
58            field.setLong(null, 5);
59
60            field = WifiNative.class.getDeclaredField("sWifiIfaceHandles");
61            field.setAccessible(true);
62            long[] wifiIfaceHandles = {
63                    10 };
64            field.set(null, wifiIfaceHandles);
65        }
66
67        initHalMock();
68    }
69
70    /*
71     * JSON data-model for passing arguments between mock host (java) and mock
72     * HAL (C):
73     * {
74     *      "name" : { "type" : "int|byte_array", "value" : 123 | [1, 2, 3, 4] }
75     * }
76     */
77
78    private static final String TYPE_KEY = "type";
79    private static final String VALUE_KEY = "value";
80
81    private static final String TYPE_INT = "int";
82    private static final String TYPE_BYTE_ARRAY = "byte_array";
83
84    public static Bundle convertJsonToBundle(String jsonArgs) throws JSONException {
85        if (VDBG) Log.v(TAG, "convertJsonToBundle: jsonArgs=" + jsonArgs);
86
87        Bundle bundle = new Bundle();
88
89        JSONObject jsonObject = new JSONObject(jsonArgs);
90        Iterator<String> iter = jsonObject.keys();
91        while (iter.hasNext()) {
92            String key = iter.next();
93            JSONObject field = jsonObject.optJSONObject(key);
94
95            String type = field.getString(TYPE_KEY);
96
97            if (TYPE_INT.equals(type)) {
98                bundle.putInt(key, field.optInt(VALUE_KEY));
99            } else if (TYPE_BYTE_ARRAY.equals(type)) {
100                JSONArray array = field.optJSONArray(VALUE_KEY);
101                byte[] bArray = new byte[array.length()];
102                for (int i = 0; i < array.length(); ++i) {
103                    bArray[i] = (byte) array.getInt(i);
104                }
105                bundle.putByteArray(key, bArray);
106            } else {
107                throw new JSONException("Unexpected TYPE read from mock HAL -- '" + type + "'");
108            }
109        }
110
111        if (DBG) Log.d(TAG, "convertJsonToBundle: returning bundle=" + bundle);
112        return bundle;
113    }
114
115    public static JSONObject convertBundleToJson(Bundle bundle) throws JSONException {
116        if (VDBG) Log.v(TAG, "convertBundleToJson: bundle=" + bundle.toString());
117
118        JSONObject json = new JSONObject();
119        for (String key : bundle.keySet()) {
120            Object value = bundle.get(key);
121            JSONObject child = new JSONObject();
122            if (value instanceof Integer) {
123                child.put(TYPE_KEY, TYPE_INT);
124                child.put(VALUE_KEY, ((Integer) value).intValue());
125            } else if (value instanceof byte[]) {
126                byte[] array = (byte[]) value;
127                JSONArray jsonArray = new JSONArray();
128                for (int i = 0; i < array.length; ++i) {
129                    jsonArray.put(array[i]);
130                }
131                child.put(TYPE_KEY, TYPE_BYTE_ARRAY);
132                child.put(VALUE_KEY, jsonArray);
133            } else {
134                throw new JSONException("Unexpected type of JSON tree node (not an Integer "
135                        + "or byte[]): " + value);
136            }
137            json.put(key, child);
138        }
139
140        if (DBG) Log.d(TAG, "convertBundleToJson: returning JSONObject=" + json);
141        return json;
142    }
143}
144