/// <summary> /// Push a single file /// </summary> /// <param name="local">the local file to push</param> /// <param name="remotePath">the remote file (length max is 1024)</param> /// <param name="monitor">the monitor. The monitor must be started already.</param> /// <returns> /// a SyncResult object with a code and an optional message. /// </returns> /// <exception cref="System.ArgumentNullException">monitor;Monitor cannot be null</exception> /// <exception cref="ArgumentNullException">Throws if monitor is null</exception> private SyncResult DoPushFile(string local, string remotePath, ISyncProgressMonitor monitor) { if (monitor == null) { throw new ArgumentNullException("monitor", "Monitor cannot be null"); } FileStream fs = null; byte[] msg; int timeOut = DdmPreferences.Timeout; Log.d(TAG, "Remote File: {0}", remotePath); try { byte[] remotePathContent = remotePath.GetBytes(AdbHelper.DEFAULT_ENCODING); if (remotePathContent.Length > REMOTE_PATH_MAX_LENGTH) { return(new SyncResult(ErrorCodeHelper.RESULT_REMOTE_PATH_LENGTH)); } // this shouldn't happen but still... if (!File.Exists(local)) { return(new SyncResult(ErrorCodeHelper.RESULT_NO_LOCAL_FILE)); } // create the stream to read the file fs = new FileStream(local, System.IO.FileMode.Open, FileAccess.Read); // create the header for the action msg = CreateSendFileRequest(SEND.GetBytes( ), remotePathContent, (FileMode)0644); } catch (EncoderFallbackException e) { return(new SyncResult(ErrorCodeHelper.RESULT_REMOTE_PATH_ENCODING, e)); } catch (FileNotFoundException e) { return(new SyncResult(ErrorCodeHelper.RESULT_FILE_READ_ERROR, e)); } // and send it. We use a custom try/catch block to make the difference between // file and network IO exceptions. try { AdbHelper.Instance.Write(Channel, msg, -1, timeOut); } catch (IOException e) { return(new SyncResult(ErrorCodeHelper.RESULT_CONNECTION_ERROR, e)); } // create the buffer used to read. // we read max SYNC_DATA_MAX, but we need 2 4 bytes at the beginning. if (DataBuffer == null) { DataBuffer = new byte[SYNC_DATA_MAX + 8]; } byte[] bDATA = DATA.GetBytes( ); Array.Copy(bDATA, 0, DataBuffer, 0, bDATA.Length); // look while there is something to read while (true) { // check if we're canceled if (monitor.IsCanceled) { return(new SyncResult(ErrorCodeHelper.RESULT_CANCELED)); } // read up to SYNC_DATA_MAX int readCount = 0; try { readCount = fs.Read(DataBuffer, 8, SYNC_DATA_MAX); } catch (IOException e) { return(new SyncResult(ErrorCodeHelper.RESULT_FILE_READ_ERROR, e)); } if (readCount == 0) { // we reached the end of the file break; } // now send the data to the device // first write the amount read readCount.Swap32bitsToArray(DataBuffer, 4); // now write it try { AdbHelper.Instance.Write(Channel, DataBuffer, readCount + 8, timeOut); } catch (IOException e) { return(new SyncResult(ErrorCodeHelper.RESULT_CONNECTION_ERROR, e)); } // and advance the monitor monitor.Advance(readCount); } // close the local file try { fs.Close( ); } catch (IOException e) { return(new SyncResult(ErrorCodeHelper.RESULT_FILE_READ_ERROR, e)); } try { // create the DONE message long time = DateTime.Now.CurrentTimeMillis( ) / 1000; msg = CreateRequest(DONE, (int)time); // and send it. AdbHelper.Instance.Write(Channel, msg, -1, timeOut); // read the result, in a byte array containing 2 ints // (id, size) byte[] result = new byte[8]; AdbHelper.Instance.Read(Channel, result, -1 /* full length */, timeOut); if (!CheckResult(result, OKAY.GetBytes( ))) { if (CheckResult(result, FAIL.GetBytes( ))) { // read some error message... int len = result.Swap32bitFromArray(4); AdbHelper.Instance.Read(Channel, DataBuffer, len, timeOut); // output the result? String message = DataBuffer.GetString(0, len); Log.e("ddms", "transfer error: " + message); return(new SyncResult(ErrorCodeHelper.RESULT_UNKNOWN_ERROR, message)); } return(new SyncResult(ErrorCodeHelper.RESULT_UNKNOWN_ERROR)); } } catch (IOException e) { return(new SyncResult(ErrorCodeHelper.RESULT_CONNECTION_ERROR, e)); } // files pushed have no permissions... // lets check if we can get to the file... if (this.Device.FileSystem.Exists(remotePath)) { this.Device.FileSystem.Chmod(remotePath, "0666"); } return(new SyncResult(ErrorCodeHelper.RESULT_OK)); }
/// <summary> /// Pulls a remote file /// </summary> /// <param name="remotePath">the remote file (length max is 1024)</param> /// <param name="localPath">the local destination</param> /// <param name="monitor">the monitor. The monitor must be started already.</param> /// <returns>a SyncResult object with a code and an optional message.</returns> /// <exception cref="ArgumentNullException">Throws if monitor is null</exception> private SyncResult DoPullFile(string remotePath, string localPath, ISyncProgressMonitor monitor) { if (monitor == null) { throw new ArgumentNullException("monitor", "Monitor cannot be null"); } byte[] msg = null; byte[] pullResult = new byte[8]; int timeOut = DdmPreferences.Timeout; try { byte[] remotePathContent = remotePath.GetBytes(AdbHelper.DEFAULT_ENCODING); if (remotePathContent.Length > REMOTE_PATH_MAX_LENGTH) { return(new SyncResult(ErrorCodeHelper.RESULT_REMOTE_PATH_LENGTH)); } // create the full request message msg = CreateFileRequest(RECV.GetBytes( ), remotePathContent); // and send it. AdbHelper.Instance.Write(Channel, msg, -1, timeOut); // read the result, in a byte array containing 2 ints // (id, size) AdbHelper.Instance.Read(Channel, pullResult, -1, timeOut); // check we have the proper data back if (CheckResult(pullResult, DATA.GetBytes( )) == false && CheckResult(pullResult, DONE.GetBytes( )) == false) { return(new SyncResult(ErrorCodeHelper.RESULT_CONNECTION_ERROR)); } } catch (EncoderFallbackException e) { Log.e(TAG, e); return(new SyncResult(ErrorCodeHelper.RESULT_REMOTE_PATH_ENCODING, e)); } catch (IOException e) { Log.e(TAG, e); return(new SyncResult(ErrorCodeHelper.RESULT_CONNECTION_ERROR, e)); } // access the destination file FileInfo f = new FileInfo(localPath); // create the stream to write in the file. We use a new try/catch block to differentiate // between file and network io exceptions. FileStream fos = null; try { fos = new FileStream(f.FullName, System.IO.FileMode.Create, FileAccess.Write); } catch (FileNotFoundException e) { return(new SyncResult(ErrorCodeHelper.RESULT_FILE_WRITE_ERROR, e)); } // the buffer to read the data byte[] data = new byte[SYNC_DATA_MAX]; using ( fos ) { // loop to get data until we're done. while (true) { // check if we're canceled if (monitor.IsCanceled) { return(new SyncResult(ErrorCodeHelper.RESULT_CANCELED)); } // if we're done, we stop the loop if (CheckResult(pullResult, DONE.GetBytes( ))) { break; } if (CheckResult(pullResult, DATA.GetBytes( )) == false) { // hmm there's an error return(new SyncResult(ErrorCodeHelper.RESULT_CONNECTION_ERROR)); } int length = pullResult.Swap32bitFromArray(4); if (length > SYNC_DATA_MAX) { // buffer overrun! // error and exit return(new SyncResult(ErrorCodeHelper.RESULT_BUFFER_OVERRUN)); } try { // now read the length we received AdbHelper.Instance.Read(Channel, data, length, timeOut); // get the header for the next packet. AdbHelper.Instance.Read(Channel, pullResult, -1, timeOut); } catch (IOException e) { Log.e(TAG, e); return(new SyncResult(ErrorCodeHelper.RESULT_CONNECTION_ERROR, e)); } // write the content in the file try { fos.Write(data, 0, length); } catch (IOException e) { return(new SyncResult(ErrorCodeHelper.RESULT_FILE_WRITE_ERROR, e)); } monitor.Advance(length); } try { fos.Flush( ); } catch (IOException e) { Log.e(TAG, e); return(new SyncResult(ErrorCodeHelper.RESULT_FILE_WRITE_ERROR, e)); } } return(new SyncResult(ErrorCodeHelper.RESULT_OK)); }
/// <summary> /// Get the stderr/stdout outputs of a process and return when the process is done. /// Both <b>must</b> be read or the process will block on windows. /// </summary> /// <param name="process">The process to get the ouput from</param> /// <param name="errorOutput">The array to store the stderr output. cannot be null.</param> /// <param name="stdOutput">The array to store the stdout output. cannot be null.</param> /// <param name="waitforReaders">if true, this will wait for the reader threads.</param> /// <returns>the process return code.</returns> private int GrabProcessOutput(Process process, List <String> errorOutput, List <String> stdOutput, bool waitforReaders) { if (errorOutput == null) { throw new ArgumentNullException("errorOutput"); } if (stdOutput == null) { throw new ArgumentNullException("stdOutput"); } // read the lines as they come. if null is returned, it's // because the process finished Thread t1 = new Thread(new ThreadStart(delegate { // create a buffer to read the stdoutput try { using (StreamReader sr = process.StandardError) { while (!sr.EndOfStream) { String line = sr.ReadLine( ); if (!String.IsNullOrEmpty(line)) { Log.e(ADB, line); errorOutput.Add(line); } } } } catch (Exception) { // do nothing. } })); Thread t2 = new Thread(new ThreadStart(delegate { // create a buffer to read the std output try { using (StreamReader sr = process.StandardOutput) { while (!sr.EndOfStream) { String line = sr.ReadLine( ); if (!String.IsNullOrEmpty(line)) { stdOutput.Add(line); } } } } catch (Exception) { // do nothing. } })); t1.Start( ); t2.Start( ); // it looks like on windows process#waitFor() can return // before the thread have filled the arrays, so we wait for both threads and the // process itself. if (waitforReaders) { try { t1.Join( ); } catch (ThreadInterruptedException) { } try { t2.Join( ); } catch (ThreadInterruptedException) { } } // get the return code from the process process.WaitForExit( ); return(process.ExitCode); }
public void RunCatLog(IPEndPoint address, IDevice device, string filePath, LogReceiver receiver) { if (device.IsOnline && (receiver != null)) { int num = 0x1400; Action action = null; Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); try { socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, new LingerOption(true, 0)); socket.ReceiveTimeout = -1; socket.ReceiveBufferSize = num + 1; socket.Blocking = true; socket.Connect(AndroidDebugBridge.SocketAddress); if (action == null) { action = delegate { if (socket != null) { socket.Close(); } }; } receiver.CancelAction = action; this.SetDevice(socket, device); //byte[] data = Instance.FormAdbRequest(string.Format("shell:cat {0}", filePath)); byte[] data = Instance.FormAdbRequest(string.Format("log:{0}", filePath)); if (!this.Write(socket, data)) { throw new AdbException("failed submitting shell command"); } AdbResponse response = Instance.ReadAdbResponse(socket, false); if (!response.IOSuccess || !response.Okay) { throw new AdbException("sad result from adb: " + response.Message); } byte[] buffer = new byte[num + 1]; byte num2 = 0; while ((device.IsOnline && (receiver != null)) && !receiver.IsCancelled) { int num3 = socket.Receive(buffer); if (num3 > 0) { using (MemoryStream stream = new MemoryStream()) { for (int i = 0; i < num3; i++) { if ((((num3 > (i + 1)) && (buffer[i] == 13)) && (buffer[i + 1] == 10)) || ((num2 == 13) && (buffer[i] == 10))) { stream.WriteByte(10); i++; } else { stream.WriteByte(buffer[i]); } if (i == (num3 - 1)) { num2 = buffer[i]; } } receiver.ParseNewData(stream.ToArray(), 0, (int)stream.Length); //continue; } } } } catch (SocketException exception) { if (exception.SocketErrorCode != SocketError.ConnectionAborted) { Log.e("Socket error while receiving response", exception); } } finally { if (socket != null) { socket.Dispose(); } } } }
/// <include file='.\FileListingService.xml' path='/FileListingService/GetChildren/*'/> public FileEntry[] GetChildren(FileEntry entry, bool useCache, IListingReceiver receiver) { // first thing we do is check the cache, and if we already have a recent // enough children list, we just return that. if (useCache && !entry.NeedFetch) { return(entry.Children.ToArray( )); } // if there's no receiver, then this is a synchronous call, and we // return the result of ls if (receiver == null) { DoLS(entry); return(entry.Children.ToArray( )); } // this is a asynchronous call. // we launch a thread that will do ls and give the listing // to the receiver Thread t = new Thread(new ParameterizedThreadStart(delegate(object stateData) { var state = stateData as ThreadState; DoLS(entry); receiver.SetChildren(state.Entry, state.Entry.Children.ToArray( )); FileEntry[] children = state.Entry.Children.ToArray( ); if (children.Length > 0 && children[0].IsApplicationPackage) { var map = new Dictionary <String, FileEntry> ( ); children.ForEach(child => { map.Add(child.FullPath, child); }); // call pm. String command = PM_FULL_LISTING; try { this.Device.ExecuteShellCommand(command, new PackageManagerListingReceiver(map, receiver)); } catch (IOException e) { // adb failed somehow, we do nothing. Log.e("FileListingService", e); } } // if another thread is pending, launch it lock ( Threads ) { // first remove ourselves from the list Threads.Remove(state.Thread); // then launch the next one if applicable. if (Threads.Count > 0) { Thread ct = Threads[0]; ct.Start(new ThreadState { Thread = ct, Entry = entry }); } } })); t.Name = "ls " + entry.FullPath; // we don't want to run multiple ls on the device at the same time, so we // store the thread in a list and launch it only if there's no other thread running. // the thread will launch the next one once it's done. lock ( Threads ) { // add to the list Threads.Add(t); // if it's the only one, launch it. if (Threads.Count == 1) { t.Start(new ThreadState { Thread = t }); } } // and we return null. return(null); }
private void UpdateDevices(List <Device> list) { // because we are going to call mServer.deviceDisconnected which will acquire this lock // we lock it first, so that the AndroidDebugBridge lock is always locked first. lock (AndroidDebugBridge.GetLock( )) { lock ( Devices ) { // For each device in the current list, we look for a matching the new list. // * if we find it, we update the current object with whatever new information // there is // (mostly state change, if the device becomes ready, we query for build info). // We also remove the device from the new list to mark it as "processed" // * if we do not find it, we remove it from the current list. // Once this is done, the new list contains device we aren't monitoring yet, so we // add them to the list, and start monitoring them. for (int d = 0; d < Devices.Count;) { Device device = Devices[d]; // look for a similar device in the new list. int count = list.Count; bool foundMatch = false; for (int dd = 0; dd < count; dd++) { Device newDevice = list[dd]; // see if it matches in id and serial number. if (String.Compare(newDevice.SerialNumber, device.SerialNumber, true) == 0) { foundMatch = true; // update the state if needed. if (device.State != newDevice.State) { device.State = newDevice.State; device.OnStateChanged(EventArgs.Empty); // if the device just got ready/online, we need to start // monitoring it. if (device.IsOnline) { if (AndroidDebugBridge.ClientSupport) { if (StartMonitoringDevice(device) == false) { Log.e(TAG, "Failed to start monitoring {0}", device.SerialNumber); } } if (device.Properties.Count == 0) { QueryNewDeviceForInfo(device); } } } // remove the new device from the list since it's been used list.RemoveAt(dd); break; } } if (foundMatch == false) { // the device is gone, we need to remove it, and keep current index // to process the next one. RemoveDevice(device); device.State = DeviceState.Offline; device.OnStateChanged(EventArgs.Empty); Server.OnDeviceDisconnected(new DeviceEventArgs(device)); } else { // process the next one d++; } } // at this point we should still have some new devices in newList, so we // process them. foreach (Device newDevice in list) { // add them to the list Devices.Add(newDevice); if (Server != null) { newDevice.State = DeviceState.Online; newDevice.OnStateChanged(EventArgs.Empty); Server.OnDeviceConnected(new DeviceEventArgs(newDevice)); } // start monitoring them. if (AndroidDebugBridge.ClientSupport) { if (newDevice.IsOnline) { StartMonitoringDevice(newDevice); } } // look for their build info. if (newDevice.IsOnline) { QueryNewDeviceForInfo(newDevice); } } } } list.Clear( ); }
/// <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.Start( ) == 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; } } if (MainAdbConnection != null && !IsMonitoring && MainAdbConnection.Connected) { 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) { if (!IsRunning) { 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) { Log.e(TAG, ex); } } while (IsRunning); }