package com.marswin89.marsdaemon.strategy; import java.io.File; import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import android.annotation.SuppressLint; import android.app.Activity; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.os.IBinder; import android.os.Parcel; import android.os.RemoteException; import android.util.Log; import com.marswin89.marsdaemon.DaemonConfigurations; import com.marswin89.marsdaemon.IDaemonStrategy; import com.marswin89.marsdaemon.nativ.NativeDaemonAPI21; /** * the strategy in android API 23. * * @author Mars * */ public class DaemonStrategy23 implements IDaemonStrategy{ private final static String INDICATOR_DIR_NAME = "indicators"; private final static String INDICATOR_PERSISTENT_FILENAME = "indicator_p"; private final static String INDICATOR_DAEMON_ASSISTANT_FILENAME = "indicator_d"; private final static String OBSERVER_PERSISTENT_FILENAME = "observer_p"; private final static String OBSERVER_DAEMON_ASSISTANT_FILENAME = "observer_d"; private IBinder mRemote; private Parcel mBroadcastData; private DaemonConfigurations mConfigs; @Override public boolean onInitialization(Context context) { return initIndicatorFiles(context); } @Override public void onPersistentCreate(final Context context, DaemonConfigurations configs) { initAmsBinder(); initBroadcastParcel(context, configs.DAEMON_ASSISTANT_CONFIG.RECEIVER_NAME); sendBroadcastByAmsBinder(); Thread t = new Thread(){ public void run() { File indicatorDir = context.getDir(INDICATOR_DIR_NAME, Context.MODE_PRIVATE); new NativeDaemonAPI21(context).doDaemon( new File(indicatorDir, INDICATOR_PERSISTENT_FILENAME).getAbsolutePath(), new File(indicatorDir, INDICATOR_DAEMON_ASSISTANT_FILENAME).getAbsolutePath(), new File(indicatorDir, OBSERVER_PERSISTENT_FILENAME).getAbsolutePath(), new File(indicatorDir, OBSERVER_DAEMON_ASSISTANT_FILENAME).getAbsolutePath()); }; }; t.start(); ComponentName componentName = new ComponentName(context.getPackageName(), configs.PERSISTENT_CONFIG.SERVICE_NAME); Intent intent = new Intent(); intent.setComponent(componentName); context.startService(intent); if(configs != null && configs.LISTENER != null){ this.mConfigs = configs; configs.LISTENER.onPersistentStart(context); } } @Override public void onDaemonAssistantCreate(final Context context, DaemonConfigurations configs) { initAmsBinder(); initBroadcastParcel(context, configs.PERSISTENT_CONFIG.RECEIVER_NAME); sendBroadcastByAmsBinder(); Thread t = new Thread(){ public void run() { File indicatorDir = context.getDir(INDICATOR_DIR_NAME, Context.MODE_PRIVATE); new NativeDaemonAPI21(context).doDaemon( new File(indicatorDir, INDICATOR_DAEMON_ASSISTANT_FILENAME).getAbsolutePath(), new File(indicatorDir, INDICATOR_PERSISTENT_FILENAME).getAbsolutePath(), new File(indicatorDir, OBSERVER_DAEMON_ASSISTANT_FILENAME).getAbsolutePath(), new File(indicatorDir, OBSERVER_PERSISTENT_FILENAME).getAbsolutePath()); }; }; t.start(); ComponentName componentName = new ComponentName(context.getPackageName(), configs.DAEMON_ASSISTANT_CONFIG.SERVICE_NAME); Intent intent = new Intent(); intent.setComponent(componentName); context.startService(intent); if(configs != null && configs.LISTENER != null){ this.mConfigs = configs; configs.LISTENER.onDaemonAssistantStart(context); } } @Override public void onDaemonDead() { if(sendBroadcastByAmsBinder()){ if(mConfigs != null && mConfigs.LISTENER != null){ mConfigs.LISTENER.onWatchDaemonDaed(); } android.os.Process.killProcess(android.os.Process.myPid()); } } private void initAmsBinder(){ Class<?> activityManagerNative; try { activityManagerNative = Class.forName("android.app.ActivityManagerNative"); Object amn = activityManagerNative.getMethod("getDefault").invoke(activityManagerNative); Field mRemoteField = amn.getClass().getDeclaredField("mRemote"); mRemoteField.setAccessible(true); mRemote = (IBinder) mRemoteField.get(amn); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (NoSuchFieldException e) { e.printStackTrace(); } } @SuppressLint("Recycle")// when process dead, we should save time to restart and kill self, don`t take a waste of time to recycle private void initBroadcastParcel(Context context, String broadcastName){ Intent intent = new Intent(); ComponentName componentName = new ComponentName(context.getPackageName(), broadcastName); intent.setComponent(componentName); intent.setFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); /* // Object contextImpl = ((Application)context.getApplicationContext()).getBaseContext(); //this context is ContextImpl, get MainThread instance immediately Field mainThreadField = context.getClass().getDeclaredField("mMainThread"); mainThreadField.setAccessible(true); Object mainThread = mainThreadField.get(context); //get ApplicationThread instance Object applicationThread = mainThread.getClass().getMethod("getApplicationThread").invoke(mainThread); //get Binder Binder callerBinder = (Binder) (applicationThread.getClass().getMethod("asBinder").invoke(applicationThread)); */ // UserHandle userHandle = android.os.Process.myUserHandle(); // int handle = (Integer) userHandle.getClass().getMethod("getIdentifier").invoke(userHandle); mBroadcastData = Parcel.obtain(); mBroadcastData.writeInterfaceToken("android.app.IActivityManager"); // mBroadcastData.writeStrongBinder(callerBinder); mBroadcastData.writeStrongBinder(null); intent.writeToParcel(mBroadcastData, 0); mBroadcastData.writeString(intent.resolveTypeIfNeeded(context.getContentResolver())); mBroadcastData.writeStrongBinder(null); mBroadcastData.writeInt(Activity.RESULT_OK); mBroadcastData.writeString(null); mBroadcastData.writeBundle(null); mBroadcastData.writeString(null); mBroadcastData.writeInt(-1); mBroadcastData.writeInt(0); mBroadcastData.writeInt(0); // mBroadcastData.writeInt(handle); mBroadcastData.writeInt(0); } private boolean sendBroadcastByAmsBinder(){ try { if(mRemote == null || mBroadcastData == null){ Log.e("Daemon", "REMOTE IS NULL or PARCEL IS NULL !!!"); return false; } mRemote.transact(14, mBroadcastData, null, 0);//BROADCAST_INTENT_TRANSACTION = 0x00000001 + 13 return true; } catch (RemoteException e) { e.printStackTrace(); return false; } } private boolean initIndicatorFiles(Context context){ File dirFile = context.getDir(INDICATOR_DIR_NAME, Context.MODE_PRIVATE); if(!dirFile.exists()){ dirFile.mkdirs(); } try { createNewFile(dirFile, INDICATOR_PERSISTENT_FILENAME); createNewFile(dirFile, INDICATOR_DAEMON_ASSISTANT_FILENAME); return true; } catch (IOException e) { e.printStackTrace(); return false; } } private void createNewFile(File dirFile, String fileName) throws IOException{ File file = new File(dirFile, fileName); if(!file.exists()){ file.createNewFile(); } } }