private void UpdateDebuggablePackages()
        {
            // When running test Tools don't exist
            if (m_Runtime.Tools == null)
            {
                return;
            }
            var startTime       = DateTime.Now;
            var packagePIDCache = new Dictionary <string, int>();

            CheckIfPackagesExited(packagePIDCache);

            int    topActivityPid         = 0;
            string topActivityPackageName = string.Empty;
            bool   checkProjectPackage    = true;
            var    selectedDevice         = m_Runtime.DeviceQuery.SelectedDevice;

            if (AndroidLogcatUtilities.GetTopActivityInfo(m_Runtime.Tools.ADB, selectedDevice, ref topActivityPackageName, ref topActivityPid) &&
                topActivityPid > 0)
            {
                m_Runtime.UserSettings.CreatePackageInformation(topActivityPackageName, topActivityPid, selectedDevice);

                checkProjectPackage = topActivityPackageName != PlayerSettings.applicationIdentifier;
            }

            if (checkProjectPackage)
            {
                int projectApplicationPid = GetPidFromPackageName(packagePIDCache, PlayerSettings.applicationIdentifier, selectedDevice);
                m_Runtime.UserSettings.CreatePackageInformation(PlayerSettings.applicationIdentifier, projectApplicationPid, selectedDevice);
            }

            m_Runtime.UserSettings.CleanupDeadPackagesForDevice(m_Runtime.DeviceQuery.SelectedDevice);
            AndroidLogcatInternalLog.Log("UpdateDebuggablePackages finished in " + (DateTime.Now - startTime).Milliseconds + " ms");
        }
        private static IAndroidLogcatTaskResult QueryMemoryAsync(IAndroidLogcatTaskInput input)
        {
            var workInput = ((AndroidLogcatQueryMemoryInput)input);
            var adb       = workInput.adb;

            if (adb == null)
            {
                throw new NullReferenceException("ADB interface has to be valid");
            }

            var cmd = "-s " + workInput.deviceId + " shell dumpsys meminfo " + workInput.packageName;

            AndroidLogcatInternalLog.Log("{0} {1}", adb.GetADBPath(), cmd);

            string outputMsg = string.Empty;

            try
            {
                outputMsg = adb.Run(new[] { cmd }, "Failed to query memory for " + workInput.packageName);
            }
            catch (Exception ex)
            {
                AndroidLogcatInternalLog.Log("Failed to query memory: \n" + ex.Message);
            }
            var result = new AndroidLogcatQueryMemoryResult();

            result.deviceId         = workInput.deviceId;
            result.packageName      = workInput.packageName;
            result.packageProcessId = workInput.packageProcessId;
            result.contents         = outputMsg;
            //AndroidLogcatInternalLog.Log(outputMsg);

            return(result);
        }
Beispiel #3
0
        private void WorkerThread(object o)
        {
            AndroidLogcatInternalLog.Log("Worker thread started");
            Profiler.BeginThreadProfiling("AndroidLogcat", "Dispatcher");

            while (m_AutoResetEvent.WaitOne() && m_Running)
            {
                //Debug.Log("Executing");
                AsyncTask task = null;
                lock (m_AsyncTaskQueue)
                {
                    if (m_AsyncTaskQueue.Count > 0)
                    {
                        task = m_AsyncTaskQueue.Dequeue();
                    }
                }
                if (task != null && task.asyncAction != null)
                {
                    m_Sampler.Begin();
                    var result = task.asyncAction.Invoke(task.taskData);
                    m_Sampler.End();

                    lock (m_IntegrateTaskQueue)
                    {
                        m_IntegrateTaskQueue.Enqueue(new IntegrationTask()
                        {
                            integrateAction = task.integrateAction, result = result
                        });
                    }
                }
            }
            AndroidLogcatInternalLog.Log("Worker thread exited");
            Profiler.EndThreadProfiling();
            m_FinishedEvent.Set();
        }
Beispiel #4
0
        internal void Schedule(IAndroidLogcatTaskInput taskData, Func <IAndroidLogcatTaskInput, IAndroidLogcatTaskResult> asyncAction, Action <IAndroidLogcatTaskResult> integrateAction, bool synchronous)
        {
            if (!m_Running)
            {
                AndroidLogcatInternalLog.Log("Ignore schedule action, because dispatcher is not running.");
                return;
            }

            if (synchronous)
            {
                integrateAction(asyncAction.Invoke(taskData));
                return;
            }

            lock (m_AsyncTaskQueue)
            {
                var task = new AsyncTask()
                {
                    taskData = taskData, asyncAction = asyncAction, integrateAction = integrateAction
                };
                m_AsyncTaskQueue.Enqueue(task);
                if (!m_AutoResetEvent.Set())
                {
                    throw new Exception("Failed to signal auto reset event in dispatcher.");
                }
            }
        }
