blob: 9c834aaece8592c510e9c119dbdd7a5e5439fcb9 [file] [log] [blame]
/*
* 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 */