示例#1
0
		/// <summary>
		/// Create and connect a new pass-through socket, from the host to a port on
		/// the device.
		/// </summary>
		/// <param name="adbSockAddr"> </param>
		/// <param name="device"> the device to connect to. Can be null in which case the connection will be
		/// to the first available device. </param>
		/// <param name="devicePort"> the port we're opening </param>
		/// <exception cref="TimeoutException"> in case of timeout on the connection. </exception>
		/// <exception cref="IOException"> in case of I/O error on the connection. </exception>
		/// <exception cref="AdbCommandRejectedException"> if adb rejects the command </exception>
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
//ORIGINAL LINE: public static java.nio.channels.SocketChannel open(java.net.InetSocketAddress adbSockAddr, Device device, int devicePort) throws java.io.IOException, TimeoutException, AdbCommandRejectedException
		public static SocketChannel open(EndPoint adbSockAddr, Device device, int devicePort)
		{

			SocketChannel adbChan = SocketChannel.open(adbSockAddr);
			try
			{
				adbChan.socket().NoDelay = true;
				adbChan.configureBlocking(false);

				// if the device is not -1, then we first tell adb we're looking to
				// talk to a specific device
				setDevice(adbChan, device);

				var req = createAdbForwardRequest(null, devicePort);
				// Log.hexDump(req);

				write(adbChan, req);

				AdbResponse resp = readAdbResponse(adbChan, false);
				if (resp.okay == false)
				{
					throw new AdbCommandRejectedException(resp.message);
				}

				adbChan.configureBlocking(true);
			}
			catch (TimeoutException e)
			{
				adbChan.close();
				throw e;
			}
			catch (IOException e)
			{
				adbChan.close();
				throw e;
			}

			return adbChan;
		}
示例#2
0
		/// <summary>
		/// Reboot the device.
		/// </summary>
		/// <param name="into"> what to reboot into (recovery, bootloader).  Or null to just reboot. </param>
		/// <exception cref="TimeoutException"> in case of timeout on the connection. </exception>
		/// <exception cref="AdbCommandRejectedException"> if adb rejects the command </exception>
		/// <exception cref="IOException"> in case of I/O error on the connection. </exception>
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
//ORIGINAL LINE: public static void reboot(String into, java.net.InetSocketAddress adbSockAddr, Device device) throws TimeoutException, AdbCommandRejectedException, java.io.IOException
		public static void reboot(string into, EndPoint adbSockAddr, Device device)
		{
			byte[] request;
			if (into == null)
			{
				request = formAdbRequest("reboot:"); //$NON-NLS-1$
			}
			else
			{
				request = formAdbRequest("reboot:" + into); //$NON-NLS-1$
			}

			SocketChannel adbChan = null;
			try
			{
				adbChan = SocketChannel.open(adbSockAddr);
				adbChan.configureBlocking(false);

				// if the device is not -1, then we first tell adb we're looking to talk
				// to a specific device
				setDevice(adbChan, device);

				write(adbChan, request);
			}
			finally
			{
				if (adbChan != null)
				{
					adbChan.close();
				}
			}
		}
示例#3
0
		/// <summary>
		/// Remove a port forwarding between a local and a remote port. </summary>
		/// <param name="adbSockAddr"> the socket address to connect to adb </param>
		/// <param name="device"> the device on which to remove the port fowarding </param>
		/// <param name="localPort"> the local port of the forward </param>
		/// <param name="remotePort"> the remote port. </param>
		/// <exception cref="TimeoutException"> in case of timeout on the connection. </exception>
		/// <exception cref="AdbCommandRejectedException"> if adb rejects the command </exception>
		/// <exception cref="IOException"> in case of I/O error on the connection. </exception>
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
//ORIGINAL LINE: public static void removeForward(java.net.InetSocketAddress adbSockAddr, Device device, int localPort, int remotePort) throws TimeoutException, AdbCommandRejectedException, java.io.IOException
		public static void removeForward(EndPoint adbSockAddr, Device device, int localPort, int remotePort)
		{

			SocketChannel adbChan = null;
			try
			{
				adbChan = SocketChannel.open(adbSockAddr);
				adbChan.configureBlocking(false);

				var request = formAdbRequest(string.Format("host-serial:{0}:killforward:tcp:{1:D};tcp:{2:D}", device.serialNumber, localPort, remotePort)); //$NON-NLS-1$

				write(adbChan, request);

				AdbResponse resp = readAdbResponse(adbChan, false); // readDiagString
				if (resp.okay == false)
				{
					Log.w("remove-forward", "Error creating forward: " + resp.message);
					throw new AdbCommandRejectedException(resp.message);
				}
			}
			finally
			{
				if (adbChan != null)
				{
					adbChan.close();
				}
			}
		}