Beispiel #5
0
        public static Version ParseVersion(string versionString)
        {
#if NET_2_0
            return(ParseVersionLegacy(versionString));
#else
            var vals = versionString.Split('.');

            // Version.TryParse isn't capable of parsing digits without dots, for ex., 1
            if (vals.Length == 1)
            {
                int n;
                if (!int.TryParse(vals[0], out n))
                {
                    AndroidLogcatInternalLog.Log("Failed to parse android OS version '{0}'", versionString);
                    return(new Version(0, 0));
                }
                return(new Version(n, 0));
            }

            Version version;
            if (!Version.TryParse(versionString, out version))
            {
                AndroidLogcatInternalLog.Log("Failed to parse android OS version '{0}'", versionString);
                return(new Version(0, 0));
            }
            return(version);
#endif
        }
        private void OnDeviceDisconnected(string deviceId)
        {
            StopLogCat();
            var msg = "Either adb.exe crashed or device disconnected (device id: " + GetDeviceDetailsFor(deviceId) + ")";

            AndroidLogcatInternalLog.Log(msg);
            var index = m_DeviceIds.IndexOf(deviceId);

            if (index == -1)
            {
                return;
            }

            m_DeviceIds.RemoveAt(index);
            ArrayUtility.RemoveAt(ref m_DeviceDetails, index);

            m_SelectedDeviceIndex = -1;
            m_SelectedDeviceId    = null;

            if (m_DeviceIds.Count > 0)
            {
                SetSelectedDeviceByIndex(0, true);
            }
            else
            {
                UpdateStatusBar(msg);
            }
        }
        private void OnEnable()
        {
            AndroidLogcatInternalLog.Log("OnEnable");

            if (m_SearchField == null)
            {
                m_SearchField = new SearchField();
            }

            if (m_TagControl == null)
            {
                m_TagControl = new AndroidLogcatTagsControl();
            }
            m_TagControl.TagSelectionChanged += TagSelectionChanged;

            m_SelectedDeviceIndex = -1;
            m_SelectedDeviceId    = null;

            m_TimeOfLastAutoConnectStart = DateTime.Now;
            EditorApplication.update    += Update;

            m_FinishedAutoselectingPackage = false;
            AndroidLogcatInternalLog.Log("Package: {0}, Auto select: {1}", PlayerSettings.applicationIdentifier, AutoSelectPackage);

            m_StatusBar = new AndroidLogcatStatusBar();
        }
        private static IAndroidLogcatTaskResult QueryDevicesAsync(IAndroidLogcatTaskInput input)
        {
            var adb = ((AndroidLogcatRetrieveDeviceIdsInput)input).adb;

            if (adb == null)
                throw new NullReferenceException("ADB interface has to be valid");

            var result = new AndroidLogcatRetrieveDeviceIdsResult();
            result.notifyListeners = ((AndroidLogcatRetrieveDeviceIdsInput)input).notifyListeners;

            AndroidLogcatInternalLog.Log("{0} devices", adb.GetADBPath());
            try
            {
                var adbOutput = adb.Run(new[] { "devices" }, "Unable to list connected devices. ");
                foreach (var line in adbOutput.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries).Select(line => line.Trim()))
                {
                    AndroidLogcatInternalLog.Log(" " + line);
                    AndroidLogcatRetrieveDeviceIdsResult.DeviceInfo info;
                    if (ParseDeviceInfo(line, out info.id, out info.state))
                        result.deviceInfo.Add(info);
                }
            }
            catch (Exception ex)
            {
                AndroidLogcatInternalLog.Log(ex.Message);
                result.deviceInfo = new List<AndroidLogcatRetrieveDeviceIdsResult.DeviceInfo>();
            }

            return result;
        }
        internal static IAndroidLogcatTaskResult Execute(IAndroidLogcatTaskInput input)
        {
            var adb = ((AndroidLogcatRetrieveDeviceIdsInput)input).adb;

            if (adb == null)
            {
                throw new NullReferenceException("ADB interface has to be valid");
            }

            var result = new AndroidLogcatRetrieveDeviceIdsResult();

            AndroidLogcatInternalLog.Log("{0} devices", adb.GetADBPath());
            var adbOutput = adb.Run(new[] { "devices" }, "Unable to list connected devices. ");

            foreach (var line in adbOutput.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries).Select(line => line.Trim()))
            {
                AndroidLogcatInternalLog.Log(" " + line);
                if (line.EndsWith("device"))
                {
                    var deviceId = line.Split(new[] { '\t', ' ' })[0];
                    result.deviceIds.Add(deviceId);
                }
            }

            return(result);
        }
        internal void SelectDevice(IAndroidLogcatDevice device, bool notifyListeners = true)
        {
            if (m_SelectedDevice == device)
                return;

            if (device != null && device.State != IAndroidLogcatDevice.DeviceState.Connected)
            {
                AndroidLogcatInternalLog.Log("Trying to select device which is not connected: " + device.Id);
                if (m_SelectedDevice == null)
                    return;

                m_SelectedDevice = null;
            }
            else
            {
                m_SelectedDevice = device;
            }

            if (m_SelectedDevice != null && !m_Devices.Keys.Contains(m_SelectedDevice.Id))
                throw new Exception("Selected device is not among our listed devices");

            m_Runtime.UserSettings.LastSelectedDeviceId = m_SelectedDevice != null ? m_SelectedDevice.Id : "";

            if (notifyListeners)
                DeviceSelected?.Invoke(m_SelectedDevice);
        }
        private void OnEnable()
        {
            AndroidLogcatInternalLog.Log("OnEnable");
            m_Runtime = AndroidLogcatManager.instance.Runtime;

            if (m_SearchField == null)
            {
                m_SearchField = new SearchField();
            }

            if (m_TagControl == null)
            {
                m_TagControl = new AndroidLogcatTagsControl();
            }
            m_TagControl.TagSelectionChanged += TagSelectionChanged;

            m_SelectedDeviceIndex = -1;
            m_SelectedDeviceId    = null;

            m_TimeOfLastAutoConnectStart = DateTime.Now;
            m_Runtime.OnUpdate          += Update;

            m_FinishedAutoselectingPackage = false;
            AndroidLogcatInternalLog.Log("Package: {0}, Auto select: {1}", PlayerSettings.applicationIdentifier, AutoSelectPackage);

            m_StatusBar = new AndroidLogcatStatusBar();

            m_Runtime.Settings.OnSettingsChanged += OnSettingsChanged;

            // Can't apply settings here, apparently EditorStyles aren't initialized yet.
            m_ApplySettings = true;
        }
        internal void OnDisable()
        {
            if (!AndroidBridge.AndroidExtensionsInstalled)
            {
                return;
            }

            if (m_Runtime == null)
            {
                AndroidLogcatInternalLog.Log("Runtime was already destroyed.");
                return;
            }
            m_Runtime.UserSettings.Tags.TagSelectionChanged -= TagSelectionChanged;

            m_Runtime.Closing -= OnDisable;

            m_Runtime.DeviceQuery.DeviceSelected -= OnSelectedDevice;

            if (m_Runtime.Settings != null)
            {
                m_Runtime.Settings.OnSettingsChanged -= OnSettingsChanged;
            }

            StopLogCat();

            m_Runtime.Update -= OnUpdate;
            AndroidLogcatInternalLog.Log("OnDisable, Auto select: {0}", m_AutoSelectPackage);
            m_Runtime = null;
        }
        private LogEntry ParseLogEntry(Match m)
        {
            DateTime dateTime;
            var      dateValue = m.Groups["date"].Value;

            if (LogPrintFormat == kThreadTime)
            {
                dateValue = "1999-" + dateValue;
            }

            try
            {
                dateTime = DateTime.Parse(dateValue);
            }
            catch (Exception ex)
            {
                dateTime = new DateTime();
                AndroidLogcatInternalLog.Log("Failed to parse date: " + dateValue + "\n" + ex.Message);
            }

            var entry = new LogEntry(
                dateTime,
                Int32.Parse(m.Groups["pid"].Value),
                Int32.Parse(m.Groups["tid"].Value),
                PriorityStringToEnum(m.Groups["priority"].Value),
                m.Groups["tag"].Value,
                m.Groups["msg"].Value);

            return(entry);
        }
        private void InitFilterRegex(string filter)
        {
            if (string.IsNullOrEmpty(filter))
            {
                return;
            }

            if (m_Device.SupportsFilteringByRegex)
            {
                // When doing searching by filter, we use --regex command.
                // Note: there's no command line argument to disable or enable regular expressions for logcat
                // Thus when we want to disable regular expressions, we simply provide filter with escaped characters to --regex command
                this.m_Filter = m_FilterIsRegex ? filter : Regex.Escape(filter);
                return;
            }

            if (!this.m_FilterIsRegex)
            {
                this.m_Filter = filter;
                return;
            }

            try
            {
                this.m_Filter       = filter;
                m_ManualFilterRegex = new Regex(m_Filter, RegexOptions.Compiled);
            }
            catch (Exception ex)
            {
                var error = string.Format("Input search filter '{0}' is not a valid regular expression.", Regex.Escape(m_Filter));
                AndroidLogcatInternalLog.Log(error);

                throw new ArgumentException(error, ex);
            }
        }
        protected void OnEnableInternal(AndroidLogcatRuntimeBase runtime)
        {
            AndroidLogcatInternalLog.Log("OnEnable");
            m_Runtime = runtime;

            if (m_SearchField == null)
            {
                m_SearchField = new SearchField();
            }

            m_Runtime.ProjectSettings.Tags.TagSelectionChanged += TagSelectionChanged;

            m_TimeOfLastAutoConnectStart = DateTime.Now;
            m_Runtime.Update            += OnUpdate;

            m_FinishedAutoselectingPackage = false;
            AndroidLogcatInternalLog.Log("Package: {0}, Auto select: {1}", PlayerSettings.applicationIdentifier, AutoSelectPackage);

            m_StatusBar = new AndroidLogcatStatusBar();

            m_Runtime.Settings.OnSettingsChanged += OnSettingsChanged;

            m_MemoryViewer = new AndroidLogcatMemoryViewer(this, m_Runtime);

            // Can't apply settings here, apparently EditorStyles aren't initialized yet.
            m_ApplySettings = true;

            m_Runtime.DeviceQuery.Clear();
            m_Runtime.DeviceQuery.DeviceSelected += OnSelectedDevice;

            // Since Runtime.OnDisable can be called earlier than this window OnClose, we must ensure the order
            m_Runtime.Closing += OnDisable;
        }
