/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.gecko.fxa.receivers; import android.app.IntentService; import android.content.Context; import android.content.Intent; import org.mozilla.gecko.background.common.log.Logger; import org.mozilla.gecko.background.fxa.oauth.FxAccountAbstractClient; import org.mozilla.gecko.background.fxa.oauth.FxAccountAbstractClientException.FxAccountAbstractClientRemoteException; import org.mozilla.gecko.background.fxa.oauth.FxAccountOAuthClient10; import org.mozilla.gecko.fxa.FxAccountConstants; import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount; import org.mozilla.gecko.fxa.sync.FxAccountNotificationManager; import org.mozilla.gecko.fxa.sync.FxAccountSyncAdapter; import org.mozilla.gecko.sync.repositories.android.ClientsDatabase; import org.mozilla.gecko.sync.repositories.android.FennecTabsRepository; import java.util.concurrent.Executor; /** * A background service to clean up after a Firefox Account is deleted. *
* Note that we specifically handle deleting the pickle file using a Service and a
* BroadcastReceiver, rather than a background thread, to allow channels sharing a Firefox account
* to delete their respective pickle files (since, if one remains, the account will be restored
* when that channel is used).
*/
public class FxAccountDeletedService extends IntentService {
public static final String LOG_TAG = FxAccountDeletedService.class.getSimpleName();
public FxAccountDeletedService() {
super(LOG_TAG);
}
@Override
protected void onHandleIntent(final Intent intent) {
// We have an in-memory accounts cache which we use for a variety of tasks; it needs to be cleared.
// It should be fine to invalidate it before doing anything else, as the tasks below do not rely
// on this data.
AndroidFxAccount.invalidateCaches();
// Intent can, in theory, be null. Bug 1025937.
if (intent == null) {
Logger.debug(LOG_TAG, "Short-circuiting on null intent.");
return;
}
final Context context = this;
long intentVersion = intent.getLongExtra(
FxAccountConstants.ACCOUNT_DELETED_INTENT_VERSION_KEY, 0);
long expectedVersion = FxAccountConstants.ACCOUNT_DELETED_INTENT_VERSION;
if (intentVersion != expectedVersion) {
Logger.warn(LOG_TAG, "Intent malformed: version " + intentVersion + " given but " +
"version " + expectedVersion + "expected. Not cleaning up after deleted Account.");
return;
}
// Android Account name, not Sync encoded account name.
final String accountName = intent.getStringExtra(
FxAccountConstants.ACCOUNT_DELETED_INTENT_ACCOUNT_KEY);
if (accountName == null) {
Logger.warn(LOG_TAG, "Intent malformed: no account name given. Not cleaning up after " +
"deleted Account.");
return;
}
// Fire up gecko and unsubscribe push
final Intent geckoIntent = new Intent();
geckoIntent.setAction("create-services");
geckoIntent.setClassName(context, "org.mozilla.gecko.GeckoService");
geckoIntent.putExtra("category", "android-push-service");
geckoIntent.putExtra("data", "android-fxa-unsubscribe");
final AndroidFxAccount fxAccount = AndroidFxAccount.fromContext(context);
geckoIntent.putExtra("org.mozilla.gecko.intent.PROFILE_NAME",
intent.getStringExtra(FxAccountConstants.ACCOUNT_DELETED_INTENT_ACCOUNT_PROFILE));
context.startService(geckoIntent);
// Delete client database and non-local tabs.
Logger.info(LOG_TAG, "Deleting the entire Fennec clients database and non-local tabs");
FennecTabsRepository.deleteNonLocalClientsAndTabs(context);
// Clear Firefox Sync client tables.
try {
Logger.info(LOG_TAG, "Deleting the Firefox Sync clients database.");
ClientsDatabase db = null;
try {
db = new ClientsDatabase(context);
db.wipeClientsTable();
db.wipeCommandsTable();
} finally {
if (db != null) {
db.close();
}
}
} catch (Exception e) {
Logger.warn(LOG_TAG, "Got exception deleting the Firefox Sync clients database; ignoring.", e);
}
// Remove any displayed notifications.
new FxAccountNotificationManager(FxAccountSyncAdapter.NOTIFICATION_ID).clear(context);
// Bug 1147275: Delete cached oauth tokens. There's no way to query all
// oauth tokens from Android, so this is tricky to do comprehensively. We
// can query, individually, for specific oauth tokens to delete, however.
final String oauthServerURI = intent.getStringExtra(FxAccountConstants.ACCOUNT_OAUTH_SERVICE_ENDPOINT_KEY);
final String[] tokens = intent.getStringArrayExtra(FxAccountConstants.ACCOUNT_DELETED_INTENT_ACCOUNT_AUTH_TOKENS);
if (oauthServerURI != null && tokens != null) {
final Executor directExecutor = new Executor() {
@Override
public void execute(Runnable runnable) {
runnable.run();
}
};
final FxAccountOAuthClient10 oauthClient = new FxAccountOAuthClient10(oauthServerURI, directExecutor);
for (String token : tokens) {
if (token == null) {
Logger.error(LOG_TAG, "Cached OAuth token is null; should never happen. Ignoring.");
continue;
}
try {
oauthClient.deleteToken(token, new FxAccountAbstractClient.RequestDelegate