Add guest mode functionality (2/5)

Add a flag to enable() to start Bluetooth in restricted
mode. In restricted mode, all devices that are paired during
restricted mode are deleted upon leaving restricted mode.
Right now restricted mode is only entered while a guest
user is active.

Bug: 27410683
Change-Id: I8f23d28ef0aa3a8df13d469c73005c8e1b894d19
diff --git a/system/btif/include/btif_api.h b/system/btif/include/btif_api.h
index dcaecfc..ed67b9e 100644
--- a/system/btif/include/btif_api.h
+++ b/system/btif/include/btif_api.h
@@ -89,6 +89,23 @@
 
 /*******************************************************************************
 **
+** Function         is_restricted_mode
+**
+** Description      Checks if BT was enabled in restriced mode. In restricted
+**                  mode, bonds that are created are marked as temporary.
+**                  These bonds persist until we leave restricted mode, at
+**                  which point they will be deleted from the config. Also
+**                  while in restricted mode, the user can access devices
+**                  that are already paired before entering restricted mode,
+**                  but they cannot remove any of these devices.
+**
+** Returns          bool
+**
+*******************************************************************************/
+bool is_restricted_mode(void);
+
+/*******************************************************************************
+**
 ** Function         btif_get_adapter_properties
 **
 ** Description      Fetches all local adapter properties
diff --git a/system/btif/include/btif_storage.h b/system/btif/include/btif_storage.h
index 03debef..bc1060c 100644
--- a/system/btif/include/btif_storage.h
+++ b/system/btif/include/btif_storage.h
@@ -262,6 +262,18 @@
 *******************************************************************************/
 bt_status_t btif_storage_remove_hid_info(bt_bdaddr_t *remote_bd_addr);
 
