Android kills the service very frequently - android

We prepared an Android application with a service that maintains MQTT connection with our server. The service returns a *START_STICKY* from its onStartCommand in order for Android to restart the service in case it kills the service for resource shortages. But the problem is, the service is killed very frequently by Android OS. It sometimes kills the service once in few seconds, even if no other process works on the device(with 2GB of ram). Why Android is killing my service so frequently? How can I lessen the number of restarts? My service should be killed as less as possible, because it disconnects my tcp connection and client have to reconnect again, causing quite a big load on our server. What can be wrong with this code? Thanks
public class GTAndroidMQTTService extends Service implements MqttCallback {
private void init() {
this.clientId = Settings.System.getString(getContentResolver(), Secure.ANDROID_ID);
}
#Override
#Deprecated
public void onStart(Intent intent, int startId) {
logger("onStart() called");
super.onStart(intent, startId);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
logger("onStartCommand() called");
if (client == null) {
try {
init();
conOpt = new MqttConnectOptions();
conOpt.setCleanSession(false);
conOpt.setUserName("...");
conOpt.setPassword("...");
try {
char[] keystorePass = getString(R.string.keystorepass).toCharArray();
KeyStore keyStore = KeyStore.getInstance("BKS");
keyStore.load(getApplicationContext().getResources().openRawResource(R.raw.prdkey),
keystorePass);
TrustManagerFactory trustManagerFactory = TrustManagerFactory
.getInstance(KeyManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory
.getDefaultAlgorithm());
kmf.init(keyStore, keystorePass);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);
conOpt.setSocketFactory(sslContext.getSocketFactory());
} catch (Exception ea) {
}
client = new MqttClient(this.mqttURL, clientId, new MqttDefaultFilePersistence(folder));
client.setCallback(this);
conOpt.setKeepAliveInterval(this.keepAliveSeconds);
} catch (MqttException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (intent == null) {
Log.i("TAG", "Android restarted the service[START_STICKY]");
if (client != null) {
tryToEstablishConnection();
}
}
return START_STICKY;
}
public void unsubscribe(String topicName) throws MqttException {
try {
client.unsubscribe(topicName);
} catch (Exception e) {
Log.i("TAG", "Unsubscribing from topic \"" + topicName + "has failed: " + e.toString());
}
}
private void retry() {
try {
notifyUserWithServiceStatus("Status Changed", "Status", "Connecting");
client.connect(conOpt);
notifyUserWithServiceStatus("Status Changed", "Status", "User Connected #" + (++retrycnt));
} catch (Exception e) {
notifyUserWithServiceStatus("Status Changed", "Status", "Cannot Connect");
e.printStackTrace();
}
}
public void subscribe(String topicName, int qos) throws MqttException {
try {
client.subscribe(topicName, qos);
} catch (Exception e) {
}
}
public void disconnect() {
try {
client.disconnect();
} catch (MqttException e) {
e.printStackTrace();
}
}
#Override
public IBinder onBind(Intent intent) {
logger("onBind() called");
return null;
}
#Override
public void onCreate() {
logger("onCreate() called");
super.onCreate();
}
#Override
public void connectionLost(Throwable arg0) { // Connection lost
notifyUserWithServiceStatus("Status Changed", "Status", "Connection Lost!");
tryToEstablishConnection();
}
private void tryToEstablishConnection() {
if (!retrying) {
retrying = true;
new Thread(new Runnable() {
#Override
public void run() {
for (;;) {
try {
if (isOnline() && !isConnected()) {
retry();
Thread.sleep(RETRY_INTERVAL);
} else if (isConnected()) {
retrying = false;
break;
} else if (!isOnline()) {
retrying = false;
break;
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}).start();
}
}
private class NetworkConnectionIntentReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context ctx, Intent intent) {
PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MQTT");
wl.acquire();
if (isOnline() && !isConnected())
notifyUserWithServiceStatus("Status Changed", "Status", "Online but not connected");
else if (!isOnline())
notifyUserWithServiceStatus("Status Changed", "Status", "Connection Lost!");
tryToEstablishConnection();
wl.release();
}
}
private boolean isConnected() {
try {
return client.isConnected();
} catch (Exception e) {
return false;
}
}
private boolean isOnline() {
ConnectivityManager conMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo i = conMgr.getActiveNetworkInfo();
if (i == null)
return false;
if (!i.isConnected())
return false;
if (!i.isAvailable())
return false;
return true;
}
#Override
public void onDestroy() {
logger("onDestroy() called");
try {
client.disconnect();
Log.i("TAG", "Service stopped");
} catch (MqttException e) {
e.printStackTrace();
}
super.onDestroy();
}
#Override
public void deliveryComplete(IMqttDeliveryToken arg0) {
// TODO Auto-generated method stub
}
}

It sounds as though your service is running in the Application process; is it directly tied to your Activity?
You'll want to run it a different process entirely; you can do this by adding the following declaration in your manifest:
<service
android:name=".ServiceClassName"
android:process=":yourappname_background" >
And then use the same android:process attribute for any receiver declarations as well.

Does binding to your service keep it alive?

Some Background:
When you create a service you have to make sure your work is started in a background thread. IntentService runs on a background thread while a Service runs on the Main Thread.
A service runs in the main thread of the application that hosts it, by default
Source: http://developer.android.com/guide/components/services.html
Take a look at http://developer.android.com/guide/components/services.html#ExtendingIntentService
Read below for similar issues.
Similar answer in: Service vs IntentService
The Service can be used in tasks with no UI, but shouldn't be too long. If you need to perform long tasks, you must use threads within Service.
Also I would suggest reading CommonsWare's answer to How to always run a service in the background?
My Suggestion:
I would move to an IntentService or WakefulIntentService and consider updating information with an fixed interval instead of using a constant tcp connection. A HTTP based API could provide same information over SSL.

Related

QoS=1 with MqttAsyncClient subscription miss messages

I have foreground service acting as MQTT client. I'm using MqttAsyncClient mqttClient for this purpose.
I'm using QoS=1 on subscribe to topic:
mqttClient.subscribe("sensors/s1/", 1);
But in case my phone gets offline for some period of time it miss current period messages. Whole code is below.
Im my another application I'm using MqttAndroidClient mqttAndroidClient and in this case QoS=1 brings all missed messages.
mqttAndroidClient.subscribe(topic, 1, null, new IMqttActionListener() {...})
Why subscription with MqttAsyncClient with QoS=1 not retrieves all messages?
Whole code :
public class MqttGndService extends Service {
private String ip="ssl:myserver",port="8887";
private final IBinder mBinder = new LocalBinder();
private Handler mHandler;
private static final String TAG = "mqttservice";
private static boolean hasWifi = false;
private static boolean hasMmobile = false;
private ConnectivityManager mConnMan;
private volatile IMqttAsyncClient mqttClient;
private String uniqueID;
class MQTTBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
IMqttToken token;
boolean hasConnectivity = false;
boolean hasChanged = false;
NetworkInfo infos[] = mConnMan.getAllNetworkInfo();
for (int i = 0; i < infos.length; i++) {
if (infos[i].getTypeName().equalsIgnoreCase("MOBILE")) {
if ((infos[i].isConnected() != hasMmobile)) {
hasChanged = true;
hasMmobile = infos[i].isConnected();
}
Timber.tag(Utils.TIMBER_TAG).v( infos[i].getTypeName() + " is " + infos[i].isConnected());
} else if (infos[i].getTypeName().equalsIgnoreCase("WIFI")) {
if ((infos[i].isConnected() != hasWifi)) {
hasChanged = true;
hasWifi = infos[i].isConnected();
}
Timber.tag(Utils.TIMBER_TAG).v(infos[i].getTypeName() + " is " + infos[i].isConnected());
}
}
hasConnectivity = hasMmobile || hasWifi;
Timber.tag(Utils.TIMBER_TAG).v( "hasConn: " + hasConnectivity + " hasChange: " + hasChanged + " - " + (mqttClient == null || !mqttClient.isConnected()));
if (hasConnectivity && hasChanged && (mqttClient == null || !mqttClient.isConnected())) {
Timber.tag(Utils.TIMBER_TAG).v("Ready to connect");
doConnect();
Timber.tag(Utils.TIMBER_TAG).v("do connect done");
} else
{
Timber.tag(Utils.TIMBER_TAG).v("Connection not possible");
}
}
}
public class LocalBinder extends Binder {
public MqttGndService getService() {
// Return this instance of LocalService so clients can call public methods
return MqttGndService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
public void publish(String topic, MqttMessage message) {
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);// we create a 'shared" memory where we will share our preferences for the limits and the values that we get from onsensorchanged
try {
mqttClient.publish(topic, message);
} catch (MqttException e) {
e.printStackTrace();
}
}
#Override
public void onCreate() {
Timber.tag(Utils.TIMBER_TAG).v("Creating MQTT service");
mHandler = new Handler();//for toasts
IntentFilter intentf = new IntentFilter();
setClientID();
intentf.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
registerReceiver(new MQTTBroadcastReceiver(), new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
mConnMan = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
Timber.tag(Utils.TIMBER_TAG).v( "onConfigurationChanged()");
android.os.Debug.waitForDebugger();
super.onConfigurationChanged(newConfig);
}
#Override
public void onDestroy() {
super.onDestroy();
Timber.tag(Utils.TIMBER_TAG).v("Service onDestroy");
}
private void setClientID() {
uniqueID = android.provider.Settings.Secure.getString(getContentResolver(), android.provider.Settings.Secure.ANDROID_ID);
Timber.tag(Utils.TIMBER_TAG).v("uniqueID=" + uniqueID);
}
private void doConnect() {
String broker = ip + ":" + port;
Timber.tag(Utils.TIMBER_TAG).v("mqtt_doConnect()");
IMqttToken token;
MqttConnectOptions options = new MqttConnectOptions();
options.setCleanSession(true);
options.setMaxInflight(100);//handle more messages!!so as not to disconnect
options.setAutomaticReconnect(true);
options.setConnectionTimeout(1000);
options.setKeepAliveInterval(300);
options.setUserName("cc50e3e91bf4");
options.setPassword("b".toCharArray());
try {
options.setSocketFactory(SocketFactoryMQ.getSocketFactory(this,""));
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (UnrecoverableKeyException e) {
e.printStackTrace();
}
Timber.tag(Utils.TIMBER_TAG).v("set socket factory done");
try {
mqttClient = new MqttAsyncClient(broker, uniqueID, new MemoryPersistence());
token = mqttClient.connect(options);
token.waitForCompletion(3500);
mqttClient.setCallback(new MqttCallback() {
#Override
public void connectionLost(Throwable throwable) {
try {
mqttClient.disconnectForcibly();
mqttClient.connect();
} catch (MqttException e) {
e.printStackTrace();
}
}
#Override
public void messageArrived(String topic, MqttMessage msg) throws Exception {
Timber.tag(Utils.TIMBER_TAG).v("Message arrived from topic " + topic+ " msg: " + msg );
}
#Override
public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
System.out.println("published");
}
});
Timber.tag(Utils.TIMBER_TAG).v("will subscribe");
mqttClient.subscribe("sensors/s1/", 1);
} catch (MqttSecurityException e) {
Timber.tag(Utils.TIMBER_TAG).v("general connect exception");
e.printStackTrace();
} catch (MqttException e) {
switch (e.getReasonCode()) {
case MqttException.REASON_CODE_BROKER_UNAVAILABLE:
mHandler.post(new ToastRunnable("WE ARE OFFLINE BROKER_UNAVAILABLE!", 1500));
break;
case MqttException.REASON_CODE_CLIENT_TIMEOUT:
mHandler.post(new ToastRunnable("WE ARE OFFLINE CLIENT_TIMEOUT!", 1500));
break;
case MqttException.REASON_CODE_CONNECTION_LOST:
mHandler.post(new ToastRunnable("WE ARE OFFLINE CONNECTION_LOST!", 1500));
break;
case MqttException.REASON_CODE_SERVER_CONNECT_ERROR:
Timber.tag(Utils.TIMBER_TAG).v( "c " + e.getMessage());
e.printStackTrace();
break;
case MqttException.REASON_CODE_FAILED_AUTHENTICATION:
Intent i = new Intent("RAISEALLARM");
i.putExtra("ALLARM", e);
Timber.tag(Utils.TIMBER_TAG).v("b " + e.getMessage());
break;
default:
Timber.tag(Utils.TIMBER_TAG).v( "a " + e.getMessage() +" "+ e.toString());
}
}
mHandler.post(new ToastRunnable("WE ARE ONLINE!", 500));
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Timber.tag(Utils.TIMBER_TAG).v("onStartCommand");
String input = intent.getStringExtra(INTENT_ID);
Timber.tag(Utils.TIMBER_TAG).v("onStartCommand "+ input);
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,
0, notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Example Service")
.setContentText(input)
.setSmallIcon(R.drawable.ic_android)
.setContentIntent(pendingIntent)
.build();
startForeground(1, notification);
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyApp::MyWakelockTag");
wakeLock.acquire();
return START_STICKY;
}
}
You are setting cleansession to true (options.setCleanSession(true)); from the docs for setCleanSession:
If set to true the client and server will not maintain state across restarts of the client, the server or the connection. This means
Message delivery to the specified QOS cannot be maintained if the client, server or connection are restarted
The server will treat a subscription as non-durable
I think that the mqtt specs state this more clearly:
If CleanSession is set to 1, the Client and Server MUST discard any previous Session and start a new one. This Session lasts as long as the Network Connection. State data associated with this Session MUST NOT be reused in any subsequent Session
So when your application looses the connection the session is discarded and new messages will not be queued up for delivery. In addition unless you resubscribe when the connection comes back up you will not receive any additional messages.
However be aware that if you set cleansession to false then any new messages received while your client is offline will be queued for delivery (subject to the configuration of the broker) and this might not be what you want to happen if the client could be offline for a long time.

Android Paho Mqtt does not reconnet after wifi reconnects

I am using mqtt android client to stream locations. This works fine until when the internet connection is lost. The mqtt client does not reconnect as expected. What should I do to make sure the paho mqtt reconnects to the broker.
I want to force the mqtt client to reconnect to the broker and continue to publish locations when a connection returns.
Below is my code.
public class MqttClientHelperService2 extends Service {
private MqttAndroidClient mqttAndroidClient;
BroadcastReceiver broadcastReceiver;
private final String SERVER_URL = "tcp://000.102.110.**:1883";
private final String CLIENT_ID = "client_id";
private final String MQTT_TOPIC = "livelocations/local";
LiveLocation liveLocation;
#Override
public void onCreate() {
super.onCreate();
Thread newThread = new Thread(){
public void run(){
init();
}
};
newThread.start();
if (Build.VERSION.SDK_INT >= 26) {
String CHANNEL_ID = "my_channel_01";
NotificationChannel channel = new NotificationChannel(CHANNEL_ID,
"Channel human readable title",
NotificationManager.IMPORTANCE_LOW);
((NotificationManager) Objects.requireNonNull(getSystemService(Context.NOTIFICATION_SERVICE))).
createNotificationChannel(channel);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("")
.setContentText("")
.setSmallIcon(R.mipmap.ic_launcher).build();
startForeground(1, notification);
}
}
private void init() {
mqttAndroidClient = new MqttAndroidClient(getApplicationContext(), SERVER_URL, CLIENT_ID);
mqttAndroidClient.setCallback(new MqttCallback() {
#Override
public void connectionLost(Throwable cause) {
}
#Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
}
#Override
public void deliveryComplete(IMqttDeliveryToken token) {
}
});
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
liveLocation= new LiveLocation(
intent.getIntExtra("driver_id", 0),
intent.getDoubleExtra("latitude", 0),
intent.getDoubleExtra("longitude", 0),
"");
connectMqtt();
return START_STICKY;
}
private MqttConnectOptions getMqttOptions(){
MqttConnectOptions mqttConnectOptions = new MqttConnectOptions();
mqttConnectOptions.setMqttVersion(MqttConnectOptions.MQTT_VERSION_3_1_1);
mqttConnectOptions.setAutomaticReconnect(true);
mqttConnectOptions.setCleanSession(false);
return mqttConnectOptions;
}
private void connectMqtt() {
try {
IMqttToken iMqttToken = mqttAndroidClient.connect(getMqttOptions());
iMqttToken.setActionCallback(new IMqttActionListener() {
#Override
public void onSuccess(IMqttToken asyncActionToken) {
Log.e("phanuel-log", "connecting ......." + Calendar.getInstance().getTime());
publishToServer(liveLocation);
}
#Override
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
Log.e("phanuel-log-error", "connection error");
}
});
} catch (MqttException e) {
e.printStackTrace();
}
}
#Override
public void onDestroy() {
if(mqttAndroidClient != null){
try {
mqttAndroidClient.unregisterResources();
mqttAndroidClient.close();
mqttAndroidClient.disconnect();
} catch (Exception e){
e.printStackTrace();
}
}
unregisterReceiver(broadcastReceiver);
broadcastReceiver = null;
super.onDestroy();
}
private boolean isNetworkAvailable() {
ConnectivityManager connectivityManager
= (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
assert connectivityManager != null;
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
return activeNetworkInfo != null && activeNetworkInfo.isConnectedOrConnecting();
}
void publishToServer(final LiveLocation location) {
try {
if (location.getDriverId() > 0){
mqttAndroidClient.connect(getMqttOptions(), null, new IMqttActionListener() {
#Override
public void onSuccess(IMqttToken asyncActionToken) {
JSONObject locationJsonObject = new JSONObject();
try {
locationJsonObject.put("driverId", location.getDriverId());
locationJsonObject.put("driverLatitude", location.getLatitude());
locationJsonObject.put("driverLongitude", location.getLongitude());
locationJsonObject.put("driverTimeStamp", Calendar.getInstance().getTime());
} catch (JSONException e) {
e.printStackTrace();
}
MqttMessage mqttMessage = new MqttMessage();
mqttMessage.setPayload(locationJsonObject.toString().getBytes());
mqttMessage.setQos(0);
mqttMessage.setRetained(false);
try {
mqttAndroidClient.publish(MQTT_TOPIC, mqttMessage);
}catch (MqttException e){
e.printStackTrace();
}
}
#Override
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
Log.e("mqtt-client", "Failed to connect");
Log.e("mqtt-cleint", exception.toString());
}
});
}
} catch (MqttException e){
e.printStackTrace();
}
}
}
There are multiple ways to handle your scenario.
If you are using mqtt only to publish from android side then you can
call init() function (connect to mqtt server) before publishing in
mqtt. After message published you can disconnect from mqtt server.
If you always need alive mqtt connection then whenever mqtt connection is broken
then connectionLost method is called. You can reconnect at this method.
You can have thread keep checking whether mqtt connection is alive and you can reconnect if disconnected

VPNService doesn't work in all app android

I implemented a vpnservice that block all packets,it works in most app and blocks fine but it doesn't work in some apps . why is that ?
myVpnService is like below.
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// Start a new session by creating a new thread.
mThread = new Thread(new Runnable() {
#Override
public void run() {
try {
builder = new Builder();
mInterface = builder.setSession("ClashDisconnect")
.addAddress("192.168.0.1", 32)
.addDnsServer("8.8.8.4")
.addRoute("0.0.0.0", 1).establish();
Log.d("after establish", "yes");
DatagramChannel tunnel = DatagramChannel.open();
// Connect to the server, localhost is used for demonstration only.
tunnel.connect(new InetSocketAddress("127.0.0.1", 8081));
//d. Protect this socket, so package send by it will not be feedback to the vpn service.
protect(tunnel.socket());
//e. Use a loop to pass packets.
while (true) {
Thread.sleep(100);
}
} catch (Exception e) {
// Catch any exception
Log.d("Exception", "in Catch");
e.printStackTrace();
} finally {
try {
if (mInterface != null) {
mInterface.close();
mInterface = null;
}
} catch (Exception e) {
}
}
}
}, "MyVpnRunnable");
//start the service
mThread.start();
onDestroy();
}
};
return START_STICKY;
}
#Override
public void onDestroy() {
// TODO Auto-generated method stub
if (mThread != null) {
mThread.interrupt();
mThread = null;
builder = null;
}
super.onDestroy();
}
and another weird problem is it work in some phone but not all phone .

