ADB? Debug ADB (ADB sets the code sorting of its own log and sets the ADB's own log to be visible)

Keywords: Android shell Linux Unix

Preface

Preceding text

Overview of ADB (I)
ADB(2) ﹣ adbd ﹣ main() function code sorting
ADB(3) ﹣ adbd ﹣ adbd ﹣ main() function code sorting
Code sorting of the host side of ADB (IV)
ADB(5) sorting out the code related to the adb server on the host side

First of all, we know that ADB indirectly calls and outputs log information to developers to debug programs in Android. There is a log class in Android, which is specially used to process log of our developers or system. ADB itself is a program, so we can also debug ADB itself. We can modify and optimize ADB module Add our own log to debug.

Next, from two parts of ADB (ADB, adbd), that is, ADB in the android device side and ADB in the host development host side, we can see how the log related settings of ADB work; by default, the log of ADB (ADB, adbd) is invisible, so how can we make the log of ADB visible to developers?

1, Debugging of adbd

First of all, let's take a look at the log of the adbd part; this is to understand how the startup process of the adbd is. Unfamiliar students can come to us first ADB(2) ﹣ adbd ﹣ main() function code sorting Go and have a look.

After we are familiar with the start process of adbd, we know that in the main() function of adbd, we will call ADB ﹐ trace ﹐ to set the initialization of the debugging function of adbd; it will turn on and off the log output of adbd according to the system settings and save it to the file with the specified path for developers to use.
We still return to the source code, which is the basis of all our methods at the upper level:

1. adbd_main()_adb_trace_init()

/system/core/adb/daemon/main.cpp

int main(int argc, char** argv) {
  	...
    adb_trace_init(argv);
	...
}

You can see that adb_trace_init() is tracked in the main() method to track log; let's look at the adb_trace_init() function and see how it is implemented.

2. adbd_ adb_trace_init()

void adb_trace_init(char** argv) {
#if !ADB_HOST
	 // Don't open log file if no tracing, since this will block
	  // the crypto unmount of /data
	  if (!get_trace_setting().empty()) {
	      if (unix_isatty(STDOUT_FILENO) == 0) {
	          start_device_log();
	      }
	  }
#endif
	...
	android::base::InitLogging(argv, &AdbLogger);
	...
	setup_trace_mask();
	VLOG(ADB) << adb_version();
}

2.1 get_trace_setting()

In the adb_trace_init() function, first judge the ADB_HOST. Because it is running in adbd, Android.mk file assigns the ADB_HOST in the adbd code to 0 when compiling, so here! ADB_HOST is true, and the next code will surely go. Then judge whether the trace setting is empty by get trace setting(). The implementation of get trace setting() is as follows:

std::string get_trace_setting() {
   return android::base::GetProperty("persist.adb.trace_mask", "");
#endif

We can see that get ﹐ trace ﹐ setting() is to confirm whether to generate the log of adbd according to the setting of "persist. ADB. Trace ﹐ mask"; if the setting is not empty, the UNIX ﹐ isatty() function will be called to make a judgment again; how to judge? Then look

2.2 unix_isatty()

static __inline__ int unix_isatty(int fd) {
    return isatty(fd);
}

The function of isatty() is called by uni ˊ isatty(). The main function of this function is to check the device type and judge whether fd is terminal. What do you mean by this passage? I understand it this way: our standard output and standard error output are fd, but they can be directly input and displayed on the terminal, while other fd cannot, which is the function of isatty(). Simply put, this is to use standard output and standard error output to collect log s.

2.3 start_device_log()

When the above conditions are met, it means that the log switch is turned on, and we can collect logs. Here is a call to the start_device_log() function. Let's see how it is implemented internally:

void start_device_log(void) {
    int fd = unix_open(get_log_file_name().c_str(),
                       O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0640);
    if (fd == -1) {
        return;
    }

    // Redirect stdout and stderr to the log file.
    dup2(fd, STDOUT_FILENO);
    dup2(fd, STDERR_FILENO);
    fprintf(stderr, "--- adb starting (pid %d) ---\n", getpid());
    unix_close(fd);
}

Before start device log() can collect the log, you need to find the file and path to save the log. Here, call the get log file name() function to realize:

2.3.1 get_log_file_name()

static std::string get_log_file_name() {
    struct tm now;
    time_t t;
    tzset();
    time(&t);
    localtime_r(&t, &now);

    char timestamp[PATH_MAX];
    strftime(timestamp, sizeof(timestamp), "%Y-%m-%d-%H-%M-%S", &now);

    return android::base::StringPrintf("/data/adb/adb-%s-%d", timestamp,
                                       getpid());
}

The internal implementation of get log file name() is very simple, which is to return a file path in the format of / data/adb / + time tag + process ID number of current adbd

2.3.2 dup2()

Before saving the log file, you can write the data in it. But instead of writing the data directly, we use the copy method to copy the standard output and standard error output information to the file fd of saving the log through the dup2() function.

Just learn DUP, dup2

By the way, let's see the use of two functions DUP and dup2

#include <unistd.h>
int dup(int fd);
int dup2(int fd, int fd2);

😒 😒 😒 😒 😒 😒 😒 😒 😒 😒 😒 😒
int dup (old Fu fd): old Fu fd is the descriptor of an open file. Its return value is the smallest available file descriptor for the current process. The returned fd and old Fu fd point to the same file.
int dup2 (old FD, new FD): it's a bit more complex. It has different situations. We just need to know its role here, which is to redirect standard output and standard error output to the specified file.

2.4 android::base::InitLogging()

This function is provided by Android. It is mainly used to initialize the log that Android system is running. The log Association of our adbd function is not very large. Let's not go into details;

2.5 setup_trace_mask()

After the initialization of the related log, the setup ﹣ trace ﹣ mask(); will be transferred. This is mainly to set the mask of the log of ADB (ADB, adbd). Get the flag class from the trace settings of the system to build the mask, where the 1 and all flag representations allow all types.

  • The adb on the host side is mainly determined by obtaining the adb ﹐ trace environment variable,
  • The adbd of Android device is judged by the system attribute of persist.adb.trace_mask;
static void setup_trace_mask() {
    const std::string trace_setting = get_trace_setting();
    if (trace_setting.empty()) {
        return;
    }

    std::unordered_map<std::string, int> trace_flags = {
        {"1", -1},
        {"all", -1},
        {"adb", ADB},
        {"sockets", SOCKETS},
        {"packets", PACKETS},
        {"rwx", RWX},
        {"usb", USB},
        {"sync", SYNC},
        {"sysdeps", SYSDEPS},
        {"transport", TRANSPORT},
        {"jdwp", JDWP},
        {"services", SERVICES},
        {"auth", AUTH},
        {"fdevent", FDEVENT},
        {"shell", SHELL}};

    std::vector<std::string> elements = android::base::Split(trace_setting, " ");
    for (const auto& elem : elements) {
        const auto& flag = trace_flags.find(elem);
        if (flag == trace_flags.end()) {
            LOG(ERROR) << "Unknown trace flag: " << elem;
            continue;
        }

        if (flag->second == -1) {
            // -1 is used for the special values "1" and "all" that enable all
            // tracing.
            adb_trace_mask = ~0;
            break;
        } else {
            adb_trace_mask |= 1 << flag->second;
        }
    }

    if (adb_trace_mask != 0) {
        android::base::SetMinimumLogSeverity(android::base::VERBOSE);
    }
}

Summary

  • To see the log of the adbd process on the device side, we know from the above ADB ﹣ trace ﹣ init(), that we need to manually set the system property "persist. ADB. Trace ﹣ mask", which can be realized through setprop
  • The logs of the adb on the device side are stored in / data/adb

Specific operation example:

1. Set properties

adb shell setprop persist.adb.trace_mask 1

2. Restart adbd

adb shell pkill adbd

2, Debugging of adb

Similar to the adbd on Android, the debugging of the adb on host also needs to change the configuration and open it. We can also start from the main() function:
start-up

int main(int argc, char** argv) {
    adb_trace_init(argv);
    return adb_commandline(argc - 1, const_cast<const char**>(argv + 1));
}

It can be found by the above code. The adb on the host side also calls the adb? Trace? Init() function to initialize trace. According to the previous sorting basis, let's see how the host end is set specifically:

1.adb_trace_init

void adb_trace_init(char** argv) {
#if !ADB_HOST
    // Don't open log file if no tracing, since this will block
    // the crypto unmount of /data
    if (!get_trace_setting().empty()) {
        if (unix_isatty(STDOUT_FILENO) == 0) {
            start_device_log();
        }
    }
#endif

#if ADB_HOST && !defined(_WIN32)
    // adb historically ignored $ANDROID_LOG_TAGS but passed it through to logcat.
    // If set, move it out of the way so that libbase logging doesn't try to parse it.
    std::string log_tags;
    char* ANDROID_LOG_TAGS = getenv("ANDROID_LOG_TAGS");
    if (ANDROID_LOG_TAGS) {start-up
        log_tags = ANDROID_LOG_TAGS;
        unsetenv("ANDROID_LOG_TAGS");
    }
#endif

    android::base::InitLogging(argv, &AdbLogger);

#if ADB_HOST && !defined(_WIN32)
    // Put $ANDROID_LOG_TAGS back so we can pass it to logcat.
    if (!log_tags.empty()) setenv("ANDROID_LOG_TAGS", log_tags.c_str(), 1);
#endif

    setup_trace_mask();

    VLOG(ADB) << adb_version();
}

This time, our program is running on the host side. According to the judgment of! ADB_HOST, in Android.mk, assign the ADB_HOST in the host side program to 1, that is, if "! ADB_HOST" is false, you won't go through the following code:

#if !ADB_HOST
    // Don't open log file if no tracing, since this will block
    // the crypto unmount of /data
    if (!get_trace_setting().empty()) {
        if (unix_isatty(STDOUT_FILENO) == 0) {
            start_device_log();
        }
    }
#endif

However, corresponding operations will be added to the host side as follows:

void adb_trace_init(char** argv) {
...
#if ADB_HOST && !defined(_WIN32)
    // adb historically ignored $ANDROID_LOG_TAGS but passed it through to logcat.
    // If set, move it out of the way so that libbase logging doesn't try to parse it.
    std::string log_tags;
    char* ANDROID_LOG_TAGS = getenv("ANDROID_LOG_TAGS");
    if (ANDROID_LOG_TAGS) {
        log_tags = ANDROID_LOG_TAGS;
        unsetenv("ANDROID_LOG_TAGS");
    }
#endif
    android::base::InitLogging(argv, &AdbLogger);
#if ADB_HOST && !defined(_WIN32)
    // Put $ANDROID_LOG_TAGS back so we can pass it to logcat.
    if (!log_tags.empty()) setenv("ANDROID_LOG_TAGS", log_tags.c_str(), 1);
#endif
...
}

As above code,

  • First, the environment variable "Android log tags" will be obtained. According to the annotation, we know that the previous adb will ignore $Android log tags, but it will still be passed to logcat. If the variable "Android log tags" is set in the system, we will remove it, so the logging of libbase will not parse it.

  • Then, after the completion of the logcat related initialization, the "Android log tags" variable will be restored to the original state.

1.1 setup_trace_mask

This is similar to the log mask operation of the above adbd. The main difference is that the acquisition of the system environment variable "ADB trace" is different from that of the adbd.
At this point, we will find that the log mask settings of the ADB on the host side and the adbd on the device side are the same, but the log initialization is not the same. We did not find where the log output is set in the adb_trace_init() on the host side. Therefore, the log on the host side should be set in other places. Let's take a look.

2.setup_daemon_logging

In previous chapters ADB(5) sorting out the code related to the adb server on the host side In, we see that there is a setup ﹣ daemon ﹣ logging() function, which was not in-depth at that time. Now we need to take a good look at the implementation of this function;

static void setup_daemon_logging() {
    const std::string log_file_path(GetLogFilePath());
    int fd = unix_open(log_file_path.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0640);
    if (fd == -1) {
        fatal("cannot open '%s': %s", log_file_path.c_str(), strerror(errno));
    }
    if (dup2(fd, STDOUT_FILENO) == -1) {
        fatal("cannot redirect stdout: %s", strerror(errno));
    }
    if (dup2(fd, STDERR_FILENO) == -1) {
        fatal("cannot redirect stderr: %s", strerror(errno));
    }
    unix_close(fd);

    fprintf(stderr, "--- adb starting (pid %d) ---\n", getpid());
    LOG(INFO) << adb_version();
}

2.1 GetLogFilePath

In the setup ﹣ daemon ﹣ logging() function, the GetLogFilePath() function will be called first to get the path of the log file. The operation of getting the file path is definitely suitable for the system. Let's see how the GetLogFilePath() function is implemented

std::string GetLogFilePath() {
#if defined(_WIN32)
    const char log_name[] = "adb.log";
    WCHAR temp_path[MAX_PATH];
    // https://msdn.microsoft.com/en-us/library/windows/desktop/aa364992%28v=vs.85%29.aspx
    DWORD nchars = GetTempPathW(arraysize(temp_path), temp_path);
    if (nchars >= arraysize(temp_path) || nchars == 0) {
        // If string truncation or some other error.
        fatal("cannot retrieve tsetup_trace_maskemporary file path: %s\n",
              android::base::SystemErrorCodeToString(GetLastError()).c_str());
    }
    std::string temp_path_utf8;
    if (!android::base::WideToUTF8(temp_path, &temp_path_utf8)) {
        fatal_errno("cannot convert temporary file path from UTF-16 to UTF-8");
    }
    return temp_path_utf8 + log_name;
#else
    const char* tmp_dir = getenv("TMPDIR");
    if (tmp_dir == nullptr) tmp_dir = "/tmp";
    return android::base::StringPrintf("%s/adb.%u.log", tmp_dir, getuid());
#endif
}

As for the above code, we can see in the linux system that the log of the adb server is saved in the path of / tmp; the name is "ADB." + "getuid()" + "log"; getuid() gets the user ID of the current process.

After obtaining the path and name of the saved log, the next operation calls the unix_open() [encapsulates the open()] function to open the file, and....... EN grace. How do you seem to know each other?? Yes, the next operation is the same as the operation of the start? Device? Log() function in the analysis of adbd.

Summary

  • To see the log of the adb process on the host side, we learned from the above combing that we need to set the environment variable "adb trace" manually, which can be realized through export
  • The log of the adb on the host side is stored in '/ tmp,

Specific operation example [linux system]:

1. Kill the original adb process

adb kill-server

2. Set environment variables

export ADB_TRACE =1

3. Restart adb

adb start-server

compare

Comparing the initialization process of the ADB log on the host side with that of the adbd log on the device side, we find that the two processes are very similar. Both the standard output and the standard error output data are dup ed into the log file. Then, the priority of the log is controlled by the environment variables ADB trace and persist.adb.trace mask. By default, both logs are not output.
We just need to set the corresponding environment variable (system property for adndroid) to the corresponding data,

Specific reference is as follows:

    std::unordered_map<std::string, int> trace_flags = {
        {"1", -1},
        {"all", -1},
        {"adb", ADB},
        {"sockets", SOCKETS},
        {"packets", PACKETS},
        {"rwx", RWX},
        {"usb", USB},
        {"sync", SYNC},
        {"sysdeps", SYSDEPS},
        {"transport", TRANSPORT},
        {"jdwp", JDWP},
        {"services", SERVICES},
        {"auth", AUTH},
        {"fdevent", FDEVENT},
        {"shell", SHELL}};
Published 45 original articles, won praise 35, visited 8167
Private letter follow

Posted by Nimbuz on Tue, 25 Feb 2020 18:26:40 -0800