nexus: Implement wifi scanner and fix a lot of bugs

Signed-off-by: San Mehat <san@google.com>
diff --git a/nexus/WifiScanner.cpp b/nexus/WifiScanner.cpp
new file mode 100644
index 0000000..590d895
--- /dev/null
+++ b/nexus/WifiScanner.cpp
@@ -0,0 +1,96 @@
+#include <errno.h>
+#include <pthread.h>
+
+#define LOG_TAG "WifiScanner"
+#include <cutils/log.h>
+
+#include "WifiScanner.h"
+#include "Supplicant.h"
+
+extern "C" int pthread_cancel(pthread_t thread);
+
+WifiScanner::WifiScanner(Supplicant *suppl, int period) {
+    mSuppl = suppl;
+    mPeriod = period;
+    mActive = false;
+    mWorkerRunning = false;
+    mAbortRequest = false;
+    pthread_mutex_init(&mAbortRequestLock, NULL);
+    pthread_mutex_init(&mWorkerLock, NULL);
+}
+
+int WifiScanner::startPeriodicScan(bool active) {
+    mActive = active;
+
+    pthread_mutex_lock(&mWorkerLock);
+    if (mWorkerRunning) {
+        errno = EBUSY;
+        return -1;
+    }
+
+    pthread_attr_t attr;
+    pthread_attr_init(&attr);
+    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+
+    if (pthread_create(&mWorker, &attr, WifiScanner::threadStart, this))
+        return -1;
+
+    return 0;
+}
+
+void *WifiScanner::threadStart(void *obj) {
+    WifiScanner *me = reinterpret_cast<WifiScanner *>(obj);
+    me->run();
+    pthread_exit(NULL);
+    return NULL;
+}
+
+void WifiScanner::threadCleanup(void *obj) {
+    WifiScanner *me = reinterpret_cast<WifiScanner *>(obj);
+
+    me->mWorkerRunning = false;
+    pthread_mutex_unlock(&me->mWorkerLock);
+
+    if (me->mAbortRequest) {
+        me->mAbortRequest = false;
+        pthread_mutex_unlock(&me->mAbortRequestLock);
+    }
+}
+
+int WifiScanner::stopPeriodicScan() {
+    pthread_mutex_lock(&mAbortRequestLock);
+    pthread_mutex_lock(&mWorkerLock);
+    if (mWorkerRunning)
+        mAbortRequest = true;
+    pthread_mutex_unlock(&mWorkerLock);
+    pthread_mutex_unlock(&mAbortRequestLock);
+
+    return 0;
+}
+
+void WifiScanner::run() {
+    LOGD("Thread started");
+
+    mWorkerRunning = true;
+    pthread_cleanup_push(WifiScanner::threadCleanup, this);
+    pthread_mutex_unlock(&mWorkerLock);
+
+    while(1) {
+        LOGD("Triggering periodic scan");
+        if (mSuppl->triggerScan(mActive)) {
+            LOGW("Error triggering scan (%s)", strerror(errno));
+        }
+
+        sleep(mPeriod);
+        pthread_mutex_lock(&mAbortRequestLock);
+        if (mAbortRequest) {
+            LOGD("Abort request!");
+            goto out;
+        }
+        pthread_mutex_unlock(&mAbortRequestLock);
+    }
+
+out:
+    pthread_cleanup_pop(1);
+    pthread_mutex_unlock(&mWorkerLock);
+}