• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package com.android.server.wifi;
18 
19 import android.content.Context;
20 import android.net.wifi.WifiConfiguration;
21 import android.net.wifi.WifiConfiguration.KeyMgmt;
22 import android.os.Environment;
23 import android.os.Handler;
24 import android.os.Message;
25 import android.os.Messenger;
26 import android.util.Log;
27 
28 import com.android.internal.util.AsyncChannel;
29 import com.android.internal.R;
30 import com.android.internal.util.State;
31 import com.android.internal.util.StateMachine;
32 
33 import java.io.BufferedInputStream;
34 import java.io.BufferedOutputStream;
35 import java.io.DataInputStream;
36 import java.io.DataOutputStream;
37 import java.io.FileInputStream;
38 import java.io.FileOutputStream;
39 import java.io.IOException;
40 import java.util.UUID;
41 
42 /**
43  * Provides API to the WifiStateMachine for doing read/write access
44  * to soft access point configuration
45  */
46 class 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 = 1;
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 
WifiApConfigStore(Context context, Handler target)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 
makeWifiApConfigStore(Context context, Handler target)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 {
processMessage(Message message)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 {
processMessage(Message message)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 = (WifiConfiguration) message.obj;
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 {
enter()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 
processMessage(Message message)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 
loadApConfiguration()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) {
154                 Log.e(TAG, "Bad version on hotspot configuration file, set defaults");
155                 setDefaultApConfiguration();
156                 return;
157             }
158             config.SSID = in.readUTF();
159             int authType = in.readInt();
160             config.allowedKeyManagement.set(authType);
161             if (authType != KeyMgmt.NONE) {
162                 config.preSharedKey = in.readUTF();
163             }
164             mWifiApConfig = config;
165         } catch (IOException ignore) {
166             setDefaultApConfiguration();
167         } finally {
168             if (in != null) {
169                 try {
170                     in.close();
171                 } catch (IOException e) {}
172             }
173         }
174     }
175 
getMessenger()176     Messenger getMessenger() {
177         return new Messenger(getHandler());
178     }
179 
writeApConfiguration(final WifiConfiguration config)180     private void writeApConfiguration(final WifiConfiguration config) {
181         DataOutputStream out = null;
182         try {
183             out = new DataOutputStream(new BufferedOutputStream(
184                         new FileOutputStream(AP_CONFIG_FILE)));
185 
186             out.writeInt(AP_CONFIG_FILE_VERSION);
187             out.writeUTF(config.SSID);
188             int authType = config.getAuthType();
189             out.writeInt(authType);
190             if(authType != KeyMgmt.NONE) {
191                 out.writeUTF(config.preSharedKey);
192             }
193         } catch (IOException e) {
194             Log.e(TAG, "Error writing hotspot configuration" + e);
195         } finally {
196             if (out != null) {
197                 try {
198                     out.close();
199                 } catch (IOException e) {}
200             }
201         }
202     }
203 
204     /* Generate a default WPA2 based configuration with a random password.
205        We are changing the Wifi Ap configuration storage from secure settings to a
206        flat file accessible only by the system. A WPA2 based default configuration
207        will keep the device secure after the update */
setDefaultApConfiguration()208     private void setDefaultApConfiguration() {
209         WifiConfiguration config = new WifiConfiguration();
210         config.SSID = mContext.getString(R.string.wifi_tether_configure_ssid_default);
211         config.allowedKeyManagement.set(KeyMgmt.WPA2_PSK);
212         String randomUUID = UUID.randomUUID().toString();
213         //first 12 chars from xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
214         config.preSharedKey = randomUUID.substring(0, 8) + randomUUID.substring(9,13);
215         sendMessage(WifiStateMachine.CMD_SET_AP_CONFIG, config);
216     }
217 }
218