[adbwifi] Make AdbManager changes for adb over WiFi.

This CL has a couple of notable changes:
- Add communication layer between adbd, system server, and Settings UI
- Add system notification (Wireless debugging connected) when at least
  one device is connected.
- Add trusted networks (BSSID) to the keystore.
  - Changed the keystore format to:
    <keyStore version="1">
    <adbKey ... />
    <wifiAP ... />
    </keyStore>
 - Currently, trusted networks don't have a expiration time. Also, only
   way to clear it is by blowing up the keystore (revoke permissions).
- Add pairing mechanism:
  - Using libadbwifi_pairing_connection C++ library to pair a device
    using SPAKE2 protocol over TLS.
  - Register MDNS service for client discovery.
- Removed ability to ctl.start/stop adbd from UsbDeviceManager
  - AdbService now controls when to do this

Bug: 111434128, 119490154, 119492574

Test: Manual. From developer options:
1) USB debugging off, WiFi Debugging off
- Ensure both transports are disabled by trying to connect via WiFi and
USB.
2) USB debugging on, WiFi Debugging off
- Connections via USB are available, WiFi is disabled
3) USB debugging off, WiFi Debugging on
- Connections via WiFi are available (IP + port), USB is not available
4) USB debugging on, WiFi Debugging on
- Check both transports work

Change-Id: I9f87679d195da99a55b6faf7131da1f1af65fe01
Exempt-From-Owner-Approval: approved in aosp master
(cherry picked from commit a5969b5a1d)
This commit is contained in:
Joshua Duong
2018-12-03 15:21:46 -08:00
parent a1fb6f5b1d
commit f24fb19dbf
7 changed files with 1517 additions and 100 deletions

View File