Beispiel #16
0
        public static int ParsePidInfo(string packageName, string commandOutput)
        {
            string line = null;

            // Note: Regex is very slow, looping through string is much faster
            using (var sr = new StringReader(commandOutput))
            {
                while ((line = sr.ReadLine()) != null)
                {
                    if (line.EndsWith(packageName))
                    {
                        break;
                    }
                }
            }

            if (string.IsNullOrEmpty(line))
            {
                AndroidLogcatInternalLog.Log("Cannot get process status for '{0}'.", packageName);
                return(-1);
            }

            var   regex = new Regex(@"\b\d+");
            Match match = regex.Match(line);

            if (!match.Success)
            {
                AndroidLogcatInternalLog.Log("Failed to parse pid of '{0}'from '{1}'.", packageName, line);
                return(-1);
            }

            return(int.Parse(match.Groups[0].Value));
        }
Beispiel #17
0
        public static string GetPackageNameFromPid(AndroidBridge.ADB adb, IAndroidLogcatDevice device, int processId)
        {
            if (device == null)
            {
                return(string.Empty);
            }

            try
            {
                // Note: Flag -o doesn't work on Android 5.0 devices (tested on LGE LG-D620, 5.0.2)
                string cmd = string.Format("-s {0} shell ps -p {1}", device.Id, processId);

                AndroidLogcatInternalLog.Log("{0} {1}", adb.GetADBPath(), cmd);
                var output = adb.Run(new[] { cmd }, "Unable to get the package name for pid " + processId);
                if (string.IsNullOrEmpty(output))
                {
                    return(string.Empty);
                }

                var result = ProcessOutputFromPS(output);
                if (string.IsNullOrEmpty(result))
                {
                    AndroidLogcatInternalLog.Log("Unable to get the package name for pid " + processId + "\nOutput:\n" + output);
                }
                return(result);
            }
            catch (Exception ex)
            {
                AndroidLogcatInternalLog.Log(ex.Message);
                return(string.Empty);
            }
        }
        /// <summary>
        /// Return the pid of the given package on the given device.
        /// </summary>
        public static int GetPidFromPackageName(AndroidBridge.ADB adb, IAndroidLogcatDevice device, string packageName)
        {
            if (device == null)
                return -1;

            try
            {
                string cmd = null;
                if (device.SupportsFilteringByPid)
                    cmd = string.Format("-s {0} shell pidof -s {1}", device.Id, packageName);
                else
                    cmd = string.Format("-s {0} shell ps", device.Id);

                AndroidLogcatInternalLog.Log("{0} {1}", adb.GetADBPath(), cmd);
                var output = adb.Run(new[] { cmd }, "Unable to get the pid of the given packages.");
                if (string.IsNullOrEmpty(output))
                    return -1;

                if (device.SupportsFilteringByPid)
                {
                    AndroidLogcatInternalLog.Log(output);
                    return int.Parse(output);
                }

                return ParsePidInfo(packageName, output);
            }
            catch (Exception ex)
            {
                AndroidLogcatInternalLog.Log(ex.Message);
                return -1;
            }
        }
 public void OnEnable()
 {
     if (!AndroidBridge.AndroidExtensionsInstalled)
     {
         return;
     }
     ms_Instance = this;
 }
