WifiApConfigStore.java revision 0e8f0d87d62589d9dda54d5a4941d0309e3ecf2a
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.content.Context; 20import android.net.wifi.WifiConfiguration; 21import android.net.wifi.WifiConfiguration.KeyMgmt; 22import android.os.Environment; 23import android.os.Handler; 24import android.os.Message; 25import android.os.Messenger; 26import android.util.Log; 27 28import com.android.internal.util.AsyncChannel; 29import com.android.internal.R; 30import com.android.internal.util.State; 31import com.android.internal.util.StateMachine; 32 33import java.io.BufferedInputStream; 34import java.io.BufferedOutputStream; 35import java.io.DataInputStream; 36import java.io.DataOutputStream; 37import java.io.FileInputStream; 38import java.io.FileOutputStream; 39import java.io.IOException; 40import java.util.UUID; 41 42/** 43 * Provides API to the WifiStateMachine for doing read/write access 44 * to soft access point configuration 45 */ 46class WifiApConfigStore extends StateMachine { 47 48 private Context mContext; 49 private static final String TAG = "WifiApConfigStore"; 50 51 private static final String AP_CONFIG_FILE = Environment.getDataDirectory() + 52 "/misc/wifi/softap.conf"; 53 54 private static final int AP_CONFIG_FILE_VERSION = 2; 55 56 private State mDefaultState = new DefaultState(); 57 private State mInactiveState = new InactiveState(); 58 private State mActiveState = new ActiveState(); 59 60 private WifiConfiguration mWifiApConfig = null; 61 private AsyncChannel mReplyChannel = new AsyncChannel(); 62 63 WifiApConfigStore(Context context, Handler target) { 64 super(TAG, target.getLooper()); 65 66 mContext = context; 67 addState(mDefaultState); 68 addState(mInactiveState, mDefaultState); 69 addState(mActiveState, mDefaultState); 70 71 setInitialState(mInactiveState); 72 } 73 74 public static WifiApConfigStore makeWifiApConfigStore(Context context, Handler target) { 75 WifiApConfigStore s = new WifiApConfigStore(context, target); 76 s.start(); 77 return s; 78 } 79 80 class DefaultState extends State { 81 public boolean processMessage(Message message) { 82 switch (message.what) { 83 case WifiStateMachine.CMD_SET_AP_CONFIG: 84 case WifiStateMachine.CMD_SET_AP_CONFIG_COMPLETED: 85 Log.e(TAG, "Unexpected message: " + message); 86 break; 87 case WifiStateMachine.CMD_REQUEST_AP_CONFIG: 88 mReplyChannel.replyToMessage(message, 89 WifiStateMachine.CMD_RESPONSE_AP_CONFIG, mWifiApConfig); 90 break; 91 default: 92 Log.e(TAG, "Failed to handle " + message); 93 break; 94 } 95 return HANDLED; 96 } 97 } 98 99 class InactiveState extends State { 100 public boolean processMessage(Message message) { 101 switch (message.what) { 102 case WifiStateMachine.CMD_SET_AP_CONFIG: 103 WifiConfiguration config = (WifiConfiguration)message.obj; 104 if (config.SSID != null) { 105 mWifiApConfig = config; 106 transitionTo(mActiveState); 107 } else { 108 Log.e(TAG, "Try to setup AP config without SSID: " + message); 109 } 110 break; 111 default: 112 return NOT_HANDLED; 113 } 114 return HANDLED; 115 } 116 } 117 118 class ActiveState extends State { 119 public void enter() { 120 new Thread(new Runnable() { 121 public void run() { 122 writeApConfiguration(mWifiApConfig); 123 sendMessage(WifiStateMachine.CMD_SET_AP_CONFIG_COMPLETED); 124 } 125 }).start(); 126 } 127 128 public boolean processMessage(Message message) { 129 switch (message.what) { 130 //TODO: have feedback to the user when we do this 131 //to indicate the write is currently in progress 132 case WifiStateMachine.CMD_SET_AP_CONFIG: 133 deferMessage(message); 134 break; 135 case WifiStateMachine.CMD_SET_AP_CONFIG_COMPLETED: 136 transitionTo(mInactiveState); 137 break; 138 default: 139 return NOT_HANDLED; 140 } 141 return HANDLED; 142 } 143 } 144 145 void loadApConfiguration() { 146 DataInputStream in = null; 147 try { 148 WifiConfiguration config = new WifiConfiguration(); 149 in = new DataInputStream(new BufferedInputStream(new FileInputStream( 150 AP_CONFIG_FILE))); 151 152 int version = in.readInt(); 153 if ((version != 1) && (version != 2)) { 154 Log.e(TAG, "Bad version on hotspot configuration file, set defaults"); 155 setDefaultApConfiguration(); 156 return; 157 } 158 config.SSID = in.readUTF(); 159 160 if (version >= 2) { 161 config.apBand = in.readInt(); 162 config.apChannel = in.readInt(); 163 } 164 165 int authType = in.readInt(); 166 config.allowedKeyManagement.set(authType); 167 if (authType != KeyMgmt.NONE) { 168 config.preSharedKey = in.readUTF(); 169 } 170 mWifiApConfig = config; 171 } catch (IOException ignore) { 172 setDefaultApConfiguration(); 173 } finally { 174 if (in != null) { 175 try { 176 in.close(); 177 } catch (IOException e) {} 178 } 179 } 180 } 181 182 Messenger getMessenger() { 183 return new Messenger(getHandler()); 184 } 185 186 private void writeApConfiguration(final WifiConfiguration config) { 187 DataOutputStream out = null; 188 try { 189 out = new DataOutputStream(new BufferedOutputStream( 190 new FileOutputStream(AP_CONFIG_FILE))); 191 192 out.writeInt(AP_CONFIG_FILE_VERSION); 193 out.writeUTF(config.SSID); 194 out.writeInt(config.apBand); 195 out.writeInt(config.apChannel); 196 int authType = config.getAuthType(); 197 out.writeInt(authType); 198 if(authType != KeyMgmt.NONE) { 199 out.writeUTF(config.preSharedKey); 200 } 201 } catch (IOException e) { 202 Log.e(TAG, "Error writing hotspot configuration" + e); 203 } finally { 204 if (out != null) { 205 try { 206 out.close(); 207 } catch (IOException e) {} 208 } 209 } 210 } 211 212 /* Generate a default WPA2 based configuration with a random password. 213 We are changing the Wifi Ap configuration storage from secure settings to a 214 flat file accessible only by the system. A WPA2 based default configuration 215 will keep the device secure after the update */ 216 private void setDefaultApConfiguration() { 217 WifiConfiguration config = new WifiConfiguration(); 218 config.SSID = mContext.getString(R.string.wifi_tether_configure_ssid_default); 219 config.allowedKeyManagement.set(KeyMgmt.WPA2_PSK); 220 String randomUUID = UUID.randomUUID().toString(); 221 //first 12 chars from xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx 222 config.preSharedKey = randomUUID.substring(0, 8) + randomUUID.substring(9,13); 223 sendMessage(WifiStateMachine.CMD_SET_AP_CONFIG, config); 224 } 225} 226