示例#4
0
		/// <summary>
		/// Runs the Event log service on the <seealso cref="Device"/>, and provides its output to the
		/// <seealso cref="LogReceiver"/>.
		/// <p/>This call is blocking until <seealso cref="LogReceiver#isCancelled()"/> returns true. </summary>
		/// <param name="adbSockAddr"> the socket address to connect to adb </param>
		/// <param name="device"> the Device on which to run the service </param>
		/// <param name="rcvr"> the <seealso cref="LogReceiver"/> to receive the log output </param>
		/// <exception cref="TimeoutException"> in case of timeout on the connection. </exception>
		/// <exception cref="AdbCommandRejectedException"> if adb rejects the command </exception>
		/// <exception cref="IOException"> in case of I/O error on the connection. </exception>
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
//ORIGINAL LINE: public static void runEventLogService(java.net.InetSocketAddress adbSockAddr, Device device, com.android.ddmlib.log.LogReceiver rcvr) throws TimeoutException, AdbCommandRejectedException, java.io.IOException
		public static void runEventLogService(EndPoint adbSockAddr, Device device, LogReceiver rcvr)
		{
			runLogService(adbSockAddr, device, "events", rcvr); //$NON-NLS-1$
		}
示例#5
0
		/// <summary>
		/// Runs a log service on the <seealso cref="Device"/>, and provides its output to the <seealso cref="LogReceiver"/>.
		/// <p/>This call is blocking until <seealso cref="LogReceiver#isCancelled()"/> returns true. </summary>
		/// <param name="adbSockAddr"> the socket address to connect to adb </param>
		/// <param name="device"> the Device on which to run the service </param>
		/// <param name="logName"> the name of the log file to output </param>
		/// <param name="rcvr"> the <seealso cref="LogReceiver"/> to receive the log output </param>
		/// <exception cref="TimeoutException"> in case of timeout on the connection. </exception>
		/// <exception cref="AdbCommandRejectedException"> if adb rejects the command </exception>
		/// <exception cref="IOException"> in case of I/O error on the connection. </exception>
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
//ORIGINAL LINE: public static void runLogService(java.net.InetSocketAddress adbSockAddr, Device device, String logName, com.android.ddmlib.log.LogReceiver rcvr) throws TimeoutException, AdbCommandRejectedException, java.io.IOException
		public static void runLogService(EndPoint adbSockAddr, Device device, string logName, LogReceiver rcvr)
		{
			SocketChannel adbChan = null;

			try
			{
				adbChan = SocketChannel.open(adbSockAddr);
				adbChan.configureBlocking(false);

				// if the device is not -1, then we first tell adb we're looking to talk
				// to a specific device
				setDevice(adbChan, device);

				var request = formAdbRequest("log:" + logName);
				write(adbChan, request);

				AdbResponse resp = readAdbResponse(adbChan, false); // readDiagString
				if (resp.okay == false)
				{
					throw new AdbCommandRejectedException(resp.message);
				}

				var data = new byte[16384];
				ByteBuffer buf = ByteBuffer.wrap(data);
				while (true)
				{
					int count;

					if (rcvr != null && rcvr.cancelled)
					{
						break;
					}

					count = adbChan.read(buf);
					if (count < 0)
					{
						break;
					}
                    else if (count == 0)
                    {
                        Thread.Sleep(WAIT_TIME*5);
                    }
                    else
                    {
                        if (rcvr != null)
                        {
                            rcvr.parseNewData(buf.array(), buf.arrayOffset(), buf.position);
                        }
                        buf.rewind();
                    }
				}
			}
			finally
			{
				if (adbChan != null)
				{
					adbChan.close();
				}
			}
		}