Beispiel #20
0
        private static void IntegrateConnectToDevice(IAndroidLogcatTaskResult result)
        {
            var r = (AndroidLogcatConnectToDeviceResult)result;

            AndroidLogcatInternalLog.Log(r.message);
            EditorUtility.ClearProgressBar();
            EditorUtility.DisplayDialog(r.success ? "Success" : "Failure", r.message, "Ok");
        }
        private void DisconnectDevice(IAndroidLogcatDevice device)
        {
            var command = "disconnect " + device.Id;

            AndroidLogcatInternalLog.Log("adb " + command);
            var result = m_Runtime.Tools.ADB.Run(new[] { command }, "Failed to disconnect " + device.Id);

            AndroidLogcatInternalLog.Log(result);
        }
        private void Update()
        {
            if (m_DeviceIds != null && m_DeviceIds.Count == 0)
                UpdateConnectedDevicesList(false);

            if (m_DeviceIds.Count == 0)
                return;

            if (m_AutoSelectPackage && !m_FinishedAutoselectingPackage)
            {
                // This is for AutoRun triggered by "Build And Run".
                if ((DateTime.Now - m_TimeOfLastAutoConnectUpdate).TotalMilliseconds < kMillisecondsBetweenConsecutiveAutoConnectChecks)
                    return;
                AndroidLogcatInternalLog.Log("Waiting for {0} launch, elapsed {1} seconds", PlayerSettings.applicationIdentifier, (DateTime.Now - m_TimeOfLastAutoConnectStart).Seconds);
                m_TimeOfLastAutoConnectUpdate = DateTime.Now;

                ResetPackages(m_DeviceIds[0]);

                int projectApplicationPid = GetPidFromPackageName(PlayerSettings.applicationIdentifier, m_DeviceIds[0]);
                var package = CreatePackageInformation(PlayerSettings.applicationIdentifier, projectApplicationPid, m_DeviceIds[0]);
                if (package != null)
                {
                    AndroidLogcatInternalLog.Log("Auto selecting package {0}", PlayerSettings.applicationIdentifier);
                    // Note: Don't call SelectPackage as that will reset m_AutoselectPackage
                    m_SelectedPackage = package;
                    m_SelectedDeviceIndex = 0;
                    m_SelectedDeviceId = m_DeviceIds[m_SelectedDeviceIndex];

                    RestartLogCat();
                    m_FinishedAutoselectingPackage = true;
                    UpdateStatusBar();
                }
                else
                {
                    var timeoutMS = (DateTime.Now - m_TimeOfLastAutoConnectStart).TotalMilliseconds;
                    if (timeoutMS > kMillisecondsMaxAutoconnectTimeOut)
                    {
                        var msg = string.Format("Timeout {0} ms while waiting for '{1}' to launch.", timeoutMS, PlayerSettings.applicationIdentifier);
                        UpdateStatusBar(msg);
                        AndroidLogcatInternalLog.Log(msg);
                        m_FinishedAutoselectingPackage = true;
                    }
                }
            }
            else
            {
                if (m_SelectedDeviceId == null)
                {
                    int selectedDeviceIndex;
                    PackageInformation selectedPackage;
                    GetSelectedDeviceIndex(out selectedDeviceIndex, out selectedPackage);
                    SetSelectedDeviceByIndex(selectedDeviceIndex, true);
                    SelectPackage(selectedPackage);
                }
            }
        }
        private void OnLogcatDisconnected(IAndroidLogcatDevice device)
        {
            StopLogCat();
            var msg = "Either adb application crashed or device disconnected (device id: " + device.DisplayName + ")";

            AndroidLogcatInternalLog.Log(msg);

            m_Runtime.DeviceQuery.UpdateConnectedDevicesList(true);
            UpdateStatusBar(msg);
        }
        public static void ShowLog(bool immediate)
        {
            if (ms_Instance == null)
            {
                ms_Instance = ScriptableObject.CreateInstance <AndroidLogcatInternalLog>();
            }

            ms_Instance.titleContent = new GUIContent("Internal Log");
            ms_Instance.Show(immediate);
            ms_Instance.Focus();
        }
        private void OnDisable()
        {
            if (m_Runtime.Settings != null)
            {
                m_Runtime.Settings.OnSettingsChanged -= OnSettingsChanged;
            }

            StopLogCat();
            m_Runtime.OnUpdate -= Update;
            AndroidLogcatInternalLog.Log("OnDisable, Auto select: {0}", m_AutoSelectPackage);
        }
        internal void Clear()
        {
            if (m_MessageProvider != null)
            {
                throw new InvalidOperationException("Cannot clear logcat when logcat process is alive.");
            }

            AndroidLogcatInternalLog.Log("{0} -s {1} logcat -c", adb.GetADBPath(), Device.Id);
            var adbOutput = adb.Run(new[] { "-s", Device.Id, "logcat", "-c" }, "Failed to clear logcat.");

            AndroidLogcatInternalLog.Log(adbOutput);
        }