+/*******************************************************************************
+**
+** Function         btif_storage_is_retricted_device
+**
+** Description      BTIF storage API - checks if this device is a restricted device
+**
+** Returns          TRUE  if the device is labled as restricted
+**                  FALSE otherwise
+**
+*******************************************************************************/
+BOOLEAN btif_storage_is_restricted_device(const bt_bdaddr_t *remote_bd_addr);
+
 #if (BLE_INCLUDED == TRUE)
 bt_status_t btif_storage_add_ble_bonding_key( bt_bdaddr_t *remote_bd_addr,
                                               char *key,
diff --git a/system/btif/src/bluetooth.c b/system/btif/src/bluetooth.c
index e0399ab..1414138 100644
--- a/system/btif/src/bluetooth.c
+++ b/system/btif/src/bluetooth.c
@@ -59,6 +59,7 @@
 #include "osi/include/wakelock.h"
 #include "stack_manager.h"
 #include "btif_config.h"
+#include "btif_storage.h"
 #include "btif/include/btif_debug_btsnoop.h"
 #include "btif/include/btif_debug_conn.h"
 #include "btif/include/btif_media.h"
@@ -68,6 +69,7 @@
 ************************************************************************************/
 
 bt_callbacks_t *bt_hal_cbacks = NULL;
+bool restricted_mode = FALSE;
 
 /************************************************************************************
 **  Externs
@@ -139,8 +141,10 @@
   return BT_STATUS_SUCCESS;
 }
 
-static int enable(void) {
-  LOG_INFO(LOG_TAG, "%s", __func__);
+static int enable(bool start_restricted) {
+  LOG_INFO(LOG_TAG, "%s: start restricted = %d", __func__, start_restricted);
+
+  restricted_mode = start_restricted;
 
   if (!interface_ready())
     return BT_STATUS_NOT_READY;
@@ -161,6 +165,10 @@
   stack_manager_get_interface()->clean_up_stack();
 }
 
+bool is_restricted_mode() {
+  return restricted_mode;
+}
+
 static int get_adapter_properties(void)
 {
     /* sanity check */
@@ -281,6 +289,9 @@
 
 static int remove_bond(const bt_bdaddr_t *bd_addr)
 {
+    if (is_restricted_mode() && !btif_storage_is_restricted_device(bd_addr))
+        return BT_STATUS_SUCCESS;
+
     /* sanity check */
     if (interface_ready() == FALSE)
         return BT_STATUS_NOT_READY;
diff --git a/system/btif/src/btif_config.c b/system/btif/src/btif_config.c
index 64b5818..fd5ee69 100644
--- a/system/btif/src/btif_config.c
+++ b/system/btif/src/btif_config.c
@@ -30,6 +30,7 @@
 #include "bt_types.h"
 #include "btcore/include/bdaddr.h"
 #include "btcore/include/module.h"
+#include "btif_api.h"
 #include "btif_common.h"
 #include "btif_config.h"
 #include "btif_config_transcode.h"
@@ -67,6 +68,7 @@
 static bool is_factory_reset(void);
 static void delete_config_files(void);
 static void btif_config_remove_unpaired(config_t *config);
+static void btif_config_remove_restricted(config_t *config);
 
 static enum ConfigSource {
   NOT_LOADED,
@@ -153,6 +155,10 @@
 
   btif_config_remove_unpaired(config);
 
+  // Cleanup temporary pairings if we have left guest mode
+  if (!is_restricted_mode())
+    btif_config_remove_restricted(config);
+
   // TODO(sharvil): use a non-wake alarm for this once we have
   // API support for it. There's no need to wake the system to
   // write back to disk.
@@ -499,6 +505,22 @@
     pthread_mutex_unlock(&lock);
 }
 
+static void btif_config_remove_restricted(config_t* config) {
+  assert(config != NULL);
+
+  pthread_mutex_lock(&lock);
+  const config_section_node_t *snode = config_section_begin(config);
+  while (snode != config_section_end(config)) {
+    const char *section = config_section_name(snode);
+    if (string_is_bdaddr(section) && config_has_key(config, section, "Restricted")) {
+        BTIF_TRACE_DEBUG("%s: Removing restricted device %s", __func__, section);
+        config_remove_section(config, section);
+    }
+    snode = config_section_next(snode);
+  }
+  pthread_mutex_unlock(&lock);
+}
+
 static bool is_factory_reset(void) {
   char factory_reset[PROPERTY_VALUE_MAX] = {0};
   property_get("persist.bluetooth.factoryreset", factory_reset, "false");
diff --git a/system/btif/src/btif_storage.c b/system/btif/src/btif_storage.c
index e058a14..791203f 100644
--- a/system/btif/src/btif_storage.c
+++ b/system/btif/src/btif_storage.c
@@ -793,6 +793,13 @@
     int ret = btif_config_set_int(bdstr, "LinkKeyType", (int)key_type);
     ret &= btif_config_set_int(bdstr, "PinLength", (int)pin_length);
     ret &= btif_config_set_bin(bdstr, "LinkKey", link_key, sizeof(LINK_KEY));
+
+    if (is_restricted_mode()) {
+        BTIF_TRACE_WARNING("%s: '%s' pairing will be removed if unrestricted",
+                         __func__, bdstr);
+        btif_config_set_int(bdstr, "Restricted", 1);
+    }
+
     /* write bonded info immediately */
     btif_config_flush();
     return ret ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
@@ -1474,3 +1481,20 @@
     return bt_status;
 }
 
+/*******************************************************************************
+**
+** Function         btif_storage_is_restricted_device
+**
+** Description      BTIF storage API - checks if this device is a restricted device
+**
+** Returns          TRUE  if the device is labeled as restricted
+**                  FALSE otherwise
+**
+*******************************************************************************/
+BOOLEAN btif_storage_is_restricted_device(const bt_bdaddr_t *remote_bd_addr)
+{
+    bdstr_t bdstr;
+    bdaddr_to_string(remote_bd_addr, bdstr, sizeof(bdstr));
+
+    return btif_config_exist(bdstr, "Restricted");
+}
diff --git a/system/service/adapter.cpp b/system/service/adapter.cpp
index 891bc08..45826b2 100644
--- a/system/service/adapter.cpp
+++ b/system/service/adapter.cpp
@@ -105,7 +105,7 @@
     return state_.load() == ADAPTER_STATE_ON;
   }
 
-  bool Enable() override {
+  bool Enable(bool start_restricted) override {
     AdapterState current_state = GetState();
     if (current_state != ADAPTER_STATE_OFF) {
       LOG(INFO) << "Adapter not disabled - state: "
@@ -118,7 +118,7 @@
     state_ = ADAPTER_STATE_TURNING_ON;
     NotifyAdapterStateChanged(current_state, state_);
 
-    int status = hal::BluetoothInterface::Get()->GetHALInterface()->enable();
+    int status = hal::BluetoothInterface::Get()->GetHALInterface()->enable(start_restricted);
     if (status != BT_STATUS_SUCCESS) {
       LOG(ERROR) << "Failed to enable Bluetooth - status: "
                  << BtStatusText((const bt_status_t)status);
diff --git a/system/service/adapter.h b/system/service/adapter.h
index 8594f20..11226ce 100644
--- a/system/service/adapter.h
+++ b/system/service/adapter.h
@@ -82,7 +82,10 @@
   // to the controller, otherwise returns false. A successful call to this
   // method only means that the enable request has been sent to the Bluetooth
   // controller and does not imply that the operation itself succeeded.
-  virtual bool Enable() = 0;
+  // The |start_restricted| flag enables the adapter in restricted mode. In
+  // restricted mode, bonds that are created are marked as restricted in the
+  // config file. These devices are deleted upon leaving restricted mode.
+  virtual bool Enable(bool start_restricted) = 0;
 
   // Powers off the Bluetooth radio. Returns true, if the disable request was
   // successfully sent to the Bluetooth controller.
diff --git a/system/service/client/main.cpp b/system/service/client/main.cpp
index 078e1ff..87fdaf5 100644
--- a/system/service/client/main.cpp
+++ b/system/service/client/main.cpp
@@ -259,8 +259,24 @@
 }
 
 void HandleEnable(IBluetooth* bt_iface, const vector<string>& args) {
-  CHECK_NO_ARGS(args);
-  PrintCommandStatus(bt_iface->Enable());
+  bool is_restricted_mode = false;
+
+  for (auto iter : args) {
+    const std::string& arg = iter;
+    if (arg == "-h") {
+      static const char kUsage[] =
+          "Usage: start-adv [flags]\n"
+          "\n"
+          "Flags:\n"
+          "\t--restricted|-r\tStart in restricted mode\n";
+      cout << kUsage << endl;
+      return;
+    } else if (arg == "--restricted" || arg == "-r") {
+      is_restricted_mode = true;
+    }
+  }
+
+  PrintCommandStatus(bt_iface->Enable(is_restricted_mode));
 }
 
 void HandleGetState(IBluetooth* bt_iface, const vector<string>& args) {
@@ -697,7 +713,7 @@
 } kCommandMap[] = {
   { "help", HandleHelp, "\t\t\tDisplay this message" },
   { "disable", HandleDisable, "\t\t\tDisable Bluetooth" },
-  { "enable", HandleEnable, "\t\t\tEnable Bluetooth" },
+  { "enable", HandleEnable, "\t\t\tEnable Bluetooth (-h for options)" },
   { "get-state", HandleGetState, "\t\tGet the current adapter state" },
   { "is-enabled", HandleIsEnabled, "\t\tReturn if Bluetooth is enabled" },
   { "get-local-address", HandleGetLocalAddress,
diff --git a/system/service/common/bluetooth/binder/IBluetooth.cpp b/system/service/common/bluetooth/binder/IBluetooth.cpp
index 65d13078..3fb0916 100644
--- a/system/service/common/bluetooth/binder/IBluetooth.cpp
+++ b/system/service/common/bluetooth/binder/IBluetooth.cpp
@@ -81,7 +81,8 @@
     }
     case ENABLE_TRANSACTION: {
       CHECK_INTERFACE(IBluetooth, data, reply);
-      bool result = Enable();
+      bool start_restricted = data.readBool();
+      bool result = Enable(start_restricted);
       reply->writeInt32(result);
       return android::NO_ERROR;
     }
@@ -182,10 +183,11 @@
   return reply.readInt32();
 }
 
-bool BpBluetooth::Enable() {
+bool BpBluetooth::Enable(bool start_restricted) {
   Parcel data, reply;
 
   data.writeInterfaceToken(IBluetooth::getInterfaceDescriptor());
+  data.writeBool(start_restricted);
   remote()->transact(IBluetooth::ENABLE_TRANSACTION, data, &reply);
 
   return reply.readInt32();
diff --git a/system/service/common/bluetooth/binder/IBluetooth.h b/system/service/common/bluetooth/binder/IBluetooth.h
index 54e0b19..ad1d33c 100644
--- a/system/service/common/bluetooth/binder/IBluetooth.h
+++ b/system/service/common/bluetooth/binder/IBluetooth.h
@@ -134,7 +134,7 @@
 
   virtual bool IsEnabled() = 0;
   virtual int GetState() = 0;
-  virtual bool Enable() = 0;
+  virtual bool Enable(bool start_restricted) = 0;
   virtual bool EnableNoAutoConnect() = 0;
   virtual bool Disable() = 0;
 
@@ -184,7 +184,7 @@
   // IBluetooth overrides:
   bool IsEnabled() override;
   int GetState() override;
-  bool Enable() override;
+  bool Enable(bool start_restricted) override;
   bool EnableNoAutoConnect() override;
   bool Disable() override;
 
diff --git a/system/service/hal/fake_bluetooth_interface.cpp b/system/service/hal/fake_bluetooth_interface.cpp
index a0b4eaa..5036c63 100644
--- a/system/service/hal/fake_bluetooth_interface.cpp
+++ b/system/service/hal/fake_bluetooth_interface.cpp
@@ -23,7 +23,7 @@
 
 FakeBluetoothInterface::Manager g_hal_manager;
 
-int FakeHALEnable() {
+int FakeHALEnable(bool start_restricted) {
   return g_hal_manager.enable_succeed ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
 }
 
diff --git a/system/service/ipc/binder/bluetooth_binder_server.cpp b/system/service/ipc/binder/bluetooth_binder_server.cpp
index 7b216ca..198ccf6 100644
--- a/system/service/ipc/binder/bluetooth_binder_server.cpp
+++ b/system/service/ipc/binder/bluetooth_binder_server.cpp
@@ -50,9 +50,9 @@
   return adapter_->GetState();
 }
 
-bool BluetoothBinderServer::Enable() {
+bool BluetoothBinderServer::Enable(bool start_restricted) {
   VLOG(2) << __func__;
-  return adapter_->Enable();
+  return adapter_->Enable(start_restricted);
 }
 
 bool BluetoothBinderServer::EnableNoAutoConnect() {
diff --git a/system/service/ipc/binder/bluetooth_binder_server.h b/system/service/ipc/binder/bluetooth_binder_server.h
index 4c85a2d..351a858 100644
--- a/system/service/ipc/binder/bluetooth_binder_server.h
+++ b/system/service/ipc/binder/bluetooth_binder_server.h
@@ -45,7 +45,7 @@
   // IBluetooth overrides:
   bool IsEnabled() override;
   int GetState() override;
-  bool Enable() override;
+  bool Enable(bool start_restricted) override;
   bool EnableNoAutoConnect() override;
   bool Disable() override;
 
@@ -65,7 +65,6 @@
   android::sp<IBluetoothGattServer> GetGattServerInterface() override;
 
   android::status_t dump(int fd, const android::Vector<android::String16>& args) override;
-
   // bluetooth::Adapter::Observer overrides:
   void OnAdapterStateChanged(bluetooth::Adapter* adapter,
                              bluetooth::AdapterState prev_state,
diff --git a/system/service/test/adapter_unittest.cpp b/system/service/test/adapter_unittest.cpp
index 1c2df52..1d094a4 100644
--- a/system/service/test/adapter_unittest.cpp
+++ b/system/service/test/adapter_unittest.cpp
@@ -127,12 +127,12 @@
   EXPECT_EQ(bluetooth::ADAPTER_STATE_OFF, adapter_->GetState());
 
   // Enable fails at HAL level
-  EXPECT_FALSE(adapter_->Enable());
+  EXPECT_FALSE(adapter_->Enable(false));
   EXPECT_EQ(bluetooth::ADAPTER_STATE_OFF, adapter_->GetState());
 
   // Enable success
   fake_hal_manager_->enable_succeed = true;
-  EXPECT_TRUE(adapter_->Enable());
+  EXPECT_TRUE(adapter_->Enable(false));
 
   // Should have received a state update.
   EXPECT_EQ(bluetooth::ADAPTER_STATE_OFF, observer.prev_state());
@@ -140,7 +140,7 @@
 
   // Enable fails because not disabled
   EXPECT_EQ(bluetooth::ADAPTER_STATE_TURNING_ON, adapter_->GetState());
-  EXPECT_FALSE(adapter_->Enable());
+  EXPECT_FALSE(adapter_->Enable(false));
 
   // Adapter state updates properly
   fake_hal_iface_->NotifyAdapterStateChanged(BT_STATE_ON);
@@ -151,7 +151,7 @@
   EXPECT_EQ(bluetooth::ADAPTER_STATE_ON, observer.cur_state());
 
   // Enable fails because already enabled
-  EXPECT_FALSE(adapter_->Enable());
+  EXPECT_FALSE(adapter_->Enable(false));
 }
 
 TEST_F(AdapterTest, Disable) {
diff --git a/system/service/test/mock_adapter.h b/system/service/test/mock_adapter.h
index d46ea03..b561926 100644
--- a/system/service/test/mock_adapter.h
+++ b/system/service/test/mock_adapter.h
@@ -32,7 +32,7 @@
   MOCK_METHOD1(RemoveObserver, void(Observer*));
   MOCK_CONST_METHOD0(GetState, AdapterState());
   MOCK_CONST_METHOD0(IsEnabled, bool());
-  MOCK_METHOD0(Enable, bool());
+  MOCK_METHOD1(Enable, bool(bool));
   MOCK_METHOD0(Disable, bool());
   MOCK_CONST_METHOD0(GetName, std::string());
   MOCK_METHOD1(SetName, bool(const std::string&));
diff --git a/system/test/suite/adapter/adapter_unittest.cpp b/system/test/suite/adapter/adapter_unittest.cpp
index d2bf0fa..1f78b21 100644
--- a/system/test/suite/adapter/adapter_unittest.cpp
+++ b/system/test/suite/adapter/adapter_unittest.cpp
@@ -38,7 +38,7 @@
   EXPECT_EQ(GetState(), BT_STATE_OFF) <<
     "Test should be run with Adapter disabled";
 
-  EXPECT_EQ(bt_interface()->enable(), BT_STATUS_SUCCESS);
+  EXPECT_EQ(bt_interface()->enable(false), BT_STATUS_SUCCESS);
   semaphore_wait(adapter_state_changed_callback_sem_);
   EXPECT_EQ(GetState(), BT_STATE_ON) <<  "Adapter did not turn on.";
 
@@ -52,7 +52,7 @@
     << "Test should be run with Adapter disabled";
 
   for (int i = 0; i < kTestRepeatCount; ++i) {
-    EXPECT_EQ(bt_interface()->enable(), BT_STATUS_SUCCESS);
+    EXPECT_EQ(bt_interface()->enable(false), BT_STATUS_SUCCESS);
     semaphore_wait(adapter_state_changed_callback_sem_);
     EXPECT_EQ(GetState(), BT_STATE_ON) <<  "Adapter did not turn on.";
 
@@ -65,7 +65,7 @@
 TEST_F(BluetoothTest, AdapterSetGetName) {
   bt_property_t *new_name = property_new_name("BluetoothTestName1");
 
-  EXPECT_EQ(bt_interface()->enable(), BT_STATUS_SUCCESS);
+  EXPECT_EQ(bt_interface()->enable(false), BT_STATUS_SUCCESS);
   semaphore_wait(adapter_state_changed_callback_sem_);
   EXPECT_EQ(GetState(), BT_STATE_ON)
     << "Test should be run with Adapter enabled";
@@ -115,7 +115,7 @@
 }
 
 TEST_F(BluetoothTest, AdapterStartDiscovery) {
-  EXPECT_EQ(bt_interface()->enable(), BT_STATUS_SUCCESS);
+  EXPECT_EQ(bt_interface()->enable(false), BT_STATUS_SUCCESS);
   semaphore_wait(adapter_state_changed_callback_sem_);
   EXPECT_EQ(GetState(), BT_STATE_ON)
     << "Test should be run with Adapter enabled";
@@ -131,7 +131,7 @@
 }
 
 TEST_F(BluetoothTest, AdapterCancelDiscovery) {
-  EXPECT_EQ(bt_interface()->enable(), BT_STATUS_SUCCESS);
+  EXPECT_EQ(bt_interface()->enable(false), BT_STATUS_SUCCESS);
   semaphore_wait(adapter_state_changed_callback_sem_);
   EXPECT_EQ(GetState(), BT_STATE_ON)
     << "Test should be run with Adapter enabled";
@@ -156,7 +156,7 @@
   bt_bdaddr_t bdaddr = { { 0x22, 0x22, 0x22, 0x22, 0x22, 0x22 } };
 
   for (int i = 0; i < kTestRepeatCount; ++i) {
-    EXPECT_EQ(bt_interface()->enable(), BT_STATUS_SUCCESS);
+    EXPECT_EQ(bt_interface()->enable(false), BT_STATUS_SUCCESS);
     semaphore_wait(adapter_state_changed_callback_sem_);
     EXPECT_EQ(GetState(), BT_STATE_ON) <<  "Adapter did not turn on.";
 
diff --git a/system/test/suite/gatt/gatt_test.cpp b/system/test/suite/gatt/gatt_test.cpp
index 1506247..a7912bb 100644
--- a/system/test/suite/gatt/gatt_test.cpp
+++ b/system/test/suite/gatt/gatt_test.cpp
@@ -37,7 +37,7 @@
   status_ = 0;
 
   BluetoothTest::SetUp();
-  ASSERT_EQ(bt_interface()->enable(), BT_STATUS_SUCCESS);
+  ASSERT_EQ(bt_interface()->enable(false), BT_STATUS_SUCCESS);
   semaphore_wait(adapter_state_changed_callback_sem_);
   EXPECT_TRUE(GetState() == BT_STATE_ON);