Inheritance: IDevice
Exemple #1
0
        public bool CreateForward( IPEndPoint adbSockAddr, Device device, int localPort, int remotePort )
        {
            Socket adbChan = new Socket ( AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp );
            try {
                adbChan.Connect ( adbSockAddr );
                adbChan.Blocking = true;

                byte[] request = FormAdbRequest ( String.Format ( "host-serial:{0}:forward:tcp:{1};tcp:{2}", //$NON-NLS-1$
                                device.SerialNumber, localPort, remotePort ) );

                if ( !Write ( adbChan, request ) ) {
                    throw new IOException ( "failed to submit the forward command." );
                }

                AdbResponse resp = ReadAdbResponse ( adbChan, false /* readDiagString */);
                if ( !resp.IOSuccess || !resp.Okay ) {
                    throw new IOException ( "Device rejected command: " + resp.Message );
                }
            } finally {
                if ( adbChan != null ) {
                    adbChan.Close ( );
                }
            }

            return true;
        }
Exemple #2
0
 /// <summary>
 /// Executes a shell command on the remote device
 /// </summary>
 /// <param name="endPoint">The end point.</param>
 /// <param name="command">The command.</param>
 /// <param name="device">The device.</param>
 /// <param name="rcvr">The RCVR.</param>
 /// <param name="maxTimeToOutputResponse">The max time to output response.</param>
 public void ExecuteRemoteRootCommand( IPEndPoint endPoint, String command, Device device, IShellOutputReceiver rcvr, int maxTimeToOutputResponse )
 {
     ExecuteRemoteCommand ( endPoint, String.Format ( "su -c \"{0}\"", command ), device, rcvr );
 }
Exemple #3
0
        public void Reboot( String into, IPEndPoint adbSockAddr, Device device )
        {
            byte[] request;
            if ( into == null ) {
                request = FormAdbRequest ( "reboot:" ); //$NON-NLS-1$
            } else {
                request = FormAdbRequest ( "reboot:" + into ); //$NON-NLS-1$
            }

            Socket adbChan = new Socket ( AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp );
            try {
                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 IOException ( "failed asking for reboot" );
                }
            } finally {
                if ( adbChan != null ) {
                    adbChan.Close ( );
                }
            }
        }
Exemple #4
0
 /// <summary>
 /// Executes a shell command on the remote device
 /// </summary>
 /// <param name="endPoint">The socket end point</param>
 /// <param name="command">The command to execute</param>
 /// <param name="device">The device to execute on</param>
 /// <param name="rcvr">The shell output receiver</param>
 /// <exception cref="FileNotFoundException">Throws if the result is 'command': not found</exception>
 /// <exception cref="IOException">Throws if there is a problem reading / writing to the socket</exception>
 /// <exception cref="OperationCanceledException">Throws if the execution was canceled</exception>
 /// <exception cref="EndOfStreamException">Throws if the Socket.Receice ever returns -1</exception>
 public void ExecuteRemoteCommand( IPEndPoint endPoint, String command, Device device, IShellOutputReceiver rcvr )
 {
     ExecuteRemoteCommand ( endPoint, command, device, rcvr, int.MaxValue );
 }
Exemple #5
0
 /// <summary>
 /// Executes a shell command on the remote device
 /// </summary>
 /// <param name="endPoint">The end point.</param>
 /// <param name="command">The command.</param>
 /// <param name="device">The device.</param>
 /// <param name="rcvr">The RCVR.</param>
 /// <remarks>Should check if you CanSU before calling this.</remarks>
 public void ExecuteRemoteRootCommand( IPEndPoint endPoint, String command, Device device, IShellOutputReceiver rcvr )
 {
     ExecuteRemoteRootCommand ( endPoint, String.Format ( "su -c \"{0}\"", command ), device, rcvr, int.MaxValue );
 }
