/// <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"); } Log.I(TAG, "Pulling file '" + localPath + "' from '" + Device + remotePath + "'."); byte[] pullResult = new byte[8]; int timeOut = DdmPreferences.Timeout; try { byte[] remotePathContent = StringHelper.GetBytes(remotePath, AdbHelper.DEFAULT_ENCODING); if (remotePathContent.Length > REMOTE_PATH_MAX_LENGTH) { return(new SyncResult(ErrorCodeHelper.RESULT_REMOTE_PATH_LENGTH)); } // create the full request message byte[] msg = CreateFileRequest(StringHelper.GetBytes(RECV), 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); // check we have the proper data back if (CheckResult(pullResult, StringHelper.GetBytes(DATA)) == false && CheckResult(pullResult, StringHelper.GetBytes(DONE)) == 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; try { fos = new FileStream(f.FullName, System.IO.FileMode.Create, FileAccess.Write); } catch (FileNotFoundException e) { Log.E(TAG, 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 cancelled if (monitor.IsCanceled) { return(new SyncResult(ErrorCodeHelper.RESULT_CANCELED)); } // if we're done, we stop the loop if (CheckResult(pullResult, StringHelper.GetBytes(DONE))) { break; } if (CheckResult(pullResult, StringHelper.GetBytes(DATA)) == false) { // hmm there's an error return(new SyncResult(ErrorCodeHelper.RESULT_CONNECTION_ERROR)); } int length = ArrayHelper.Swap32bitFromArray(pullResult, 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); // get the header for the next packet. AdbHelper.Instance.Read(Channel, pullResult, -1); } 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, data.Length); } catch (IOException e) { Log.E(TAG, 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)); } try { fos.Close(); fos.Dispose(); } catch (IOException e) { Log.E(TAG, e); } } return(new SyncResult(ErrorCodeHelper.RESULT_OK)); }
/// <summary> /// Gets the children. /// </summary> /// <param name="entry">The entry.</param> /// <param name="useCache">if set to <c>true</c> [use cache].</param> /// <param name="receiver">The receiver.</param> /// <returns></returns> 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) { ThreadState 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) { Dictionary <string, FileEntry> map = new Dictionary <string, FileEntry>(); foreach (FileEntry child in children) { string path = child.FullPath; map.Add(path, 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 }); } } })) { 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); }
/// <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="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"); } Log.I(TAG, "Pushing file '" + local + "' to '" + Device + remotePath + "'."); byte[] msg; int timeOut = DdmPreferences.Timeout; FileStream fs; try { byte[] remotePathContent = StringHelper.GetBytes(remotePath, 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(StringHelper.GetBytes(SEND), remotePathContent, (FileMode)0644); } catch (EncoderFallbackException e) { Log.E(TAG, e); return(new SyncResult(ErrorCodeHelper.RESULT_REMOTE_PATH_ENCODING, e)); } catch (FileNotFoundException e) { Log.E(TAG, 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) { Log.E(TAG, 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 = StringHelper.GetBytes(DATA); 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; 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 ArrayHelper.Swap32bitsToArray(readCount, 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(); fs.Dispose(); } catch (IOException e) { Log.E(TAG, e); } try { // create the DONE message long time = DateTimeHelper.CurrentTimeMillis(DateTime.Now) / 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 */); if (!CheckResult(result, StringHelper.GetBytes(OKAY))) { if (CheckResult(result, StringHelper.GetBytes(FAIL))) { // read some error message... int len = ArrayHelper.Swap32bitFromArray(result, 4); AdbHelper.Instance.Read(Channel, DataBuffer, len); // output the result? string message = StringHelper.GetString(DataBuffer, 0, len); Log.E(TAG, "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... this.Device.FileSystem.Chmod(remotePath, "0666"); 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); }
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; // 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) { device.RetrieveDeviceInfo(); } } device.OnStateChanged(EventArgs.Empty); } // 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.RetrieveDeviceInfo(false); newDevice.OnStateChanged(EventArgs.Empty); Server.OnDeviceConnected(new DeviceEventArgs(newDevice)); } // start monitoring them. if (AndroidDebugBridge.ClientSupport) { if (newDevice.IsOnline) { StartMonitoringDevice(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.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); }