Sanity check for system service restarts.

This commit is contained in:
Moxie Marlinspike 2012-08-05 12:41:31 -07:00
parent 2f6642a234
commit 8520cb558a
3 changed files with 50 additions and 45 deletions

View File

@ -34,6 +34,8 @@ public class ApplicationMigrationService extends Service
@Override @Override
public void onStart(Intent intent, int startId) { public void onStart(Intent intent, int startId) {
if (intent == null) return;
if (intent.getAction() != null && intent.getAction().equals(MIGRATE_DATABASE)) { if (intent.getAction() != null && intent.getAction().equals(MIGRATE_DATABASE)) {
handleDatabaseMigration((MasterSecret)intent.getParcelableExtra("master_secret")); handleDatabaseMigration((MasterSecret)intent.getParcelableExtra("master_secret"));
} }

View File

@ -75,6 +75,8 @@ public class KeyCachingService extends Service {
@Override @Override
public void onStart(Intent intent, int startId) { public void onStart(Intent intent, int startId) {
if (intent == null) return;
if (intent.getAction() != null && intent.getAction().equals(CLEAR_KEY_ACTION)) if (intent.getAction() != null && intent.getAction().equals(CLEAR_KEY_ACTION))
handleClearKey(); handleClearKey();
else if (intent.getAction() != null && intent.getAction().equals(ACTIVITY_START_EVENT)) else if (intent.getAction() != null && intent.getAction().equals(ACTIVITY_START_EVENT))

View File

@ -1,6 +1,6 @@
/** /**
* Copyright (C) 2011 Whisper Systems * Copyright (C) 2011 Whisper Systems
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
@ -10,20 +10,12 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.thoughtcrime.securesms.service; package org.thoughtcrime.securesms.service;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.CanonicalSessionMigrator;
import org.thoughtcrime.securesms.util.WorkerThread;
import android.app.Service; import android.app.Service;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.ComponentName; import android.content.ComponentName;
@ -33,14 +25,21 @@ import android.content.IntentFilter;
import android.content.ServiceConnection; import android.content.ServiceConnection;
import android.os.Handler; import android.os.Handler;
import android.os.IBinder; import android.os.IBinder;
import android.os.Looper;
import android.os.Message; import android.os.Message;
import android.util.Log; import android.util.Log;
import android.widget.Toast; import android.widget.Toast;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.CanonicalSessionMigrator;
import org.thoughtcrime.securesms.util.WorkerThread;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
/** /**
* Services that handles sending/receiving of SMS/MMS. * Services that handles sending/receiving of SMS/MMS.
* *
* @author Moxie Marlinspike * @author Moxie Marlinspike
*/ */
@ -54,27 +53,27 @@ public class SendReceiveService extends Service {
public static final String RECEIVE_MMS_ACTION = "org.thoughtcrime.securesms.SendReceiveService.RECEIVE_MMS_ACTION"; public static final String RECEIVE_MMS_ACTION = "org.thoughtcrime.securesms.SendReceiveService.RECEIVE_MMS_ACTION";
public static final String DOWNLOAD_MMS_ACTION = "org.thoughtcrime.securesms.SendReceiveService.DOWNLOAD_MMS_ACTION"; public static final String DOWNLOAD_MMS_ACTION = "org.thoughtcrime.securesms.SendReceiveService.DOWNLOAD_MMS_ACTION";
public static final String DOWNLOAD_MMS_CONNECTIVITY_ACTION = "org.thoughtcrime.securesms.SendReceiveService.DOWNLOAD_MMS_CONNECTIVITY_ACTION"; public static final String DOWNLOAD_MMS_CONNECTIVITY_ACTION = "org.thoughtcrime.securesms.SendReceiveService.DOWNLOAD_MMS_CONNECTIVITY_ACTION";
private static final int SEND_SMS = 0; private static final int SEND_SMS = 0;
private static final int RECEIVE_SMS = 1; private static final int RECEIVE_SMS = 1;
private static final int SEND_MMS = 2; private static final int SEND_MMS = 2;
private static final int RECEIVE_MMS = 3; private static final int RECEIVE_MMS = 3;
private static final int DOWNLOAD_MMS = 4; private static final int DOWNLOAD_MMS = 4;
private ToastHandler toastHandler; private ToastHandler toastHandler;
private SmsReceiver smsReceiver; private SmsReceiver smsReceiver;
private SmsSender smsSender; private SmsSender smsSender;
private MmsReceiver mmsReceiver; private MmsReceiver mmsReceiver;
private MmsSender mmsSender; private MmsSender mmsSender;
private MmsDownloader mmsDownloader; private MmsDownloader mmsDownloader;
private MasterSecret masterSecret; private MasterSecret masterSecret;
private NewKeyReceiver receiver; private NewKeyReceiver receiver;
private List<Runnable> workQueue; private List<Runnable> workQueue;
private List<Runnable> pendingSecretList; private List<Runnable> pendingSecretList;
private Thread workerThread; private Thread workerThread;
@Override @Override
public void onCreate() { public void onCreate() {
initializeHandlers(); initializeHandlers();
@ -83,9 +82,11 @@ public class SendReceiveService extends Service {
initializeWorkQueue(); initializeWorkQueue();
initializeMasterSecret(); initializeMasterSecret();
} }
@Override @Override
public void onStart(Intent intent, int startId) { public void onStart(Intent intent, int startId) {
if (intent == null) return;
if (intent.getAction().equals(SEND_SMS_ACTION)) if (intent.getAction().equals(SEND_SMS_ACTION))
scheduleSecretRequiredIntent(SEND_SMS, intent); scheduleSecretRequiredIntent(SEND_SMS, intent);
else if (intent.getAction().equals(RECEIVE_SMS_ACTION)) else if (intent.getAction().equals(RECEIVE_SMS_ACTION))
@ -98,7 +99,7 @@ public class SendReceiveService extends Service {
scheduleIntent(RECEIVE_MMS, intent); scheduleIntent(RECEIVE_MMS, intent);
else if (intent.getAction().equals(DOWNLOAD_MMS_ACTION) || intent.getAction().equals(DOWNLOAD_MMS_CONNECTIVITY_ACTION)) else if (intent.getAction().equals(DOWNLOAD_MMS_ACTION) || intent.getAction().equals(DOWNLOAD_MMS_CONNECTIVITY_ACTION))
scheduleSecretRequiredIntent(DOWNLOAD_MMS, intent); scheduleSecretRequiredIntent(DOWNLOAD_MMS, intent);
else else
Log.w("SendReceiveService", "Received intent with unknown action: " + intent.getAction()); Log.w("SendReceiveService", "Received intent with unknown action: " + intent.getAction());
} }
@ -106,11 +107,11 @@ public class SendReceiveService extends Service {
public IBinder onBind(Intent intent) { public IBinder onBind(Intent intent) {
return null; return null;
} }
private void initializeHandlers() { private void initializeHandlers() {
toastHandler = new ToastHandler(); toastHandler = new ToastHandler();
} }
private void initializeProcessors() { private void initializeProcessors() {
smsReceiver = new SmsReceiver(this); smsReceiver = new SmsReceiver(this);
smsSender = new SmsSender(this); smsSender = new SmsSender(this);
@ -118,15 +119,15 @@ public class SendReceiveService extends Service {
mmsSender = new MmsSender(this); mmsSender = new MmsSender(this);
mmsDownloader = new MmsDownloader(this, toastHandler); mmsDownloader = new MmsDownloader(this, toastHandler);
} }
private void initializeWorkQueue() { private void initializeWorkQueue() {
pendingSecretList = new LinkedList<Runnable>(); pendingSecretList = new LinkedList<Runnable>();
workQueue = new LinkedList<Runnable>(); workQueue = new LinkedList<Runnable>();
workerThread = new WorkerThread(workQueue, "SendReceveService-WorkerThread"); workerThread = new WorkerThread(workQueue, "SendReceveService-WorkerThread");
workerThread.start(); workerThread.start();
} }
private void initializeMasterSecret() { private void initializeMasterSecret() {
receiver = new NewKeyReceiver(); receiver = new NewKeyReceiver();
IntentFilter filter = new IntentFilter(KeyCachingService.NEW_KEY_EVENT); IntentFilter filter = new IntentFilter(KeyCachingService.NEW_KEY_EVENT);
@ -135,18 +136,18 @@ public class SendReceiveService extends Service {
Intent bindIntent = new Intent(this, KeyCachingService.class); Intent bindIntent = new Intent(this, KeyCachingService.class);
bindService(bindIntent, serviceConnection, Context.BIND_AUTO_CREATE); bindService(bindIntent, serviceConnection, Context.BIND_AUTO_CREATE);
} }
private void initializeWithMasterSecret(MasterSecret masterSecret) { private void initializeWithMasterSecret(MasterSecret masterSecret) {
Log.w("SendReceiveService", "SendReceive service got master secret: " + masterSecret); Log.w("SendReceiveService", "SendReceive service got master secret: " + masterSecret);
if (masterSecret != null) { if (masterSecret != null) {
synchronized (workQueue) { synchronized (workQueue) {
this.masterSecret = masterSecret; this.masterSecret = masterSecret;
Iterator<Runnable> iterator = pendingSecretList.iterator(); Iterator<Runnable> iterator = pendingSecretList.iterator();
while (iterator.hasNext()) while (iterator.hasNext())
workQueue.add(iterator.next()); workQueue.add(iterator.next());
workQueue.notifyAll(); workQueue.notifyAll();
} }
} }
@ -155,50 +156,50 @@ public class SendReceiveService extends Service {
private void initializeAddressCanonicalization() { private void initializeAddressCanonicalization() {
CanonicalSessionMigrator.migrateSessions(this); CanonicalSessionMigrator.migrateSessions(this);
} }
private void scheduleIntent(int what, Intent intent) { private void scheduleIntent(int what, Intent intent) {
Runnable work = new SendReceiveWorkItem(intent, what); Runnable work = new SendReceiveWorkItem(intent, what);
synchronized (workQueue) { synchronized (workQueue) {
workQueue.add(work); workQueue.add(work);
workQueue.notifyAll(); workQueue.notifyAll();
} }
} }
private void scheduleSecretRequiredIntent(int what, Intent intent) { private void scheduleSecretRequiredIntent(int what, Intent intent) {
Runnable work = new SendReceiveWorkItem(intent, what); Runnable work = new SendReceiveWorkItem(intent, what);
synchronized (workQueue) { synchronized (workQueue) {
if (masterSecret != null) { if (masterSecret != null) {
workQueue.add(work); workQueue.add(work);
workQueue.notifyAll(); workQueue.notifyAll();
} else { } else {
pendingSecretList.add(work); pendingSecretList.add(work);
} }
} }
} }
private class SendReceiveWorkItem implements Runnable { private class SendReceiveWorkItem implements Runnable {
private final Intent intent; private final Intent intent;
private final int what; private final int what;
public SendReceiveWorkItem(Intent intent, int what) { public SendReceiveWorkItem(Intent intent, int what) {
this.intent = intent; this.intent = intent;
this.what = what; this.what = what;
} }
public void run() { public void run() {
switch (what) { switch (what) {
case RECEIVE_SMS: smsReceiver.process(masterSecret, intent); return; case RECEIVE_SMS: smsReceiver.process(masterSecret, intent); return;
case SEND_SMS: smsSender.process(masterSecret, intent); return; case SEND_SMS: smsSender.process(masterSecret, intent); return;
case RECEIVE_MMS: mmsReceiver.process(masterSecret, intent); return; case RECEIVE_MMS: mmsReceiver.process(masterSecret, intent); return;
case SEND_MMS: mmsSender.process(masterSecret, intent); return; case SEND_MMS: mmsSender.process(masterSecret, intent); return;
case DOWNLOAD_MMS: mmsDownloader.process(masterSecret, intent); return; case DOWNLOAD_MMS: mmsDownloader.process(masterSecret, intent); return;
} }
} }
} }
public class ToastHandler extends Handler { public class ToastHandler extends Handler {
public void makeToast(String toast) { public void makeToast(String toast) {
Message message = this.obtainMessage(); Message message = this.obtainMessage();
@ -218,12 +219,12 @@ public class SendReceiveService extends Service {
initializeWithMasterSecret(masterSecret); initializeWithMasterSecret(masterSecret);
SendReceiveService.this.unbindService(this); SendReceiveService.this.unbindService(this);
} }
public void onServiceDisconnected(ComponentName name) {} public void onServiceDisconnected(ComponentName name) {}
}; };
private class NewKeyReceiver extends BroadcastReceiver { private class NewKeyReceiver extends BroadcastReceiver {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
@ -231,5 +232,5 @@ public class SendReceiveService extends Service {
initializeWithMasterSecret((MasterSecret)intent.getParcelableExtra("master_secret")); initializeWithMasterSecret((MasterSecret)intent.getParcelableExtra("master_secret"));
} }
}; };
} }