Exemple #6
0
        /// <summary>
        /// Executes the remote command.
        /// </summary>
        /// <param name="endPoint">The end point.</param>
        /// <param name="command">The command.</param>
        /// <param name="device">The device.</param>
        /// <param name="rcvr">The RCVR.</param>
        /// <param name="maxTimeToOutputResponse">The max time to output response.</param>
        /// <exception cref="AdbException">failed submitting shell command</exception>
        /// <exception cref="System.OperationCanceledException"></exception>
        /// <exception cref="Managed.Adb.Exceptions.ShellCommandUnresponsiveException"></exception>
        /// <exception cref="System.IO.FileNotFoundException"></exception>
        /// <exception cref="UnknownOptionException"></exception>
        /// <exception cref="CommandAbortingException"></exception>
        /// <exception cref="PermissionDeniedException"></exception>
        public void ExecuteRemoteCommand( IPEndPoint endPoint, String command, Device device, IShellOutputReceiver rcvr, int maxTimeToOutputResponse )
        {
            Socket socket = new Socket ( AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp );

            if ( !device.IsOnline ) {
                return;
            }

            try {
                socket.Connect ( endPoint );
                socket.Blocking = true;

                SetDevice ( socket, device );

                byte[] request = FormAdbRequest ( "shell:" + command );
                if ( !Write ( socket, request ) ) {
                    throw new AdbException ( "failed submitting shell command" );
                }

                AdbResponse resp = ReadAdbResponse ( socket, false /* readDiagString */);
                if ( !resp.IOSuccess || !resp.Okay ) {
                    throw new AdbException ( "sad result from adb: " + resp.Message );
                }

                byte[] data = new byte[16384];
                int timeToResponseCount = 0;

                while ( true ) {
                    int count;

                    if ( rcvr != null && rcvr.IsCancelled ) {
                        this.LogWarn("execute: cancelled" );
                        throw new OperationCanceledException ( );
                    }

                    count = socket.Receive ( data );
                    if ( count < 0 ) {
                        // we're at the end, we flush the output
                        rcvr.Flush ( );
                        this.LogInfo("execute '" + command + "' on '" + device + "' : EOF hit. Read: " + count );
                        break;
                    } else if ( count == 0 ) {
                        try {
                            int wait = WAIT_TIME * 5;
                            timeToResponseCount += wait;
                            if ( maxTimeToOutputResponse > 0 && timeToResponseCount > maxTimeToOutputResponse ) {
                                throw new AdbException ( );
                            }
                            Thread.Sleep ( wait );
                        } catch ( ThreadInterruptedException ) { }
                    } else {
                        timeToResponseCount = 0;

                        string[] cmd = command.Trim ( ).Split ( new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries );
                        string sdata = data.GetString ( 0, count, AdbHelper.DEFAULT_ENCODING );

                        var sdataTrimmed = sdata.Trim ( );
                        if ( sdataTrimmed.EndsWith ( String.Format ( "{0}: not found", cmd[0] ) ) ) {
                            this.LogWarn( "The remote execution returned: '{0}: not found'", cmd[0] );
                            throw new FileNotFoundException ( string.Format ( "The remote execution returned: '{0}: not found'", cmd[0] ) );
                        }

                        if ( sdataTrimmed.EndsWith ( "No such file or directory" ) ) {
                            this.LogWarn ( "The remote execution returned: {0}", sdataTrimmed );
                            throw new FileNotFoundException ( String.Format ( "The remote execution returned: {0}", sdataTrimmed ) );
                        }

                        // for "unknown options"
                        if ( sdataTrimmed.Contains ( "Unknown option" ) ) {
                            this.LogWarn ( "The remote execution returned: {0}", sdataTrimmed );
                            throw new UnknownOptionException ( sdataTrimmed );
                        }

                        // for "aborting" commands
                        if ( sdataTrimmed.IsMatch ( "Aborting.$" ) ) {
                            this.LogWarn ( "The remote execution returned: {0}", sdataTrimmed );
                            throw new CommandAbortingException ( sdataTrimmed );
                        }

                        // for busybox applets
                        // cmd: applet not found
                        if ( sdataTrimmed.IsMatch ( "applet not found$" ) && cmd.Length > 1 ) {
                            this.LogWarn ( "The remote execution returned: '{0}'", sdataTrimmed );
                            throw new FileNotFoundException ( string.Format ( "The remote execution returned: '{0}'", sdataTrimmed ) );
                        }

                        // checks if the permission to execute the command was denied.
                        // workitem: 16822
                        if ( sdataTrimmed.IsMatch ( "(permission|access) denied$" ) ) {
                            this.LogWarn ( "The remote execution returned: '{0}'", sdataTrimmed );
                            throw new PermissionDeniedException ( String.Format ( "The remote execution returned: '{0}'", sdataTrimmed ) );
                        }

                        // Add the data to the receiver
                        if ( rcvr != null ) {
                            rcvr.AddOutput ( data, 0, count );
                        }
                    }
                }
            } /*catch ( Exception e ) {
                Log.e ( TAG, e );
                Console.Error.WriteLine ( e.ToString ( ) );
                throw;
            }*/ finally {
                if ( socket != null ) {
                    socket.Close ( );
                }
                rcvr.Flush ( );
            }
        }
        public void RegisterDevice(Device device, DeviceListItem dli)
        {
            try {
                var kvp = new List<KeyValuePair<String, String>>();
                var useragent = String.Format("{0}", this.GetType().Assembly.GetName().Version.ToString());

                // if the Id is an IP, we need to find the real SerialNumber.
                var realSerialNo = device.SerialNumber;
                var kvpid = new KeyValuePair<string, string>("Id", realSerialNo);
                if(realSerialNo.Contains(":")) {
                    // it is probably an IP:PORT combo. Lets try to get the real serial number, or what we have if we can't find it.
                    var tid = device.Properties.FirstOrValue(x => x.Key == "ro.serialno" || x.Key == "ro.boot.serialno", new KeyValuePair<string, string>("default.serialno", realSerialNo)).Value;
                    if(!string.IsNullOrWhiteSpace(tid) && tid != realSerialNo) {
                        kvpid = new KeyValuePair<string, string>("Id", tid);
                        realSerialNo = tid;
                    }
                }

                // should we record
                if(!ShouldRecordStatistics(realSerialNo)) {
                    this.LogDebug("Skipping registration of device because delay not reached.");
                    return;
                }

                kvp.Add(kvpid);
                kvp.Add(new KeyValuePair<string, string>("ProductName", dli.ProductName));
                kvp.Add(new KeyValuePair<string, string>("ModelName", dli.ModelName));
                kvp.Add(new KeyValuePair<string, string>("DeviceName", dli.DeviceName));

                device.Properties.Add("ro.droidexplorer.version", useragent);
                device.Properties.Add("ro.droidexplorer.root", true.ToString());
                device.Properties.Add("ro.droidexplorer.busybox", true.ToString());
                device.Properties.Add("ro.droidexplorer.architecture", Architecture.IsRunningX64 ? "x64" : "x86");
                device.Properties.Add("ro.droidexplorer.platform", Environment.OSVersion.Platform.ToString());
                device.Properties.Add("ro.droidexplorer.platformversion", Environment.OSVersion.VersionString);

                var propCount = 0;
                foreach(var item in device.Properties.Where(item => !FilteredProperties.Contains(item.Key))) {
                    kvp.Add(new KeyValuePair<String, String>(String.Format("Properties[{0}].Name", propCount), item.Key));
                    kvp.Add(new KeyValuePair<String, String>(String.Format("Properties[{0}].Value", propCount), item.Value));
                    ++propCount;
                }

                var req = HttpWebRequest.Create(CreateUrl("device/add")) as HttpWebRequest;
                req.UserAgent = useragent;
                AddAuthenticationHeaders(req);

                req.ContentType = "application/x-www-form-urlencoded";
                req.Method = "POST";

                var data = CreateFormattedPostRequest(kvp);

                var bytes = data.GetBytes();
                req.ContentLength = bytes.Length;
                req.Timeout = 60 * 1000;
                using(var rs = req.GetRequestStream()) {
                    rs.Write(bytes, 0, bytes.Length);
                }
                using(var resp = req.GetResponse() as HttpWebResponse) {
                    if(resp.StatusCode != HttpStatusCode.OK) {
                        this.LogError(String.Format("POST Statistics Failed (Error Code: {1}): {0}", resp.StatusDescription, resp.StatusCode));
                    }
                }

                // track when we recorded this
                Settings.Instance.SystemSettings.SetLastRecordCloud(realSerialNo);
            } catch(WebException ex) {
                this.LogError(ex.Message, ex);
            }
        }
