/// <summary> /// Creates a new bridge. /// </summary> /// <param name="osLocation">the location of the command line tool</param> /// <exception cref="ArgumentException"></exception> /// <exception cref="FileNotFoundException"></exception> private AndroidDebugBridge(string osLocation) { if (string.IsNullOrEmpty(osLocation)) { throw new ArgumentException(); } if (!File.Exists(osLocation)) { Log.D(LOG_TAG, "Unable to locate ADB at {0}.", osLocation); throw new FileNotFoundException("unable to locate adb in the specified location"); } AdbOsLocation = osLocation; CheckAdbVersion(); }
public Debugger(IClient client, int listenPort) { this.Client = client; this.ListenPort = listenPort; IPEndPoint endPoint = new IPEndPoint(IPAddress.Loopback, listenPort); ListenChannel = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) { Blocking = false, ExclusiveAddressUse = false }; ListenChannel.Bind(endPoint); ConnectionState = ConnectionStates.NotConnected; Log.D(LOG_TAG, this.ToString()); }
/// <summary> /// Stops the adb host side server. /// </summary> /// <returns>true if success</returns> private bool StopAdb() { if (string.IsNullOrEmpty(AdbOsLocation)) { Log.E(ADB, "Cannot stop adb when AndroidDebugBridge is created without the location of adb."); return(false); } int status = -1; try { string command = "kill-server"; ProcessStartInfo psi = new ProcessStartInfo(AdbOsLocation, command) { CreateNoWindow = true, WindowStyle = ProcessWindowStyle.Hidden, UseShellExecute = false, RedirectStandardError = true, RedirectStandardOutput = true }; using (Process proc = Process.Start(psi)) { proc.WaitForExit(); status = proc.ExitCode; } } catch (IOException) { // we'll return false; } catch (Exception) { // we'll return false; } if (status != 0) { Log.W(LOG_TAG, "'adb kill-server' failed -- run manually if necessary"); return(false); } Log.D(LOG_TAG, "'adb kill-server' succeeded"); return(true); }
/// <summary> /// Attempts to connect to the debug bridge server. /// </summary> /// <returns>a connect socket if success, null otherwise</returns> private Socket OpenAdbConnection() { Log.D(TAG, "Connecting to adb for Device List Monitoring..."); Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); try { socket.Connect(AndroidDebugBridge.SocketAddress); socket.NoDelay = true; } catch (Exception e) { Log.W(TAG, e); socket = null; } return(socket); }
/// <summary> /// Pulls file(s) or folder(s). /// </summary> /// <param name="entries">the remote item(s) to pull</param> /// <param name="localPath">The local destination. If the entries count is > 1 or if the unique entry is a /// folder, this should be a folder.</param> /// <param name="monitor">The progress monitor. Cannot be null.</param> /// <returns>a SyncResult object with a code and an optional message.</returns> /// <exception cref="ArgumentNullException">Throws if monitor is null</exception> public SyncResult Pull(IEnumerable <FileEntry> entries, string localPath, ISyncProgressMonitor monitor) { if (monitor == null) { throw new ArgumentNullException("monitor", "Monitor cannot be null"); } // first we check the destination is a directory and exists DirectoryInfo d = new DirectoryInfo(localPath); if (!d.Exists) { return(new SyncResult(ErrorCodeHelper.RESULT_NO_DIR_TARGET)); } if (!FileInfoHelper.IsDirectory(d)) { return(new SyncResult(ErrorCodeHelper.RESULT_TARGET_IS_FILE)); } // get a FileListingService object FileListingService fls = new FileListingService(Device); // compute the number of file to move long total = GetTotalRemoteFileSize(entries, fls); Log.D(TAG, "Pull total transfer: {0}", total); // start the monitor monitor.Start(total); SyncResult result = DoPull(entries, localPath, fls, monitor); monitor.Stop(); return(result); }
/// <summary> /// Pushes a file to device /// </summary> /// <param name="localFilePath">the absolute path to file on local host</param> /// <returns>destination path on device for file</returns> /// <exception cref="IOException">if fatal error occurred when pushing file</exception> public string SyncPackageToDevice(string localFilePath) { try { string packageFileName = Path.GetFileName(localFilePath); // only root has access to /data/local/tmp/... not sure how adb does it then... // workitem: 16823 // string remoteFilePath = string.Format ( "/data/local/tmp/{0}", packageFileName ); string remoteFilePath = LinuxPath.Combine(TEMP_DIRECTORY_FOR_INSTALL, packageFileName); Log.D(LOG_TAG, string.Format("Uploading {0} onto device '{1}'", packageFileName, this)); SyncService sync = SyncService; if (sync != null) { string message = string.Format("Uploading file onto device '{0}'", this); Log.D(LOG_TAG, message); SyncResult result = sync.PushFile(localFilePath, remoteFilePath, SyncService.NullProgressMonitor); if (result.Code != ErrorCodeHelper.RESULT_OK) { throw new IOException(string.Format("Unable to upload file: {0}", result.Message)); } } else { throw new IOException("Unable to open sync connection!"); } return(remoteFilePath); } catch (IOException e) { Log.E(LOG_TAG, string.Format("Unable to open sync connection! reason: {0}", e.Message)); throw; } }
/// <summary> /// Processes the new lines. /// </summary> /// <param name="lines">The lines.</param> protected override void ProcessNewLines(string[] lines) { foreach (string line in lines) { // no need to handle empty lines. if (line.Length == 0) { continue; } // run the line through the regexp Regex regex = new Regex(FileListingService.LS_PATTERN_EX, RegexOptions.Compiled); Match m = regex.Match(line.Trim()); if (!m.Success) { Log.D(LOG_TAG, "not match: {0}", line); continue; } // get the name string name = m.Groups[9].Value; // if the parent is root, we only accept selected items // eff that - you get it all... /*if ( Parent.IsRoot ) { * bool found = false; * foreach ( string approved in FileListingService.RootLevelApprovedItems ) { * if ( string.Compare ( approved, name, false ) == 0 ) { * found = true; * break; * } * } * * // if it's not in the approved list we skip this entry. * if ( found == false ) { * continue; * } * }*/ // get the rest of the groups string permissions = m.Groups[1].Value; string owner = m.Groups[2].Value; string group = m.Groups[3].Value; bool isExec = string.Compare(m.Groups[10].Value, "*", true) == 0; string sizeData = m.Groups[4].Value.Trim(); long.TryParse(string.IsNullOrEmpty(sizeData) ? "0" : sizeData, out long size); string date1 = m.Groups[5].Value.Trim(); string date2 = m.Groups[6].Value.Trim(); string date3 = m.Groups[7].Value.Trim(); DateTime date = DateTimeHelper.GetEpoch(); string time = m.Groups[8].Value.Trim(); if (string.IsNullOrEmpty(time)) { time = date.ToString("HH:mm"); } if (date1.Length == 3) { // check if we don't have a year and use current if we don't string tyear = string.IsNullOrEmpty(date3) ? DateTime.Now.Year.ToString() : date3; date = DateTime.ParseExact(string.Format("{0}-{1}-{2} {3}", date1, date2.PadLeft(2, '0'), tyear, time), "MMM-dd-yyyy HH:mm", CultureInfo.GetCultureInfo("en-US")); } else if (date1.Length == 4) { date = DateTime.ParseExact(string.Format("{0}-{1}-{2} {3}", date1, date2.PadLeft(2, '0'), date3, time), "yyyy-MM-dd HH:mm", CultureInfo.GetCultureInfo("en-US")); } string info = null; string linkName = null; // and the type FileListingService.FileTypes objectType = FileListingService.FileTypes.Other; switch (permissions[0]) { case '-': objectType = FileListingService.FileTypes.File; break; case 'b': objectType = FileListingService.FileTypes.Block; break; case 'c': objectType = FileListingService.FileTypes.Character; break; case 'd': objectType = FileListingService.FileTypes.Directory; break; case 'l': objectType = FileListingService.FileTypes.Link; break; case 's': objectType = FileListingService.FileTypes.Socket; break; case 'p': objectType = FileListingService.FileTypes.FIFO; break; } // now check what we may be linking to if (objectType == FileListingService.FileTypes.Link) { string[] segments = name.Split(new string[] { " -> " }, StringSplitOptions.RemoveEmptyEntries); // we should have 2 segments if (segments.Length == 2) { // update the entry name to not contain the link name = segments[0]; // and the link name info = segments[1]; // now get the path to the link string[] pathSegments = info.Split(new string[] { FileListingService.FILE_SEPARATOR }, StringSplitOptions.RemoveEmptyEntries); if (pathSegments.Length == 1) { // the link is to something in the same directory, // unless the link is .. if (string.Compare("..", pathSegments[0], false) == 0) { // set the type and we're done. objectType = FileListingService.FileTypes.DirectoryLink; } else { // either we found the object already // or we'll find it later. } } } else { } linkName = info; // add an arrow in front to specify it's a link. info = string.Format(LINK_FORMAT, info); } // get the entry, either from an existing one, or a new one FileEntry entry = GetExistingEntry(name); if (entry == null) { entry = new FileEntry(Parent.Device, Parent, name, objectType, false /* isRoot */); } // add some misc info entry.Permissions = new FilePermissions(permissions); entry.Size = size; entry.Date = date; entry.Owner = owner; entry.Group = group; entry.IsExecutable = isExec; entry.LinkName = linkName; if (objectType == FileListingService.FileTypes.Link) { entry.Info = info; } Entries.Add(entry); } }
/// <summary> /// Queries adb for its version number and checks it against #MIN_VERSION_NUMBER and MAX_VERSION_NUMBER /// </summary> private void CheckAdbVersion() { // default is bad check VersionCheck = false; if (string.IsNullOrEmpty(AdbOsLocation)) { Log.D(LOG_TAG, "AdbOsLocation is Empty"); return; } try { Log.D(LOG_TAG, string.Format("Checking '{0} version'", AdbOsLocation)); ProcessStartInfo psi = new ProcessStartInfo(AdbOsLocation, "version") { WindowStyle = ProcessWindowStyle.Hidden, CreateNoWindow = true, UseShellExecute = false, RedirectStandardError = true, RedirectStandardOutput = true }; List <string> errorOutput = new List <string>(); List <string> stdOutput = new List <string>(); using (Process proc = Process.Start(psi)) { int status = GrabProcessOutput(proc, errorOutput, stdOutput, true /* waitForReaders */); if (status != 0) { StringBuilder builder = new StringBuilder("'adb version' failed!"); builder.AppendLine(string.Empty); foreach (string error in errorOutput) { builder.AppendLine(error); } Log.LogAndDisplay(LogLevel.Error, "adb", builder.ToString()); return; } } // check both stdout and stderr foreach (string line in stdOutput) { if (ScanVersionLine(line)) { return; } } foreach (string line in errorOutput) { if (ScanVersionLine(line)) { return; } } Log.LogAndDisplay(LogLevel.Error, ADB, "Failed to parse the output of 'adb version'"); } catch (IOException e) { Log.LogAndDisplay(LogLevel.Error, ADB, "Failed to get the adb version: " + e.Message); } }
/// <summary> /// /// </summary> /// <param name="entries"></param> /// <param name="localPath"></param> /// <param name="fls"></param> /// <param name="monitor"></param> /// <returns></returns> /// <exception cref="System.IO.IOException">Throws if unable to create a file or folder</exception> /// <exception cref="System.ArgumentNullException">Throws if the ISyncProgressMonitor is null</exception> private SyncResult DoPull(IEnumerable <FileEntry> entries, string localPath, FileListingService fileListingService, ISyncProgressMonitor monitor) { if (monitor == null) { throw new ArgumentNullException("monitor", "Monitor cannot be null"); } // check if we're cancelled if (monitor.IsCanceled) { return(new SyncResult(ErrorCodeHelper.RESULT_CANCELED)); } // check if we need to create the local directory DirectoryInfo localDir = new DirectoryInfo(localPath); if (!localDir.Exists) { localDir.Create(); } foreach (FileEntry e in entries) { // check if we're cancelled if (monitor.IsCanceled) { return(new SyncResult(ErrorCodeHelper.RESULT_CANCELED)); } // the destination item (folder or file) string dest = Path.Combine(localPath, e.Name); // get type (we only pull directory and files for now) FileListingService.FileTypes type = e.Type; if (type == FileListingService.FileTypes.Directory) { monitor.StartSubTask(e.FullPath, dest); // then recursively call the content. Since we did a ls command // to get the number of files, we can use the cache FileEntry[] children = fileListingService.GetChildren(e, true, null); SyncResult result = DoPull(children, dest, fileListingService, monitor); if (result.Code != ErrorCodeHelper.RESULT_OK) { return(result); } monitor.Advance(1); } else if (type == FileListingService.FileTypes.File) { monitor.StartSubTask(e.FullPath, dest); SyncResult result = DoPullFile(e.FullPath, dest, monitor); if (result.Code != ErrorCodeHelper.RESULT_OK) { return(result); } } else if (type == FileListingService.FileTypes.Link) { monitor.StartSubTask(e.FullPath, dest); SyncResult result = DoPullFile(e.FullResolvedPath, dest, monitor); if (result.Code != ErrorCodeHelper.RESULT_OK) { return(result); } } else { Log.D(TAG, string.Format("unknown type to transfer: {0}", type)); } } return(new SyncResult(ErrorCodeHelper.RESULT_OK)); }
/// <summary> /// Gets the frame buffer from the specified end point. /// </summary> /// <param name="adbSockAddr">The adb sock addr.</param> /// <param name="device">The device.</param> /// <returns></returns> public RawImage GetFrameBuffer(IPEndPoint adbSockAddr, IDevice device) { RawImage imageParams = new RawImage(); byte[] request = FormAdbRequest("framebuffer:"); //$NON-NLS-1$ byte[] nudge = { 0 }; byte[] reply; Socket adbChan = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); try { adbChan.ReceiveTimeout = SOCKET_TIMEOUT; adbChan.SendTimeout = SOCKET_TIMEOUT; adbChan.Connect(adbSockAddr); adbChan.Blocking = true; // if the device is not -1, then we first tell adb we're looking to talk // to a specific device SetDevice(adbChan, device); if (!Write(adbChan, request)) { throw new AdbException("failed asking for frame buffer"); } AdbResponse resp = ReadAdbResponse(adbChan, false /* readDiagstring */); if (!resp.IOSuccess || !resp.Okay) { Log.E(TAG, "Got timeout or unhappy response from ADB fb req: " + resp.Message); adbChan.Close(); return(null); } // first the protocol version. reply = new byte[4]; if (!Read(adbChan, reply)) { Log.E(TAG, "got partial reply from ADB fb:"); adbChan.Close(); return(null); } BinaryReader buf; int version = 0; using (MemoryStream ms = new MemoryStream(reply)) { buf = new BinaryReader(ms); version = buf.ReadInt32(); } // get the header size (this is a count of int) int headerSize = RawImage.GetHeaderSize(version); // read the header reply = new byte[headerSize * 4]; if (!Read(adbChan, reply)) { Log.W(TAG, "got partial reply from ADB fb:"); adbChan.Close(); return(null); } using (MemoryStream ms = new MemoryStream(reply)) { buf = new BinaryReader(ms); // fill the RawImage with the header if (imageParams.ReadHeader(version, buf) == false) { Log.W(TAG, "Unsupported protocol: " + version); return(null); } } Log.D(TAG, "image params: bpp=" + imageParams.Bpp + ", size=" + imageParams.Size + ", width=" + imageParams.Width + ", height=" + imageParams.Height); if (!Write(adbChan, nudge)) { throw new AdbException("failed nudging"); } adbChan.ReceiveTimeout = SOCKET_TIMEOUT_FRAMEBUFFER; reply = new byte[imageParams.Size]; if (!Read(adbChan, reply)) { Log.W(TAG, "got truncated reply from ADB fb data"); adbChan.Close(); return(null); } imageParams.Data = reply; } finally { if (adbChan != null) { adbChan.Close(); } } return(imageParams); }
/// <summary> /// Reads the adb response. /// </summary> /// <param name="socket">The socket.</param> /// <param name="readDiagstring">if set to <c>true</c> [read diag string].</param> /// <returns></returns> public AdbResponse ReadAdbResponse(Socket socket, bool readDiagstring) { AdbResponse resp = new AdbResponse(); byte[] reply = new byte[4]; if (!Read(socket, reply)) { return(resp); } resp.IOSuccess = true; if (IsOkay(reply)) { resp.Okay = true; } else { readDiagstring = true; // look for a reason after the FAIL resp.Okay = false; } // not a loop -- use "while" so we can use "break" while (readDiagstring) { // length string is in next 4 bytes byte[] lenBuf = new byte[4]; if (!Read(socket, lenBuf)) { Log.D(TAG, "Expected diagnostic string not found"); break; } string lenStr = ReplyTostring(lenBuf); int len; try { len = int.Parse(lenStr, System.Globalization.NumberStyles.HexNumber); } catch (FormatException) { Log.E(TAG, "Expected digits, got '{0}' : {1} {2} {3} {4}", lenBuf[0], lenBuf[1], lenBuf[2], lenBuf[3]); Log.E(TAG, "reply was {0}", ReplyTostring(reply)); break; } byte[] msg = new byte[len]; if (!Read(socket, msg)) { Log.E(TAG, "Failed reading diagnostic string, len={0}", len); break; } resp.Message = ReplyTostring(msg); Log.E(TAG, "Got reply '{0}', diag='{1}'", ReplyTostring(reply), resp.Message); break; } return(resp); }
/// <summary> /// Monitors the devices. This connects to the Debug Bridge /// </summary> private void DeviceMonitorLoop() { IsRunning = true; do { try { if (MainAdbConnection == null) { Log.D(TAG, "Opening adb connection"); MainAdbConnection = OpenAdbConnection(); if (MainAdbConnection == null) { ConnectionAttemptCount++; Log.E(TAG, "Connection attempts: {0}", ConnectionAttemptCount); if (ConnectionAttemptCount > 10) { if (Server.Restart() == false) { RestartAttemptCount++; Log.E(TAG, "adb restart attempts: {0}", RestartAttemptCount); } else { RestartAttemptCount = 0; } } WaitBeforeContinue(); } else { Log.D(TAG, "Connected to adb for device monitoring"); ConnectionAttemptCount = 0; } } //break; if (MainAdbConnection != null && !IsMonitoring) { IsMonitoring = SendDeviceListMonitoringRequest(); } if (IsMonitoring) { // read the length of the incoming message int length = ReadLength(MainAdbConnection, LengthBuffer); if (length >= 0) { // read the incoming message ProcessIncomingDeviceData(length); // flag the fact that we have build the list at least once. HasInitialDeviceList = true; } } } catch (IOException ioe) { Log.E(TAG, "Adb connection Error: ", ioe); IsMonitoring = false; if (MainAdbConnection != null) { try { MainAdbConnection.Close(); } catch (IOException) { // we can safely ignore that one. } MainAdbConnection = null; } } catch (Exception /*ex*/) { //Console.WriteLine ( ex ); } } while (IsRunning); }