@ -68,42 +68,41 @@ public class I2PDActivity extends Activity {
@@ -68,42 +68,41 @@ public class I2PDActivity extends Activity {
private static final DaemonSingleton daemon = DaemonSingleton . getInstance ( ) ;
private final DaemonSingleton . StateUpdateListener daemonStateUpdatedListener =
new DaemonSingleton . StateUpdateListener ( ) {
private final DaemonSingleton . StateUpdateListener daemonStateUpdatedListener = new DaemonSingleton . StateUpdateListener ( ) {
@Override
public void daemonStateUpdate ( )
{
public void daemonStateUpdate ( ) {
processAssets ( ) ;
runOnUiThread ( ( ) - > {
try {
if ( textView = = null ) return ;
Throwable tr = daemon . getLastThrowable ( ) ;
if ( tr ! = null ) {
textView . setText ( throwableToString ( tr ) ) ;
return ;
}
DaemonSingleton . State state = daemon . getState ( ) ;
String startResultStr = DaemonSingleton . State . startFailed . equals ( state ) ? String . format ( ": %s" , daemon . getDaemonStartResult ( ) ) : "" ;
String graceStr = DaemonSingleton . State . gracefulShutdownInProgress . equals ( state ) ? String . format ( ": %s %s" , formatGraceTimeRemaining ( ) , getText ( R . string . remaining ) ) : "" ;
textView . setText ( String . format ( "%s%s%s" , getText ( state . getStatusStringResourceId ( ) ) , startResultStr , graceStr ) ) ;
} catch ( Throwable tr ) {
Log . e ( TAG , "error ignored" , tr ) ;
}
} ) ;
try {
if ( textView = = null )
return ;
Throwable tr = daemon . getLastThrowable ( ) ;
if ( tr ! = null ) {
textView . setText ( throwableToString ( tr ) ) ;
return ;
}
DaemonSingleton . State state = daemon . getState ( ) ;
String startResultStr = DaemonSingleton . State . startFailed . equals ( state ) ? String . format ( ": %s" , daemon . getDaemonStartResult ( ) ) : "" ;
String graceStr = DaemonSingleton . State . gracefulShutdownInProgress . equals ( state ) ? String . format ( ": %s %s" , formatGraceTimeRemaining ( ) , getText ( R . string . remaining ) ) : "" ;
textView . setText ( String . format ( "%s%s%s" , getText ( state . getStatusStringResourceId ( ) ) , startResultStr , graceStr ) ) ;
} catch ( Throwable tr ) {
Log . e ( TAG , "error ignored" , tr ) ;
}
} ) ;
}
} ;
private static volatile long graceStartedMillis ;
private static final Object graceStartedMillis_LOCK = new Object ( ) ;
private static final Object graceStartedMillis_LOCK = new Object ( ) ;
private Menu optionsMenu ;
private static String formatGraceTimeRemaining ( ) {
long remainingSeconds ;
synchronized ( graceStartedMillis_LOCK ) {
remainingSeconds = Math . round ( Math . max ( 0 , graceStartedMillis + GRACEFUL_DELAY_MILLIS - System . currentTimeMillis ( ) ) / 1000 . 0D ) ;
synchronized ( graceStartedMillis_LOCK ) {
remainingSeconds = Math . round ( Math . max ( 0 , graceStartedMillis + GRACEFUL_DELAY_MILLIS - System . currentTimeMillis ( ) ) / 1000 . 0D ) ;
}
long remainingMinutes = ( long ) Math . floor ( remainingSeconds / 60 . 0D ) ;
long remSec = remainingSeconds - remainingMinutes * 60 ;
return remainingMinutes + ":" + ( remSec / 10 ) + remSec % 10 ;
long remainingMinutes = ( long ) Math . floor ( remainingSeconds / 60 . 0D ) ;
long remSec = remainingSeconds - remainingMinutes * 60 ;
return remainingMinutes + ":" + ( remSec / 10 ) + remSec % 10 ;
}
@Override
@ -117,10 +116,8 @@ public class I2PDActivity extends Activity {
@@ -117,10 +116,8 @@ public class I2PDActivity extends Activity {
daemonStateUpdatedListener . daemonStateUpdate ( ) ;
// request permissions
if ( Build . VERSION . SDK_INT > = 23 )
{
if ( ContextCompat . checkSelfPermission ( this , Manifest . permission . WRITE_EXTERNAL_STORAGE ) ! = PackageManager . PERMISSION_GRANTED )
{
if ( Build . VERSION . SDK_INT > = 23 ) {
if ( ContextCompat . checkSelfPermission ( this , Manifest . permission . WRITE_EXTERNAL_STORAGE ) ! = PackageManager . PERMISSION_GRANTED ) {
ActivityCompat . requestPermissions ( this ,
new String [ ] { Manifest . permission . WRITE_EXTERNAL_STORAGE } ,
MY_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE ) ;
@ -131,7 +128,7 @@ public class I2PDActivity extends Activity {
@@ -131,7 +128,7 @@ public class I2PDActivity extends Activity {
doBindService ( ) ;
final Timer gracefulQuitTimer = getGracefulQuitTimer ( ) ;
if ( gracefulQuitTimer ! = null ) {
if ( gracefulQuitTimer ! = null ) {
long gracefulStopAtMillis ;
synchronized ( graceStartedMillis_LOCK ) {
gracefulStopAtMillis = graceStartedMillis + GRACEFUL_DELAY_MILLIS ;
@ -148,9 +145,9 @@ public class I2PDActivity extends Activity {
@@ -148,9 +145,9 @@ public class I2PDActivity extends Activity {
textView = null ;
daemon . removeStateChangeListener ( daemonStateUpdatedListener ) ;
//cancelGracefulStop0();
try {
try {
doUnbindService ( ) ;
} catch ( Throwable tr ) {
} catch ( Throwable tr ) {
Log . e ( TAG , "" , tr ) ;
}
}
@ -158,20 +155,20 @@ public class I2PDActivity extends Activity {
@@ -158,20 +155,20 @@ public class I2PDActivity extends Activity {
@Override
public void onRequestPermissionsResult ( int requestCode , @NonNull String [ ] permissions , @NonNull int [ ] grantResults )
{
if ( requestCode = = MY_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE ) {
if ( grantResults . length > 0 & & grantResults [ 0 ] = = PackageManager . PERMISSION_GRANTED )
Log . e ( TAG , "WR_EXT_STORAGE perm granted" ) ;
else {
Log . e ( TAG , "WR_EXT_STORAGE perm declined, stopping i2pd" ) ;
i2pdStop ( ) ;
//TODO must work w/o this perm, ask orignal
}
}
if ( requestCode = = MY_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE ) {
if ( grantResults . length > 0 & & grantResults [ 0 ] = = PackageManager . PERMISSION_GRANTED )
Log . e ( TAG , "WR_EXT_STORAGE perm granted" ) ;
else {
Log . e ( TAG , "WR_EXT_STORAGE perm declined, stopping i2pd" ) ;
i2pdStop ( ) ;
//TODO must work w/o this perm, ask orignal
}
}
}
private void cancelGracefulStop0 ( ) {
Timer gracefulQuitTimer = getGracefulQuitTimer ( ) ;
if ( gracefulQuitTimer ! = null ) {
if ( gracefulQuitTimer ! = null ) {
gracefulQuitTimer . cancel ( ) ;
setGracefulQuitTimer ( null ) ;
}
@ -216,7 +213,8 @@ public class I2PDActivity extends Activity {
@@ -216,7 +213,8 @@ public class I2PDActivity extends Activity {
private void doBindService ( ) {
synchronized ( I2PDActivity . class ) {
if ( mIsBound ) return ;
if ( mIsBound )
return ;
// Establish a connection with the service. We use an explicit
// class name because we want a specific service implementation that
// we know will be running in our own process (and thus won't be
@ -256,10 +254,11 @@ public class I2PDActivity extends Activity {
@@ -256,10 +254,11 @@ public class I2PDActivity extends Activity {
// as you specify a parent activity in AndroidManifest.xml.
int id = item . getItemId ( ) ;
switch ( id ) {
switch ( id ) {
case R . id . action_stop :
i2pdStop ( ) ;
return true ;
i2pdStop ( ) ;
return true ;
case R . id . action_graceful_stop :
synchronized ( graceStartedMillis_LOCK ) {
if ( getGracefulQuitTimer ( ) ! = null )
@ -268,9 +267,15 @@ public class I2PDActivity extends Activity {
@@ -268,9 +267,15 @@ public class I2PDActivity extends Activity {
i2pdGracefulStop ( ) ;
}
return true ;
case R . id . action_battery_otimizations :
onActionBatteryOptimizations ( ) ;
return true ;
case R . id . action_reload_tunnels_config :
onReloadTunnelsConfig ( ) ;
return true ;
case R . id . action_start_webview :
setContentView ( R . layout . webview ) ;
this . webView = ( WebView ) findViewById ( R . id . webview1 ) ;
@ -291,100 +296,100 @@ public class I2PDActivity extends Activity {
@@ -291,100 +296,100 @@ public class I2PDActivity extends Activity {
try {
startActivity ( new Intent ( ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS ) ) ;
} catch ( ActivityNotFoundException e ) {
Log . e ( TAG , "BATT_OPTIM_DIALOG_ActvtNotFound" , e ) ;
Log . e ( TAG , "BATT_OPTIM_DIALOG_ActvtNotFound" , e ) ;
Toast . makeText ( this , R . string . os_version_does_not_support_battery_optimizations_show_os_dialog_api , Toast . LENGTH_SHORT ) . show ( ) ;
}
}
}
private void onReloadTunnelsConfig ( ) {
Log . d ( TAG , "reloading tunnels" ) ;
daemon . reloadTunnelsConfigs ( ) ;
Toast . makeText ( this , R . string . tunnels_reloading , Toast . LENGTH_SHORT ) . show ( ) ;
}
private void i2pdStop ( ) {
cancelGracefulStop0 ( ) ;
new Thread ( ( ) - > {
Log . d ( TAG , "stopping" ) ;
try {
daemon . stopDaemon ( ) ;
} catch ( Throwable tr ) {
Log . e ( TAG , "" , tr ) ;
}
quit ( ) ; //TODO make menu items for starting i2pd. On my Android, I need to reboot the OS to restart i2pd.
} , "stop" ) . start ( ) ;
Log . d ( TAG , "stopping" ) ;
try {
daemon . stopDaemon ( ) ;
} catch ( Throwable tr ) {
Log . e ( TAG , "" , tr ) ;
}
quit ( ) ; //TODO make menu items for starting i2pd. On my Android, I need to reboot the OS to restart i2pd.
} , "stop" ) . start ( ) ;
}
private static volatile Timer gracefulQuitTimer ;
private void i2pdGracefulStop ( ) {
if ( daemon . getState ( ) = = DaemonSingleton . State . stopped ) {
Toast . makeText ( this , R . string . already_stopped ,
Toast . LENGTH_SHORT ) . show ( ) ;
if ( daemon . getState ( ) = = DaemonSingleton . State . stopped ) {
Toast . makeText ( this , R . string . already_stopped , Toast . LENGTH_SHORT ) . show ( ) ;
return ;
}
if ( getGracefulQuitTimer ( ) ! = null ) {
Toast . makeText ( this , R . string . graceful_stop_is_already_in_progress ,
Toast . LENGTH_SHORT ) . show ( ) ;
if ( getGracefulQuitTimer ( ) ! = null ) {
Toast . makeText ( this , R . string . graceful_stop_is_already_in_progress , Toast . LENGTH_SHORT ) . show ( ) ;
return ;
}
Toast . makeText ( this , R . string . graceful_stop_is_in_progress ,
Toast . LENGTH_SHORT ) . show ( ) ;
Toast . makeText ( this , R . string . graceful_stop_is_in_progress , Toast . LENGTH_SHORT ) . show ( ) ;
new Thread ( ( ) - > {
try {
Log . d ( TAG , "grac stopping" ) ;
if ( daemon . isStartedOkay ( ) ) {
daemon . stopAcceptingTunnels ( ) ;
long gracefulStopAtMillis ;
synchronized ( graceStartedMillis_LOCK ) {
graceStartedMillis = System . currentTimeMillis ( ) ;
gracefulStopAtMillis = graceStartedMillis + GRACEFUL_DELAY_MILLIS ;
}
rescheduleGraceStop ( null , gracefulStopAtMillis ) ;
} else {
i2pdStop ( ) ;
}
} catch ( Throwable tr ) {
Log . e ( TAG , "" , tr ) ;
}
} , "gracInit" ) . start ( ) ;
try {
Log . d ( TAG , "graceful stopping" ) ;
if ( daemon . isStartedOkay ( ) ) {
daemon . stopAcceptingTunnels ( ) ;
long gracefulStopAtMillis ;
synchronized ( graceStartedMillis_LOCK ) {
graceStartedMillis = System . currentTimeMillis ( ) ;
gracefulStopAtMillis = graceStartedMillis + GRACEFUL_DELAY_MILLIS ;
}
rescheduleGraceStop ( null , gracefulStopAtMillis ) ;
} else
i2pdStop ( ) ;
} catch ( Throwable tr ) {
Log . e ( TAG , "" , tr ) ;
}
} , "gracInit" ) . start ( ) ;
}
private void cancelGracefulStop ( )
{
cancelGracefulStop0 ( ) ;
new Thread ( ( ) - > {
try
{
Log . d ( TAG , "canceling grac stop" ) ;
if ( daemon . isStartedOkay ( ) ) {
try {
Log . d ( TAG , "canceling graceful stop" ) ;
if ( daemon . isStartedOkay ( ) ) {
daemon . startAcceptingTunnels ( ) ;
runOnUiThread ( ( ) - > Toast . makeText ( this , R . string . shutdown_canceled , Toast . LENGTH_SHORT ) . show ( ) ) ;
}
else
i2pdStop ( ) ;
}
catch ( Throwable tr )
{
Log . e ( TAG , "" , tr ) ;
}
} , "gracCancel" ) . start ( ) ;
} else
i2pdStop ( ) ;
} catch ( Throwable tr ) {
Log . e ( TAG , "" , tr ) ;
}
} , "gracCancel" ) . start ( ) ;
}
private void rescheduleGraceStop ( Timer gracefulQuitTimerOld , long gracefulStopAtMillis ) {
if ( gracefulQuitTimerOld ! = null ) gracefulQuitTimerOld . cancel ( ) ;
if ( gracefulQuitTimerOld ! = null )
gracefulQuitTimerOld . cancel ( ) ;
final Timer gracefulQuitTimer = new Timer ( true ) ;
setGracefulQuitTimer ( gracefulQuitTimer ) ;
gracefulQuitTimer . schedule ( new TimerTask ( ) {
gracefulQuitTimer . schedule ( new TimerTask ( ) {
@Override
public void run ( ) {
i2pdStop ( ) ;
}
} , Math . max ( 0 , gracefulStopAtMillis - System . currentTimeMillis ( ) ) ) ;
} , Math . max ( 0 , gracefulStopAtMillis - System . currentTimeMillis ( ) ) ) ;
final TimerTask tickerTask = new TimerTask ( ) {
@Override
public void run ( ) {
daemonStateUpdatedListener . daemonStateUpdate ( ) ;
}
} ;
gracefulQuitTimer . scheduleAtFixedRate ( tickerTask , 0 /*start delay*/ , 1000 /*millis period*/ ) ;
gracefulQuitTimer . scheduleAtFixedRate ( tickerTask , 0 /*start delay*/ , 1000 /*millis period*/ ) ;
}
private static Timer getGracefulQuitTimer ( ) {
@ -454,9 +459,9 @@ public class I2PDActivity extends Activity {
@@ -454,9 +459,9 @@ public class I2PDActivity extends Activity {
* /
private void copyFileAsset ( String path ) {
File file = new File ( i2pdpath , path ) ;
if ( ! file . exists ( ) ) {
if ( ! file . exists ( ) ) {
try {
try ( InputStream in = getAssets ( ) . open ( path ) ) {
try ( InputStream in = getAssets ( ) . open ( path ) ) {
try ( OutputStream out = new FileOutputStream ( file ) ) {
byte [ ] buffer = new byte [ 1024 ] ;
int read = in . read ( buffer ) ;
@ -475,97 +480,102 @@ public class I2PDActivity extends Activity {
@@ -475,97 +480,102 @@ public class I2PDActivity extends Activity {
private void deleteRecursive ( File fileOrDirectory ) {
if ( fileOrDirectory . isDirectory ( ) ) {
File [ ] files = fileOrDirectory . listFiles ( ) ;
if ( files ! = null ) {
if ( files ! = null ) {
for ( File child : files ) {
deleteRecursive ( child ) ;
}
}
}
boolean deleteResult = fileOrDirectory . delete ( ) ;
if ( ! deleteResult ) Log . e ( TAG , "fileOrDirectory.delete() returned " + deleteResult + ", absolute path='" + fileOrDirectory . getAbsolutePath ( ) + "'" ) ;
if ( ! deleteResult )
Log . e ( TAG , "fileOrDirectory.delete() returned " + deleteResult + ", absolute path='" + fileOrDirectory . getAbsolutePath ( ) + "'" ) ;
}
private void processAssets ( ) {
if ( ! assetsCopied ) try {
assetsCopied = true ; // prevent from running on every state update
File holderFile = new File ( i2pdpath , "assets.ready" ) ;
String versionName = BuildConfig . VERSION_NAME ; // here will be app version, like 2.XX.XX
StringBuilder text = new StringBuilder ( ) ;
if ( holderFile . exists ( ) ) {
try { // if holder file exists, read assets version string
FileReader fileReader = new FileReader ( holderFile ) ;
try {
BufferedReader br = new BufferedReader ( fileReader ) ;
try {
String line ;
while ( ( line = br . readLine ( ) ) ! = null ) {
text . append ( line ) ;
}
} finally {
try {
br . close ( ) ;
} catch ( IOException e ) {
Log . e ( TAG , "" , e ) ;
}
}
} finally {
try {
fileReader . close ( ) ;
} catch ( IOException e ) {
Log . e ( TAG , "" , e ) ;
}
}
} catch ( IOException e ) {
Log . e ( TAG , "" , e ) ;
}
}
// if version differs from current app version or null, try to delete certificates folder
if ( ! text . toString ( ) . contains ( versionName ) ) try {
boolean deleteResult = holderFile . delete ( ) ;
if ( ! deleteResult ) Log . e ( TAG , "holderFile.delete() returned " + deleteResult + ", absolute path='" + holderFile . getAbsolutePath ( ) + "'" ) ;
File certPath = new File ( i2pdpath , "certificates" ) ;
deleteRecursive ( certPath ) ;
}
catch ( Throwable tr ) {
Log . e ( TAG , "" , tr ) ;
}
if ( ! assetsCopied ) {
try {
assetsCopied = true ; // prevent from running on every state update
File holderFile = new File ( i2pdpath , "assets.ready" ) ;
String versionName = BuildConfig . VERSION_NAME ; // here will be app version, like 2.XX.XX
StringBuilder text = new StringBuilder ( ) ;
if ( holderFile . exists ( ) ) {
try { // if holder file exists, read assets version string
FileReader fileReader = new FileReader ( holderFile ) ;
try {
BufferedReader br = new BufferedReader ( fileReader ) ;
try {
String line ;
while ( ( line = br . readLine ( ) ) ! = null ) {
text . append ( line ) ;
}
} finally {
try {
br . close ( ) ;
} catch ( IOException e ) {
Log . e ( TAG , "" , e ) ;
}
}
} finally {
try {
fileReader . close ( ) ;
} catch ( IOException e ) {
Log . e ( TAG , "" , e ) ;
}
}
} catch ( IOException e ) {
Log . e ( TAG , "" , e ) ;
}
}
// copy assets. If processed file exists, it won't be overwritten
copyAsset ( "addressbook" ) ;
copyAsset ( "certificates" ) ;
copyAsset ( "tunnels.d" ) ;
copyAsset ( "i2pd.conf" ) ;
copyAsset ( "subscriptions.txt" ) ;
copyAsset ( "tunnels.conf" ) ;
// if version differs from current app version or null, try to delete certificates folder
if ( ! text . toString ( ) . contains ( versionName ) )
try {
boolean deleteResult = holderFile . delete ( ) ;
if ( ! deleteResult )
Log . e ( TAG , "holderFile.delete() returned " + deleteResult + ", absolute path='" + holderFile . getAbsolutePath ( ) + "'" ) ;
File certPath = new File ( i2pdpath , "certificates" ) ;
deleteRecursive ( certPath ) ;
}
catch ( Throwable tr ) {
Log . e ( TAG , "" , tr ) ;
}
// update holder file about successful copying
FileWriter writer = new FileWriter ( holderFile ) ;
try {
writer . append ( versionName ) ;
} finally {
try {
writer . close ( ) ;
} catch ( IOException e ) {
Log . e ( TAG , "on writer close" , e ) ;
}
}
}
catch ( Throwable tr )
{
Log . e ( TAG , "on assets copying" , tr ) ;
// copy assets. If processed file exists, it won't be overwritten
copyAsset ( "addressbook" ) ;
copyAsset ( "certificates" ) ;
copyAsset ( "tunnels.d" ) ;
copyAsset ( "i2pd.conf" ) ;
copyAsset ( "subscriptions.txt" ) ;
copyAsset ( "tunnels.conf" ) ;
// update holder file about successful copying
FileWriter writer = new FileWriter ( holderFile ) ;
try {
writer . append ( versionName ) ;
} finally {
try {
writer . close ( ) ;
} catch ( IOException e ) {
Log . e ( TAG , "on writer close" , e ) ;
}
}
}
catch ( Throwable tr )
{
Log . e ( TAG , "on assets copying" , tr ) ;
}
}
}
@SuppressLint ( "BatteryLife" )
private void openBatteryOptimizationDialogIfNeeded ( ) {
boolean questionEnabled = getPreferences ( ) . getBoolean ( getBatteryOptimizationPreferenceKey ( ) , true ) ;
Log . i ( TAG , "BATT_OPTIM_questionEnabled==" + questionEnabled ) ;
Log . i ( TAG , "BATT_OPTIM_questionEnabled==" + questionEnabled ) ;
if ( ! isKnownIgnoringBatteryOptimizations ( )
& & android . os . Build . VERSION . SDK_INT > = android . os . Build . VERSION_CODES . M
& & questionEnabled ) {
@ -576,7 +586,7 @@ public class I2PDActivity extends Activity {
@@ -576,7 +586,7 @@ public class I2PDActivity extends Activity {
try {
startActivity ( new Intent ( Settings . ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS , Uri . parse ( PACKAGE_URI_SCHEME + getPackageName ( ) ) ) ) ;
} catch ( ActivityNotFoundException e ) {
Log . e ( TAG , "BATT_OPTIM_ActvtNotFound" , e ) ;
Log . e ( TAG , "BATT_OPTIM_ActvtNotFound" , e ) ;
Toast . makeText ( this , R . string . device_does_not_support_disabling_battery_optimizations , Toast . LENGTH_SHORT ) . show ( ) ;
}
} ) ;
@ -595,14 +605,14 @@ public class I2PDActivity extends Activity {
@@ -595,14 +605,14 @@ public class I2PDActivity extends Activity {
if ( Build . VERSION . SDK_INT > = Build . VERSION_CODES . M ) {
final PowerManager pm = ( PowerManager ) getSystemService ( POWER_SERVICE ) ;
if ( pm = = null ) {
Log . i ( TAG , "BATT_OPTIM: POWER_SERVICE==null" ) ;
return false ;
}
boolean ignoring = pm . isIgnoringBatteryOptimizations ( getPackageName ( ) ) ;
Log . i ( TAG , "BATT_OPTIM: ignoring==" + ignoring ) ;
return ignoring ;
Log . i ( TAG , "BATT_OPTIM: POWER_SERVICE==null" ) ;
return false ;
}
boolean ignoring = pm . isIgnoringBatteryOptimizations ( getPackageName ( ) ) ;
Log . i ( TAG , "BATT_OPTIM: ignoring==" + ignoring ) ;
return ignoring ;
} else {
Log . i ( TAG , "BATT_OPTIM: old sdk version==" + Build . VERSION . SDK_INT ) ;
Log . i ( TAG , "BATT_OPTIM: old sdk version==" + Build . VERSION . SDK_INT ) ;
return false ;
}
}
@ -626,12 +636,12 @@ public class I2PDActivity extends Activity {
@@ -626,12 +636,12 @@ public class I2PDActivity extends Activity {
//moveTaskToBack(true);
finish ( ) ;
}
} catch ( Throwable tr ) {
} catch ( Throwable tr ) {
Log . e ( TAG , "" , tr ) ;
}
try {
try {
daemon . stopDaemon ( ) ;
} catch ( Throwable tr ) {
} catch ( Throwable tr ) {
Log . e ( TAG , "" , tr ) ;
}
System . exit ( 0 ) ;