@@ -255,6 +255,10 @@ message SystemMessage {
// Inform the user a foreground service while-in-use permission is restricted.
NOTE_FOREGROUND_SERVICE_WHILE_IN_USE_PERMISSION = 61;
// Display the Android Debug Protocol status
// Package: android
NOTE_ADB_WIFI_ACTIVE = 62;
// ADD_NEW_IDS_ABOVE_THIS_LINE
// Legacy IDs with arbitrary values appear below
// Legacy IDs existed as stable non-conflicting constants prior to the O release

View File

@@ -21,8 +21,10 @@ import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.ContentObserver;
import android.debug.AdbManager;
import android.debug.AdbManagerInternal;
import android.debug.AdbTransportType;
import android.debug.IAdbManager;
@@ -34,6 +36,7 @@ import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings;
import android.service.adb.AdbServiceDumpProto;
import android.sysprop.AdbProperties;
@@ -44,6 +47,7 @@ import android.util.proto.ProtoOutputStream;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.internal.util.dump.DualDumpOutputStream;
import com.android.server.FgThread;
import com.android.server.LocalServices;
@@ -54,12 +58,34 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
/**
* The Android Debug Bridge (ADB) service. This controls the availability of ADB and authorization
* of devices allowed to connect to ADB.
*/
public class AdbService extends IAdbManager.Stub {
/**
* Adb native daemon.
*/
static final String ADBD = "adbd";
/**
* Command to start native service.
*/
static final String CTL_START = "ctl.start";
/**
* Command to start native service.
*/
static final String CTL_STOP = "ctl.stop";
// The tcp port adb is currently using
AtomicInteger mConnectionPort = new AtomicInteger(-1);
private final AdbConnectionPortListener mPortListener = new AdbConnectionPortListener();
private AdbDebuggingManager.AdbConnectionPortPoller mConnectionPortPoller;
/**
* Manages the service lifecycle for {@code AdbService} in {@code SystemServer}.
*/
@@ -129,9 +155,8 @@ public class AdbService extends IAdbManager.Stub {
mIsAdbUsbEnabled = containsFunction(
SystemProperties.get(USB_PERSISTENT_CONFIG_PROPERTY, ""),
UsbManager.USB_FUNCTION_ADB);
// TODO(joshuaduong): Read the adb wifi state from a persistent system
// property (persist.sys.adb.wifi).
mIsAdbWifiEnabled = false;
mIsAdbWifiEnabled = "1".equals(
SystemProperties.get(WIFI_PERSISTENT_CONFIG_PROPERTY, "0"));
// register observer to listen for settings changes
mObserver = new AdbSettingsObserver();
@@ -189,6 +214,7 @@ public class AdbService extends IAdbManager.Stub {
* May also contain vendor-specific default functions for testing purposes.
*/
private static final String USB_PERSISTENT_CONFIG_PROPERTY = "persist.sys.usb.config";
private static final String WIFI_PERSISTENT_CONFIG_PROPERTY = "persist.adb.tls_server.enable";
private final Context mContext;
private final ContentResolver mContentResolver;
@@ -245,8 +271,9 @@ public class AdbService extends IAdbManager.Stub {
}
@Override
public void allowDebugging(boolean alwaysAllow, String publicKey) {
public void allowDebugging(boolean alwaysAllow, @NonNull String publicKey) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null);
Preconditions.checkStringNotEmpty(publicKey);
if (mDebuggingManager != null) {
mDebuggingManager.allowDebugging(alwaysAllow, publicKey);
}
@@ -296,53 +323,118 @@ public class AdbService extends IAdbManager.Stub {
}
@Override
public void allowWirelessDebugging(boolean alwaysAllow, String bssid) {
public void allowWirelessDebugging(boolean alwaysAllow, @NonNull String bssid) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null);
// TODO(joshuaduong): NOT IMPLEMENTED
Preconditions.checkStringNotEmpty(bssid);
if (mDebuggingManager != null) {
mDebuggingManager.allowWirelessDebugging(alwaysAllow, bssid);
}
}
@Override
public void denyWirelessDebugging() {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null);
// TODO(joshuaduong): NOT IMPLEMENTED
if (mDebuggingManager != null) {
mDebuggingManager.denyWirelessDebugging();
}
}
@Override
public Map<String, PairDevice> getPairedDevices() {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null);
// TODO(joshuaduong): NOT IMPLEMENTED
if (mDebuggingManager != null) {
return mDebuggingManager.getPairedDevices();
}
return null;
}
@Override
public void unpairDevice(String fingerprint) {
public void unpairDevice(@NonNull String fingerprint) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null);
// TODO(joshuaduong): NOT IMPLEMENTED
Preconditions.checkStringNotEmpty(fingerprint);
if (mDebuggingManager != null) {
mDebuggingManager.unpairDevice(fingerprint);
}
}
@Override
public void enablePairingByPairingCode() {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null);
// TODO(joshuaduong): NOT IMPLEMENTED
if (mDebuggingManager != null) {
mDebuggingManager.enablePairingByPairingCode();
}
}
@Override
public void enablePairingByQrCode(String serviceName, String password) {
public void enablePairingByQrCode(@NonNull String serviceName, @NonNull String password) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null);
// TODO(joshuaduong): NOT IMPLEMENTED
Preconditions.checkStringNotEmpty(serviceName);
Preconditions.checkStringNotEmpty(password);
if (mDebuggingManager != null) {
mDebuggingManager.enablePairingByQrCode(serviceName, password);
}
}
@Override
public void disablePairing() {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null);
// TODO(joshuaduong): NOT IMPLEMENTED
if (mDebuggingManager != null) {
mDebuggingManager.disablePairing();
}
}
@Override
public int getAdbWirelessPort() {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_DEBUGGING, null);
// TODO(joshuaduong): NOT IMPLEMENTED
return 0;
if (mDebuggingManager != null) {
return mDebuggingManager.getAdbWirelessPort();
}
// If ro.adb.secure=0
return mConnectionPort.get();
}
/**
* This listener is only used when ro.adb.secure=0. Otherwise, AdbDebuggingManager will
* do this.
*/
class AdbConnectionPortListener implements AdbDebuggingManager.AdbConnectionPortListener {
public void onPortReceived(int port) {
if (port > 0 && port <= 65535) {
mConnectionPort.set(port);
} else {
mConnectionPort.set(-1);
// Turn off wifi debugging, since the server did not start.
try {
Settings.Global.putInt(mContentResolver,
Settings.Global.ADB_WIFI_ENABLED, 0);
} catch (SecurityException e) {
// If UserManager.DISALLOW_DEBUGGING_FEATURES is on, that this setting can't
// be changed.
Slog.d(TAG, "ADB_ENABLED is restricted.");
}
}
broadcastPortInfo(mConnectionPort.get());
}
}
private void broadcastPortInfo(int port) {
Intent intent = new Intent(AdbManager.WIRELESS_DEBUG_STATE_CHANGED_ACTION);
intent.putExtra(AdbManager.WIRELESS_STATUS_EXTRA, (port >= 0)
? AdbManager.WIRELESS_STATUS_CONNECTED
: AdbManager.WIRELESS_STATUS_DISCONNECTED);
intent.putExtra(AdbManager.WIRELESS_DEBUG_PORT_EXTRA, port);
mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
Slog.i(TAG, "sent port broadcast port=" + port);
}
private void startAdbd() {
SystemProperties.set(CTL_START, ADBD);
}
private void stopAdbd() {
if (!mIsAdbUsbEnabled && !mIsAdbWifiEnabled) {
SystemProperties.set(CTL_STOP, ADBD);
}
}
private void setAdbEnabled(boolean enable, byte transportType) {
@@ -356,11 +448,33 @@ public class AdbService extends IAdbManager.Stub {
mIsAdbUsbEnabled = enable;
} else if (transportType == AdbTransportType.WIFI && enable != mIsAdbWifiEnabled) {
mIsAdbWifiEnabled = enable;
if (mIsAdbWifiEnabled) {
if (!AdbProperties.secure().orElse(false) && mDebuggingManager == null) {
// Start adbd. If this is secure adb, then we defer enabling adb over WiFi.
SystemProperties.set(WIFI_PERSISTENT_CONFIG_PROPERTY, "1");
mConnectionPortPoller =
new AdbDebuggingManager.AdbConnectionPortPoller(mPortListener);
mConnectionPortPoller.start();
}
} else {
// Stop adb over WiFi.
SystemProperties.set(WIFI_PERSISTENT_CONFIG_PROPERTY, "0");
if (mConnectionPortPoller != null) {
mConnectionPortPoller.cancelAndWait();
mConnectionPortPoller = null;
}
}
} else {
// No change
return;
}
if (enable) {
startAdbd();
} else {
stopAdbd();
}
for (IAdbTransport transport : mTransports.values()) {
try {
transport.onAdbEnabled(enable, transportType);

View File

@@ -24,6 +24,7 @@ cc_library_static {
"BroadcastRadio/regions.cpp",
"stats/PowerStatsPuller.cpp",
"stats/SubsystemSleepStatePuller.cpp",
"com_android_server_adb_AdbDebuggingManager.cpp",
"com_android_server_am_BatteryStatsService.cpp",
"com_android_server_connectivity_Vpn.cpp",
"com_android_server_ConsumerIrService.cpp",
@@ -86,6 +87,8 @@ cc_library_static {
cc_defaults {
name: "libservices.core-libs",
shared_libs: [
"libadb_pairing_server",
"libadb_pairing_connection",
"libandroid_runtime",
"libandroidfw",
"libaudioclient",

View File

@@ -0,0 +1,168 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* 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.
*/
#define LOG_TAG "AdbDebuggingManager-JNI"
#define LOG_NDEBUG 0
#include <algorithm>
#include <condition_variable>
#include <mutex>
#include <optional>
#include <random>
#include <string>
#include <vector>
#include <adb/pairing/pairing_server.h>
#include <android-base/properties.h>
#include <utils/Log.h>
#include <nativehelper/JNIHelp.h>
#include "jni.h"
namespace android {
// ----------------------------------------------------------------------------
namespace {
template <class T, class N>
class JSmartWrapper {
public:
JSmartWrapper(JNIEnv* env, T* jData) : mEnv(env), mJData(jData) {}
virtual ~JSmartWrapper() = default;
const N* data() const { return mRawData; }
jsize size() const { return mSize; }
protected:
N* mRawData = nullptr;
JNIEnv* mEnv = nullptr;
T* mJData = nullptr;
jsize mSize = 0;
}; // JSmartWrapper
class JStringUTFWrapper : public JSmartWrapper<jstring, const char> {
public:
explicit JStringUTFWrapper(JNIEnv* env, jstring* str) : JSmartWrapper(env, str) {
mRawData = env->GetStringUTFChars(*str, NULL);
mSize = env->GetStringUTFLength(*str);
}
virtual ~JStringUTFWrapper() {
if (data()) {
mEnv->ReleaseStringUTFChars(*mJData, mRawData);
}
}
}; // JStringUTFWrapper
struct ServerDeleter {
void operator()(PairingServerCtx* p) { pairing_server_destroy(p); }
};
using PairingServerPtr = std::unique_ptr<PairingServerCtx, ServerDeleter>;
struct PairingResultWaiter {
std::mutex mutex_;
std::condition_variable cv_;
std::optional<bool> is_valid_;
PeerInfo peer_info_;
static void ResultCallback(const PeerInfo* peer_info, void* opaque) {
auto* p = reinterpret_cast<PairingResultWaiter*>(opaque);
{
std::unique_lock<std::mutex> lock(p->mutex_);
if (peer_info) {
memcpy(&(p->peer_info_), peer_info, sizeof(PeerInfo));
}
p->is_valid_ = (peer_info != nullptr);
}
p->cv_.notify_one();
}
};
PairingServerPtr sServer;
std::unique_ptr<PairingResultWaiter> sWaiter;
} // namespace
static jint native_pairing_start(JNIEnv* env, jobject thiz, jstring guid, jstring password) {
// Server-side only sends its GUID on success.
PeerInfo system_info = {};
system_info.type = ADB_DEVICE_GUID;
JStringUTFWrapper guidWrapper(env, &guid);
memcpy(system_info.data, guidWrapper.data(), guidWrapper.size());
JStringUTFWrapper passwordWrapper(env, &password);
// Create the pairing server
sServer = PairingServerPtr(
pairing_server_new_no_cert(reinterpret_cast<const uint8_t*>(passwordWrapper.data()),
passwordWrapper.size(), &system_info, 0));
sWaiter.reset(new PairingResultWaiter);
uint16_t port = pairing_server_start(sServer.get(), sWaiter->ResultCallback, sWaiter.get());
if (port == 0) {
ALOGE("Failed to start pairing server");
return -1;
}
return port;
}
static void native_pairing_cancel(JNIEnv* /* env */, jclass /* clazz */) {
if (sServer != nullptr) {
sServer.reset();
}
}
static jboolean native_pairing_wait(JNIEnv* env, jobject thiz) {
ALOGI("Waiting for pairing server to complete");
std::unique_lock<std::mutex> lock(sWaiter->mutex_);
if (!sWaiter->is_valid_.has_value()) {
sWaiter->cv_.wait(lock, [&]() { return sWaiter->is_valid_.has_value(); });
}
if (!*(sWaiter->is_valid_)) {
return JNI_FALSE;
}
std::string peer_public_key = reinterpret_cast<char*>(sWaiter->peer_info_.data);
// Write to PairingThread's member variables
jclass clazz = env->GetObjectClass(thiz);
jfieldID mPublicKey = env->GetFieldID(clazz, "mPublicKey", "Ljava/lang/String;");
jstring jpublickey = env->NewStringUTF(peer_public_key.c_str());
env->SetObjectField(thiz, mPublicKey, jpublickey);
return JNI_TRUE;
}
// ----------------------------------------------------------------------------
static const JNINativeMethod gPairingThreadMethods[] = {
/* name, signature, funcPtr */
{"native_pairing_start", "(Ljava/lang/String;Ljava/lang/String;)I",
(void*)native_pairing_start},
{"native_pairing_cancel", "()V", (void*)native_pairing_cancel},
{"native_pairing_wait", "()Z", (void*)native_pairing_wait},
};
int register_android_server_AdbDebuggingManager(JNIEnv* env) {
int res = jniRegisterNativeMethods(env,
"com/android/server/adb/AdbDebuggingManager$PairingThread",
gPairingThreadMethods, NELEM(gPairingThreadMethods));
(void)res; // Faked use when LOG_NDEBUG.
LOG_FATAL_IF(res < 0, "Unable to register native methods.");
return 0;
}
} /* namespace android */

View File

@@ -61,6 +61,7 @@ int register_com_android_server_soundtrigger_middleware_AudioSessionProviderImpl
int register_android_server_incremental_IncrementalManagerService(JNIEnv* env);
int register_android_server_com_android_server_pm_PackageManagerShellCommandDataLoader(JNIEnv* env);
int register_android_server_stats_pull_StatsPullAtomService(JNIEnv* env);
int register_android_server_AdbDebuggingManager(JNIEnv* env);
};
using namespace android;
@@ -115,5 +116,6 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
register_android_server_incremental_IncrementalManagerService(env);
register_android_server_com_android_server_pm_PackageManagerShellCommandDataLoader(env);
register_android_server_stats_pull_StatsPullAtomService(env);
register_android_server_AdbDebuggingManager(env);
return JNI_VERSION_1_4;
}

View File

@@ -1719,21 +1719,6 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
*/
private static final int ENUMERATION_TIME_OUT_MS = 2000;
/**
* Command to start native service.
*/
protected static final String CTL_START = "ctl.start";
/**
* Command to start native service.
*/
protected static final String CTL_STOP = "ctl.stop";
/**
* Adb native daemon.
*/
protected static final String ADBD = "adbd";
/**
* Gadget HAL fully qualified instance name for registering for ServiceNotification.
*/
@@ -1932,17 +1917,7 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
return;
}
try {
if ((config & UsbManager.FUNCTION_ADB) != 0) {
/**
* Start adbd if ADB function is included in the configuration.
*/
setSystemProperty(CTL_START, ADBD);
} else {
/**
* Stop adbd otherwise.
*/
setSystemProperty(CTL_STOP, ADBD);
}
// Adbd will be started by AdbService once Global.ADB_ENABLED is set.
UsbGadgetCallback usbGadgetCallback = new UsbGadgetCallback(mCurrentRequest,
config, chargingFunctions);
mGadgetProxy.setCurrentUsbFunctions(config, usbGadgetCallback,