package android.taobao.atlas.runtime.newcomponent.service; import android.app.IServiceConnection; import android.app.Service; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ServiceInfo; import android.os.Binder; import android.os.Build; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.RemoteException; import android.taobao.atlas.hack.AndroidHack; import android.taobao.atlas.hack.AtlasHacks; import android.taobao.atlas.hack.Hack; import android.taobao.atlas.runtime.ContextImplHook; import android.taobao.atlas.runtime.RuntimeVariables; import android.taobao.atlas.runtime.newcomponent.activity.ActivityBridge; import android.taobao.atlas.runtime.newcomponent.receiver.ReceiverBridge; import android.util.Log; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.Map; /** * Created by guanjie on 2017/4/2. */ public class BaseDelegateService extends Service{ private ServiceDispatcherImpl dispatcher = new ServiceDispatcherImpl(); @Override public void onCreate() { super.onCreate(); } @Override public IBinder onBind(Intent intent) { return dispatcher; } public static class ServiceDispatcherImpl extends IDelegateBinder.Stub{ private Handler mMainHandler; private HashMap<AdditionalServiceRecord,Service> mActivateServices = new HashMap<>(); public ServiceDispatcherImpl(){ mMainHandler = new Handler(Looper.getMainLooper()); } @Override public IBinder startService(final Intent serviceIntent, ServiceInfo info) throws RemoteException { Log.e("BaseDelegateService","startService"); mMainHandler.post(new Runnable() { @Override public void run() { AdditionalServiceRecord record = retriveServiceByComponent(serviceIntent.getComponent()); if(record == null) { //create new service record = handleCreateService(serviceIntent.getComponent()); } record.calledStart = true; if(record!=null) { handleServiceArgs(serviceIntent, record); } } }); return null; } @Override public IBinder bindService(final Intent serviceIntent, IBinder activityToken, final IServiceConnection conn) throws RemoteException { Log.e("BaseDelegateService","bindService"); mMainHandler.post(new Runnable() { @Override public void run() { AdditionalServiceRecord record = retriveServiceByComponent(serviceIntent.getComponent()); if(record == null) { //create new service record = handleCreateService(serviceIntent.getComponent()); } if(record !=null ){ IBinder binder = mActivateServices.get(record).onBind(serviceIntent); if(!record.activeConnections.contains(conn)){ record.activeConnections.add(conn); } try { conn.connected(record.component,binder); } catch (RemoteException e) { e.printStackTrace(); } } } }); return null; } @Override public boolean unbindService(IServiceConnection conn) throws RemoteException { Log.e("BaseDelegateService","unbindService"); Iterator iter = mActivateServices.entrySet().iterator(); AdditionalServiceRecord record = null; while (iter.hasNext()) { Map.Entry<AdditionalServiceRecord,Service> entry = (Map.Entry<AdditionalServiceRecord,Service>) iter.next(); AdditionalServiceRecord tmpRecord = entry.getKey(); if(tmpRecord.activeConnections.contains(conn)){ //service has created record = tmpRecord; break; } } if(record!=null){ record.activeConnections.remove(conn); if(record.activeConnections.size()==0){ if(!record.calledStart || (record.calledStart && record.delayStop)){ //service can stop Service service = mActivateServices.remove(record); service.onDestroy(); return true; } } } return false; } @Override public int stopService(Intent serviceIntent) throws RemoteException { Log.e("BaseDelegateService","stopService"); AdditionalServiceRecord record = retriveServiceByComponent(serviceIntent.getComponent()); if(record!=null){ if(record.activeConnections.size()>0){ record.delayStop = true; }else{ mActivateServices.get(record).onDestroy(); } } return 0; } @Override public Intent handleActivityStack(Intent intent,ActivityInfo info) throws RemoteException { ActivityBridge.handleActivityStack(info,intent); return intent; } @Override public void handleReceiver(final Intent intent, final ActivityInfo info) throws RemoteException { mMainHandler.post(new Runnable() { @Override public void run() { ReceiverBridge.postOnReceived(intent,info); } }); } private AdditionalServiceRecord handleCreateService(ComponentName componentName){ try { Class serviceClazz = RuntimeVariables.delegateClassLoader.loadClass(componentName.getClassName()); Service service = (Service)serviceClazz.newInstance(); Object contextImpl = null; Object activityThread = AndroidHack.getActivityThread(); Object loadedApk = AndroidHack.getLoadedApk(RuntimeVariables.androidApplication,activityThread,RuntimeVariables.androidApplication.getPackageName()); Hack.HackedMethod ContextImpl_createAppContext = AtlasHacks.ContextImpl.method("createAppContext",AtlasHacks.ActivityThread.getmClass(),AtlasHacks.LoadedApk.getmClass()); if(ContextImpl_createAppContext.getMethod()!=null){ contextImpl = ContextImpl_createAppContext.invoke(AtlasHacks.ContextImpl.getmClass(),activityThread,loadedApk); }else{ Hack.HackedMethod ContextImpl_init = AtlasHacks.ContextImpl.method("init",AtlasHacks.LoadedApk.getmClass(), IBinder.class,AtlasHacks.ActivityThread.getmClass()); contextImpl = AtlasHacks.ContextImpl.getmClass().newInstance(); ContextImpl_init.invoke(contextImpl, loadedApk,null,activityThread); } Object gDefault = null; if(Build.VERSION.SDK_INT>25 || (Build.VERSION.SDK_INT==25&&Build.VERSION.PREVIEW_SDK_INT>0)){ gDefault=AtlasHacks.ActivityManager_IActivityManagerSingleton.get(AtlasHacks.ActivityManager.getmClass()); }else{ gDefault=AtlasHacks.ActivityManagerNative_gDefault.get(AtlasHacks.ActivityManagerNative.getmClass()); } AtlasHacks.ContextImpl_setOuterContext.invoke(contextImpl,service); ContextImplHook hook = new ContextImplHook((Context) contextImpl,serviceClazz.getClassLoader()); //create binder AdditionalServiceRecord record = new AdditionalServiceRecord(componentName); AtlasHacks.Service_attach.invoke(service,hook,activityThread,serviceClazz.getName(), record,RuntimeVariables.androidApplication, gDefault); service.onCreate(); mActivateServices.put(record,service); return record; } catch (Throwable e) { e.printStackTrace(); return null; } } private void handleServiceArgs(Intent serviceIntent,IBinder token){ Service service = mActivateServices.get(token); if(service!=null){ if(serviceIntent!=null) { serviceIntent.setExtrasClassLoader(service.getClassLoader()); } service.onStartCommand(serviceIntent,Service.START_FLAG_RETRY,0); } } private AdditionalServiceRecord retriveServiceByComponent(ComponentName component){ Iterator iter = mActivateServices.entrySet().iterator(); while (iter.hasNext()) { Map.Entry<AdditionalServiceRecord,Service> entry = (Map.Entry<AdditionalServiceRecord,Service>) iter.next(); AdditionalServiceRecord tmpRecord = entry.getKey(); if(tmpRecord.component.equals(component)){ //service has created return tmpRecord; } } return null; } } public static class AdditionalServiceRecord extends Binder { final ComponentName component; public final ArrayList<IServiceConnection> activeConnections = new ArrayList<>(); public boolean delayStop = false; public boolean calledStart = false; public AdditionalServiceRecord(ComponentName componentName){ this.component = componentName; } } }