Beispiel #27
0
        public static int ParseTopActivityPackageInfo(string commandOutput, out string packageName)
        {
            packageName = "";
            if (string.IsNullOrEmpty(commandOutput))
            {
                return(-1);
            }

            // Note: Regex is very slow, looping through string is much faster
            string line = null;

            using (var sr = new StringReader(commandOutput))
            {
                do
                {
                    while ((line = sr.ReadLine()) != null)
                    {
                        if (line.Contains("top-activity") ||        // Top Activity when device is not locked
                            line.Contains("top-sleeping"))          // Top Activity when device is locked
                        {
                            break;
                        }
                    }

                    if (string.IsNullOrEmpty(line))
                    {
                        AndroidLogcatInternalLog.Log("Cannot find top activity.");
                        return(-1);
                    }

                    AndroidLogcatInternalLog.Log(line);

                    var reg   = new Regex(@"(?<pid>\d+)\:(?<package>\S+)\/\S+\s+\(top-\S+\)");
                    var match = reg.Match(line);
                    if (!match.Success)
                    {
                        AndroidLogcatInternalLog.Log("Match '{0}' failed.", line);
                        return(-1);
                    }

                    int pid = int.Parse(match.Groups["pid"].Value);

                    // There can be lines with (top-activity) at the end, but pid == 0, not sure what are those, but definetly not top activities
                    if (pid > 0)
                    {
                        packageName = match.Groups["package"].Value;
                        return(pid);
                    }

                    // Continue looking for top activity
                }while (true);
            }
        }
        internal string[] RunAddr2Line(string symbolFilePath, string[] addresses)
        {
            // https://sourceware.org/binutils/docs/binutils/addr2line.html
            var args = "-C -f -p -e \"" + symbolFilePath + "\" " + string.Join(" ", addresses.ToArray());

            AndroidLogcatInternalLog.Log($"\"{m_Addr2LinePath}\" {args}");
            var result = Shell.RunProcess(
                m_Addr2LinePath, args);

            ValidateResult(result);
            return(result.GetStandardOut().Split(new[] { '\n', '\r' }, System.StringSplitOptions.RemoveEmptyEntries));
        }
        string CopyIP(string deviceId)
        {
            var command = "-s " + deviceId + " shell ip route";

            AndroidLogcatInternalLog.Log("adb " + command);
            var result = m_Runtime.Tools.ADB.Run(new[] { command }, "Failed to query ip");

            AndroidLogcatInternalLog.Log(result);
            var ip = ParseIPAddress(result);

            return(string.IsNullOrEmpty(ip) ? "Failed to get IP address" : ip);
        }
        private void OnDisable()
        {
            if (m_TagControl.TagWindow != null)
            {
                m_TagControl.TagWindow.Close();
                m_TagControl.TagWindow = null;
            }

            StopLogCat();
            EditorApplication.update -= Update;
            AndroidLogcatInternalLog.Log("OnDisable, Auto select: {0}", m_AutoSelectPackage);
        }