/// <summary> /// 拷贝文件到设备 /// localFile:本地文件 /// remoutFile:设备存储文件路径 /// </summary> private bool DoPushFile(Device device, string localFile, string remoutFile, int bufferSize = 64 * 1024, int maxtimeout = 9000) { FileStream fs = null; byte[] remoutFileBytes = Encoding.UTF8.GetBytes(remoutFile); fs = new FileStream(localFile, FileMode.Open, FileAccess.Read); //socket Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); try { socket.Connect(this.SocketAddress); socket.ReceiveTimeout = maxtimeout; socket.SendTimeout = maxtimeout; socket.Blocking = true; socket.ReceiveBufferSize = bufferSize; this.SetDevice(socket, device); this.SendAsyncReqest(socket); var request = AdbSocketHelper.CreateSendFileRequest( Encoding.UTF8.GetBytes("SEND"), remoutFileBytes); AdbSocketHelper.Write(socket, request); //send data var buf = new byte[bufferSize + 8]; var cdata = Encoding.UTF8.GetBytes("DATA"); Array.Copy(cdata, 0, buf, 0, cdata.Length); int readindex = 1; while (readindex > 0) { readindex = fs.Read(buf, 8, bufferSize); readindex.Swap32bitsToArray(buf, 4); AdbSocketHelper.Write(socket, buf, readindex + 8); } // create the DONE message long time = 1447655524; var msg = AdbSocketHelper.CreateRequest(Encoding.UTF8.GetBytes("DONE"), (int)time); AdbSocketHelper.Write(socket, msg); var result = new byte[8]; AdbSocketHelper.Read(socket, result); if (!AdbSocketHelper.CheckResult(result, Encoding.UTF8.GetBytes("OKEY"))) { throw new Exception("Push file:RESULT_UNKNOWN_ERROR"); } return(true); } catch (Exception ex) { } finally { fs.Dispose(); this.DisposeSocket(socket); } return(false); }
/// <summary> /// 执行文件拷贝钱,发生异步通知,测试 /// </summary> /// <param name="socket"></param> private void SendAsyncReqest(Socket socket) { byte[] request = AdbSocketHelper.FormAdbRequest("sync:"); AdbSocketHelper.Write(socket, request); var res = AdbSocketHelper.ReadResponse(socket); if (!res.IsOkay) { throw new ApplicationException("socket response error:" + res.Data); } }
/// <summary> /// 查找当前设备列表 如果返回null 说明adb连接失败 /// </summary> /// <returns>如果返回null 说明adb连接失败</returns> private List <Device> FindCurConnectDevices() { List <Device> result = new List <Device>(); using (AdbSocketOperator _androidManagementSocket = new AdbSocketOperator()) { if (!_androidManagementSocket.IsOpened) { return(null); } try { var request = AdbSocketHelper.CmdToBytes("host:devices"); _androidManagementSocket.Write(request); var res = _androidManagementSocket.ReadResponse(); if (res.IsOkay) { var len = _androidManagementSocket.ReadDataLength(4); var data = new byte[len]; _androidManagementSocket.Read(data); string devString = Encoding.UTF8.GetString(data); if (!string.IsNullOrWhiteSpace(devString)) { string[] devices = devString.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries); Regex re = new Regex(Re_DeviceList_Info, RegexOptions.Compiled | RegexOptions.IgnoreCase); foreach (var ds in devices) { Match m = re.Match(ds); if (!m.Success) { LoggerManagerSingle.Instance.Error(string.Format("无法识别的设备信息:{0}", ds)); continue; } Device d = new Device(m.Groups[1].Value); var st = m.Groups[2].Value; //找到的设备都为在线状态 if (st == "device") { d.Status = EnumDeviceStatus.Online; result.Add(d); } } } } } catch (Exception e) { LoggerManagerSingle.Instance.Error(e); } } return(result); }
/// <summary> /// 执行shell命令,返回string /// </summary> /// <param name="command"></param> /// <param name="device"></param> /// <param name="receiver"></param> /// <param name="buffersize"></param> /// <param name="maxtimeout"></param> /// <returns></returns> /// private string ExecuteRemoteCommandString(string command, Device device, AbstractOutputReceiver receiver, int buffersize = 16 * 1024, int maxtimeout = 3000) { if (String.IsNullOrWhiteSpace(command) || device == null) { throw new ArgumentException("The command or device is invalid"); } Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); try { socket.Connect(this.SocketAddress); socket.ReceiveTimeout = maxtimeout; socket.SendTimeout = maxtimeout; socket.ReceiveBufferSize = buffersize; this.SetDevice(socket, device); //reqest var request = AdbSocketHelper.FormAdbRequest("shell:" + command); AdbSocketHelper.Write(socket, request); //response var res = AdbSocketHelper.ReadResponse(socket); if (!res.IsOkay) { throw new ApplicationException(string.Format("device[{0}] response error:{1}", device.SerialNumber, res.Data)); } //read AdbSocketHelper.Read(socket, receiver, buffersize); //验证输出是否合法 //determines weahter the output is valid var tdata = receiver.Data.ToString().Trim(); return(tdata); } catch (DoneWithReadException de) { } catch (SocketException ex) { throw new ApplicationException(string.Format("The shell command\"{0} \" has become unresponsive! ,max timeout:{1}", command, maxtimeout)); } finally { this.DisposeSocket(socket); } return(string.Empty); }
/// <summary> /// 设置当前使用的设备 /// Sets the device. /// </summary> private void SetDevice(Socket adbChan, Device device) { String msg = "host:transport:" + device.SerialNumber; byte[] device_query = AdbSocketHelper.FormAdbRequest(msg); AdbSocketHelper.Write(adbChan, device_query); var res = AdbSocketHelper.ReadResponse(adbChan); if (!res.IsOkay) { if (String.Compare("device not found", res.Data, StringComparison.OrdinalIgnoreCase) == 0) { throw new ApplicationException(string.Format("I'm so sorry,device[{0}] not found", device.SerialNumber)); } else { throw new ApplicationException("device (" + device + ") request rejected: " + res.Data); } } }
/// <summary> /// 执行ADB指令,可以指定端口,device可以为null,若为null则不指定设备。 /// 结果接收器receiver可以为null,为null则不处理结果数据 /// </summary> public void ExecuteAdbSocketCommand(Device device, string command, int port = 5037, AbstractOutputReceiver receiver = null, int bufSize = 16 * 1024, int timeOut = 9000) { Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); try { socket.Connect(IPAddress.Loopback, port); socket.Blocking = true; socket.ReceiveBufferSize = bufSize; socket.SendBufferSize = bufSize; socket.ReceiveTimeout = timeOut; socket.SendTimeout = timeOut; if (device != null) { this.SetDevice(socket, device); } byte[] request = AdbSocketHelper.FormAdbRequest(command); AdbSocketHelper.Write(socket, request); var res = AdbSocketHelper.ReadResponse(socket); if (!res.IsOkay) { throw new Exception(string.Format("Device rejected command:{0}. Error:{1} ", command, res.Data)); } if (receiver != null) { AdbSocketHelper.Read(socket, receiver, bufSize); } } finally { this.DisposeSocket(socket); } }
/// <summary> /// 判断文件或者路径是否存在 /// </summary> /// <param name="device"></param> /// <param name="path"></param> /// <returns></returns> private bool IsExistsFileOrPath(Device device, string path) { int buffersize = 16 * 1024; int maxtimeout = 9000; DefaultReceiver receiver = new DefaultReceiver(); string command = string.Format("ls -l {0}", path.TrimEnd(new char[] { '#', 'F' })); if (device.IsRoot) { command = string.Format("su -c \"{0}\" ", command); } Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); try { socket.Connect(this.SocketAddress); socket.ReceiveTimeout = maxtimeout; socket.SendTimeout = maxtimeout; socket.ReceiveBufferSize = buffersize; //设置当前使用设备 String msg = "host:transport:" + device.SerialNumber; byte[] device_query = AdbSocketHelper.FormAdbRequest(msg); AdbSocketHelper.Write(socket, device_query); var res = AdbSocketHelper.ReadResponse(socket); if (!res.IsOkay) { return(false); } //reqest var request = AdbSocketHelper.FormAdbRequest("shell:" + command); AdbSocketHelper.Write(socket, request); //response res = AdbSocketHelper.ReadResponse(socket); if (!res.IsOkay) { return(false); } //read AdbSocketHelper.Read(socket, receiver, buffersize); //验证输出是否合法 //determines weahter the output is valid string[] cmd = command.Trim().Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); var tdata = receiver.Data.ToString().Trim(); if (tdata.Contains(String.Format("{0}: not found", cmd[0]))) { return(false); } if (tdata.Contains("No such file or directory")) { return(false); } if (tdata.Contains("no closing quote")) { return(false); } } finally { this.DisposeSocket(socket); } return(true); }
/// <summary> /// 执行SPF app指令,并返回结果。 /// </summary> /// <returns></returns> public string ExecuteSPFAppCommand(Device device, string command = "basic_info", int timeout = 12000) { // 服务启动提取失败:是否进行过重试 int doretry = 0; DoRetry: var port = _ForwardProt++; Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); try { /** * 启动APP: * 目前APP支持两种启动方式,一种为服务命令,一种为直接启动组件 * 服务启动方式:优点是用户不需要做任何操作,缺点是启动服务不稳定,针对部分手机启动受权限限制 * 组件启动方式:优点是启动服务稳定,缺点是启动组件时屏幕会闪动一下,用户体验比较差 * 综合上述两种启动方式,在APP中提供两种启动方式,有限已服务启动,启动失败后再通过组件方式进行启动 */ // 服务启动 if (!AppServiceStart(device, port, 12345) || doretry == 1 || doretry == 2) { // 组件启动 AppAmStart(device, port, 12345); } socket.Connect(IPAddress.Loopback, port); socket.Blocking = true; socket.ReceiveBufferSize = 16 * 1024; socket.SendBufferSize = 16 * 1024; socket.ReceiveTimeout = timeout; socket.SendTimeout = timeout; byte[] request = Encoding.UTF8.GetBytes(command); AdbSocketHelper.Write(socket, request); var res = AdbSocketHelper.ReadResponse(socket); if (!res.IsOkay) { // 服务启动提取数据失败后则转变为组件方式启动提取数据 if (doretry == 0) { doretry = 1; goto DoRetry; } else { throw new Exception(string.Format("Device rejected command:{0}. Error:{1} ", command, res.Data)); } } var sizebuf = new byte[16]; socket.Receive(sizebuf); int length = Convert.ToInt32(sizebuf.GetString(Encoding.UTF8), 16); var databuf = new byte[length]; socket.ReceiveBufferSize = length; AdbSocketHelper.Read(socket, databuf, length); return(databuf.GetString(Encoding.UTF8)); } catch (Exception ex) { if (doretry <= 1) { doretry = 2; goto DoRetry; } else { throw new Exception("ReceiveSPFAppData Error,", ex); } } finally { this.DisposeSocket(socket); //remove forward try { var sc2 = String.Format("host-serial:{0}:killforward-all", device.SerialNumber); this.ExecuteAdbSocketCommand(null, sc2); } catch { } } }
/// <summary> /// 执行文件拷贝到本地操作 /// </summary> private void DoPullFile(Device device, string sourceFile, string local, PullFileReceiver receiver = null, int bufferSize = 64 * 1024, int maxtimeout = 9000, bool trycat = true) { if (device == null || String.IsNullOrWhiteSpace(sourceFile) || String.IsNullOrWhiteSpace(local)) { return; } #region /data/data/文件处理 //只处理/data/data/文件夹下文件 bool IsNeedMoveFile = sourceFile.Replace('\\', '/').StartsWith("/data/data/") && sourceFile.EndsWith(".db"); var dr = new DefaultReceiver(); string rmCmd = ""; if (IsNeedMoveFile) { string tempSrc = string.Format("/data/local/tmp/{0}", FileHelper.GetFileName(local)); string cpCmd = string.Format("cp {0} /data/local/tmp", sourceFile); this.ExecuteRemoteAutoCommandNoException(cpCmd, device, dr); //拷贝/data/data/ 到/data/local/tmp if (this.IsExistsFileOrPath(device, tempSrc)) //判断是否拷贝成功 { this.UpgradeFilePermission(device, tempSrc); //提权 sourceFile = tempSrc; rmCmd = string.Format("rm {0}", tempSrc); } } #endregion receiver = receiver ?? new PullFileReceiver(local); Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); try { socket.Connect(this.SocketAddress); socket.ReceiveTimeout = maxtimeout; socket.SendTimeout = maxtimeout; socket.Blocking = true; socket.ReceiveBufferSize = bufferSize; this.SetDevice(socket, device); this.SendAsyncReqest(socket); var request = AdbSocketHelper.FormPullFileRequest(sourceFile); AdbSocketHelper.Write(socket, request); receiver.DoReceive(socket); } catch (ADBConnectionException cex) { var mes = string.Format("pull file[{0}] failed:{1}", sourceFile, cex.Message); if (trycat) { var rec = new CatToFileReceiver(local); rec.OnReceiveData = receiver.OnReceiveData; var rt = this.CatToFile(device, sourceFile, local, rec); if (rt != string.Empty) { throw new Exception(rt); } } else { throw new ApplicationException(mes, cex); } } catch (Exception ex) { throw new ApplicationException(string.Format("pull file[{0}] failed", sourceFile), ex); } finally { if (IsNeedMoveFile && !String.IsNullOrWhiteSpace(rmCmd)) {//删除temp文件 try { this.ExecuteRemoteAutoCommandNoException(rmCmd, device, dr); } catch { } } this.DisposeSocket(socket); } }