示例#6
0
        private void removeDevice(Device device)
        {
            device.clearClientList();
            mDevices.Remove(device);

            SocketChannel channel = device.clientMonitoringSocket;
            if (channel != null)
            {
                try
                {
                    channel.close();
                }
                catch (IOException)
                {
                    // doesn't really matter if the close fails.
                }
            }
        }
示例#7
0
		/// <summary>
		/// Retrieve the frame buffer from the device. </summary>
		/// <exception cref="TimeoutException"> in case of timeout on the connection. </exception>
		/// <exception cref="AdbCommandRejectedException"> if adb rejects the command </exception>
		/// <exception cref="IOException"> in case of I/O error on the connection. </exception>
//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
//ORIGINAL LINE: static RawImage getFrameBuffer(java.net.InetSocketAddress adbSockAddr, Device device) throws TimeoutException, AdbCommandRejectedException, java.io.IOException
		internal static RawImage getFrameBuffer(EndPoint adbSockAddr, Device device)
		{

			RawImage imageParams = new RawImage();
			var request = formAdbRequest("framebuffer:"); //$NON-NLS-1$
			byte[] nudge = {0};
			byte[] reply;

			SocketChannel adbChan = null;
			try
			{
				adbChan = SocketChannel.open(adbSockAddr);
				adbChan.configureBlocking(false);

				// if the device is not -1, then we first tell adb we're looking to talk
				// to a specific device
				setDevice(adbChan, device);

				write(adbChan, request);

				AdbResponse resp = readAdbResponse(adbChan, false); // readDiagString
				if (resp.okay == false)
				{
					throw new AdbCommandRejectedException(resp.message);
				}

				// first the protocol version.
				reply = new byte[4];
				read(adbChan, reply);

				ByteBuffer buf = ByteBuffer.wrap(reply);
				buf.order = ByteOrder.LITTLE_ENDIAN;

                int version = buf.getInt();

				// get the header size (this is a count of int)
				int headerSize = RawImage.getHeaderSize(version);

				// read the header
				reply = new byte[headerSize * 4];
				read(adbChan, reply);

				buf = ByteBuffer.wrap(reply);
				buf.order = ByteOrder.LITTLE_ENDIAN;

				// fill the RawImage with the header
				if (imageParams.readHeader(version, buf) == false)
				{
					Log.e("Screenshot", "Unsupported protocol: " + version);
					return null;
				}

				Log.d("ddms", "image params: bpp=" + imageParams.bpp + ", size=" + imageParams.size + ", width=" + imageParams.width + ", height=" + imageParams.height);

				write(adbChan, nudge);

				reply = new byte[imageParams.size];
				read(adbChan, reply);

				imageParams.data = reply;
			}
			finally
			{
				if (adbChan != null)
				{
					adbChan.close();
				}
			}

			return imageParams;
		}
示例#8
0
        /// <summary>
        /// Opens and creates a new client.
        /// @return
        /// </summary>
        private void openClient(Device device, int pid, int port, MonitorThread monitorThread)
        {

            SocketChannel clientSocket;
            try
            {
                clientSocket = AdbHelper.createPassThroughConnection(AndroidDebugBridge.socketAddress, device, pid);

                // required for Selector
                clientSocket.configureBlocking(false);
            }
            catch (ArgumentException)
            {
                Log.d("DeviceMonitor", "Unknown Jdwp pid: " + pid);
                return;
            }
            catch (TimeoutException)
            {
                Log.w("DeviceMonitor", "Failed to connect to client '" + pid + "': timeout");
                return;
            }
            catch (AdbCommandRejectedException e)
            {
                Log.w("DeviceMonitor", "Adb rejected connection to client '" + pid + "': " + e.Message);
                return;

            }
            catch (Exception ioe)
            {
                Log.w("DeviceMonitor", "Failed to connect to client '" + pid + "': " + ioe.Message);
                return;
            }

            createClient(device, pid, clientSocket, port, monitorThread);
        }
