package android.app;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import android.app.ActivityManagerNative;
import android.app.ActivityThread;
import android.app.Application;
import android.app.Instrumentation;
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.text.TextUtils;
/**
* 插件service对应的代理类
*
* @author zhaoxuyang
*
*/
public class PluginBlankService extends Service {
/**
* 插件service的类名
*/
public static final String SERVICE_NAME = "servicename";
/**
* 插件的名称
*/
public static final String PLUGIN_NAME = "pluginname";
/**
* ServiceConnection
*/
public static final String SERVICE_CONNECTION = "serviceconnection";
/**
* 类型
*/
public static final String TYPE = "type";
/**
* 启动service
*/
public static final int START_TYPE = 1;
/**
* 停止service
*/
public static final int STOP_TYPE = 2;
/**
* bind service
*/
public static final int BIND_TYPE = 3;
/**
* unbind service
*/
public static final int UNBIND_TYPE = 4;
/**
* 已启动的service
*/
private HashMap<String, ServiceRecord> mCreateServices = new HashMap<String, ServiceRecord>();
@Override
public void onCreate() {
super.onCreate();
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
String serviceName = intent.getStringExtra(SERVICE_NAME);
String pluginName = intent.getStringExtra(PLUGIN_NAME);
int type = intent.getIntExtra(TYPE, -1);
IBinder binder = intent.getParcelableExtra(SERVICE_CONNECTION);
String key = pluginName + "-" + serviceName;
if (TextUtils.isEmpty(serviceName) || TextUtils.isEmpty(pluginName)
|| (type != START_TYPE && type != STOP_TYPE && type != BIND_TYPE && type != UNBIND_TYPE)) {
return super.onStartCommand(intent, flags, startId);
}
if (mCreateServices.containsKey(key)) {
ServiceRecord sr = mCreateServices.get(key);
switch (type) {
case START_TYPE:
sr.mService.onStartCommand(intent, flags, startId);
break;
case STOP_TYPE:
if (sr.mConnections.size() == 0) {
sr.mService.onDestroy();
mCreateServices.remove(key);
}
break;
case BIND_TYPE:
if (binder != null) {
IServiceConnection conn = IServiceConnection.Stub.asInterface(binder);
sr.mConnections.add(conn);
if (sr.mIbinder == null) {
sr.mIbinder = sr.mService.onBind(intent);
}
try {
conn.connected(new ComponentName(pluginName, serviceName), sr.mIbinder);
} catch (RemoteException e) {
e.printStackTrace();
}
}
break;
case UNBIND_TYPE:
if (binder != null) {
IServiceConnection conn = IServiceConnection.Stub.asInterface(binder);
sr.mConnections.remove(conn);
try {
conn.connected(new ComponentName(pluginName, serviceName), null);
} catch (RemoteException e) {
e.printStackTrace();
}
if (sr.mConnections.size() == 0) {
sr.mIbinder = null;
sr.mService.onUnbind(intent);
sr.mService.onDestroy();
mCreateServices.remove(key);
}
}
break;
}
} else {
if (type == START_TYPE || type == BIND_TYPE) {
ServiceRecord sr = createService(pluginName, serviceName, key);
if (sr != null) {
if (type == START_TYPE) {
sr.mService.onStartCommand(intent, flags, startId);
}
if (type == BIND_TYPE) {
if (binder != null) {
IServiceConnection conn = IServiceConnection.Stub.asInterface(binder);
sr.mConnections.add(conn);
if (sr.mIbinder == null) {
sr.mIbinder = sr.mService.onBind(intent);
}
try {
conn.connected(new ComponentName(pluginName, serviceName), sr.mIbinder);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
}
}
}
return super.onStartCommand(intent, flags, startId);
}
private ServiceRecord createService(String pluginName, String serviceName, String key) {
ServiceRecord sr = null;
try {
PluginManagerImpl manager = PluginManagerImpl.getInstance();
Plugin plugin = manager.getPlugin(pluginName);
ActivityThread thread = manager.mActivityThread;
Instrumentation instrumentation = thread.getInstrumentation();
Object packageInfo = plugin.mRealPackageInfo;
Context context = this;
if (manager.init != null) {
Constructor construct = manager.contextImpl.getDeclaredConstructor();
construct.setAccessible(true);
context = (Context) construct.newInstance();
manager.init.invoke(context, packageInfo, null, thread);
} else {
context = (Context) manager.createAppContext.invoke(null, thread, packageInfo);
}
Service service = (Service) plugin.mClassLoader.loadClass(serviceName).newInstance();
manager.setOuterContext.invoke(context, service);
service.attach(this, thread, serviceName, new LocalBinder(),
(Application) manager.makeApplication.invoke(packageInfo, false, instrumentation),
ActivityManagerNative.getDefault());
service.onCreate();
sr = new ServiceRecord();
sr.mService = service;
mCreateServices.put(key, sr);
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return sr;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
super.onDestroy();
Iterator<ServiceRecord> iter = mCreateServices.values().iterator();
while (iter.hasNext()) {
iter.next().mService.onDestroy();
}
mCreateServices.clear();
}
/**
* 占位的
*
* @author zhaoxuyang
*
*/
public static class LocalBinder extends Binder {
}
/**
*
* @author zhaoxuyang
* @since 2015-2-18
*/
class ServiceRecord {
public Service mService;
public HashSet<IServiceConnection> mConnections = new HashSet<IServiceConnection>();
public IBinder mIbinder;
}
public static class PluginServiceConnection extends IServiceConnection.Stub {
public ServiceConnection conn;
@Override
public void connected(ComponentName cn, IBinder binder) throws RemoteException {
if (conn != null) {
if (binder != null) {
conn.onServiceConnected(cn, binder);
} else {
conn.onServiceDisconnected(cn);
}
}
}
}
}