diff options
-rw-r--r-- | adbconnection/adbconnection.cc | 257 | ||||
-rw-r--r-- | adbconnection/adbconnection.h | 42 | ||||
-rw-r--r-- | runtime/native/dalvik_system_VMDebug.cc | 65 | ||||
-rw-r--r-- | runtime/runtime_callbacks.cc | 40 | ||||
-rw-r--r-- | runtime/runtime_callbacks.h | 23 |
5 files changed, 372 insertions, 55 deletions
diff --git a/adbconnection/adbconnection.cc b/adbconnection/adbconnection.cc index 55eac932d3..2ef7a842fa 100644 --- a/adbconnection/adbconnection.cc +++ b/adbconnection/adbconnection.cc @@ -16,6 +16,7 @@ #include "adbconnection.h" +#include <dlfcn.h> #include <jni.h> #include <sys/eventfd.h> #include <sys/ioctl.h> @@ -74,8 +75,7 @@ using dt_fd_forward::kSkipHandshakeMessage; using android::base::StringPrintf; static constexpr const char kJdwpHandshake[14] = { - 'J', 'D', 'W', 'P', '-', 'H', 'a', 'n', 'd', 's', 'h', 'a', 'k', 'e' -}; + 'J', 'D', 'W', 'P', '-', 'H', 'a', 'n', 'd', 's', 'h', 'a', 'k', 'e'}; static constexpr int kEventfdLocked = 0; static constexpr int kEventfdUnlocked = 1; @@ -92,8 +92,88 @@ static constexpr uint8_t kDdmChunkCommand = 1; static std::optional<AdbConnectionState> gState; static std::optional<pthread_t> gPthread; -static bool IsDebuggingPossible() { - return art::Dbg::IsJdwpAllowed(); +// ADB apex method v2 +using AdbApexProcessName = void (*)(const char*); +AdbApexProcessName apex_adbconnection_client_set_current_process_name = nullptr; +using AdbApexPackageName = void (*)(const char*); +AdbApexPackageName apex_adbconnection_client_add_application = nullptr; +AdbApexPackageName apex_adbconnection_client_remove_application = nullptr; +using AdbApexWaitingForDebugger = void (*)(bool); +AdbApexWaitingForDebugger apex_adbconnection_client_set_waiting_for_debugger = nullptr; +using AdbApexSendUpdate = void (*)(AdbConnectionClientContext*); +AdbApexSendUpdate apex_adbconnection_client_send_update = nullptr; +using AdbApexHasPendingUpdate = bool (*)(); +AdbApexHasPendingUpdate apex_adbconnection_client_has_pending_update = nullptr; +using AdbApexSetUserId = void (*)(int); +AdbApexSetUserId apex_adbconnection_client_set_user_id = nullptr; + +void apex_adbconnection_client_set_current_process_name_noop(const char*) {} +void apex_adbconnection_client_add_application_noop(const char*) {} +void apex_adbconnection_client_remove_application_noop(const char*) {} +void apex_adbconnection_client_set_waiting_for_debugger_noop(bool) {} +void apex_adbconnection_client_send_update_noop(AdbConnectionClientContext*) {} +bool apex_adbconnection_client_has_pending_update_noop() { return false; } +void apex_adbconnection_client_set_user_id_noop(int) {} + +static void RetrieveApexPointers() { + apex_adbconnection_client_set_current_process_name = + (AdbApexProcessName)dlsym(RTLD_DEFAULT, "adbconnection_client_set_current_process_name"); + if (!apex_adbconnection_client_set_current_process_name) { + VLOG(jdwp) << "Unable to dlsym adbconnection_client_set_current_process_name"; + apex_adbconnection_client_set_current_process_name = + apex_adbconnection_client_set_current_process_name_noop; + } + + apex_adbconnection_client_add_application = + (AdbApexPackageName)dlsym(RTLD_DEFAULT, "adbconnection_client_add_application"); + if (!apex_adbconnection_client_add_application) { + VLOG(jdwp) << "Unable to dlsym adbconnection_client_add_application"; + apex_adbconnection_client_add_application = apex_adbconnection_client_add_application_noop; + } + + apex_adbconnection_client_remove_application = + (AdbApexPackageName)dlsym(RTLD_DEFAULT, "adbconnection_client_remove_application"); + if (!apex_adbconnection_client_remove_application) { + VLOG(jdwp) << "Unable to dlsym adbconnection_client_remove_application"; + apex_adbconnection_client_remove_application = + apex_adbconnection_client_remove_application_noop; + } + + apex_adbconnection_client_set_waiting_for_debugger = (AdbApexWaitingForDebugger)dlsym( + RTLD_DEFAULT, "adbconnection_client_set_waiting_for_debugger"); + if (!apex_adbconnection_client_set_waiting_for_debugger) { + VLOG(jdwp) << "Unable to dlsym adbconnection_client_set_waiting_for_debugger"; + apex_adbconnection_client_set_waiting_for_debugger = + apex_adbconnection_client_set_waiting_for_debugger_noop; + } + + apex_adbconnection_client_send_update = + (AdbApexSendUpdate)dlsym(RTLD_DEFAULT, "adbconnection_client_send_update"); + if (!apex_adbconnection_client_send_update) { + VLOG(jdwp) << "Unable to dlsym adbconnection_client_send_update"; + apex_adbconnection_client_send_update = apex_adbconnection_client_send_update_noop; + } + + apex_adbconnection_client_has_pending_update = + (AdbApexHasPendingUpdate)dlsym(RTLD_DEFAULT, "adbconnection_client_has_pending_update"); + if (!apex_adbconnection_client_has_pending_update) { + VLOG(jdwp) << "Unable to dlsym adbconnection_client_has_pending_update"; + apex_adbconnection_client_has_pending_update = + apex_adbconnection_client_has_pending_update_noop; + } + + apex_adbconnection_client_set_user_id = + (AdbApexSetUserId)dlsym(RTLD_DEFAULT, "adbconnection_client_set_user_id"); + if (!apex_adbconnection_client_set_user_id) { + VLOG(jdwp) << "Unable to dlsym adbconnection_client_set_user_id"; + apex_adbconnection_client_set_user_id = apex_adbconnection_client_set_user_id_noop; + } +} + +static bool IsDebuggingPossible() { return art::Dbg::IsJdwpAllowed(); } + +static bool IsDebuggableOrProfilable() { + return IsDebuggingPossible() || art::Runtime::Current()->IsProfileableFromShell(); } // Begin running the debugger. @@ -101,7 +181,7 @@ void AdbConnectionDebuggerController::StartDebugger() { // The debugger thread is started for a debuggable or profileable-from-shell process. // The pid will be send to adbd for adb's "track-jdwp" and "track-app" services. // The thread will also set up the jdwp tunnel if the process is debuggable. - if (IsDebuggingPossible() || art::Runtime::Current()->IsProfileableFromShell()) { + if (IsDebuggableOrProfilable()) { connection_->StartDebuggerThreads(); } else { LOG(ERROR) << "Not starting debugger since process cannot load the jdwp agent."; @@ -135,15 +215,31 @@ void AdbConnectionDdmCallback::DdmPublishChunk(uint32_t type, connection_->PublishDdmData(type, data); } +void AdbConnectionAppInfoCallback::SetCurrentProcessName(const std::string& process_name) { + connection_->SetCurrentProcessName(process_name); +} + +void AdbConnectionAppInfoCallback::AddApplication(const std::string& package_name) { + connection_->AddApplication(package_name); +} + +void AdbConnectionAppInfoCallback::RemoveApplication(const std::string& package_name) { + connection_->RemoveApplication(package_name); +} + +void AdbConnectionAppInfoCallback::SetWaitingForDebugger(bool waiting) { + connection_->SetWaitingForDebugger(waiting); +} + +void AdbConnectionAppInfoCallback::SetUserId(int user_id) { connection_->SetUserId(user_id); } + class ScopedEventFdLock { public: explicit ScopedEventFdLock(int fd) : fd_(fd), data_(0) { TEMP_FAILURE_RETRY(read(fd_, &data_, sizeof(data_))); } - ~ScopedEventFdLock() { - TEMP_FAILURE_RETRY(write(fd_, &data_, sizeof(data_))); - } + ~ScopedEventFdLock() { TEMP_FAILURE_RETRY(write(fd_, &data_, sizeof(data_))); } private: int fd_; @@ -151,24 +247,25 @@ class ScopedEventFdLock { }; AdbConnectionState::AdbConnectionState(const std::string& agent_name) - : agent_name_(agent_name), - controller_(this), - ddm_callback_(this), - sleep_event_fd_(-1), - control_ctx_(nullptr, adbconnection_client_destroy), - local_agent_control_sock_(-1), - remote_agent_control_sock_(-1), - adb_connection_socket_(-1), - adb_write_event_fd_(-1), - shutting_down_(false), - agent_loaded_(false), - agent_listening_(false), - agent_has_socket_(false), - sent_agent_fds_(false), - performed_handshake_(false), - notified_ddm_active_(false), - next_ddm_id_(1), - started_debugger_threads_(false) { + : agent_name_(agent_name), + controller_(this), + ddm_callback_(this), + appinfo_callback_(this), + sleep_event_fd_(-1), + control_ctx_(nullptr, adbconnection_client_destroy), + local_agent_control_sock_(-1), + remote_agent_control_sock_(-1), + adb_connection_socket_(-1), + adb_write_event_fd_(-1), + shutting_down_(false), + agent_loaded_(false), + agent_listening_(false), + agent_has_socket_(false), + sent_agent_fds_(false), + performed_handshake_(false), + notified_ddm_active_(false), + next_ddm_id_(1), + started_debugger_threads_(false) { // Add the startup callback. art::ScopedObjectAccess soa(art::Thread::Current()); art::Runtime::Current()->GetRuntimeCallbacks()->AddDebuggerControlCallback(&controller_); @@ -200,8 +297,10 @@ static art::ObjPtr<art::mirror::Object> CreateAdbConnectionThread(art::Thread* s art::Handle<art::mirror::Object> system_thread_group = hs.NewHandle( system_thread_group_field->GetDeclaringClass()->GetFieldObject<art::mirror::Object>( system_thread_group_field->GetOffset())); - return art::WellKnownClasses::java_lang_Thread_init->NewObject<'L', 'L', 'I', 'Z'>( - hs, self, system_thread_group, thr_name, /*priority=*/ 0, /*daemon=*/ true).Get(); + return art::WellKnownClasses::java_lang_Thread_init + ->NewObject<'L', 'L', 'I', 'Z'>( + hs, self, system_thread_group, thr_name, /*priority=*/0, /*daemon=*/true) + .Get(); } struct CallbackData { @@ -211,9 +310,7 @@ struct CallbackData { static void* CallbackFunction(void* vdata) { std::unique_ptr<CallbackData> data(reinterpret_cast<CallbackData*>(vdata)); - art::Thread* self = art::Thread::Attach(kAdbConnectionThreadName, - true, - data->thr_); + art::Thread* self = art::Thread::Attach(kAdbConnectionThreadName, true, data->thr_); CHECK(self != nullptr) << "threads_being_born_ should have ensured thread could be attached."; // The name in Attach() is only for logging. Set the thread name. This is important so // that the thread is no longer seen as starting up. @@ -254,6 +351,7 @@ void AdbConnectionState::StartDebuggerThreads() { { art::ScopedObjectAccess soa(art::Thread::Current()); art::Runtime::Current()->GetRuntimeCallbacks()->AddDdmCallback(&ddm_callback_); + art::Runtime::Current()->GetRuntimeCallbacks()->AddAppInfoCallback(&appinfo_callback_); } // Setup the socketpair we use to talk to the agent. bool has_sockets; @@ -288,13 +386,11 @@ void AdbConnectionState::StartDebuggerThreads() { } // Note: Using pthreads instead of std::thread to not abort when the thread cannot be // created (exception support required). - std::unique_ptr<CallbackData> data(new CallbackData { this, thr }); + std::unique_ptr<CallbackData> data(new CallbackData{this, thr}); started_debugger_threads_ = true; gPthread.emplace(); - int pthread_create_result = pthread_create(&gPthread.value(), - nullptr, - &CallbackFunction, - data.get()); + int pthread_create_result = + pthread_create(&gPthread.value(), nullptr, &CallbackFunction, data.get()); if (pthread_create_result != 0) { gPthread.reset(); started_debugger_threads_ = false; @@ -309,9 +405,7 @@ void AdbConnectionState::StartDebuggerThreads() { data.release(); // NOLINT pthreads API. } -static bool FlagsSet(int16_t data, int16_t flags) { - return (data & flags) == flags; -} +static bool FlagsSet(int16_t data, int16_t flags) { return (data & flags) == flags; } void AdbConnectionState::CloseFds() { { @@ -351,6 +445,41 @@ void AdbConnectionState::PublishDdmData(uint32_t type, const art::ArrayRef<const SendDdmPacket(NextDdmId(), DdmPacketType::kCmd, type, data); } +void AdbConnectionState::SetCurrentProcessName(const std::string& process_name) { + DCHECK(IsDebuggableOrProfilable()); + VLOG(jdwp) << "SetCurrentProcessName '" << process_name << "'"; + apex_adbconnection_client_set_current_process_name(process_name.c_str()); + WakeupPollLoop(); +} + +void AdbConnectionState::AddApplication(const std::string& package_name) { + DCHECK(IsDebuggableOrProfilable()); + VLOG(jdwp) << "AddApplication'" << package_name << "'"; + apex_adbconnection_client_add_application(package_name.c_str()); + WakeupPollLoop(); +} + +void AdbConnectionState::RemoveApplication(const std::string& package_name) { + DCHECK(IsDebuggableOrProfilable()); + VLOG(jdwp) << "RemoveApplication'" << package_name << "'"; + apex_adbconnection_client_remove_application(package_name.c_str()); + WakeupPollLoop(); +} + +void AdbConnectionState::SetWaitingForDebugger(bool waiting) { + DCHECK(IsDebuggableOrProfilable()); + VLOG(jdwp) << "SetWaitingForDebugger'" << waiting << "'"; + apex_adbconnection_client_set_waiting_for_debugger(waiting); + WakeupPollLoop(); +} + +void AdbConnectionState::SetUserId(int user_id) { + DCHECK(IsDebuggableOrProfilable()); + VLOG(jdwp) << "SetUserId'" << user_id << "'"; + apex_adbconnection_client_set_user_id(user_id); + WakeupPollLoop(); +} + void AdbConnectionState::SendDdmPacket(uint32_t id, DdmPacketType packet_type, uint32_t type, @@ -533,7 +662,7 @@ bool AdbConnectionState::SetupAdbConnection() { } void AdbConnectionState::RunPollLoop(art::Thread* self) { - DCHECK(IsDebuggingPossible() || art::Runtime::Current()->IsProfileableFromShell()); + DCHECK(IsDebuggableOrProfilable()); CHECK_NE(agent_name_, ""); CHECK_EQ(self->GetState(), art::ThreadState::kNative); art::Locks::mutator_lock_->AssertNotHeld(self); @@ -547,6 +676,13 @@ void AdbConnectionState::RunPollLoop(art::Thread* self) { } while (!shutting_down_ && control_ctx_) { bool should_listen_on_connection = !agent_has_socket_ && !sent_agent_fds_; + // By default we are always interested in read and hangup events on the control ctx. + int16_t interestingControlEventSet = POLLIN | POLLRDHUP; + if (apex_adbconnection_client_has_pending_update()) { + // If we have an update for ADBd, we also want to know when the control ctx + // socket is writable. + interestingControlEventSet |= POLLOUT; + } struct pollfd pollfds[4] = { {sleep_event_fd_, POLLIN, 0}, // -1 as an fd causes it to be ignored by poll @@ -554,7 +690,7 @@ void AdbConnectionState::RunPollLoop(art::Thread* self) { // Check for the control_sock_ actually going away. We always monitor for POLLIN, even if // we already have an adbd socket. This allows to reject incoming debugger connection if // there is already have one connected. - {adbconnection_client_pollfd(control_ctx_.get()), POLLIN | POLLRDHUP, 0}, + {adbconnection_client_pollfd(control_ctx_.get()), interestingControlEventSet, 0}, // if we have not loaded the agent either the adb_connection_socket_ is -1 meaning we // don't have a real connection yet or the socket through adb needs to be listened to for // incoming data that the agent or this plugin can handle. @@ -564,8 +700,9 @@ void AdbConnectionState::RunPollLoop(art::Thread* self) { PLOG(ERROR) << "Failed to poll!"; return; } - // We don't actually care about doing this we just use it to wake us up. - // const struct pollfd& sleep_event_poll = pollfds[0]; + VLOG(jdwp) << "adbconnection poll awakening"; + + const struct pollfd& sleep_event_poll = pollfds[0]; const struct pollfd& agent_control_sock_poll = pollfds[1]; const struct pollfd& control_sock_poll = pollfds[2]; const struct pollfd& adb_socket_poll = pollfds[3]; @@ -652,12 +789,19 @@ void AdbConnectionState::RunPollLoop(art::Thread* self) { } else if (agent_listening_ && !sent_agent_fds_) { VLOG(jdwp) << "Sending agent fds again on data."; // Agent was already loaded so it can deal with the handshake. - SendAgentFds(/*require_handshake=*/ true); + SendAgentFds(/*require_handshake=*/true); } + } else if (FlagsSet(control_sock_poll.revents, POLLOUT)) { + VLOG(jdwp) << "Sending state update to adbd"; + apex_adbconnection_client_send_update(control_ctx_.get()); } else if (FlagsSet(adb_socket_poll.revents, POLLRDHUP)) { CHECK(IsDebuggingPossible()); // This path is unexpected for a profileable process. DCHECK(!agent_has_socket_); CloseFds(); + } else if (FlagsSet(sleep_event_poll.revents, POLLIN)) { + // Poll was awakened via fdevent, we need to decrease fdevent counter to prevent poll from + // triggering again. + AcknowledgeWakeup(); } else { VLOG(jdwp) << "Woke up poll without anything to do!"; } @@ -916,19 +1060,36 @@ std::string AdbConnectionState::MakeAgentArg() { return agent_name_ + "=" + parameters.join(); } -void AdbConnectionState::StopDebuggerThreads() { - // The regular agent system will take care of unloading the agent (if needed). - shutting_down_ = true; - // Wakeup the poll loop. +void AdbConnectionState::WakeupPollLoop() { + if (!control_ctx_) { + return; + } + uint64_t data = 1; if (sleep_event_fd_ != -1) { TEMP_FAILURE_RETRY(write(sleep_event_fd_, &data, sizeof(data))); } } +void AdbConnectionState::AcknowledgeWakeup() { + uint64_t data; + if (sleep_event_fd_ != -1) { + TEMP_FAILURE_RETRY(read(sleep_event_fd_, &data, sizeof(data))); + } +} + +void AdbConnectionState::StopDebuggerThreads() { + // The regular agent system will take care of unloading the agent (if needed). + shutting_down_ = true; + WakeupPollLoop(); +} + // The plugin initialization function. extern "C" bool ArtPlugin_Initialize() { DCHECK(art::Runtime::Current()->GetJdwpProvider() == art::JdwpProvider::kAdbConnection); + + RetrieveApexPointers(); + // TODO Provide some way for apps to set this maybe? gState.emplace(kDefaultJdwpAgentName); return ValidateJdwpOptions(art::Runtime::Current()->GetJdwpOptions()); diff --git a/adbconnection/adbconnection.h b/adbconnection/adbconnection.h index b6309e735d..d1d1e51067 100644 --- a/adbconnection/adbconnection.h +++ b/adbconnection/adbconnection.h @@ -24,6 +24,7 @@ #include <limits> #include <memory> +#include <string> #include <vector> #include "adbconnection/client.h" @@ -69,6 +70,21 @@ struct AdbConnectionDdmCallback : public art::DdmCallback { AdbConnectionState* connection_; }; +struct AdbConnectionAppInfoCallback : public art::AppInfoCallback { + explicit AdbConnectionAppInfoCallback(AdbConnectionState* connection) : connection_(connection) {} + + void AddApplication(const std::string& package_name) REQUIRES_SHARED(art::Locks::mutator_lock_); + void RemoveApplication(const std::string& package_name) + REQUIRES_SHARED(art::Locks::mutator_lock_); + void SetCurrentProcessName(const std::string& process_name) + REQUIRES_SHARED(art::Locks::mutator_lock_); + void SetWaitingForDebugger(bool waiting) REQUIRES_SHARED(art::Locks::mutator_lock_); + void SetUserId(int uid) REQUIRES_SHARED(art::Locks::mutator_lock_); + + private: + AdbConnectionState* connection_; +}; + class AdbConnectionState { public: explicit AdbConnectionState(const std::string& name); @@ -82,6 +98,15 @@ class AdbConnectionState { // hand-shaking yet. void PublishDdmData(uint32_t type, const art::ArrayRef<const uint8_t>& data); + // Wake up the poll. Call this if the set of interesting event has changed. They will be + // recalculated and poll will be called again via fdevent write. This wakeup relies on fdevent + // and should be ACKed via AcknowledgeWakeup. + void WakeupPollLoop(); + + // After a call to WakeupPollLoop, the fdevent internal counter should be decreased via + // this method. This should be called after WakeupPollLoop was called and poll triggered. + void AcknowledgeWakeup(); + // Stops debugger threads during shutdown. void StopDebuggerThreads(); @@ -90,6 +115,22 @@ class AdbConnectionState { return started_debugger_threads_; } + // Should be called by Framework when it changes its process name. + void SetCurrentProcessName(const std::string& process_name); + + // Should be called by Framework when it adds an app to a process. + // This can be called several times (see android:process) + void AddApplication(const std::string& package_name); + + // Should be called by Framework when it removes an app from a process. + void RemoveApplication(const std::string& package_name); + + // Should be called by Framework when its debugging state changes. + void SetWaitingForDebugger(bool waiting); + + // Should be called by Framework when the UserID is known. + void SetUserId(int uid); + private: uint32_t NextDdmId(); @@ -121,6 +162,7 @@ class AdbConnectionState { AdbConnectionDebuggerController controller_; AdbConnectionDdmCallback ddm_callback_; + AdbConnectionAppInfoCallback appinfo_callback_; // Eventfd used to allow the StopDebuggerThreads function to wake up sleeping threads android::base::unique_fd sleep_event_fd_; diff --git a/runtime/native/dalvik_system_VMDebug.cc b/runtime/native/dalvik_system_VMDebug.cc index 137b04fede..18120fe826 100644 --- a/runtime/native/dalvik_system_VMDebug.cc +++ b/runtime/native/dalvik_system_VMDebug.cc @@ -55,13 +55,16 @@ namespace art HIDDEN { static jobjectArray VMDebug_getVmFeatureList(JNIEnv* env, jclass) { ScopedObjectAccess soa(Thread::ForEnv(env)); - return soa.AddLocalReference<jobjectArray>(CreateStringArray(soa.Self(), { - "method-trace-profiling", - "method-trace-profiling-streaming", - "method-sample-profiling", - "hprof-heap-dump", - "hprof-heap-dump-streaming", - })); + return soa.AddLocalReference<jobjectArray>( + CreateStringArray(soa.Self(), + { + "method-trace-profiling", + "method-trace-profiling-streaming", + "method-sample-profiling", + "hprof-heap-dump", + "hprof-heap-dump-streaming", + "app_info", + })); } static void VMDebug_startAllocCounting(JNIEnv*, jclass) { @@ -514,6 +517,49 @@ static void VMDebug_setAllocTrackerStackDepth(JNIEnv* env, jclass, jint stack_de } } +static void VMDebug_setCurrentProcessName(JNIEnv* env, jclass, jstring process_name) { + ScopedFastNativeObjectAccess soa(env); + + // Android application ID naming convention states: + // "The name can contain uppercase or lowercase letters, numbers, and underscores ('_')" + // This is fine to convert to std::string + const char* c_process_name = env->GetStringUTFChars(process_name, NULL); + Runtime::Current()->GetRuntimeCallbacks()->SetCurrentProcessName(std::string(c_process_name)); + env->ReleaseStringUTFChars(process_name, c_process_name); +} + +static void VMDebug_addApplication(JNIEnv* env, jclass, jstring package_name) { + ScopedFastNativeObjectAccess soa(env); + + // Android application ID naming convention states: + // "The name can contain uppercase or lowercase letters, numbers, and underscores ('_')" + // This is fine to convert to std::string + const char* c_package_name = env->GetStringUTFChars(package_name, NULL); + Runtime::Current()->GetRuntimeCallbacks()->AddApplication(std::string(c_package_name)); + env->ReleaseStringUTFChars(package_name, c_package_name); +} + +static void VMDebug_removeApplication(JNIEnv* env, jclass, jstring package_name) { + ScopedFastNativeObjectAccess soa(env); + + // Android application ID naming convention states: + // "The name can contain uppercase or lowercase letters, numbers, and underscores ('_')" + // This is fine to convert to std::string + const char* c_package_name = env->GetStringUTFChars(package_name, NULL); + Runtime::Current()->GetRuntimeCallbacks()->RemoveApplication(std::string(c_package_name)); + env->ReleaseStringUTFChars(package_name, c_package_name); +} + +static void VMDebug_setWaitingForDebugger(JNIEnv* env, jclass, jboolean waiting) { + ScopedFastNativeObjectAccess soa(env); + Runtime::Current()->GetRuntimeCallbacks()->SetWaitingForDebugger(waiting); +} + +static void VMDebug_setUserId(JNIEnv* env, jclass, jint user_id) { + ScopedFastNativeObjectAccess soa(env); + Runtime::Current()->GetRuntimeCallbacks()->SetUserId(user_id); +} + static JNINativeMethod gMethods[] = { NATIVE_METHOD(VMDebug, countInstancesOfClass, "(Ljava/lang/Class;Z)J"), NATIVE_METHOD(VMDebug, countInstancesOfClasses, "([Ljava/lang/Class;Z)[J"), @@ -542,6 +588,11 @@ static JNINativeMethod gMethods[] = { NATIVE_METHOD(VMDebug, nativeAttachAgent, "(Ljava/lang/String;Ljava/lang/ClassLoader;)V"), NATIVE_METHOD(VMDebug, allowHiddenApiReflectionFrom, "(Ljava/lang/Class;)V"), NATIVE_METHOD(VMDebug, setAllocTrackerStackDepth, "(I)V"), + NATIVE_METHOD(VMDebug, setCurrentProcessName, "(Ljava/lang/String;)V"), + NATIVE_METHOD(VMDebug, setWaitingForDebugger, "(Z)V"), + NATIVE_METHOD(VMDebug, addApplication, "(Ljava/lang/String;)V"), + NATIVE_METHOD(VMDebug, removeApplication, "(Ljava/lang/String;)V"), + NATIVE_METHOD(VMDebug, setUserId, "(I)V"), }; void register_dalvik_system_VMDebug(JNIEnv* env) { diff --git a/runtime/runtime_callbacks.cc b/runtime/runtime_callbacks.cc index aad943020d..0b10d2ee1d 100644 --- a/runtime/runtime_callbacks.cc +++ b/runtime/runtime_callbacks.cc @@ -58,12 +58,52 @@ void RuntimeCallbacks::RemoveDdmCallback(DdmCallback* cb) { Remove(cb, &ddm_callbacks_); } +void RuntimeCallbacks::AddAppInfoCallback(AppInfoCallback* cb) { + WriterMutexLock mu(Thread::Current(), *callback_lock_); + appinfo_callbacks_.push_back(cb); +} + +void RuntimeCallbacks::RemoveAppInfoCallback(AppInfoCallback* cb) { + WriterMutexLock mu(Thread::Current(), *callback_lock_); + Remove(cb, &appinfo_callbacks_); +} + void RuntimeCallbacks::DdmPublishChunk(uint32_t type, const ArrayRef<const uint8_t>& data) { for (DdmCallback* cb : COPY(ddm_callbacks_)) { cb->DdmPublishChunk(type, data); } } +void RuntimeCallbacks::SetCurrentProcessName(const std::string& process_name) { + for (AppInfoCallback* cb : COPY(appinfo_callbacks_)) { + cb->SetCurrentProcessName(process_name); + } +} + +void RuntimeCallbacks::AddApplication(const std::string& package_name) { + for (AppInfoCallback* cb : COPY(appinfo_callbacks_)) { + cb->AddApplication(package_name); + } +} + +void RuntimeCallbacks::RemoveApplication(const std::string& package_name) { + for (AppInfoCallback* cb : COPY(appinfo_callbacks_)) { + cb->RemoveApplication(package_name); + } +} + +void RuntimeCallbacks::SetWaitingForDebugger(bool waiting) { + for (AppInfoCallback* cb : COPY(appinfo_callbacks_)) { + cb->SetWaitingForDebugger(waiting); + } +} + +void RuntimeCallbacks::SetUserId(int user_id) { + for (AppInfoCallback* cb : COPY(appinfo_callbacks_)) { + cb->SetUserId(user_id); + } +} + void RuntimeCallbacks::AddDebuggerControlCallback(DebuggerControlCallback* cb) { WriterMutexLock mu(Thread::Current(), *callback_lock_); debugger_control_callbacks_.push_back(cb); diff --git a/runtime/runtime_callbacks.h b/runtime/runtime_callbacks.h index 9d7e199bfa..4e355151da 100644 --- a/runtime/runtime_callbacks.h +++ b/runtime/runtime_callbacks.h @@ -70,6 +70,19 @@ class DdmCallback { REQUIRES_SHARED(Locks::mutator_lock_) = 0; }; +class AppInfoCallback { + public: + virtual ~AppInfoCallback() {} + virtual void SetCurrentProcessName(const std::string& process_name) + REQUIRES_SHARED(Locks::mutator_lock_) = 0; + virtual void AddApplication(const std::string& package_name) + REQUIRES_SHARED(Locks::mutator_lock_) = 0; + virtual void RemoveApplication(const std::string& package_name) + REQUIRES_SHARED(Locks::mutator_lock_) = 0; + virtual void SetWaitingForDebugger(bool waiting) REQUIRES_SHARED(Locks::mutator_lock_) = 0; + virtual void SetUserId(int uid) REQUIRES_SHARED(Locks::mutator_lock_) = 0; +}; + class DebuggerControlCallback { public: virtual ~DebuggerControlCallback() {} @@ -240,6 +253,15 @@ class EXPORT RuntimeCallbacks { void AddDdmCallback(DdmCallback* cb) REQUIRES_SHARED(Locks::mutator_lock_); void RemoveDdmCallback(DdmCallback* cb) REQUIRES_SHARED(Locks::mutator_lock_); + void SetCurrentProcessName(const std::string& process_name) REQUIRES_SHARED(Locks::mutator_lock_); + void AddApplication(const std::string& package_name) REQUIRES_SHARED(Locks::mutator_lock_); + void RemoveApplication(const std::string& package_name) REQUIRES_SHARED(Locks::mutator_lock_); + void SetWaitingForDebugger(bool waiting) REQUIRES_SHARED(Locks::mutator_lock_); + void SetUserId(int uid) REQUIRES_SHARED(Locks::mutator_lock_); + + void AddAppInfoCallback(AppInfoCallback* cb) REQUIRES_SHARED(Locks::mutator_lock_); + void RemoveAppInfoCallback(AppInfoCallback* cb) REQUIRES_SHARED(Locks::mutator_lock_); + void StartDebugger() REQUIRES_SHARED(Locks::mutator_lock_); // NO_THREAD_SAFETY_ANALYSIS since this is only called when we are in the middle of shutting down // and the mutator_lock_ is no longer acquirable. @@ -279,6 +301,7 @@ class EXPORT RuntimeCallbacks { GUARDED_BY(callback_lock_); std::vector<DdmCallback*> ddm_callbacks_ GUARDED_BY(callback_lock_); + std::vector<AppInfoCallback*> appinfo_callbacks_ GUARDED_BY(callback_lock_); std::vector<DebuggerControlCallback*> debugger_control_callbacks_ GUARDED_BY(callback_lock_); std::vector<ReflectiveValueVisitCallback*> reflective_value_visit_callbacks_ |