I am developing long running application, my application uses DefaultHttpClient
(I also tried with AndroidHttpClient
) periodically. I don't know but after working a while, somehow httpClient.execute
sleeps. Literally sleeps, when I wake(unlock or connect to PC) my device httpClient
immediately continues to work(throws an exception if I set timeout or just returns the response of execution). I searched and tried similar cases and non work. For wake and wifilocks, I just acquire wifi lock and wake lock before execution and release it after getting response. Nothing work, and I have no idead.
The devices I work is Galaxy S3(v4.0+) and Ace(v2.3.6)
thanks in advance.
This is MyTask that stucks, and it stucks at the line response = new MyClient(ctx).client.execute(post);
and MyClient
is a wrapper in order to handle https & certificate things.
public abstract class GenericTask extends AsyncTask<Object, Object, Document> {
public final static String TAG = "GenericTask";
private WakeLock wakeLock;
private WifiLock wifiLock;
protected HttpPost post;
public String taskId;
public Context ctx;
Object parameter;
public GenericTask(Context ctx, Object parameter) {
this.parameter = parameter;
this.ctx = ctx;
post = null;
initLock(ctx);
lock();
}
private void lock() {
try {
wakeLock.acquire();
wifiLock.acquire();
Log.d(TAG,"LockAcquired");
} catch (Exception e) {
Log.e("WlanSilencer", "Error getting Lock: " + e.getMessage());
}
}
private void unlock() {
Log.e(TAG,"unlock");
if (wakeLock.isHeld())
wakeLock.release();
if (wifiLock.isHeld())
wifiLock.release();
Log.d(TAG,"LockReleased");
}
private void initLock(Context context) {
wifiLock = ((WifiManager) context
.getSystemService(Context.WIFI_SERVICE)).createWifiLock(
WifiManager.WIFI_MODE_FULL_HIGH_PERF, "GenericTaskWifiLock");
wakeLock = ((PowerManager) context
.getSystemService(Context.POWER_SERVICE)).newWakeLock(
PowerManager.FULL_WAKE_LOCK, "GenericTaskWakeLock");
Log.d(TAG,"LockInitiated");
}
public boolean cancelTask(boolean bln) {
if(post!=null)
post.abort();
return super.cancel(bln);
}
public void execute(){
if(Build.VERSION.SDK_INT >= 11){
startNew();
}else{
startOld();
}
}
private void startOld() {
super.execute();
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
private void startNew(){
executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR );
}
@Override
protected void onPostExecute(Document doc) {
unlock();
if(doc==null){
Log.e("GenericTask: " +getClass(),"onPostExecute doc=null");
}
Log.e(TAG,"onPostExecute");
TaskManager.getInstance().returnFromTaskSuccess(doc, getClass(), taskId, parameter);
}
@Override
protected Document doInBackground(Object... params) {
Log.e(TAG,"doInBackground");
try {
return call();
} catch (InvalidKeyException e) {
OtherUtils.printStackTrace(e);
} catch (NoSuchPaddingException e) {
OtherUtils.printStackTrace(e);
} catch (InvalidAlgorithmParameterException e) {
OtherUtils.printStackTrace(e);
} catch (IllegalStateException e) {
OtherUtils.printStackTrace(e);
} catch (NoSuchAlgorithmException e) {
OtherUtils.printStackTrace(e);
} catch (IOException e) {
OtherUtils.printStackTrace(e);
} catch (TransformerException e) {
OtherUtils.printStackTrace(e);
} catch (ParserConfigurationException e) {
OtherUtils.printStackTrace(e);
}
return null;
}
protected abstract String getUrl();
protected abstract Document getRequest();
public int initialSleep() {
return 0;
}
public String getTaskId() {
return taskId;
}
public void setTaskId(String taskId) {
this.taskId = taskId;
}
protected Document call() throws IOException, TransformerException, ParserConfigurationException, InvalidKeyException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalStateException, NoSuchAlgorithmException{
Document doc = getRequest();
String url = getUrl();
Document responseXml = null;
try {
post = HttpUtils.postXml(doc, url, null);
HttpResponse response;
HttpParams httpParams = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParams, 16000);
HttpConnectionParams.setSoTimeout(httpParams, 20000);
post.setParams(httpParams);
response = new MyClient(ctx).client.execute(post);
HttpEntity resEntity = response.getEntity();
responseXml = XmlUtils.entityToXml(resEntity, null);
resEntity.consumeContent();
return responseXml;
} catch (TransformerException e) {
throw e;
} catch (IOException e) {
throw e;
}
}
}
HttpUtils:
public class HttpUtils {
public static HttpPost postXml(Document doc, String url, WrapperAsByteArrayOutputStream baos) throws IOException, TransformerConfigurationException, TransformerException
{
StringWriter xmlAsWriter = new StringWriter();
StreamResult result = new StreamResult(xmlAsWriter);
TransformerFactory.newInstance().newTransformer().transform(new DOMSource(doc), result);
HttpPost post = new HttpPost(url);
InputStreamEntity req;
if ( baos == null ) {
req = new InputStreamEntity(new ByteArrayInputStream(xmlAsWriter.toString().getBytes()), -1);
}
else {
req = new InputStreamEntity(new WrappedInputStream(new ByteArrayInputStream(xmlAsWriter.toString().getBytes()), baos), -1);
}
req.setChunked(true);
post.setEntity(req);
return post;
}
MyClient:
public class MyClient extends DefaultHttpClient { public HttpClient client;
public MyClient(Context ccc) {
super();
KeyStore localTrustStore = null;
try {
localTrustStore = KeyStore.getInstance("BKS");
} catch (KeyStoreException e) {
e.printStackTrace();
}
InputStream in = ccc.getResources().openRawResource(
R.raw.localcert);
try {
localTrustStore.load(in, "local_trust_password".toCharArray());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http", PlainSocketFactory
.getSocketFactory(), 80));
SSLSocketFactory sslSocketFactory = null;
try {
sslSocketFactory = new SSLSocketFactory(localTrustStore);
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (UnrecoverableKeyException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
}
schemeRegistry.register(new Scheme("https", sslSocketFactory, 443));
HttpParams params = new BasicHttpParams();
ClientConnectionManager cm = new ThreadSafeClientConnManager(params,
schemeRegistry);
this.client = new DefaultHttpClient(cm, params);
}
onrecieve of AlarmReciever
public void onReceive(Context context, Intent intent) {
try {
TaskManager.getInstance().sendBatteryStatus();
}
} catch (Exception e) {
Toast.makeText(
context,
"There was an error somewhere, but we still received an alarm",
Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
returnfromtask success simply checks id for thread safety, handles doc and setups new alarm like below:
Calendar cal = Calendar.getInstance();
cal.add(Calendar.SECOND, 30);
Intent intent = new Intent(ctx, AlarmReceiver.class);
PendingIntent sender = PendingIntent.getBroadcast(ctx, 2131225, intent,
PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager am = (AlarmManager) ctx
.getSystemService(Context.ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), sender);
sendBatteryStatus gethers some info to send, and pass it to a task which extends GenericTask and it normally executes new MyAsyncTask(..bla bla).execute();
As soon as you release the wake lock the CPU is allowed to go to sleep and that is most probably what happens. You perform an action using HttpClient
several times, but at some point, after releasing wake lock, the CPU hibernates.
Since you want to execute a code periodically you should use the AlarmManager
service documented here: http://developer.android.com/reference/android/app/AlarmManager.html. The alarm manager service is active even if the phone is asleep. You use it by scheduling a PendingIntent
via one of AlarmManager.set*()
methods. The alarm manager will hold a wake lock for the duration of receivers onReceive()
method but you will most probably need to acquire the WiFi lock.