Android Service exits leaving imp. data open

I am facing a grave problem. Inside a service I am opening Wifi connection and closing it after my task completes. Since, a service exits at any point i face a problem wherein the connection opens and remains open.
Is there a way i can handle this as i am using START_STICKY or i will have to handle it programmatically only?
EDIT : Can i share my intent information across couple of receivers (BroadcastReceiver). For example, I will write another receiver for action android.net.wifi.wifi_state_changed and my existing receiver is for android.intent.action.PHONE_STATE.
IF that can be achieved i can do something about it.
EDIT2 : My code is as follows:
public class CallReceiver extends BroadcastReceiver {
private static final String LOG_TAG = "CallReceiver";
private static final String CALL_ACTION = "android.intent.action.PHONE_STATE";
#Override
public void onReceive(Context context, Intent callIntent)
{
Log.d(LOG_TAG, "----------------Inside onReceive of CallReceiver----------------");
if (callIntent.getAction().equals(CALL_ACTION))
{
try
{
Intent myIntent = new Intent(context, MyService.class);
context.startService(myIntent);
}
catch (Exception e)
{
e.printStackTrace();
Log.d(LOG_TAG,"----------------Exception occured while starting service----------------");
}
}
}
}
public class MyService extends Service {
private Context context;
private static final String LOG_TAG = "MyService";
private Thread thread = null;
public MyService()
{
super();
Log.d(LOG_TAG, "----------------Inside Email Service constructor----------------");
}
public int onStartCommand(Intent myIntent, int flags, int startId)
{
Log.d(LOG_TAG, "----------------Email Service Command Started----------------");
try
{
context = getApplicationContext();
if(thread == null || !thread.isAlive())
{
thread = new Thread(new MyRunnable("Email Sender", myIntent));
thread.start();
}
}
catch (Exception e)
{
e.printStackTrace();
Log.d(LOG_TAG,
"----------------Exception occured in Email Service onStartCommand----------------");
}
return START_REDELIVER_INTENT;
}
class MyRunnable implements Runnable {
String name;
Intent myIntent;
public MyRunnable(String name, Intent myIntent) {
this.name = name;
this.myIntent = myIntent;
}
#Override
public void run()
{
try
{
doStuff(emailIntent);
}
catch (NumberFormatException e)
{
e.printStackTrace();
Log.d(LOG_TAG, e.getMessage());
}
catch (InterruptedException e)
{
e.printStackTrace();
Log.d(LOG_TAG, e.getMessage());
}
catch (Exception e)
{
e.printStackTrace();
Log.d(LOG_TAG, e.getMessage());
}
finally
{
stopSelf();
}
}
}
private void doStuff(Intent emailIntent) throws InterruptedException, Exception
{
if (context != null)
{
boolean isWifiConnection = false;
try
{
// Check if WiFi connection is available ,if yes try opening it;
// Attempt to open WiFi connection
isWifiConnection = Utility.isEnableWifiSuccessful(getApplicationContext());
Log.d(LOG_TAG, "----------------Wifi conn enabled = " + isWifiConnection
+ "----------------");
if (isWifiConnection)
{
// Do more stuff
}
}
catch (Exception e)
{
e.printStackTrace();
throw e;
}
finally
{
// Code never reaches here !! Somehow, the service stops and by
// the time the service stops,
// WiFi has been enabled
try
{
if (isWifiConnection)
{
Utility.isDisableWifiSuccessful(getApplicationContext());
}
}
catch (Exception e)
{
e.printStackTrace();
Log.d(LOG_TAG,
"----------------Error occured while closing network connections----------------");
}
}
}
else
{
Log.d(LOG_TAG, "----------------Context is null----------------");
}
}
#Override
public IBinder onBind(Intent intent)
{
// TODO Auto-generated method stub
return null;
}
}
Now, if i have another receiver as NetworkReceiver
public class NetworkReceiver extends BroadcastReceiver {
private static final String ACTION = "android.net.wifi.WIFI_STATE_CHANGED";
private static final String LOG_TAG = "NetworkReceiver";
#Override
public void onReceive(Context context, Intent networkIntent)
{
if(networkIntent.getAction().equals(ACTION))
{
Log.d(LOG_TAG, "----------------Inside Network Receiver----------------");
//Do something which will keep track who has opened the WiFi connection
}
}
}
then can myIntent and networkIntent share information and can MySerivce read that information.
Any help would be really grateful.
Service exits when the memory is too low, since you are already using START_STICKY, the service will be restarted once the memory resources are available. I beleive you might need to check if the connection is opened and you are done with the task, then you have stop the service by using stopSelf().
Hope this helps.
Thanks,
Ramesh

