PageRenderTime 72ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/src/br/com/bott/droidsshd/DroidSSHd.java

https://gitlab.com/Geofferey/droidsshd-test
Java | 456 lines | 299 code | 52 blank | 105 comment | 27 complexity | 66bcf6c0f66bbfbbc6e858ba39f7fd9a MD5 | raw file
  1. /**
  2. * This file is part of DroidSSHd.
  3. * http://code.google.com/p/droidsshd
  4. *
  5. * DroidSSHd is open source software: you can redistribute it and/or modify
  6. * it under the terms of the Apache License 2.0
  7. *
  8. * DroidSSHd is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. * @author Augusto Bott (mestre) <augusto@bott.com.br>
  12. */
  13. package br.com.bott.droidsshd;
  14. import br.com.bott.droidsshd.system.*;
  15. import br.com.bott.droidsshd.tools.*;
  16. import java.util.Iterator;
  17. import android.util.Log;
  18. import android.app.Activity;
  19. import android.app.AlertDialog;
  20. import android.content.ComponentName;
  21. import android.content.Context;
  22. import android.content.DialogInterface;
  23. import android.content.Intent;
  24. import android.content.ServiceConnection;
  25. import android.os.Bundle;
  26. import android.os.Handler;
  27. import android.os.IBinder;
  28. //import android.os.Message;
  29. import android.view.Menu;
  30. import android.view.MenuInflater;
  31. import android.view.MenuItem;
  32. import android.view.View;
  33. import android.view.View.OnClickListener;
  34. import android.widget.Button;
  35. import android.widget.CheckBox;
  36. import android.widget.EditText;
  37. //import android.widget.ScrollView;
  38. public class DroidSSHd extends Activity {
  39. private static final String TAG = "DroidSSHd";
  40. // http://developer.android.com/reference/java/lang/Thread.html#setDaemon%28boolean%29
  41. // http://stackoverflow.com/questions/3011604/how-do-i-get-preferences-to-work-in-android
  42. // http://stackoverflow.com/questions/2535132/how-do-you-validate-the-format-and-values-of-edittextpreference-entered-in-androi
  43. private Button btnStartStop;
  44. private EditText status_content;
  45. private EditText status_ip_address;
  46. private EditText status_username;
  47. private EditText status_tcp_port;
  48. private CheckBox status_daemon_running_as_root;
  49. private Button preferences_button;
  50. private ReplicantThread mMonitorDaemon;
  51. private Intent mDropbearDaemonHandlerService;
  52. private DroidSSHdService mBoundDaemonHandlerService;
  53. private boolean mDaemonHandlerIsBound;
  54. private long mUpdateUIdelay = 500L;
  55. @Override
  56. public void onCreate(Bundle savedInstanceState) {
  57. super.onCreate(savedInstanceState);
  58. Base.initialize(getBaseContext());
  59. Base.setDropbearDaemonStatus(Base.DAEMON_STATUS_UNKNOWN);
  60. setContentView(R.layout.act_main);
  61. setUpUiListeners();
  62. /*if ((!Util.validateHostKeys() || (!Util.checkPathToBinaries()))) {
  63. startInitialSetupActivity();
  64. }*/
  65. Base.setDropbearDaemonStatus(Base.DAEMON_STATUS_STOPPED);
  66. Base.setManualServiceStart(true);
  67. mDropbearDaemonHandlerService = new Intent(this, br.com.bott.droidsshd.system.DroidSSHdService.class);
  68. mHandler.postDelayed(mUpdateUI, 150);
  69. }
  70. @Override
  71. protected void onStart() {
  72. super.onStart();
  73. doBindDaemonHandlerService(mDropbearDaemonHandlerService);
  74. }
  75. @Override
  76. protected void onResume() {
  77. super.onResume();
  78. Base.refresh();
  79. mHandler.postDelayed(mUpdateUI, mUpdateUIdelay);
  80. // updateStatus();
  81. if(Base.debug) {
  82. Log.d(TAG, "onResume() called");
  83. }
  84. }
  85. @Override
  86. protected void onDestroy() {
  87. doUnbindDaemonHandlerService(mDropbearDaemonHandlerService);
  88. super.onDestroy();
  89. }
  90. @Override
  91. protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  92. super.onActivityResult(requestCode, resultCode, data);
  93. if (Base.debug) {
  94. if (data!=null) {
  95. Log.v(TAG, "onActivityResult(" + requestCode + ", " + resultCode + ", " + data.toString() + ") called");
  96. } else {
  97. Log.v(TAG, "onActivityResult(" + requestCode + ", " + resultCode + ", null) called");
  98. }
  99. }
  100. /*if(resultCode==RESULT_CANCELED && requestCode==R.string.activity_initial_setup){
  101. Util.showMsg("DroidSSHd setup canceled");
  102. this.finish();
  103. }*/
  104. /* if (requestCode==R.string.activity_file_chooser) {
  105. if(Base.debug) {
  106. Log.v(TAG, "FileChooser is done");
  107. }
  108. if(resultCode==RESULT_OK){
  109. if(Base.debug){
  110. Log.v(TAG,"path = " + data.getStringExtra("path"));
  111. }
  112. }
  113. }*/
  114. }
  115. /*protected void startInitialSetupActivity() {
  116. Util.showMsg("Initial/basic setup required");
  117. Intent setup = new Intent(this, br.com.bott.droidsshd.activity.InitialSetup.class);
  118. setup.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
  119. // setup.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
  120. startActivityForResult(setup, R.string.activity_initial_setup);
  121. }*/
  122. protected void setUpUiListeners() {
  123. status_content = (EditText) findViewById(R.id.status_content);
  124. status_ip_address = (EditText) findViewById(R.id.status_ip_address);
  125. status_username = (EditText) findViewById(R.id.status_username);
  126. status_tcp_port = (EditText) findViewById(R.id.status_tcp_port);
  127. status_daemon_running_as_root = (CheckBox) findViewById(R.id.status_daemon_running_as_root);
  128. btnStartStop = (Button) findViewById(R.id.status_button);
  129. btnStartStop.setOnClickListener(new OnClickListener() {
  130. public void onClick(View v) {
  131. btnStartStop.setEnabled(false);
  132. btnStartStop.setFocusable(false);
  133. btnStartStop.setText("Working");
  134. if (Util.isDropbearDaemonRunning()) {
  135. if(Base.debug) {
  136. Log.v(TAG, "btnStartStop pressed: stopping");
  137. }
  138. stopDropbear();
  139. mHandler.postDelayed(mUpdateUI, 2000);
  140. } else {
  141. if(Base.debug) {
  142. Log.v(TAG, "btnStartStop pressed: starting");
  143. }
  144. startDropbear();
  145. mHandler.postDelayed(mUpdateUI, 1000);
  146. }
  147. // setResult(android.app.Activity.RESULT_OK);
  148. }
  149. });
  150. // mStdOut = (EditText) findViewById(R.id.stdout);
  151. // mLogView = (ScrollView) findViewById(R.id.stdout_scrollview);
  152. /* filechooser_button = (Button) findViewById(R.id.filechooser_button);
  153. filechooser_button.setOnClickListener(new OnClickListener() {
  154. @Override
  155. public void onClick(View v) {
  156. Intent p = new Intent(v.getContext(), com.h3r3t1c.filechooser.FileChooser.class);
  157. startActivityForResult(p, R.string.activity_file_chooser);
  158. }
  159. });*/
  160. preferences_button = (Button) findViewById(R.id.preferences_button);
  161. preferences_button.setOnClickListener(new OnClickListener() {
  162. public void onClick(View v) {
  163. Intent p = new Intent(v.getContext(), br.com.bott.droidsshd.activity.Preferences.class);
  164. startActivity(p);
  165. }
  166. });
  167. }
  168. public void updateStatus() {
  169. String tmp = "";
  170. Iterator<String> ipAddr = Util.getLocalIpAddress();
  171. try {
  172. while(ipAddr.hasNext()) {
  173. tmp = tmp + ipAddr.next() + " ";
  174. if (ipAddr.hasNext()) {
  175. tmp = tmp + ", ";
  176. }
  177. }
  178. } catch (Exception e) {
  179. Log.w(TAG, "updateStatus() exception in IpAddress Iterator");
  180. }
  181. status_ip_address.setText(tmp);
  182. status_username.setText(Base.getUsername());
  183. status_tcp_port.setText(String.valueOf(Base.getDaemonPort()));
  184. status_daemon_running_as_root.setChecked(Base.runDaemonAsRoot());
  185. if (Util.isDropbearDaemonRunning()) {
  186. Base.setDropbearDaemonStatus(Base.DAEMON_STATUS_STARTED);
  187. }
  188. switch (Base.getDropbearDaemonStatus()) {
  189. case Base.DAEMON_STATUS_STOPPING:
  190. btnStartStop.setEnabled(false);
  191. btnStartStop.setFocusable(false);
  192. btnStartStop.setText("Stopping");
  193. status_content.setText("Working");
  194. break;
  195. case Base.DAEMON_STATUS_STARTING:
  196. btnStartStop.setEnabled(false);
  197. btnStartStop.setFocusable(false);
  198. btnStartStop.setText("Starting");
  199. status_content.setText("Working");
  200. break;
  201. case Base.DAEMON_STATUS_STARTED:
  202. btnStartStop.setEnabled(true);
  203. btnStartStop.setFocusable(true);
  204. btnStartStop.setText("Stop");
  205. status_content.setText("Running");
  206. break;
  207. case Base.DAEMON_STATUS_STOPPED:
  208. btnStartStop.setEnabled(true);
  209. btnStartStop.setFocusable(true);
  210. btnStartStop.setText("Start");
  211. status_content.setText("Stopped");
  212. break;
  213. case Base.DAEMON_STATUS_UNKNOWN:
  214. btnStartStop.setEnabled(true);
  215. btnStartStop.setFocusable(true);
  216. btnStartStop.setText("Start");
  217. status_content.setText("Unknown");
  218. break;
  219. default:
  220. break;
  221. }
  222. }
  223. public void startDropbear() {
  224. doBindDaemonHandlerService(mDropbearDaemonHandlerService);
  225. /*if (!Util.checkPathToBinaries()) {
  226. if(Base.debug) {
  227. Log.v(TAG, "startDropbear bailing out: status was " + Base.getDropbearDaemonStatus() + ", changed to STOPPED(" + ")" );
  228. }
  229. Base.setDropbearDaemonStatus(Base.DAEMON_STATUS_STOPPED);
  230. mHandler.postDelayed(mUpdateUI, mUpdateUIdelay);
  231. Util.showMsg("Can't find dropbear binaries");
  232. return;
  233. }*/
  234. /*if (!Util.validateHostKeys()) {
  235. if(Base.debug) {
  236. Log.v(TAG, "Host keys not found");
  237. }
  238. Base.setDropbearDaemonStatus(Base.DAEMON_STATUS_STOPPED);
  239. mHandler.postDelayed(mUpdateUI, mUpdateUIdelay);
  240. Util.showMsg("Host keys not found");
  241. return;
  242. }*/
  243. if(Base.getDropbearDaemonStatus() <= Base.DAEMON_STATUS_STOPPED) {
  244. Base.setDropbearDaemonStatus(Base.DAEMON_STATUS_STARTING);
  245. if (Base.debug) {
  246. Log.d(TAG, "Status was STOPPED, now it's STARTING");
  247. }
  248. String cmd = "dropbear";
  249. Util.doRun(cmd, true, null);
  250. // Util.doRun("dropbear", true, null);
  251. // startService(mDropbearDaemonHandlerService);
  252. startLongRunningOperation();
  253. return;
  254. }
  255. }
  256. public void stopDropbear() {
  257. if (Base.debug) {
  258. Log.v(TAG, "stopDropbear() called. Current status = " + Base.getDropbearDaemonStatus() );
  259. }
  260. if ((Base.getDropbearDaemonStatus()==Base.DAEMON_STATUS_STARTED) ||
  261. Base.getDropbearDaemonStatus()==Base.DAEMON_STATUS_STARTING) {
  262. Base.setDropbearDaemonStatus(Base.DAEMON_STATUS_STOPPING);
  263. // int pid = Util.getDropbearPidFromPidFile(Base.getDropbearPidFilePath());
  264. if(Base.debug) {
  265. Log.d(TAG, "stopDropbear() killing dropbear");
  266. Log.d(TAG, "dropbearDaemonStatus = Base.DAEMON_STATUS_STOPPING");
  267. }
  268. String cmd = "killall dropbear ";
  269. // Util.doRun(cmd, Base.runDaemonAsRoot(), mLogviewHandler);
  270. Util.doRun(cmd, true, null);
  271. Util.doRun("killall dropbear", true, null);
  272. stopService(mDropbearDaemonHandlerService);
  273. startLongRunningOperation();
  274. return;
  275. };
  276. Util.releaseWakeLock();
  277. Util.releaseWifiLock();
  278. }
  279. @Override
  280. public boolean onCreateOptionsMenu(Menu menu) {
  281. MenuInflater inflater = getMenuInflater();
  282. inflater.inflate(R.menu.main_menu, menu);
  283. return true;
  284. // return super.onCreateOptionsMenu(menu);
  285. }
  286. @Override
  287. public boolean onOptionsItemSelected(MenuItem item) {
  288. switch(item.getItemId()) {
  289. case R.id.menu_settings:
  290. Intent p = new Intent(this, br.com.bott.droidsshd.activity.Preferences.class);
  291. startActivity(p);
  292. return true;
  293. case R.id.menu_quit:
  294. Util.showMsg("QUIT");
  295. this.finish();
  296. return true;
  297. case R.id.menu_refreshui:
  298. if(Base.getDropbearDaemonStatus()==Base.DAEMON_STATUS_STARTING) {
  299. Base.setDropbearDaemonStatus(Base.DAEMON_STATUS_STARTED);
  300. }
  301. if(Base.getDropbearDaemonStatus()==Base.DAEMON_STATUS_STOPPING) {
  302. Base.setDropbearDaemonStatus(Base.DAEMON_STATUS_STOPPED);
  303. }
  304. updateStatus();
  305. return true;
  306. case R.id.menu_about:
  307. // Intent i = new Intent();
  308. // i.setAction("android.intent.action.VIEW");
  309. // i.setData("http://www.android.com");
  310. // i.setType(type)
  311. // Util.showMsg("About");
  312. AlertDialog.Builder builder = new AlertDialog.Builder(this);
  313. builder.setTitle("About")
  314. .setMessage(R.string.about_message)
  315. .setCancelable(true)
  316. .setPositiveButton("OK", new DialogInterface.OnClickListener() {
  317. public void onClick(DialogInterface dialog, int id) {
  318. dialog.cancel();
  319. }
  320. });
  321. AlertDialog about = builder.create();
  322. about.show();
  323. return true;
  324. default:
  325. return super.onOptionsItemSelected(item);
  326. }
  327. }
  328. final Handler mHandler = new Handler();
  329. final Runnable mUpdateUI = new Runnable() {
  330. public void run() {
  331. updateStatus();
  332. }
  333. };
  334. // TODO - http://developer.android.com/resources/articles/painless-threading.html
  335. protected void startLongRunningOperation() {
  336. synchronized(this) {
  337. if (Base.debug) {
  338. Log.d(TAG, "startLongRunningOperation called");
  339. }
  340. // TODO - http://developer.android.com/resources/articles/timed-ui-updates.html
  341. // Runnable mUpdateTimeTask = new Runnable() {
  342. // public void run() {
  343. // final long start = mStartTime;
  344. // long millis = SystemClock.uptimeMillis() - start;
  345. // mHandler.postAtTime(this, start + (((minutes * 60) + seconds + 1) * 1000));
  346. // }
  347. // mHandler.removeCallbacks(mUpdateTimeTask);
  348. if(mMonitorDaemon!=null) {
  349. if(mMonitorDaemon.isAlive()) {
  350. mMonitorDaemon.extendLifetimeForAnother(System.currentTimeMillis()+2000);
  351. }
  352. } else {
  353. ReplicantThread mMonitorDaemon = new ReplicantThread(TAG, (System.currentTimeMillis()+2000), 600, mHandler, mUpdateUI, Base.debug);
  354. mMonitorDaemon.start();
  355. }
  356. }
  357. }
  358. /*
  359. final protected Handler mLogviewHandler = new Handler() {
  360. @Override
  361. public void handleMessage(Message msg){
  362. // mStdOut.append(msg.getData().getString("line"));
  363. // mLogView.postDelayed(new Runnable() {
  364. // public void run() {
  365. // mLogView.fullScroll(ScrollView.FOCUS_DOWN);
  366. // }
  367. // }, 200);
  368. }
  369. };
  370. */
  371. // DAEMON HANDLER
  372. private ServiceConnection mDaemonHandlerConnection = new ServiceConnection() {
  373. @Override
  374. public void onServiceConnected(ComponentName className, IBinder service) {
  375. mBoundDaemonHandlerService = ((br.com.bott.droidsshd.system.DroidSSHdService.DropbearDaemonHandlerBinder)service).getService();
  376. if(Base.debug) {
  377. Log.d(TAG, "onServiceConnected DroidSSHdService called");
  378. if (mBoundDaemonHandlerService==null){
  379. Log.d(TAG, "Failed to bind to DroidSSHdService (mBoundDaemonHandlerService is NULL)");
  380. } else {
  381. Log.d(TAG, "mBoundDaemonHandlerService = " + mBoundDaemonHandlerService.toString());
  382. }
  383. }
  384. }
  385. @Override
  386. public void onServiceDisconnected(ComponentName className) {
  387. mBoundDaemonHandlerService = null;
  388. if(Base.debug) {
  389. Log.d(TAG, "onServiceDisconnected called (mBoundDaemonHandlerService set to NULL)");
  390. }
  391. }
  392. };
  393. private void doBindDaemonHandlerService(Intent intent) {
  394. Base.setManualServiceStart(true);
  395. mDaemonHandlerIsBound = bindService(intent, mDaemonHandlerConnection, Context.BIND_AUTO_CREATE);
  396. }
  397. private void doUnbindDaemonHandlerService(Intent intent) {
  398. if (mDaemonHandlerIsBound) {
  399. unbindService(mDaemonHandlerConnection);
  400. mDaemonHandlerIsBound = false;
  401. }
  402. }
  403. }