示例#9
0
        /// <summary>
        /// Creates a client and register it to the monitor thread </summary>
        /// <param name="device"> </param>
        /// <param name="pid"> </param>
        /// <param name="socket"> </param>
        /// <param name="debuggerPort"> the debugger port. </param>
        /// <param name="monitorThread"> the <seealso cref="MonitorThread"/> object. </param>
        private void createClient(Device device, int pid, SocketChannel socket, int debuggerPort, MonitorThread monitorThread)
        {

            /*
             * Successfully connected to something. Create a Client object, add
             * it to the list, and initiate the JDWP handshake.
             */

            Client client = new Client(device, socket, pid);

            if (client.sendHandshake())
            {
                try
                {
                    if (AndroidDebugBridge.clientSupport)
                    {
                        client.listenForDebugger(debuggerPort);
                    }
                }
                catch (IOException)
                {
                    client.clientData.debuggerConnectionStatus = ClientData.DebuggerStatus.ERROR;
                    Log.e("ddms", "Can't bind to local " + debuggerPort + " for debugger");
                    // oh well
                }

                client.requestAllocationStatus();
            }
            else
            {
                Log.e("ddms", "Handshake with " + client + " failed!");
                /*
                 * The handshake send failed. We could remove it now, but if the
                 * failure is "permanent" we'll just keep banging on it and
                 * getting the same result. Keep it in the list with its "error"
                 * state so we don't try to reopen it.
                 */
            }

            if (client.valid)
            {
                device.addClient(client);
                monitorThread.addClient(client);
            }
            else
            {
                client = null;
            }
        }
示例#10
0
        //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
        //ORIGINAL LINE: private boolean sendDeviceMonitoringRequest(java.nio.channels.SocketChannel socket, Device device) throws TimeoutException, AdbCommandRejectedException, java.io.IOException
        private bool sendDeviceMonitoringRequest(SocketChannel socket, Device device)
        {

            try
            {
                AdbHelper.setDevice(socket, device);

                var request = AdbHelper.formAdbRequest("track-jdwp"); //$NON-NLS-1$

                AdbHelper.write(socket, request);

                AdbHelper.AdbResponse resp = AdbHelper.readAdbResponse(socket, false); // readDiagString

                if (resp.okay == false)
                {
                    // request was refused by adb!
                    Log.e("DeviceMonitor", "adb refused request: " + resp.message);
                }

                return resp.okay;
            }
            catch (TimeoutException e)
            {
                Log.e("DeviceMonitor", "Sending jdwp tracking request timed out!");
                throw e;
            }
            catch (IOException e)
            {
                Log.e("DeviceMonitor", "Sending jdwp tracking request failed!");
                throw e;
            }
        }
示例#11
0
        //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
        //ORIGINAL LINE: private void processIncomingJdwpData(Device device, java.nio.channels.SocketChannel monitorSocket, int length) throws java.io.IOException
        private void processIncomingJdwpData(Device device, SocketChannel monitorSocket, int length)
        {
            if (length >= 0)
            {
                // array for the current pids.
                List<int?> pidList = new List<int?>();

                // get the string data if there are any
                if (length > 0)
                {
                    var buffer = new byte[length];
                    string result = read(monitorSocket, buffer);

                    // split each line in its own list and create an array of integer pid
                    string[] pids = StringHelperClass.StringSplit(result, "\n", true); //$NON-NLS-1$

                    foreach (string pid in pids)
                    {
                        try
                        {
                            pidList.Add(Convert.ToInt32(pid));
                        }
                        catch (SystemException)
                        {
                            // looks like this pid is not really a number. Lets ignore it.
                            continue;
                        }
                    }
                }

                MonitorThread monitorThread = MonitorThread.instance;

                // Now we merge the current list with the old one.
                // this is the same mechanism as the merging of the device list.

                // For each client in the current list, we look for a matching the pid in the new list.
                // * if we find it, we do nothing, except removing the pid from its list,
                //   to mark it as "processed"
                // * if we do not find any match, we remove the client from the current list.
                // Once this is done, the new list contains pids for which we don't have clients yet,
                // so we create clients for them, add them to the list, and start monitoring them.

                IList<Client> clients = device.clientList;

                bool changed = false;

                // because MonitorThread#dropClient acquires first the monitorThread lock and then the
                // Device client list lock (when removing the Client from the list), we have to make
                // sure we acquire the locks in the same order, since another thread (MonitorThread),
                // could call dropClient itself.
                lock (monitorThread)
                {
                    lock (clients)
                    {
                        for (int c = 0; c < clients.Count; )
                        {
                            Client client = clients[c];
                            int pid = client.clientData.pid;

                            // look for a matching pid
                            int? match = null;
                            foreach (int? matchingPid in pidList)
                            {
                                if (pid == (int)matchingPid)
                                {
                                    match = matchingPid;
                                    break;
                                }
                            }

                            if (match != null)
                            {
                                pidList.Remove(match);
                                c++; // move on to the next client.
                            }
                            else
                            {
                                // we need to drop the client. the client will remove itself from the
                                // list of its device which is 'clients', so there's no need to
                                // increment c.
                                // We ask the monitor thread to not send notification, as we'll do
                                // it once at the end.
                                monitorThread.dropClient(client, false); // notify
                                changed = true;
                            }
                        }
                    }
                }

                // at this point whatever pid is left in the list needs to be converted into Clients.
                foreach (int newPid in pidList)
                {
                    openClient(device, newPid, nextDebuggerPort, monitorThread);
                    changed = true;
                }

                if (changed)
                {
                    mServer.deviceChanged(device, DeviceConstants.CHANGE_CLIENT_LIST);
                }
            }
        }