Android AVD unable to notice JmDNS services

I've had some difficulty getting JmDNS to work with my Android AVD. I've created 3 applications. An Android application which registers a ServiceListener and logs any activity, A Java application which does the same as the android application, and another Java application which registers a service. The Java listener application will pick up on the other Java application, however the android application will not. I've also tried running two AVD simultaneously to see if they'd pick up on each other and they don't. I should also mention that I have permissions for INTERNET and CHANGE_WIFI_MULSTICAST_STATE enabled. Here's my code:
Android Application:
public class BonjourActivity extends Activity {
// Multicast
private WifiManager wifi;
private MulticastLock lock;
private JmDNS jmdns;
private String type = "_im._tcp.local.";
private ServiceListener listener;
private ServiceInfo serviceInfo;
// On Create
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Multicast
wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
lock = wifi.createMulticastLock("");
lock.setReferenceCounted(true);
lock.acquire();
// JmDNS
new AsyncTask<Object, Object, Object>(){
#Override
protected Object doInBackground(Object... params) {
// Create JmDNS
try {
jmdns = JmDNS.create();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
protected void onPostExecute(Object result) {
// Add Listener
jmdns.addServiceListener(type, listener = new ServiceListener(){
#Override
public void serviceAdded(ServiceEvent ev) {
jmdns.requestServiceInfo(ev.getType(), ev.getName(), 1);
}
#Override
public void serviceRemoved(ServiceEvent ev) {
Log.d("Service", "Service Removed: " + ev.getName());
}
#Override
public void serviceResolved(ServiceEvent ev) {
Log.d("Service", "Service Resolved: " + ev.getInfo().getURL());
}
});
}
}.execute();
}
// On Destroy
public void onDestroy(){
// Release Lock
if (lock != null){
lock.release();
}
// Close JmDNS
if (jmdns != null){
jmdns.removeServiceListener(type, listener);
try {
jmdns.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
super.onDestroy();
}
}
Java Listener Application:
public class Listener {
private static JmDNS jmdns;
private static String type = "_im._tcp.local.";
private static ServiceListener serviceListener;
private static ServiceInfo serviceInfo;
// Main
public static void main(String args[]){
try {
jmdns = JmDNS.create();
jmdns.addServiceListener(type, serviceListener = new ServiceListener(){
#Override
public void serviceAdded(ServiceEvent ev) {
System.out.println("Service Added: " + ev.getName());
jmdns.requestServiceInfo(ev.getType(), ev.getName(), 1);
}
#Override
public void serviceRemoved(ServiceEvent ev) {
System.out.println("Service Removed: " + ev.getName());
}
#Override
public void serviceResolved(ServiceEvent ev) {
System.out.println("Service Resolved: " + ev.getInfo().getURL());
}
});
System.out.println("Listener Added");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Java Sender Application:
public class Sender {
private static JmDNS jmdns;
private static String type = "_im._tcp.local.";
private static ServiceListener serviceListener;
private static ServiceInfo serviceInfo;
// Main
public static void main(String args[]){
try {
jmdns = JmDNS.create();
serviceInfo = ServiceInfo.create(type, "Test IM Service", 55555, "Instant messaging test service");
jmdns.registerService(serviceInfo);
System.out.println("Sender: Service Created");
new Timer().schedule(new TimerTask(){
#Override
public void run() {
// TODO Auto-generated method stub
System.out.println("Closing..");
jmdns.unregisterAllServices();
try {
jmdns.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.exit(0);
}
}, 10000);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
In Addition, LogCat gives me a few errors when I attempt to run the application:
NetworkManagementSocketTagger setKernelCountSet(10009,0) failed with errno -2
WifiStateMachine Error! unhandled message{ what=131157 when=-1ms }
Might anyone know why the android application is unable to pick up on JmDNS services generated by other applications?
Just a little notice, The virtual device running in the emulator is not in the same network as the computer. Service discovery may not work. My implementation of jmdns does not work in the emulator. Try it on a real device.
And go to http://home.heeere.com/tech-androidjmdns.html for more details.

Categories

Resources