Exemple #8
0
        static void Main(string[] arguments)
        {
            try {
                using(var stream = typeof(Program).Assembly.GetManifestResourceStream(DroidExplorer.Resources.Strings.Log4NetDroidExplorer)) {
                    XmlConfigurator.Configure(stream);
                }
                var errorMessages = new List<string>();

                var args = new Arguments(arguments);
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
                Application.ThreadException +=
                    (sender, e) => DroidExplorer.Core.Logger.LogError(typeof(Program), e.Exception.Message, e.Exception);

                // show the splash dialog
                Program.SplashManager.ShowSplashDialog(StartUpStepCount);

                // load settings
                Logger.LogDebug ( typeof ( Program ), "Loading Droid Explorer Settings" );
                Program.SplashManager.SplashDialog.SetStepText("Loading Settings...");
                CommandRunner.Settings = Settings.Instance;
                Settings.Instance.SystemSettings = RegistrySettings.Instance;
                Program.SplashManager.SplashDialog.IncrementLoadStep(1);

                // cleanup adb? should this be done?
                Application.ApplicationExit += delegate(object sender, EventArgs e) {
                    //CommandRunner.Instance.AdbProcessCleanUp ( );
                };

                // locate sdk tools
                Logger.LogDebug ( typeof ( Program ), "Locating SDK Path" );
                Program.SplashManager.SplashDialog.SetStepText(DroidExplorer.Resources.Strings.SplashLocatingSdk);
                var sdkPath = Settings.Instance.SystemSettings.SdkPath;
                Logger.LogDebug ( typeof ( Program ), "SDK Path Set to {0}", sdkPath );

                if ( string.IsNullOrEmpty(sdkPath)) {
                    throw new ApplicationException("Unable to locate the android SDK tools, please reinstall the application.");
                }
                Program.SplashManager.SplashDialog.IncrementLoadStep(1);

                // verify the sdk tools
                Logger.LogDebug ( typeof ( Program ), "Verifying SDK Tools" );
                Program.SplashManager.SplashDialog.SetStepText("Verifying SDK Tools");

                // verify the sdk tools.
                var valid = FolderManagement.VerifyAndroidSdkTools ();
                if(!valid){
                    // if not valid - lets ask the user where it is.
                    Program.SplashManager.SplashDialog.HideExt();
                    Logger.LogWarn( typeof ( Program ), "Unable to verify the SDK tools" );

                    var browser = new FolderBrowserDialog();
                    browser.Description = "Unable to locate SDK tools path. Please select the location where you have the Android SDK installed.";
                    browser.ShowNewFolderButton = false;
                    var dResult = DialogResult.OK;
                    do {
                        dResult = browser.ShowDialog();
                        if(dResult == DialogResult.OK) {
                            Settings.Instance.SystemSettings.SdkPath = browser.SelectedPath;
                            valid = FolderManagement.VerifyAndroidSdkTools ();
                        }
                        // keep asking until the user selects a valid location, or they cancel.
                    } while(!valid && dResult == DialogResult.OK);

                    if(!valid) {
                        // they canceled. we are out of here.
                        throw new ApplicationException(DroidExplorer.Resources.Strings.SdkPathNotFoundMessage);
                    }

                    // bring it back.
                    Program.SplashManager.SplashDialog.AsyncShow();
                }

                Program.SplashManager.SplashDialog.IncrementLoadStep(1);

                // set the sdk path
                CommandRunner.Instance.SdkPath = sdkPath;
                Program.SplashManager.SplashDialog.SetStepText(DroidExplorer.Resources.Strings.SplashStartAdb);
                try {
                    // start the adb server
                    Logger.LogDebug ( typeof ( Program ), "Starting ADB Server" );

                    CommandRunner.Instance.StartServer();
                    Program.SplashManager.SplashDialog.IncrementLoadStep(1);
                } catch(AdbRootException arex) {
                    Logger.LogWarn ( typeof ( Program ), arex.Message );
                }
                // get the attached devices
                Program.SplashManager.SplashDialog.SetStepText(DroidExplorer.Resources.Strings.SplashGetDevices);
                // BUG: 15695
                // fixed this. It was because adb root was disconnecting the device and restarting it.
                // adb root is now called when you connect to a device. Although, it can cause the device to
                // not be found... another bug...
                Logger.LogDebug ( typeof ( Program ), "Getting connected devices" );
                var devices = CommandRunner.Instance.GetDevices().ToList();
                Program.SplashManager.SplashDialog.IncrementLoadStep(1);

                new Thread(() => {
                    // process the devices and send them off to the cloud
                    Logger.LogDebug ( typeof ( Program ), "Registering anonymous statistics for device types" );
                    CloudStatistics.Instance.RegisterModels(devices);
                }).Start();
                // we will increment even though the process is on a new thread.
                Program.SplashManager.SplashDialog.IncrementLoadStep(1);

                // pass in the initial path?
                // TODO: Not yet implemented.
                //var initialPath = "/";
                //if ( args.Contains ( "p", "path" ) && !string.IsNullOrWhiteSpace ( args["p", "path"] ) ) {
                //	initialPath = args["p", "path"];
                //}

                // are we attaching to a specific device?
                if ( args.Contains("d", "device")) {
                    CommandRunner.Instance.DefaultDevice = args["d", "device"];
                    Logger.LogDebug( typeof ( Program ), DroidExplorer.Resources.Strings.SplashConnectingDevice, CommandRunner.Instance.DefaultDevice);
                    Application.Run(new MainForm(  ) );
                } else {
                    // get the attached devices
                    String selectedDevice = null;
                    if(devices.Count() != 1) {
                        // we have 0 or > 1 so we need to display the "selection dialog"
                        var dsf = new GenericDeviceSelectionForm();
                        Program.SplashManager.SplashDialog.HideExt();
                        if(dsf.ShowDialog(null) == DialogResult.OK) {
                            CommandRunner.Instance.DefaultDevice = dsf.SelectedDevice;
                            Logger.LogDebug ( typeof ( Program ), DroidExplorer.Resources.Strings.SplashConnectingDevice, CommandRunner.Instance.DefaultDevice );
                            selectedDevice = dsf.SelectedDevice;
                        } else {
                            Program.SplashManager.CloseSplashDialog();
                            return;
                        }
                        Program.SplashManager.SplashDialog.AsyncShow();
                    } else {
                        selectedDevice = devices[0].SerialNumber;
                        CommandRunner.Instance.DefaultDevice = selectedDevice;
                    }

                    // try to run adb as root:
                    try {
                        Program.SplashManager.SplashDialog.SetStepText(DroidExplorer.Resources.Strings.SplashRunAdbAsRoot);
                        Logger.LogDebug ( typeof ( Program ), DroidExplorer.Resources.Strings.SplashRunAdbAsRoot );
                        CommandRunner.Instance.StartAdbAsRoot(selectedDevice);
                        // sleep a half second to let it start up.
                        Thread.Sleep ( 500 );
                    } catch(AdbRootException are) {

                        Logger.LogDebug ( typeof ( Program ), "Unable to launch ADB as root" );

                        // if we are unable to run as adb root
                        if ( Settings.Instance.WarnWhenNoAdbRoot) {
                            SplashManager.SplashDialog.Invoke((Action)(() => {
                                SplashManager.SplashDialog.Visible = false;
                            }));
                            //NoAdbRootCommands	Continue|Show more information|Exit

                            var result = TaskDialog.ShowCommandBox(
                                DroidExplorer.Resources.Strings.NoAdbRootTitle,
                                are.Message,
                                DroidExplorer.Resources.Strings.NoAdbRootMessage,
                                string.Empty,
                                string.Empty,
                                DroidExplorer.Resources.Strings.NoAdbRootCheckboxText,
                                DroidExplorer.Resources.Strings.NoAdbRootCommands,
                            false, SysIcons.Warning, SysIcons.Warning);
                            switch(TaskDialog.CommandButtonResult) {
                                case 0: // Continue
                                    // continue
                                    if(TaskDialog.VerificationChecked) {
                                        // do not warn again.
                                        Settings.Instance.WarnWhenNoAdbRoot = false;
                                    }
                                    break;
                                case 1: // continue and get more info : http://android.stackexchange.com/a/96066/1951
                                    // android enthusiasts
                                    CommandRunner.Instance.LaunchProcessWindow(DroidExplorer.Resources.Strings.AdbRootQAUrl, string.Empty, true);
                                    if(TaskDialog.VerificationChecked) {
                                        // do not warn again.
                                        Settings.Instance.WarnWhenNoAdbRoot = false;
                                    }
                                    break;
                                case 2: // link to adbd insecure by chainfire on google play
                                    CommandRunner.Instance.LaunchProcessWindow(DroidExplorer.Resources.Strings.AdbdInsecureAppUrl, string.Empty, true);
                                    Application.Exit();
                                    return;
                                default: // 3
                                    Application.Exit();
                                    return;
                            }
                            SplashManager.SplashDialog.Invoke((Action)(() => {
                                SplashManager.SplashDialog.Visible = true;
                            }));
                        }
                    }
                    // increment for adb root
                    Program.SplashManager.SplashDialog.IncrementLoadStep(1);

                    // minor hackory for getting the device for cloud stats
                    var d = new Core.Adb.Device(selectedDevice, Core.Adb.DeviceState.Online);
                    // get the device properties for registration
                    foreach(var i in CommandRunner.Instance.GetProperties(selectedDevice)) {
                        d.Properties.Add(i.Key, i.Value);
                    }
                    if(!Settings.Instance.SystemSettings.RecordDeviceInformationToCloud) {
                        Program.SplashManager.SplashDialog.SetStepText(
                            String.Format(DroidExplorer.Resources.Strings.SplashRegisterDevice,
                                KnownDeviceManager.Instance.GetDeviceFriendlyName(selectedDevice)
                            )
                        );
                        // register the device
                        CloudStatistics.Instance.RegisterDevice(d, devices.Single(x => x.SerialNumber == d.SerialNumber));
                        Program.SplashManager.SplashDialog.IncrementLoadStep(1);
                    } else {
                        // we have to increment but nothing else here
                        Program.SplashManager.SplashDialog.IncrementLoadStep(1);
                    }

                    Logger.LogDebug ( typeof ( Program ), "Launching Main UI" );
                    // connect to device
                    Program.SplashManager.SplashDialog.SetStepText(string.Format(DroidExplorer.Resources.Strings.SplashConnectingDevice, KnownDeviceManager.Instance.GetDeviceFriendlyName(CommandRunner.Instance.DefaultDevice)));

                    Application.Run(new MainForm( ) );
                }
            } catch(Exception ex) {
                var result = TaskDialog.ShowCommandBox(DroidExplorer.Resources.Strings.ErrorUncaughtTitle, ex.Message,
                    DroidExplorer.Resources.Strings.ErrorUncaughtMessage, ex.ToString(),
                    string.Empty, string.Empty, DroidExplorer.Resources.Strings.ErrorUncaughtCommands,
                    false, SysIcons.Error, SysIcons.Error);
                switch(TaskDialog.CommandButtonResult) {
                    case 1:
                        // continue
                        break;
                    case 2:
                        // android enthusiasts
                        CommandRunner.Instance.LaunchProcessWindow(DroidExplorer.Resources.Strings.SupportUrl, string.Empty, true);
                        break;
                    case 3:
                        // report bug
                        CommandRunner.Instance.LaunchProcessWindow(DroidExplorer.Resources.Strings.IssueTrackerCreateUrl, string.Empty, true);
                        break;
                    default: // 0
                        Application.Restart();
                        break;
                }
            }
        }