示例#12
0
        /// <summary>
        /// Starts a monitoring service for a device. </summary>
        /// <param name="device"> the device to monitor. </param>
        /// <returns> true if success. </returns>
        private bool startMonitoringDevice(Device device)
        {
            SocketChannel socketChannel = openAdbConnection();

            if (socketChannel != null)
            {
                try
                {
                    bool result = sendDeviceMonitoringRequest(socketChannel, device);
                    if (result)
                    {

                        if (mSelector == null)
                        {
                            startDeviceMonitorThread();
                        }

                        device.clientMonitoringSocket = socketChannel;

                        lock (mDevices)
                        {
                            // always wakeup before doing the register. The synchronized block
                            // ensure that the selector won't select() before the end of this block.
                            // @see deviceClientMonitorLoop
                            mSelector.wakeup();

                            socketChannel.configureBlocking(false);
                            socketChannel.register(mSelector, SelectionKey.OP_READ, device);
                        }

                        return true;
                    }
                }
                catch (TimeoutException)
                {
                    try
                    {
                        // attempt to close the socket if needed.
                        socketChannel.close();
                    }
                    catch (IOException)
                    {
                        // we can ignore that one. It may already have been closed.
                    }
                    Log.d("DeviceMonitor", "Connection Failure when starting to monitor device '" + device + "' : timeout");
                }
                catch (AdbCommandRejectedException e)
                {
                    try
                    {
                        // attempt to close the socket if needed.
                        socketChannel.close();
                    }
                    catch (IOException)
                    {
                        // we can ignore that one. It may already have been closed.
                    }
                    Log.d("DeviceMonitor", "Adb refused to start monitoring device '" + device + "' : " + e.Message);
                }
                catch (IOException e)
                {
                    try
                    {
                        // attempt to close the socket if needed.
                        socketChannel.close();
                    }
                    catch (IOException)
                    {
                        // we can ignore that one. It may already have been closed.
                    }
                    Log.d("DeviceMonitor", "Connection Failure when starting to monitor device '" + device + "' : " + e.Message);
                }
            }

            return false;
        }
示例#13
0
        //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
        //ORIGINAL LINE: private void queryNewDeviceForMountingPoint(final Device device, final String name) throws TimeoutException, AdbCommandRejectedException, ShellCommandUnresponsiveException, java.io.IOException
        //JAVA TO C# CONVERTER WARNING: 'final' parameters are not allowed in .NET:
        private void queryNewDeviceForMountingPoint(Device device, string name)
        {
            var tempVar = new MultiLineReceiverAnonymousInnerClassHelper();
            /*tempVar.isCancelledDelegateInstance =
                () => {
                    return false;
                };*/

            tempVar.processNewLinesDelegateInstance =
                (string[] lines) => {
                    foreach (string line in lines)
                    {
                        if (line.Length > 0)
                        {
                            // this should be the only one.
                            device.setMountingPoint(name, line);
                        }
                    }
                };
            device.executeShellCommand("echo $" + name, tempVar);
        }
