diff --git a/BUILD.gn b/BUILD.gn
index c89829f5906e4cc774a10d21e79be70fc9596faf..e6cb5cb433ed835f0c72277bdd4e3cccccb6e3fa 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -28,3 +28,15 @@ group("bluetooth") {
     "//vendor_libs:vendor-libs"
   ]
 }
+
+group("bluetooth_tests") {
+  testonly = true
+
+  deps = [
+    "//test/suite:net_test_bluedroid",
+    "//btcore:net_test_btcore",
+    "//hci:net_test_hci",
+    "//osi:net_test_osi",
+    "//device:net_test_device",
+  ]
+}
diff --git a/system/main/BUILD.gn b/system/main/BUILD.gn
index d5bde2462f69d7a453bf4dd33aec1627b8b21c21..998a2d405d25f18fd8975c326f362d685ea8d8e4 100644
--- a/system/main/BUILD.gn
+++ b/system/main/BUILD.gn
@@ -53,6 +53,7 @@ shared_library("bluetooth.default") {
     "//embdrv/sbc/decoder/include",
     "//audio_a2dp_hw",
     "//utils/include",
+    "//test/suite",
   ]
 
   deps = [
diff --git a/system/service/BUILD.gn b/system/service/BUILD.gn
index 49e389936516d08a9b9a486f3e19751f1377495d..616c7e80f13ac90404d67633476ca1f0a96ba654 100644
--- a/system/service/BUILD.gn
+++ b/system/service/BUILD.gn
@@ -16,16 +16,22 @@
 
 source_set("service") {
   sources = [
-    "a2dp_source.cpp",
-    "core_stack.cpp",
+    "adapter.cpp",
+    "adapter_state.cpp",
     "daemon.cpp",
     "gatt_server.cpp",
+    "hal/bluetooth_interface.cpp",
+    "ipc/binder/bluetooth_binder_server.cpp",
+    "ipc/binder/IBluetooth.cpp",
+    "ipc/binder/IBluetoothCallback.cpp",
+    "ipc/binder/ipc_handler_binder.cpp",
     "ipc/ipc_handler.cpp",
     "ipc/ipc_handler_linux.cpp",
     "ipc/ipc_manager.cpp",
     "ipc/linux_ipc_host.cpp",
     "logging_helpers.cpp",
     "settings.cpp",
+    "util/atomic_string.cpp",
     "uuid.cpp"
   ]
 
diff --git a/system/test/suite/BUILD.gn b/system/test/suite/BUILD.gn
new file mode 100644
index 0000000000000000000000000000000000000000..e8a80b4d72e272542811750156b1c1a1a3ef2a5c
--- /dev/null
+++ b/system/test/suite/BUILD.gn
@@ -0,0 +1,47 @@
+#
+#  Copyright (C) 2015 Google, Inc.
+#
+#  Licensed under the Apache License, Version 2.0 (the "License");
+#  you may not use this file except in compliance with the License.
+#  You may obtain a copy of the License at:
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+
+executable("net_test_bluetooth") {
+  testonly = true
+  sources = [
+    "cases/adapter.c",
+    "cases/cases.c",
+    "cases/gatt.c",
+    "cases/pan.c",
+    "cases/rfcomm.c",
+    "support/adapter.c",
+    "support/callbacks.c",
+    "support/gatt.c",
+    "support/hal.c",
+    "support/pan.c",
+    "support/rfcomm.c",
+    "main.c",
+  ]
+
+  include_dirs = [
+    "//",
+    "//test/suite",
+  ]
+
+  deps = [
+    "//btcore",
+    "//main:bluetooth.default",
+    "//osi",
+  ]
+
+  libs = [ "-lpthread", "-lrt", "-ldl" ]
+
+}
diff --git a/system/test/suite/base.h b/system/test/suite/base.h
index 935ff1771b76c12b5c0322f36a3a525e686bd1a1..018bc9e15facc641ec8fa40105c17ca1966b3d67 100644
--- a/system/test/suite/base.h
+++ b/system/test/suite/base.h
@@ -27,7 +27,6 @@
 #include <hardware/bt_gatt.h>
 #include <hardware/bt_pan.h>
 #include <hardware/bt_sock.h>
-#include <hardware/hardware.h>
 
 #ifndef ARRAY_SIZE
 #  define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
diff --git a/system/test/suite/main.c b/system/test/suite/main.c
index 24cb862fd2372d0588a02c6e0e7500cc54dbcf7f..3791f5b0bc50a4cf82c15140823f4cd8f5d132ed 100644
--- a/system/test/suite/main.c
+++ b/system/test/suite/main.c
@@ -16,7 +16,11 @@
  *
  ******************************************************************************/
 
+// TODO(jamuraa): cutils/properties used to find if zygote is running and could
+// clobber our tests.  Do something useful and similar for non-Android systems.
+#if !defined(OS_GENERIC)
 #include <cutils/properties.h>
+#endif // !defined(OS_GENERIC)
 #include <pthread.h>
 #include <stdlib.h>
 #include <unistd.h>
@@ -66,11 +70,13 @@ static void *watchdog_fn(void *arg) {
 }
 
 static bool is_shell_running(void) {
+#if !defined(OS_GENERIC)
   char property_str[100];
   property_get("init.svc.zygote", property_str, NULL);
   if (!strcmp("running", property_str)) {
     return true;
   }
+#endif // !defined(OS_GENERIC)
   return false;
 }
 
@@ -106,6 +112,7 @@ static bool is_valid(const char *test_name) {
 
 int main(int argc, char **argv) {
   const char *test_name = NULL;
+  const char *config_path = CONFIG_FILE_PATH;
   bool skip_sanity_suite = false;
 
   for (int i = 1; i < argc; ++i) {
@@ -119,6 +126,17 @@ int main(int argc, char **argv) {
       continue;
     }
 
+    if (!strcmp("--config", argv[i])) {
+      ++i;
+      if (i == argc) {
+        printf("Error: --config requires an argument.\n");
+        print_usage(argv[0]);
+        return -1;
+      }
+      config_path = argv[i];
+      continue;
+    }
+
     if (!is_valid(argv[i])) {
       printf("Error: invalid test name.\n");
       print_usage(argv[0]);
@@ -139,7 +157,7 @@ int main(int argc, char **argv) {
     return -1;
   }
 
-  config_t *config = config_new(CONFIG_FILE_PATH);
+  config_t *config = config_new(config_path);
   if (!config) {
     printf("Error: unable to open stack config file.\n");
     print_usage(argv[0]);
@@ -193,9 +211,9 @@ int main(int argc, char **argv) {
     DEFAULT = GREEN = RED = "";
   }
 
-  int pass = 0;
-  int fail = 0;
-  int case_num = 0;
+  size_t pass = 0;
+  size_t fail = 0;
+  size_t case_num = 0;
 
   // If test name is specified, run that specific test.
   // Otherwise run through the sanity suite.
@@ -204,10 +222,10 @@ int main(int argc, char **argv) {
       if (!test_name || !strcmp(test_name, sanity_suite[i].function_name)) {
         callbacks_init();
         if (sanity_suite[i].function()) {
-          printf("[%4d] %-64s [%sPASS%s]\n", ++case_num, sanity_suite[i].function_name, GREEN, DEFAULT);
+          printf("[%4zd] %-64s [%sPASS%s]\n", ++case_num, sanity_suite[i].function_name, GREEN, DEFAULT);
           ++pass;
         } else {
-          printf("[%4d] %-64s [%sFAIL%s]\n", ++case_num, sanity_suite[i].function_name, RED, DEFAULT);
+          printf("[%4zd] %-64s [%sFAIL%s]\n", ++case_num, sanity_suite[i].function_name, RED, DEFAULT);
           ++fail;
         }
         callbacks_cleanup();
@@ -218,7 +236,7 @@ int main(int argc, char **argv) {
 
   // If there was a failure in the sanity suite, don't bother running the rest of the tests.
   if (fail) {
-    printf("\n%sSanity suite failed with %d errors.%s\n", RED, fail, DEFAULT);
+    printf("\n%sSanity suite failed with %zu errors.%s\n", RED, fail, DEFAULT);
     hal_close();
     return 4;
   }
@@ -230,10 +248,10 @@ int main(int argc, char **argv) {
       callbacks_init();
       CALL_AND_WAIT(bt_interface->enable(), adapter_state_changed);
       if (test_suite[i].function()) {
-        printf("[%4d] %-64s [%sPASS%s]\n", ++case_num, test_suite[i].function_name, GREEN, DEFAULT);
+        printf("[%4zd] %-64s [%sPASS%s]\n", ++case_num, test_suite[i].function_name, GREEN, DEFAULT);
         ++pass;
       } else {
-        printf("[%4d] %-64s [%sFAIL%s]\n", ++case_num, test_suite[i].function_name, RED, DEFAULT);
+        printf("[%4zd] %-64s [%sFAIL%s]\n", ++case_num, test_suite[i].function_name, RED, DEFAULT);
         ++fail;
       }
       CALL_AND_WAIT(bt_interface->disable(), adapter_state_changed);
@@ -245,7 +263,7 @@ int main(int argc, char **argv) {
   printf("\n");
 
   if (fail) {
-    printf("%d/%d tests failed. See above for failed test cases.\n", fail, sanity_suite_size + test_suite_size);
+    printf("%zd/%zd tests failed. See above for failed test cases.\n", fail, sanity_suite_size + test_suite_size);
   } else {
     printf("All tests passed!\n");
   }
diff --git a/system/test/suite/support/hal.c b/system/test/suite/support/hal.c
index 3ebcf743c51d56c80b57abc4bb4058278550a7a4..01db93f12835c643374f82beffe6e0521d470c84 100644
--- a/system/test/suite/support/hal.c
+++ b/system/test/suite/support/hal.c
@@ -16,13 +16,17 @@
  *
  ******************************************************************************/
 
+#include <dlfcn.h>
+#include <errno.h>
 #include <signal.h>
 #include <time.h>
 
 #include "base.h"
+#include "btcore/include/hal_util.h"
 #include "support/hal.h"
 #include "osi/include/hash_functions.h"
 #include "osi/include/hash_map.h"
+#include "osi/include/log.h"
 
 #define TIMER_BUCKET_COUNT 4
 
@@ -41,7 +45,7 @@ static bt_os_callouts_t callouts = {
 
 bool hal_open(bt_callbacks_t *callbacks) {
   hw_module_t *module;
-  if (hw_get_module(BT_STACK_MODULE_ID, (hw_module_t const **)&module)) {
+  if (hal_util_load_bt_library((const struct hw_module_t **)&module)) {
     return false;
   }