Exemple #9
0
        static void Main(string[] arguments)
        {
            try {
                using (var stream = typeof(Program).Assembly.GetManifestResourceStream(DroidExplorer.Resources.Strings.Log4NetDroidExplorer)) {
                    XmlConfigurator.Configure(stream);
                }
                var errorMessages = new List <string>();

                var args = new Arguments(arguments);
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
                Application.ThreadException +=
                    (sender, e) => DroidExplorer.Core.Logger.LogError(typeof(Program), e.Exception.Message, e.Exception);

                // show the splash dialog
                Program.SplashManager.ShowSplashDialog(StartUpStepCount);

                // load settings
                Logger.LogDebug(typeof(Program), "Loading Droid Explorer Settings");
                Program.SplashManager.SplashDialog.SetStepText("Loading Settings...");
                CommandRunner.Settings           = Settings.Instance;
                Settings.Instance.SystemSettings = RegistrySettings.Instance;
                Program.SplashManager.SplashDialog.IncrementLoadStep(1);


                // cleanup adb? should this be done?
                Application.ApplicationExit += delegate(object sender, EventArgs e) {
                    //CommandRunner.Instance.AdbProcessCleanUp ( );
                };

                // locate sdk tools
                Logger.LogDebug(typeof(Program), "Locating SDK Path");
                Program.SplashManager.SplashDialog.SetStepText(DroidExplorer.Resources.Strings.SplashLocatingSdk);
                var sdkPath = Settings.Instance.SystemSettings.SdkPath;
                Logger.LogDebug(typeof(Program), "SDK Path Set to {0}", sdkPath);

                if (string.IsNullOrEmpty(sdkPath))
                {
                    throw new ApplicationException("Unable to locate the android SDK tools, please reinstall the application.");
                }
                Program.SplashManager.SplashDialog.IncrementLoadStep(1);

                // verify the sdk tools
                Logger.LogDebug(typeof(Program), "Verifying SDK Tools");
                Program.SplashManager.SplashDialog.SetStepText("Verifying SDK Tools");

                // verify the sdk tools.
                var valid = FolderManagement.VerifyAndroidSdkTools();
                if (!valid)
                {
                    // if not valid - lets ask the user where it is.
                    Program.SplashManager.SplashDialog.HideExt();
                    Logger.LogWarn(typeof(Program), "Unable to verify the SDK tools");

                    var browser = new FolderBrowserDialog();
                    browser.Description         = "Unable to locate SDK tools path. Please select the location where you have the Android SDK installed.";
                    browser.ShowNewFolderButton = false;
                    var dResult = DialogResult.OK;
                    do
                    {
                        dResult = browser.ShowDialog();
                        if (dResult == DialogResult.OK)
                        {
                            Settings.Instance.SystemSettings.SdkPath = browser.SelectedPath;
                            valid = FolderManagement.VerifyAndroidSdkTools();
                        }
                        // keep asking until the user selects a valid location, or they cancel.
                    } while(!valid && dResult == DialogResult.OK);

                    if (!valid)
                    {
                        // they canceled. we are out of here.
                        throw new ApplicationException(DroidExplorer.Resources.Strings.SdkPathNotFoundMessage);
                    }

                    // bring it back.
                    Program.SplashManager.SplashDialog.AsyncShow();
                }


                Program.SplashManager.SplashDialog.IncrementLoadStep(1);

                // set the sdk path
                CommandRunner.Instance.SdkPath = sdkPath;
                Program.SplashManager.SplashDialog.SetStepText(DroidExplorer.Resources.Strings.SplashStartAdb);
                try {
                    // start the adb server
                    Logger.LogDebug(typeof(Program), "Starting ADB Server");

                    CommandRunner.Instance.StartServer();
                    Program.SplashManager.SplashDialog.IncrementLoadStep(1);
                } catch (AdbRootException arex) {
                    Logger.LogWarn(typeof(Program), arex.Message);
                }
                // get the attached devices
                Program.SplashManager.SplashDialog.SetStepText(DroidExplorer.Resources.Strings.SplashGetDevices);
                // BUG: 15695
                // fixed this. It was because adb root was disconnecting the device and restarting it.
                // adb root is now called when you connect to a device. Although, it can cause the device to
                // not be found... another bug...
                Logger.LogDebug(typeof(Program), "Getting connected devices");
                var devices = CommandRunner.Instance.GetDevices().ToList();
                Program.SplashManager.SplashDialog.IncrementLoadStep(1);

                new Thread(() => {
                    // process the devices and send them off to the cloud
                    Logger.LogDebug(typeof(Program), "Registering anonymous statistics for device types");
                    CloudStatistics.Instance.RegisterModels(devices);
                }).Start();
                // we will increment even though the process is on a new thread.
                Program.SplashManager.SplashDialog.IncrementLoadStep(1);

                // pass in the initial path?
                // TODO: Not yet implemented.
                //var initialPath = "/";
                //if ( args.Contains ( "p", "path" ) && !string.IsNullOrWhiteSpace ( args["p", "path"] ) ) {
                //	initialPath = args["p", "path"];
                //}


                // are we attaching to a specific device?
                if (args.Contains("d", "device"))
                {
                    CommandRunner.Instance.DefaultDevice = args["d", "device"];
                    Logger.LogDebug(typeof(Program), DroidExplorer.Resources.Strings.SplashConnectingDevice, CommandRunner.Instance.DefaultDevice);
                    Application.Run(new MainForm(  ));
                }
                else
                {
                    // get the attached devices
                    String selectedDevice = null;
                    if (devices.Count() != 1)
                    {
                        // we have 0 or > 1 so we need to display the "selection dialog"
                        var dsf = new GenericDeviceSelectionForm();
                        Program.SplashManager.SplashDialog.HideExt();
                        if (dsf.ShowDialog(null) == DialogResult.OK)
                        {
                            CommandRunner.Instance.DefaultDevice = dsf.SelectedDevice;
                            Logger.LogDebug(typeof(Program), DroidExplorer.Resources.Strings.SplashConnectingDevice, CommandRunner.Instance.DefaultDevice);
                            selectedDevice = dsf.SelectedDevice;
                        }
                        else
                        {
                            Program.SplashManager.CloseSplashDialog();
                            return;
                        }
                        Program.SplashManager.SplashDialog.AsyncShow();
                    }
                    else
                    {
                        selectedDevice = devices[0].SerialNumber;
                        CommandRunner.Instance.DefaultDevice = selectedDevice;
                    }

                    // try to run adb as root:
                    try {
                        Program.SplashManager.SplashDialog.SetStepText(DroidExplorer.Resources.Strings.SplashRunAdbAsRoot);
                        Logger.LogDebug(typeof(Program), DroidExplorer.Resources.Strings.SplashRunAdbAsRoot);
                        CommandRunner.Instance.StartAdbAsRoot(selectedDevice);
                        // sleep a half second to let it start up.
                        Thread.Sleep(500);
                    } catch (AdbRootException are) {
                        Logger.LogDebug(typeof(Program), "Unable to launch ADB as root");

                        // if we are unable to run as adb root
                        if (Settings.Instance.WarnWhenNoAdbRoot)
                        {
                            SplashManager.SplashDialog.Invoke((Action)(() => {
                                SplashManager.SplashDialog.Visible = false;
                            }));
                            //NoAdbRootCommands	Continue|Show more information|Exit

                            var result = TaskDialog.ShowCommandBox(
                                DroidExplorer.Resources.Strings.NoAdbRootTitle,
                                are.Message,
                                DroidExplorer.Resources.Strings.NoAdbRootMessage,
                                string.Empty,
                                string.Empty,
                                DroidExplorer.Resources.Strings.NoAdbRootCheckboxText,
                                DroidExplorer.Resources.Strings.NoAdbRootCommands,
                                false, SysIcons.Warning, SysIcons.Warning);
                            switch (TaskDialog.CommandButtonResult)
                            {
                            case 0:                                     // Continue
                                                                        // continue
                                if (TaskDialog.VerificationChecked)
                                {
                                    // do not warn again.
                                    Settings.Instance.WarnWhenNoAdbRoot = false;
                                }
                                break;

                            case 1:                                     // continue and get more info : http://android.stackexchange.com/a/96066/1951
                                                                        // android enthusiasts
                                CommandRunner.Instance.LaunchProcessWindow(DroidExplorer.Resources.Strings.AdbRootQAUrl, string.Empty, true);
                                if (TaskDialog.VerificationChecked)
                                {
                                    // do not warn again.
                                    Settings.Instance.WarnWhenNoAdbRoot = false;
                                }
                                break;

                            case 2:                                     // link to adbd insecure by chainfire on google play
                                CommandRunner.Instance.LaunchProcessWindow(DroidExplorer.Resources.Strings.AdbdInsecureAppUrl, string.Empty, true);
                                Application.Exit();
                                return;

                            default:                                     // 3
                                Application.Exit();
                                return;
                            }
                            SplashManager.SplashDialog.Invoke((Action)(() => {
                                SplashManager.SplashDialog.Visible = true;
                            }));
                        }
                    }
                    // increment for adb root
                    Program.SplashManager.SplashDialog.IncrementLoadStep(1);

                    // minor hackory for getting the device for cloud stats
                    var d = new Core.Adb.Device(selectedDevice, Core.Adb.DeviceState.Online);
                    // get the device properties for registration
                    foreach (var i in CommandRunner.Instance.GetProperties(selectedDevice))
                    {
                        d.Properties.Add(i.Key, i.Value);
                    }
                    if (!Settings.Instance.SystemSettings.RecordDeviceInformationToCloud)
                    {
                        Program.SplashManager.SplashDialog.SetStepText(
                            String.Format(DroidExplorer.Resources.Strings.SplashRegisterDevice,
                                          KnownDeviceManager.Instance.GetDeviceFriendlyName(selectedDevice)
                                          )
                            );
                        // register the device
                        CloudStatistics.Instance.RegisterDevice(d, devices.Single(x => x.SerialNumber == d.SerialNumber));
                        Program.SplashManager.SplashDialog.IncrementLoadStep(1);
                    }
                    else
                    {
                        // we have to increment but nothing else here
                        Program.SplashManager.SplashDialog.IncrementLoadStep(1);
                    }

                    Logger.LogDebug(typeof(Program), "Launching Main UI");
                    // connect to device
                    Program.SplashManager.SplashDialog.SetStepText(string.Format(DroidExplorer.Resources.Strings.SplashConnectingDevice, KnownDeviceManager.Instance.GetDeviceFriendlyName(CommandRunner.Instance.DefaultDevice)));

                    Application.Run(new MainForm( ));
                }
            } catch (Exception ex) {
                var result = TaskDialog.ShowCommandBox(DroidExplorer.Resources.Strings.ErrorUncaughtTitle, ex.Message,
                                                       DroidExplorer.Resources.Strings.ErrorUncaughtMessage, ex.ToString(),
                                                       string.Empty, string.Empty, DroidExplorer.Resources.Strings.ErrorUncaughtCommands,
                                                       false, SysIcons.Error, SysIcons.Error);
                switch (TaskDialog.CommandButtonResult)
                {
                case 1:
                    // continue
                    break;

                case 2:
                    // android enthusiasts
                    CommandRunner.Instance.LaunchProcessWindow(DroidExplorer.Resources.Strings.SupportUrl, string.Empty, true);
                    break;

                case 3:
                    // report bug
                    CommandRunner.Instance.LaunchProcessWindow(DroidExplorer.Resources.Strings.IssueTrackerCreateUrl, string.Empty, true);
                    break;

                default:                         // 0
                    Application.Restart();
                    break;
                }
            }
        }
 /// <summary>
 /// Gets the screen shot.
 /// </summary>
 /// <returns></returns>
 private Image GetScreenShot( )
 {
     Device d = new Device ( CommandRunner.Instance.DefaultDevice, DeviceState.Online );
     RawImage ri = AdbHelper.Instance.GetFrameBuffer ( AndroidDebugBridge.SocketAddress, d );
     return GetImageFromRawImage ( ri );
 }