示例#14
0
        /// <summary>
        /// Queries a device for its build info. </summary>
        /// <param name="device"> the device to query. </param>
        private void queryNewDeviceForInfo(Device device)
        {
            // TODO: do this in a separate thread.
            try
            {
                // first get the list of properties.
                device.executeShellCommand(GetPropReceiver.GETPROP_COMMAND, new GetPropReceiver(device));

                queryNewDeviceForMountingPoint(device, DeviceConstants.MNT_EXTERNAL_STORAGE);
                queryNewDeviceForMountingPoint(device, DeviceConstants.MNT_DATA);
                queryNewDeviceForMountingPoint(device, DeviceConstants.MNT_ROOT);

                // now get the emulator Virtual Device name (if applicable).
                if (device.emulator)
                {
                    EmulatorConsole console = EmulatorConsole.getConsole(device);
                    if (console != null)
                    {
                        device.avdName = console.avdName;
                    }
                }
            }
            catch (TimeoutException)
            {
                Log.w("DeviceMonitor", string.Format("Connection timeout getting info for device {0}", device.serialNumber));

            }
            catch (AdbCommandRejectedException e)
            {
                // This should never happen as we only do this once the device is online.
                Log.w("DeviceMonitor", string.Format("Adb rejected command to get  device {0} info: {1}", device.serialNumber, e.Message));

            }
            catch (ShellCommandUnresponsiveException)
            {
                Log.w("DeviceMonitor", string.Format("Adb shell command took too long returning info for device {0}", device.serialNumber));

            }
            catch (IOException)
            {
                Log.w("DeviceMonitor", string.Format("IO Error getting info for device {0}", device.serialNumber));
            }
        }
示例#15
0
		/// <summary>
		/// Creates the receiver with the device the receiver will modify. </summary>
		/// <param name="device"> The device to modify </param>
		public GetPropReceiver(Device device)
		{
			mDevice = device;
		}
示例#16
0
		/// <summary>
		/// Create an object for a new client connection.
		/// </summary>
		/// <param name="device"> the device this client belongs to </param>
		/// <param name="chan"> the connected <seealso cref="SocketChannel"/>. </param>
		/// <param name="pid"> the client pid. </param>
		internal Client(Device device, SocketChannel chan, int pid)
		{
			mDevice = device;
			mChan = chan;

			mReadBuffer = ByteBuffer.allocate(INITIAL_BUF_SIZE);
			mWriteBuffer = ByteBuffer.allocate(WRITE_BUF_SIZE);

			mOutstandingReqs = new Dictionary<int?, ChunkHandler>();

			mConnState = ST_INIT;

			mClientData = new ClientData(pid);

			mThreadUpdateEnabled = DdmPreferences.initialThreadUpdate;
			mHeapUpdateEnabled = DdmPreferences.initialHeapUpdate;
		}
示例#17
0
 /// <summary>
 /// Creates a Sync service object. </summary>
 /// <param name="address"> The address to connect to </param>
 /// <param name="device"> the <seealso cref="Device"/> that the service connects to. </param>
 internal SyncService(EndPoint address, Device device)
 {
     mAddress = address;
     mDevice = device;
 }
示例#18
0
        /// <summary>
        /// Processes an incoming device message from the socket </summary>
        /// <param name="socket"> </param>
        /// <param name="length"> </param>
        /// <exception cref="IOException"> </exception>
        //JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
        //ORIGINAL LINE: private void processIncomingDeviceData(int length) throws java.io.IOException
        private void processIncomingDeviceData(int length)
        {
            List<Device> list = new List<Device>();

            if (length > 0)
            {
                var buffer = new byte[length];
                string result = read(mMainAdbConnection, buffer);

                string[] devices = StringHelperClass.StringSplit(result, "\n", true); //$NON-NLS-1$

                foreach (string d in devices)
                {
                    string[] param = StringHelperClass.StringSplit(d, "\t", true); //$NON-NLS-1$
                    if (param.Length == 2)
                    {
                        // new adb uses only serial numbers to identify devices
                        Device device = new Device(this, param[0], DeviceState.getState(param[1])); //serialnumber

                        //add the device to the list
                        list.Add(device);
                    }
                }
            }

            // now merge the new devices with the old ones.
            updateDevices(list);
        }