【问题标题】:How to wait for ADB output in C#?如何在 C# 中等待 ADB 输出?
【发布时间】:2020-06-25 07:08:31
【问题描述】:

我想通过 C# 程序使用ADB 命令从连接到USBdevice 接收信息,然后刷新输出。

Process process = new Process();
process.StartInfo.FileName = "adb.exe";
process.StartInfo.Arguments = "logcat -d -b main -v raw -s Command:I"; // get data in Log.I() with name == "Command"
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardInput = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.Start();

string output;
do {
    process.StandardInput.WriteLine("logcat -d -b main -v raw -s Command:I");
    output = process.StandardOutput.ReadToEnd();
} while (output.Length < 1);

Console.WriteLine(output);

process.StandardInput.WriteLine("logcat -c"); // flush logcat

process.WaitForExit();

这样做我明白程序一直在执行adb logcat -d -b main -v raw -s Command:I,难道没有办法一次调用命令并等待输出吗?

我可以在 Windows 提示符下使用:

adb shell 'logcat -b main -v raw -s UNIQUE_TAG:I | (read -n 1 && kill -2 $((BASHPID-1)))'

但这在 C# 中可行吗? 输出似乎也没有被刷新

【问题讨论】:

    标签: c# android windows command-line adb


    【解决方案1】:

    你不能多读一遍; ReadToEnd 最终意味着“直到管道关闭并且我已经消耗了所有东西,并且没有更多的数据永远到达”。 ReadToEnd 也永远不会完成,直到 adb.exe 有意 表示它已完成写入(并且永远不会再次写入),或者终止 - 所以这就是为什么你没有达到刷新.

    可以做的是读取(一次一个字节/字符,如果需要),直到你有,比如说,一行 - 所以如果这里的期望是“一个命令,一个line out”那么就很简单了。如果无法知道将返回多少行,那么您通常会使用两个线程,并有一个专用的读取器线程从 process.StandardOutput 获取数据(一次字节/字符,或逐行) 并用它做任何需要的事情。

    【讨论】:

    • 期望只听,直到设备发出一行。我已经接受了您的建议,并使用 ReadLine() 然后使用 Read() 修改了 ReadToEnd() 但在这两种情况下,它似乎仍然没有达到冲洗的程度
    • @JosB 好吧,logcat 会返回一个空行吗?因为空行是您的do 循环退出的唯一方式。请注意,EOF 与空行不同,如果输出在 换行后终止,我希望从最终的ReadToEnd 收到null,所以:你可能想要要注意这一点。最终,为了调试它,我会在某处写出来自adb 的输出,包括使null 显而易见;它会停止吗?它返回一个空行吗?它返回null 吗?我不知道 - 但这些是你应该检查的事情
    【解决方案2】:

    这就是我过去为此类事情编写代码的方式 这是我的代码希望你理解它

      //to run the all the cmd,adb.fastboot.exe command using these function
       //here in startfunc pass the .exe file u want to execute,Arguments which u want to pass 
        //string msg = It is nothing Extra message if u want to add to your final output
    
    
        private static string Execute(string Startfunc, String Arguments,string msg)
        {   
            string text = null;
            Process p = new Process();
            p.StartInfo.FileName = Startfunc;
            p.StartInfo.Arguments = Arguments;
            p.StartInfo.RedirectStandardError = true;
            p.StartInfo.RedirectStandardOutput = true;         
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.CreateNoWindow = true;
            p.EnableRaisingEvents = true;
            p.Start(); 
            do
            {
                Application.DoEvents();
                string output = p.StandardOutput.ReadToEnd();
                text += output;
                string err = p.StandardError.ReadToEnd();
                text += err;
            }
            while (!p.HasExited);
            text += msg;
            return text;
        }
    
         //now i will call above function and make it wait until we get the result
    
         private void normal_reboot_Click(object sender, EventArgs e)
        { 
            
                txt_Log.Text = "rebooting" +Environment.NewLine;
                Task t = Task.Factory.StartNew(() =>
                {
                    txt_Log.Text=Execute("adb.exe","reboot","Done");
                });
                do { Application.DoEvents(); } while (!t.IsCompleted);                                    
        }
    

    【讨论】:

    • 我……不认为这段代码像你认为的那样工作;在 do/while 循环中使用 ReadToEnd 没有意义;我认为这段代码大部分是偶然工作的(如果应用程序同时关闭stdoutstderr保持运行,它看起来会创建一个热循环)
    【解决方案3】:

    您还可以异步查找输出/错误消息。所以你不需要(阻塞)循环: 这个例子只是输出消息,但可以通过完整的方法进行扩展

    p.OutputDataReceived+= (s, e) => Console.WriteLine(e.Data);
    p.BeginOutputReadLine();//This is important, otherwise the event won't be fired
    p.ErrorDataReceived += (s, e) => Console.WriteLine(e.Data);
    p.BeginErrorReadLine();
    

    这应该打印 adb 收到的每一行

    【讨论】:

      【解决方案4】:

      下面的工作代码,我们不直接调用adb.exe,而是通过cmd.exe使用命令等待来自logcat的任何信息日志,标题为“命令”:adb shell logcat -b main -v raw -s Command:I

      private Process listeningProc;
      
      public someClass(){
         listeningProc = new Process();
         listeningProc.StartInfo.FileName = "cmd.exe";
         listeningProc.StartInfo.UseShellExecute = false;
         listeningProc.StartInfo.RedirectStandardOutput = true;
         listeningProc.StartInfo.RedirectStandardInput = true;
         listeningProc.Start();
      
         listeningProc.OutputDataReceived += new DataReceivedEventHandler(
             (s, e) => {
                 if (e.Data == "SPECIFIC_COMMAND") {
                     // do something
                 }
             }
         );
         listeningProc.BeginOutputReadLine();
      }
      
      private void ListenToCommands(){
         listeningProc.StandardInput.WriteLine("adb shell logcat -b main -v raw -s Command:I"); //Listening for Info Logs titled "Command"
      
         while (true) { }
      }
      

      要刷新 logcat 或通过 ADB 从 PC 发送任何命令,我打开另一个进程并从那里发送命令。

      编辑: 您可能希望在从 PC 通过ADB 发送的每个命令之后添加System.Threading.Thread.Sleep(2000); //pause for 2 seconds,否则设备有时在连续发送时太快不会执行所有命令

      【讨论】:

        猜你喜欢
        • 2022-01-18
        • 2016-06-26
        • 1970-01-01
        • 1970-01-01
        • 2012-05-21
        • 2015-12-25
        • 1970-01-01
        • 1970-01-01
        • 2023-01-30
        相关资源
        最近更新 更多