WifiApConfigStore.java revision c11476cd6b68ba6c5b34c99ea312c45e18a17658
1/*
2 * Copyright (C) 2010 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.app.backup.BackupManager;
20import android.content.Context;
21import android.net.wifi.WifiConfiguration;
22import android.net.wifi.WifiConfiguration.KeyMgmt;
23import android.os.Environment;
24import android.util.Log;
25
26import com.android.internal.R;
27
28import java.io.BufferedInputStream;
29import java.io.BufferedOutputStream;
30import java.io.DataInputStream;
31import java.io.DataOutputStream;
32import java.io.FileInputStream;
33import java.io.FileOutputStream;
34import java.io.IOException;
35import java.util.ArrayList;
36import java.util.UUID;
37
38/**
39 * Provides API for reading/writing soft access point configuration.
40 */
41public class WifiApConfigStore {
42
43    private static final String TAG = "WifiApConfigStore";
44
45    private static final String DEFAULT_AP_CONFIG_FILE =
46            Environment.getDataDirectory() + "/misc/wifi/softap.conf";
47
48    private static final int AP_CONFIG_FILE_VERSION = 2;
49
50    private WifiConfiguration mWifiApConfig = null;
51
52    private ArrayList<Integer> mAllowed2GChannel = null;
53
54    private final Context mContext;
55    private final String mApConfigFile;
56
57    WifiApConfigStore(Context context) {
58        this(context, DEFAULT_AP_CONFIG_FILE);
59    }
60
61    WifiApConfigStore(Context context, String apConfigFile) {
62        mContext = context;
63        mApConfigFile = apConfigFile;
64
65        String ap2GChannelListStr = mContext.getResources().getString(
66                R.string.config_wifi_framework_sap_2G_channel_list);
67        Log.d(TAG, "2G band allowed channels are:" + ap2GChannelListStr);
68
69        if (ap2GChannelListStr != null) {
70            mAllowed2GChannel = new ArrayList<Integer>();
71            String channelList[] = ap2GChannelListStr.split(",");
72            for (String tmp : channelList) {
73                mAllowed2GChannel.add(Integer.parseInt(tmp));
74            }
75        }
76
77        /* Load AP configuration from persistent storage. */
78        mWifiApConfig = loadApConfiguration(mApConfigFile);
79        if (mWifiApConfig == null) {
80            /* Use default configuration. */
81            Log.d(TAG, "Fallback to use default AP configuration");
82            mWifiApConfig = getDefaultApConfiguration();
83
84            /* Save the default configuration to persistent storage. */
85            writeApConfiguration(mApConfigFile, mWifiApConfig);
86        }
87    }
88
89    /**
90     * Return the current soft access point configuration.
91     */
92    public synchronized WifiConfiguration getApConfiguration() {
93        return mWifiApConfig;
94    }
95
96    /**
97     * Update the current soft access point configuration.
98     * Restore to default AP configuration if null is provided.
99     * This can be invoked under context of binder threads (WifiManager.setWifiApConfiguration)
100     * and WifiStateMachine thread (CMD_START_AP).
101     */
102    public synchronized void setApConfiguration(WifiConfiguration config) {
103        if (config == null) {
104            mWifiApConfig = getDefaultApConfiguration();
105        } else {
106            mWifiApConfig = config;
107        }
108        writeApConfiguration(mApConfigFile, mWifiApConfig);
109        // Stage the backup of the SettingsProvider package which backs this up
110        BackupManager.dataChanged("com.android.providers.settings");
111    }
112
113    public ArrayList<Integer> getAllowed2GChannel() {
114        return mAllowed2GChannel;
115    }
116
117    /**
118     * Load AP configuration from persistent storage.
119     */
120    private static WifiConfiguration loadApConfiguration(final String filename) {
121        WifiConfiguration config = null;
122        DataInputStream in = null;
123        try {
124            config = new WifiConfiguration();
125            in = new DataInputStream(
126                    new BufferedInputStream(new FileInputStream(filename)));
127
128            int version = in.readInt();
129            if ((version != 1) && (version != 2)) {
130                Log.e(TAG, "Bad version on hotspot configuration file");
131                return null;
132            }
133            config.SSID = in.readUTF();
134
135            if (version >= 2) {
136                config.apBand = in.readInt();
137                config.apChannel = in.readInt();
138            }
139
140            int authType = in.readInt();
141            config.allowedKeyManagement.set(authType);
142            if (authType != KeyMgmt.NONE) {
143                config.preSharedKey = in.readUTF();
144            }
145        } catch (IOException e) {
146            Log.e(TAG, "Error reading hotspot configuration " + e);
147            config = null;
148        } finally {
149            if (in != null) {
150                try {
151                    in.close();
152                } catch (IOException e) {
153                    Log.e(TAG, "Error closing hotspot configuration during read" + e);
154                }
155            }
156        }
157        return config;
158    }
159
160    /**
161     * Write AP configuration to persistent storage.
162     */
163    private static boolean writeApConfiguration(final String filename,
164                                                final WifiConfiguration config) {
165        DataOutputStream out = null;
166        try {
167            out = new DataOutputStream(new BufferedOutputStream(
168                        new FileOutputStream(filename)));
169
170            out.writeInt(AP_CONFIG_FILE_VERSION);
171            out.writeUTF(config.SSID);
172            out.writeInt(config.apBand);
173            out.writeInt(config.apChannel);
174            int authType = config.getAuthType();
175            out.writeInt(authType);
176            if (authType != KeyMgmt.NONE) {
177                out.writeUTF(config.preSharedKey);
178            }
179        } catch (IOException e) {
180            Log.e(TAG, "Error writing hotspot configuration" + e);
181            return false;
182        } finally {
183            if (out != null) {
184                try {
185                    out.close();
186                } catch (IOException e) {
187                    Log.e(TAG, "Error closing hotspot configuration during write" + e);
188                    return false;
189                }
190            }
191        }
192        return true;
193    }
194
195    /**
196     * Generate a default WPA2 based configuration with a random password.
197     * We are changing the Wifi Ap configuration storage from secure settings to a
198     * flat file accessible only by the system. A WPA2 based default configuration
199     * will keep the device secure after the update.
200     */
201    private WifiConfiguration getDefaultApConfiguration() {
202        WifiConfiguration config = new WifiConfiguration();
203        config.SSID = mContext.getResources().getString(
204                R.string.wifi_tether_configure_ssid_default);
205        config.allowedKeyManagement.set(KeyMgmt.WPA2_PSK);
206        String randomUUID = UUID.randomUUID().toString();
207        //first 12 chars from xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
208        config.preSharedKey = randomUUID.substring(0, 8) + randomUUID.substring(9, 13);
209        return config;
210    }
211}
212