10701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvistpackage com.android.hotspot2.osu;
20701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
30701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvistimport android.content.Context;
40701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvistimport android.content.Intent;
50701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvistimport android.net.Network;
60701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvistimport android.net.wifi.WifiConfiguration;
70701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvistimport android.net.wifi.WifiInfo;
80701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvistimport android.os.SystemClock;
90701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvistimport android.util.Log;
100701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
110701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvistimport com.android.hotspot2.Utils;
120701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvistimport com.android.hotspot2.flow.FlowService;
130701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvistimport com.android.hotspot2.flow.OSUInfo;
140701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvistimport com.android.hotspot2.flow.PlatformAdapter;
150701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvistimport com.android.hotspot2.pps.HomeSP;
160701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
170701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvistimport java.io.IOException;
180701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvistimport java.net.MalformedURLException;
190701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvistimport java.util.Iterator;
200701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvistimport java.util.LinkedList;
210701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
220701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvistimport javax.net.ssl.KeyManager;
230701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
240701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvistpublic class OSUFlowManager {
250701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist    private static final boolean MATCH_BSSID = false;
260701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist    private static final long WAIT_QUANTA = 10000L;
270701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist    private static final long WAIT_TIMEOUT = 1800000L;
280701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
290701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist    private final Context mContext;
300701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist    private final LinkedList<OSUFlow> mQueue;
310701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist    private FlowWorker mWorker;
320701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist    private OSUFlow mCurrent;
330701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
340701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist    public OSUFlowManager(Context context) {
350701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        mContext = context;
360701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        mQueue = new LinkedList<>();
370701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist    }
380701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
390701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist    public enum FlowType {Provisioning, Remediation, Policy}
400701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
410701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist    public static class OSUFlow implements Runnable {
420701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        private final OSUClient mOSUClient;
430701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        private final PlatformAdapter mPlatformAdapter;
440701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        private final HomeSP mHomeSP;
450701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        private final String mSpName;
460701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        private final FlowType mFlowType;
470701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        private final KeyManager mKeyManager;
480701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        private final Object mNetworkLock = new Object();
490701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        private final Network mNetwork;
500701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        private Network mResultNetwork;
510701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        private boolean mNetworkCreated;
520701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        private int mWifiNetworkId;
530701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        private volatile long mLaunchTime;
540701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        private volatile boolean mAborted;
550701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
560701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        /**
570701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist         * A policy flow.
580701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist         * @param osuInfo The OSU information for the flow (SSID, BSSID, URL)
590701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist         * @param platformAdapter the platform adapter
600701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist         * @param km A key manager for TLS
610701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist         * @throws MalformedURLException
620701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist         */
630701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        public OSUFlow(OSUInfo osuInfo, PlatformAdapter platformAdapter, KeyManager km)
640701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                throws MalformedURLException {
650701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
660701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            mWifiNetworkId = -1;
670701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            mNetwork = null;
680701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            mOSUClient = new OSUClient(osuInfo,
690701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                    platformAdapter.getKeyStore(), platformAdapter.getContext());
700701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            mPlatformAdapter = platformAdapter;
710701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            mHomeSP = null;
720701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            mSpName = osuInfo.getName(OSUManager.LOCALE);
730701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            mFlowType = FlowType.Provisioning;
740701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            mKeyManager = km;
750701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        }
760701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
770701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        /**
780701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist         * A Remediation flow for credential or policy provisioning.
790701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist         * @param network The network to use, only set for timed provisioning
800701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist         * @param osuURL The URL to connect to.
810701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist         * @param platformAdapter the platform adapter
820701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist         * @param km A key manager for TLS
830701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist         * @param homeSP The Home SP to which this remediation flow pertains.
840701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist         * @param flowType Remediation or Policy
850701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist         * @throws MalformedURLException
860701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist         */
870701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        public OSUFlow(Network network, String osuURL,
880701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                       PlatformAdapter platformAdapter, KeyManager km, HomeSP homeSP,
890701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                       FlowType flowType) throws MalformedURLException {
900701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
910701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            mNetwork = network;
920701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            mWifiNetworkId = network.netId;
930701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            mOSUClient = new OSUClient(osuURL,
940701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                    platformAdapter.getKeyStore(), platformAdapter.getContext());
950701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            mPlatformAdapter = platformAdapter;
960701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            mHomeSP = homeSP;
970701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            mSpName = homeSP.getFriendlyName();
980701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            mFlowType = flowType;
990701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            mKeyManager = km;
1000701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        }
1010701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
1020701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        private boolean deleteNetwork(OSUFlow next) {
1030701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            synchronized (mNetworkLock) {
1040701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                if (!mNetworkCreated) {
1050701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                    return false;
1060701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                } else if (next.getFlowType() != FlowType.Provisioning) {
1070701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                    return true;
1080701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                }
1090701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                OSUInfo thisInfo = mOSUClient.getOSUInfo();
1100701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                OSUInfo thatInfo = next.mOSUClient.getOSUInfo();
1110701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                if (thisInfo.getOsuSsid().equals(thatInfo.getOsuSsid())
1120701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                        && thisInfo.getOSUBssid() == thatInfo.getOSUBssid()) {
1130701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                    // Reuse the OSU network from previous and carry forward the creation fact.
1140701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                    mNetworkCreated = true;
1150701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                    return false;
1160701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                } else {
1170701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                    return true;
1180701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                }
1190701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            }
1200701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        }
1210701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
1220701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        private Network connect() throws IOException {
1230701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            Network network = networkMatch();
1240701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
1250701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            synchronized (mNetworkLock) {
1260701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                mResultNetwork = network;
1270701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                if (mResultNetwork != null) {
1280701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                    return mResultNetwork;
1290701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                }
1300701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            }
1310701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
1320701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            Log.d(OSUManager.TAG, "No network match for " + toString());
1330701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
1340701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            int osuNetworkId = -1;
1350701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            boolean created = false;
1360701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
1370701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            if (mFlowType == FlowType.Provisioning) {
1380701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                osuNetworkId = mPlatformAdapter.connect(mOSUClient.getOSUInfo());
1390701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                created = true;
1400701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            }
1410701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
1420701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            synchronized (mNetworkLock) {
1430701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                mNetworkCreated = created;
1440701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                if (created) {
1450701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                    mWifiNetworkId = osuNetworkId;
1460701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                }
1470701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                Log.d(OSUManager.TAG, String.format("%s waiting for %snet ID %d",
1480701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                        toString(), created ? "created " : "existing ", osuNetworkId));
1490701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
1500701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                while (mResultNetwork == null && !mAborted) {
1510701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                    try {
1520701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                        mNetworkLock.wait();
1530701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                    } catch (InterruptedException ie) {
1540701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                        throw new IOException("Interrupted");
1550701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                    }
1560701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                }
1570701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                if (mAborted) {
1580701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                    throw new IOException("Aborted");
1590701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                }
1600701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                Utils.delay(500L);
1610701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            }
1620701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            return mResultNetwork;
1630701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        }
1640701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
1650701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        private Network networkMatch() {
1660701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            if (mFlowType == FlowType.Provisioning) {
1670701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                OSUInfo match = mOSUClient.getOSUInfo();
1680701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                WifiConfiguration config = mPlatformAdapter.getActiveWifiConfig();
1690701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                if (config != null && bssidMatch(match, mPlatformAdapter)
1700701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                        && Utils.decodeSsid(config.SSID).equals(match.getOsuSsid())) {
1710701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                    synchronized (mNetworkLock) {
1720701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                        mWifiNetworkId = config.networkId;
1730701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                    }
1740701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                    return mPlatformAdapter.getCurrentNetwork();
1750701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                }
1760701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            } else {
1770701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                WifiConfiguration config = mPlatformAdapter.getActiveWifiConfig();
1780701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                synchronized (mNetworkLock) {
1790701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                    mWifiNetworkId = config != null ? config.networkId : -1;
1800701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                }
1810701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                return mNetwork;
1820701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            }
1830701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            return null;
1840701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        }
1850701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
1860701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        private void networkChange() {
1870701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            WifiInfo connectionInfo = mPlatformAdapter.getConnectionInfo();
1880701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            if (connectionInfo == null) {
1890701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                return;
1900701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            }
1910701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            Network network = mPlatformAdapter.getCurrentNetwork();
1920701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            Log.d(OSUManager.TAG, "New network " + network
1930701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                    + ", current OSU " + mOSUClient.getOSUInfo() +
1940701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                    ", addr " + Utils.toIpString(connectionInfo.getIpAddress()));
1950701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
1960701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            synchronized (mNetworkLock) {
1970701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                if (mResultNetwork == null && network != null && connectionInfo.getIpAddress() != 0
1980701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                        && connectionInfo.getNetworkId() == mWifiNetworkId) {
1990701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                    mResultNetwork = network;
2000701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                    mNetworkLock.notifyAll();
2010701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                }
2020701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            }
2030701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        }
2040701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
2050701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        public boolean createdNetwork() {
2060701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            synchronized (mNetworkLock) {
2070701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                return mNetworkCreated;
2080701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            }
2090701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        }
2100701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
2110701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        public FlowType getFlowType() {
2120701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            return mFlowType;
2130701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        }
2140701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
2150701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        public PlatformAdapter getPlatformAdapter() {
2160701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            return mPlatformAdapter;
2170701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        }
2180701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
2190701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        private void setLaunchTime() {
2200701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            mLaunchTime = SystemClock.currentThreadTimeMillis();
2210701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        }
2220701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
2230701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        public long getLaunchTime() {
2240701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            return mLaunchTime;
2250701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        }
2260701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
2270701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        private int getWifiNetworkId() {
2280701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            synchronized (mNetworkLock) {
2290701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                return mWifiNetworkId;
2300701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            }
2310701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        }
2320701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
2330701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        @Override
2340701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        public void run() {
2350701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            try {
2360701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                Network network = connect();
2370701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                Log.d(OSUManager.TAG, "OSU SSID Associated at " + network);
2380701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
2390701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                if (mFlowType == FlowType.Provisioning) {
2400701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                    mOSUClient.provision(mPlatformAdapter, network, mKeyManager);
2410701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                } else {
2420701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                    mOSUClient.remediate(mPlatformAdapter, network,
2430701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                            mKeyManager, mHomeSP, mFlowType);
2440701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                }
2450701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            } catch (Throwable t) {
2460701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                if (mAborted) {
2470701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                    Log.d(OSUManager.TAG, "OSU flow aborted: " + t, t);
2480701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                } else {
2490701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                    Log.w(OSUManager.TAG, "OSU flow failed: " + t, t);
2500701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                    mPlatformAdapter.provisioningFailed(mSpName, t.getMessage());
2510701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                }
2520701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            } finally {
2530701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                if (!mAborted) {
2540701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                    mOSUClient.close(false);
2550701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                }
2560701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            }
2570701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        }
2580701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
2590701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        public void abort() {
2600701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            synchronized (mNetworkLock) {
2610701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                mAborted = true;
2620701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                mNetworkLock.notifyAll();
2630701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            }
2640701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            // Sockets cannot be closed on the main thread...
2650701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            // TODO: Might want to change this to a handler.
2660701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            new Thread() {
2670701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                @Override
2680701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                public void run() {
2690701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                    try {
2700701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                        mOSUClient.close(true);
2710701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                    } catch (Throwable t) {
2720701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                        Log.d(OSUManager.TAG, "Exception aborting " + toString());
2730701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                    }
2740701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                }
2750701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            }.start();
2760701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        }
2770701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
2780701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        @Override
2790701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        public String toString() {
2800701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            return mFlowType + " for " + mSpName;
2810701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        }
2820701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist    }
2830701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
2840701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist    private class FlowWorker extends Thread {
2850701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        private final PlatformAdapter mPlatformAdapter;
2860701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
2870701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        private FlowWorker(PlatformAdapter platformAdapter) {
2880701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            mPlatformAdapter = platformAdapter;
2890701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        }
2900701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
2910701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        @Override
2920701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        public void run() {
2930701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            for (; ; ) {
2940701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                synchronized (mQueue) {
2950701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                    if (mCurrent != null && mCurrent.createdNetwork()
2960701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                            && (mQueue.isEmpty() || mCurrent.deleteNetwork(mQueue.getLast()))) {
2970701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                        mPlatformAdapter.deleteNetwork(mCurrent.getWifiNetworkId());
2980701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                    }
2990701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
3000701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                    mCurrent = null;
3010701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                    while (mQueue.isEmpty()) {
3020701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                        try {
3030701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                            mQueue.wait(WAIT_QUANTA);
3040701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                        } catch (InterruptedException ie) {
3050701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                            return;
3060701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                        }
3070701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                        if (mQueue.isEmpty()) {
3080701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                            // Bail out on time out
3090701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                            Log.d(OSUManager.TAG, "Flow worker terminating.");
3100701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                            mWorker = null;
3110701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                            mContext.stopService(new Intent(mContext, FlowService.class));
3120701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                            return;
3130701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                        }
3140701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                    }
3150701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                    mCurrent = mQueue.removeLast();
3160701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                    mCurrent.setLaunchTime();
3170701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                }
3180701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                Log.d(OSUManager.TAG, "Starting " + mCurrent);
3190701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                mCurrent.run();
3200701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                Log.d(OSUManager.TAG, "Exiting " + mCurrent);
3210701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            }
3220701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        }
3230701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist    }
3240701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
3250701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist    /*
3260701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist     * Provisioning:    Wait until there is an active WiFi info and the active WiFi config
3270701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist     *                  matches SSID and optionally BSSID.
3280701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist     * WNM Remediation: Wait until the active WiFi info matches BSSID.
3290701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist     * Timed remediation: The network is given (may be cellular).
3300701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist     */
3310701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
3320701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist    public void appendFlow(OSUFlow flow) {
3330701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        synchronized (mQueue) {
3340701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            if (mCurrent != null &&
3350701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                    SystemClock.currentThreadTimeMillis()
3360701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                            - mCurrent.getLaunchTime() >= WAIT_TIMEOUT) {
3370701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                Log.d(OSUManager.TAG, "Aborting stale OSU flow " + mCurrent);
3380701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                mCurrent.abort();
3390701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                mCurrent = null;
3400701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            }
3410701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
3420701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            if (flow.getFlowType() == FlowType.Provisioning) {
3430701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                // Kill any outstanding provisioning flows.
3440701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                Iterator<OSUFlow> flows = mQueue.iterator();
3450701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                while (flows.hasNext()) {
3460701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                    if (flows.next().getFlowType() == FlowType.Provisioning) {
3470701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                        flows.remove();
3480701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                    }
3490701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                }
3500701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
3510701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                if (mCurrent != null
3520701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                        && mCurrent.getFlowType() == FlowType.Provisioning) {
3530701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                    Log.d(OSUManager.TAG, "Aborting current provisioning flow " + mCurrent);
3540701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                    mCurrent.abort();
3550701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                    mCurrent = null;
3560701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                }
3570701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
3580701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                mQueue.addLast(flow);
3590701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            } else {
3600701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                mQueue.addFirst(flow);
3610701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            }
3620701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
3630701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            if (mWorker == null) {
3640701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                // TODO: Might want to change this to a handler.
3650701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                mWorker = new FlowWorker(flow.getPlatformAdapter());
3660701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist                mWorker.start();
3670701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            }
3680701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
3690701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            mQueue.notifyAll();
3700701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        }
3710701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist    }
3720701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
3730701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist    public void networkChange() {
3740701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        OSUFlow pending;
3750701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        synchronized (mQueue) {
3760701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            pending = mCurrent;
3770701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        }
3780701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        Log.d(OSUManager.TAG, "Network change, current flow: " + pending);
3790701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        if (pending != null) {
3800701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            pending.networkChange();
3810701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        }
3820701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist    }
3830701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist
3840701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist    private static boolean bssidMatch(OSUInfo osuInfo, PlatformAdapter platformAdapter) {
3850701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        if (MATCH_BSSID) {
3860701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            WifiInfo wifiInfo = platformAdapter.getConnectionInfo();
3870701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            return wifiInfo != null && Utils.parseMac(wifiInfo.getBSSID()) == osuInfo.getOSUBssid();
3880701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        } else {
3890701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist            return true;
3900701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist        }
3910701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist    }
3920701952aaa17dcef461d3a538048243d9fe690f1Jan Nordqvist}
393