enlace de uso simple con no crear automáticamente - ver ps. y actualizar ...
public abstract class Context {
...
/*
* @return {true} If you have successfully bound to the service,
* {false} is returned if the connection is not made
* so you will not receive the service object.
*/
public abstract boolean bindService(@RequiresPermission Intent service,
@NonNull ServiceConnection conn, @BindServiceFlags int flags);
ejemplo:
Intent bindIntent = new Intent(context, Class<Service>);
boolean bindResult = context.bindService(bindIntent, ServiceConnection, 0);
¿Por qué no usar? getRunningServices ()
List<ActivityManager.RunningServiceInfo> getRunningServices (int maxNum)
Return a list of the services that are currently running.
Nota: este método solo está destinado a depurar o implementar interfaces de usuario de tipo de gestión de servicios.
PD. La documentación de Android es engañosa. He abierto un problema en el rastreador de Google para eliminar cualquier duda:
https://issuetracker.google.com/issues/68908332
como podemos ver, el servicio de enlace en realidad invoca una transacción a través del enlazador ActivityManager a través de los enlazadores de caché del servicio: no sé qué servicio es responsable del enlace, pero como podemos ver, el resultado para el enlace es:
int res = ActivityManagerNative.getDefault().bindService(...);
return res != 0;
La transacción se realiza a través de la carpeta:
ServiceManager.getService("activity");
siguiente:
public static IBinder getService(String name) {
try {
IBinder service = sCache.get(name);
if (service != null) {
return service;
} else {
return getIServiceManager().getService(name);
Esto se establece en ActivityThread a través de:
public final void bindApplication(...) {
if (services != null) {
// Setup the service cache in the ServiceManager
ServiceManager.initServiceCache(services);
}
Esto se llama en ActivityManagerService en el método:
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
...
thread.bindApplication(... , getCommonServicesLocked(),...)
entonces:
private HashMap<String, IBinder> getCommonServicesLocked() {
pero no hay "actividad" solo paquete de ventanas y alarma.
entonces necesitamos volver a llamar:
return getIServiceManager().getService(name);
sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
esto hace llamar a través de:
mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
lo que lleva a :
BinderInternal.getContextObject()
y este es un método nativo ...
/**
* Return the global "context object" of the system. This is usually
* an implementation of IServiceManager, which you can use to find
* other services.
*/
public static final native IBinder getContextObject();
No tengo tiempo ahora para cavar en C, así que hasta que diseccione la llamada de descanso, suspenderé mi respuesta.
pero la mejor manera de verificar si el servicio se está ejecutando es crear un enlace (si el enlace no se crea, el servicio no existe) y consultar al servicio sobre su estado a través del enlace (usando el indicador interno almacenado en este estado).
actualizar 23.06.2018
los encontré interesantes:
/**
* Provide a binder to an already-bound service. This method is synchronous
* and will not start the target service if it is not present, so it is safe
* to call from {@link #onReceive}.
*
* For peekService() to return a non null {@link android.os.IBinder} interface
* the service must have published it before. In other words some component
* must have called {@link android.content.Context#bindService(Intent, ServiceConnection, int)} on it.
*
* @param myContext The Context that had been passed to {@link #onReceive(Context, Intent)}
* @param service Identifies the already-bound service you wish to use. See
* {@link android.content.Context#bindService(Intent, ServiceConnection, int)}
* for more information.
*/
public IBinder peekService(Context myContext, Intent service) {
IActivityManager am = ActivityManager.getService();
IBinder binder = null;
try {
service.prepareToLeaveProcess(myContext);
binder = am.peekService(service, service.resolveTypeIfNeeded(
myContext.getContentResolver()), myContext.getOpPackageName());
} catch (RemoteException e) {
}
return binder;
}
en breve :)
"Proporcione una carpeta a un servicio ya vinculado. Este método es sincrónico y no iniciará el servicio de destino si no está presente".
public pederService de IBinder (servicio de intención, String resolveType, String callingPackage) produce RemoteException;
* *
public static IBinder peekService(IBinder remote, Intent service, String resolvedType)
throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken("android.app.IActivityManager");
service.writeToParcel(data, 0);
data.writeString(resolvedType);
remote.transact(android.os.IBinder.FIRST_CALL_TRANSACTION+84, data, reply, 0);
reply.readException();
IBinder binder = reply.readStrongBinder();
reply.recycle();
data.recycle();
return binder;
}
* *