Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c6e64b3e authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge ""track-app" service showing debuggable/profileable apps"

parents 3a4e3825 f4ffae10
Loading
Loading
Loading
Loading
+15 −1
Original line number Diff line number Diff line
@@ -314,6 +314,7 @@ cc_binary_host {
        "libadb_protos",
        "libadb_tls_connection",
        "libandroidfw",
        "libapp_processes_protos_full",
        "libbase",
        "libcutils",
        "libcrypto_utils",
@@ -323,7 +324,7 @@ cc_binary_host {
        "liblog",
        "liblz4",
        "libmdnssd",
        "libprotobuf-cpp-lite",
        "libprotobuf-cpp-full",
        "libssl",
        "libusb",
        "libutils",
@@ -387,6 +388,7 @@ cc_library_static {

    static_libs: [
        "libadbconnection_server",
        "libapp_processes_protos_lite",
        "libdiagnose_usb",
    ],

@@ -403,6 +405,12 @@ cc_library_static {
        "liblog",
    ],

    proto: {
        type: "lite",
        static: true,
        export_proto_headers: true,
    },

    target: {
        android: {
            whole_static_libs: [
@@ -450,7 +458,9 @@ cc_library_static {
    static_libs: [
        "libadbconnection_server",
        "libadbd_core",
        "libapp_processes_protos_lite",
        "libdiagnose_usb",
        "libprotobuf-cpp-lite",
    ],

    shared_libs: [
@@ -507,6 +517,8 @@ cc_library {
    whole_static_libs: [
        "libadbconnection_server",
        "libadbd_core",
        "libapp_processes_protos_lite",
        "libprotobuf-cpp-lite",
    ],

    shared_libs: [
@@ -569,6 +581,7 @@ cc_binary {
        "libadbconnection_server",
        "libadbd",
        "libadbd_services",
        "libapp_processes_protos_lite",
        "libasyncio",
        "libbase",
        "libcap",
@@ -578,6 +591,7 @@ cc_binary {
        "liblog",
        "libmdnssd",
        "libminijail",
        "libprotobuf-cpp-lite",
        "libselinux",
        "libssl",
    ],
+1 −0
Original line number Diff line number Diff line
@@ -169,6 +169,7 @@ unique_fd execute_abb_command(std::string_view command);
int init_jdwp(void);
asocket* create_jdwp_service_socket();
asocket* create_jdwp_tracker_service_socket();
asocket* create_app_tracker_service_socket();
unique_fd create_jdwp_connection_fd(int jdwp_pid);
#endif

+49 −2
Original line number Diff line number Diff line
@@ -50,6 +50,8 @@
#include <unistd.h>
#endif

#include <google/protobuf/text_format.h>

#include "adb.h"
#include "adb_auth.h"
#include "adb_client.h"
@@ -57,6 +59,7 @@
#include "adb_io.h"
#include "adb_unique_fd.h"
#include "adb_utils.h"
#include "app_processes.pb.h"
#include "bugreport.h"
#include "client/file_sync_client.h"
#include "commandline.h"
@@ -1354,17 +1357,49 @@ static void parse_push_pull_args(const char** arg, int narg, std::vector<const c
    }
}

static int adb_connect_command(const std::string& command, TransportId* transport = nullptr) {
static int adb_connect_command(const std::string& command, TransportId* transport,
                               StandardStreamsCallbackInterface* callback) {
    std::string error;
    unique_fd fd(adb_connect(transport, command, &error));
    if (fd < 0) {
        fprintf(stderr, "error: %s\n", error.c_str());
        return 1;
    }
    read_and_dump(fd);
    read_and_dump(fd, false, callback);
    return 0;
}

static int adb_connect_command(const std::string& command, TransportId* transport = nullptr) {
    return adb_connect_command(command, transport, &DEFAULT_STANDARD_STREAMS_CALLBACK);
}

// A class that prints out human readable form of the protobuf message for "track-app" service
// (received in binary format).
class TrackAppStreamsCallback : public DefaultStandardStreamsCallback {
  public:
    TrackAppStreamsCallback() : DefaultStandardStreamsCallback(nullptr, nullptr) {}

    // Assume the buffer contains at least 4 bytes of valid data.
    void OnStdout(const char* buffer, int length) override {
        if (length < 4) return;  // Unexpected length received. Do nothing.

        adb::proto::AppProcesses binary_proto;
        // The first 4 bytes are the length of remaining content in hexadecimal format.
        binary_proto.ParseFromString(std::string(buffer + 4, length - 4));
        char summary[24];  // The following string includes digits and 16 fixed characters.
        int written = snprintf(summary, sizeof(summary), "Process count: %d\n",
                               binary_proto.process_size());
        OnStream(nullptr, stdout, summary, written);

        std::string string_proto;
        google::protobuf::TextFormat::PrintToString(binary_proto, &string_proto);
        OnStream(nullptr, stdout, string_proto.data(), string_proto.length());
    }

  private:
    DISALLOW_COPY_AND_ASSIGN(TrackAppStreamsCallback);
};

static int adb_connect_command_bidirectional(const std::string& command) {
    std::string error;
    unique_fd fd(adb_connect(command, &error));
@@ -1925,6 +1960,18 @@ int adb_commandline(int argc, const char** argv) {
        return adb_connect_command("jdwp");
    } else if (!strcmp(argv[0], "track-jdwp")) {
        return adb_connect_command("track-jdwp");
    } else if (!strcmp(argv[0], "track-app")) {
        FeatureSet features;
        std::string error;
        if (!adb_get_feature_set(&features, &error)) {
            fprintf(stderr, "error: %s\n", error.c_str());
            return 1;
        }
        if (!CanUseFeature(features, kFeatureTrackApp)) {
            error_exit("track-app is not supported by the device");
        }
        TrackAppStreamsCallback callback;
        return adb_connect_command("track-app", nullptr, &callback);
    } else if (!strcmp(argv[0], "track-devices")) {
        if (argc > 2 || (argc == 2 && strcmp(argv[1], "-l"))) {
            error_exit("usage: adb track-devices [-l]");
+99 −25
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include "sysdeps.h"

#include <errno.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -33,6 +34,7 @@
#include <thread>
#include <vector>

#include <adbconnection/process_info.h>
#include <adbconnection/server.h>
#include <android-base/cmsg.h>
#include <android-base/unique_fd.h>
@@ -41,6 +43,7 @@
#include "adb_io.h"
#include "adb_unique_fd.h"
#include "adb_utils.h"
#include "app_processes.pb.h"

using android::base::borrowed_fd;
using android::base::unique_fd;
@@ -132,18 +135,24 @@ using android::base::unique_fd;
 ** for each JDWP process, we record its pid and its connected socket
 **/

enum class TrackerKind {
    kJdwp,
    kApp,
};

static void jdwp_process_event(int socket, unsigned events, void* _proc);
static void jdwp_process_list_updated(void);
static void app_process_list_updated(void);

struct JdwpProcess;
static auto& _jdwp_list = *new std::list<std::unique_ptr<JdwpProcess>>();

struct JdwpProcess {
    JdwpProcess(unique_fd socket, pid_t pid) {
        CHECK(pid != 0);
    JdwpProcess(unique_fd socket, ProcessInfo process) {
        CHECK(process.pid != 0);

        this->socket = socket;
        this->pid = pid;
        this->process = process;
        this->fde = fdevent_create(socket.release(), jdwp_process_event, this);

        if (!this->fde) {
@@ -171,17 +180,19 @@ struct JdwpProcess {
    }

    borrowed_fd socket = -1;
    int32_t pid = -1;
    ProcessInfo process;
    fdevent* fde = nullptr;

    std::vector<unique_fd> out_fds;
};

// Populate the list of processes for "track-jdwp" service.
static size_t jdwp_process_list(char* buffer, size_t bufferlen) {
    std::string temp;

    for (auto& proc : _jdwp_list) {
        std::string next = std::to_string(proc->pid) + "\n";
        if (!proc->process.debuggable) continue;
        std::string next = std::to_string(proc->process.pid) + "\n";
        if (temp.length() + next.length() > bufferlen) {
            D("truncating JDWP process list (max len = %zu)", bufferlen);
            break;
@@ -193,7 +204,44 @@ static size_t jdwp_process_list(char* buffer, size_t bufferlen) {
    return temp.length();
}

static size_t jdwp_process_list_msg(char* buffer, size_t bufferlen) {
// Populate the list of processes for "track-app" service.
// The list is a protobuf message in the binary format for efficiency.
static size_t app_process_list(char* buffer, size_t bufferlen) {
    adb::proto::AppProcesses output;  // result that's guaranteed to fit in the given buffer
    adb::proto::AppProcesses temp;    // temporary result that may be longer than the given buffer
    std::string serialized_message;

    for (auto& proc : _jdwp_list) {
        if (!proc->process.debuggable && !proc->process.profileable) continue;
        auto* entry = temp.add_process();
        entry->set_pid(proc->process.pid);
        entry->set_debuggable(proc->process.debuggable);
        entry->set_profileable(proc->process.profileable);
        entry->set_architecture(proc->process.arch_name, proc->process.arch_name_length);
        temp.SerializeToString(&serialized_message);
        if (serialized_message.size() > bufferlen) {
            D("truncating app process list (max len = %zu)", bufferlen);
            break;
        }
        output = temp;
    }
    output.SerializeToString(&serialized_message);
    memcpy(buffer, serialized_message.data(), serialized_message.length());
    return serialized_message.length();
}

// Populate the list of processes for either "track-jdwp" or "track-app" services,
// depending on the given kind.
static size_t process_list(TrackerKind kind, char* buffer, size_t bufferlen) {
    switch (kind) {
        case TrackerKind::kJdwp:
            return jdwp_process_list(buffer, bufferlen);
        case TrackerKind::kApp:
            return app_process_list(buffer, bufferlen);
    }
}

static size_t process_list_msg(TrackerKind kind, char* buffer, size_t bufferlen) {
    // Message is length-prefixed with 4 hex digits in ASCII.
    static constexpr size_t header_len = 4;
    if (bufferlen < header_len) {
@@ -201,7 +249,7 @@ static size_t jdwp_process_list_msg(char* buffer, size_t bufferlen) {
    }

    char head[header_len + 1];
    size_t len = jdwp_process_list(buffer + header_len, bufferlen - header_len);
    size_t len = process_list(kind, buffer + header_len, bufferlen - header_len);
    snprintf(head, sizeof head, "%04zx", len);
    memcpy(buffer, head, header_len);
    return len + header_len;
@@ -213,7 +261,7 @@ static void jdwp_process_event(int socket, unsigned events, void* _proc) {

    if (events & FDE_READ) {
        // We already have the PID, if we can read from the socket, we've probably hit EOF.
        D("terminating JDWP connection %d", proc->pid);
        D("terminating JDWP connection %" PRId64, proc->process.pid);
        goto CloseProcess;
    }

@@ -223,11 +271,12 @@ static void jdwp_process_event(int socket, unsigned events, void* _proc) {

        int fd = proc->out_fds.back().get();
        if (android::base::SendFileDescriptors(socket, "", 1, fd) != 1) {
            D("sending new file descriptor to JDWP %d failed: %s", proc->pid, strerror(errno));
            D("sending new file descriptor to JDWP %" PRId64 " failed: %s", proc->process.pid,
              strerror(errno));
            goto CloseProcess;
        }

        D("sent file descriptor %d to JDWP process %d", fd, proc->pid);
        D("sent file descriptor %d to JDWP process %" PRId64, fd, proc->process.pid);

        proc->out_fds.pop_back();
        if (proc->out_fds.empty()) {
@@ -238,15 +287,20 @@ static void jdwp_process_event(int socket, unsigned events, void* _proc) {
    return;

CloseProcess:
    bool debuggable = proc->process.debuggable;
    bool profileable = proc->process.profileable;
    proc->RemoveFromList();
    jdwp_process_list_updated();
    if (debuggable) jdwp_process_list_updated();
    if (debuggable || profileable) app_process_list_updated();
}

unique_fd create_jdwp_connection_fd(int pid) {
    D("looking for pid %d in JDWP process list", pid);

    for (auto& proc : _jdwp_list) {
        if (proc->pid == pid) {
        // Don't allow JDWP connection to a non-debuggable process.
        if (!proc->process.debuggable) continue;
        if (proc->process.pid == static_cast<uint64_t>(pid)) {
            int fds[2];

            if (adb_socketpair(fds) < 0) {
@@ -338,18 +392,22 @@ asocket* create_jdwp_service_socket(void) {
 **/

struct JdwpTracker : public asocket {
    TrackerKind kind;
    bool need_initial;

    explicit JdwpTracker(TrackerKind k, bool initial) : kind(k), need_initial(initial) {}
};

static auto& _jdwp_trackers = *new std::vector<std::unique_ptr<JdwpTracker>>();

static void jdwp_process_list_updated(void) {
static void process_list_updated(TrackerKind kind) {
    std::string data;
    data.resize(1024);
    data.resize(jdwp_process_list_msg(&data[0], data.size()));
    const int kMaxLength = kind == TrackerKind::kJdwp ? 1024 : 2048;
    data.resize(kMaxLength);
    data.resize(process_list_msg(kind, &data[0], data.size()));

    for (auto& t : _jdwp_trackers) {
        if (t->peer) {
        if (t->kind == kind && t->peer) {
            // The tracker might not have been connected yet.
            apacket::payload_type payload(data.begin(), data.end());
            t->peer->enqueue(t->peer, std::move(payload));
@@ -357,6 +415,14 @@ static void jdwp_process_list_updated(void) {
    }
}

static void jdwp_process_list_updated(void) {
    process_list_updated(TrackerKind::kJdwp);
}

static void app_process_list_updated(void) {
    process_list_updated(TrackerKind::kApp);
}

static void jdwp_tracker_close(asocket* s) {
    D("LS(%d): destroying jdwp tracker service", s->id);

@@ -380,7 +446,7 @@ static void jdwp_tracker_ready(asocket* s) {
    if (t->need_initial) {
        apacket::payload_type data;
        data.resize(s->get_max_payload());
        data.resize(jdwp_process_list_msg(&data[0], data.size()));
        data.resize(process_list_msg(t->kind, &data[0], data.size()));
        t->need_initial = false;
        s->peer->enqueue(s->peer, std::move(data));
    }
@@ -393,8 +459,8 @@ static int jdwp_tracker_enqueue(asocket* s, apacket::payload_type) {
    return -1;
}

asocket* create_jdwp_tracker_service_socket(void) {
    auto t = std::make_unique<JdwpTracker>();
asocket* create_process_tracker_service_socket(TrackerKind kind) {
    auto t = std::make_unique<JdwpTracker>(kind, true);
    if (!t) {
        LOG(FATAL) << "failed to allocate JdwpTracker";
    }
@@ -407,7 +473,6 @@ asocket* create_jdwp_tracker_service_socket(void) {
    t->ready = jdwp_tracker_ready;
    t->enqueue = jdwp_tracker_enqueue;
    t->close = jdwp_tracker_close;
    t->need_initial = true;

    asocket* result = t.get();

@@ -416,19 +481,28 @@ asocket* create_jdwp_tracker_service_socket(void) {
    return result;
}

asocket* create_jdwp_tracker_service_socket() {
    return create_process_tracker_service_socket(TrackerKind::kJdwp);
}

asocket* create_app_tracker_service_socket() {
    return create_process_tracker_service_socket(TrackerKind::kApp);
}

int init_jdwp(void) {
    std::thread([]() {
        adb_thread_setname("jdwp control");
        adbconnection_listen([](int fd, pid_t pid) {
            LOG(INFO) << "jdwp connection from " << pid;
            fdevent_run_on_main_thread([fd, pid] {
        adbconnection_listen([](int fd, ProcessInfo process) {
            LOG(INFO) << "jdwp connection from " << process.pid;
            fdevent_run_on_main_thread([fd, process] {
                unique_fd ufd(fd);
                auto proc = std::make_unique<JdwpProcess>(std::move(ufd), pid);
                auto proc = std::make_unique<JdwpProcess>(std::move(ufd), process);
                if (!proc) {
                    LOG(FATAL) << "failed to allocate JdwpProcess";
                }
                _jdwp_list.emplace_back(std::move(proc));
                jdwp_process_list_updated();
                if (process.debuggable) jdwp_process_list_updated();
                if (process.debuggable || process.profileable) app_process_list_updated();
            });
        });
    }).detach();
+2 −0
Original line number Diff line number Diff line
@@ -241,6 +241,8 @@ asocket* daemon_service_to_socket(std::string_view name) {
        return create_jdwp_service_socket();
    } else if (name == "track-jdwp") {
        return create_jdwp_tracker_service_socket();
    } else if (name == "track-app") {
        return create_app_tracker_service_socket();
    } else if (android::base::ConsumePrefix(&name, "sink:")) {
        uint64_t byte_count = 0;
        if (!ParseUint(&byte_count, name)) {
Loading