Move authenticator upgrade to app upgrade time.

This used to run when the app first initializes the service map.

Bug: 9391930
Bug: 9971936
Change-Id: Iebaeb2dc94ef62edb0be0a7d5a008a26c4f5edfb
This commit is contained in:
Yu Ping Hu 2013-07-22 15:26:34 -07:00
parent 64ca2a4529
commit 462da178b1
4 changed files with 105 additions and 88 deletions

View File

@ -401,6 +401,16 @@
android:name=".service.AttachmentDownloadService$Watchdog"
android:enabled="true"/>
<!-- Handles app upgrade. This disables itself after running once. -->
<receiver
android:name=".service.EmailUpgradeBroadcastReceiver"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
</intent-filter>
</receiver>
<receiver
android:name=".service.EmailBroadcastReceiver"
android:enabled="true">

View File

@ -39,6 +39,8 @@ import com.android.emailcommon.provider.EmailContent.AccountColumns;
import com.android.emailcommon.provider.HostAuth;
import com.android.mail.utils.LogUtils;
import java.util.HashMap;
/**
* The service that really handles broadcast intents on a worker thread.
*
@ -64,6 +66,9 @@ public class EmailBroadcastProcessorService extends IntentService {
private static final String ACTION_DEVICE_POLICY_ADMIN = "com.android.email.devicepolicy";
private static final String EXTRA_DEVICE_POLICY_ADMIN = "message_code";
// Action used for EmailUpgradeBroadcastReceiver.
private static final String ACTION_UPGRADE_BROADCAST = "upgrade_broadcast_receiver";
public EmailBroadcastProcessorService() {
// Class name will be the thread name.
super(EmailBroadcastProcessorService.class.getName());
@ -82,6 +87,12 @@ public class EmailBroadcastProcessorService extends IntentService {
context.startService(i);
}
public static void processUpgradeBroadcastIntent(final Context context) {
final Intent i = new Intent(context, EmailBroadcastProcessorService.class);
i.setAction(ACTION_UPGRADE_BROADCAST);
context.startService(i);
}
/**
* Entry point for {@link com.android.email.SecurityPolicy.PolicyAdmin}. These will
* simply callback to {@link
@ -115,9 +126,54 @@ public class EmailBroadcastProcessorService extends IntentService {
} else if (ACTION_DEVICE_POLICY_ADMIN.equals(action)) {
int message = intent.getIntExtra(EXTRA_DEVICE_POLICY_ADMIN, -1);
SecurityPolicy.onDeviceAdminReceiverMessage(this, message);
} else if (ACTION_UPGRADE_BROADCAST.equals(action)) {
onAppUpgrade();
}
}
private void disableComponent(final Class<?> klass) {
getPackageManager().setComponentEnabledSetting(new ComponentName(this, klass),
PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
}
private void updateAccountManagerAccountsOfType(final String amAccountType,
final HashMap<String, String> protocolMap) {
final android.accounts.Account[] amAccounts =
AccountManager.get(this).getAccountsByType(amAccountType);
for (android.accounts.Account amAccount: amAccounts) {
EmailServiceUtils.updateAccountManagerType(this, amAccount, protocolMap);
}
}
private void onAppUpgrade() {
// TODO: Only do this for Email2Google.
// When upgrading to Email2Google, we need to essentially rename the account manager
// type for all existing accounts, so we add new ones and delete the old.
// We specify the translations in this map. We map from old protocol name to new protocol
// name, and from protocol name + "_type" to new account manager type name. (Email1 did
// not use distinct account manager types for POP and IMAP, but Email2 does, hence this
// weird mapping.)
final HashMap<String, String> protocolMap = new HashMap();
protocolMap.put("imap", getString(R.string.protocol_legacy_imap));
protocolMap.put("pop3", getString(R.string.protocol_pop3));
protocolMap.put("imap_type", getString(R.string.account_manager_type_legacy_imap));
protocolMap.put("pop3_type", getString(R.string.account_manager_type_pop3));
updateAccountManagerAccountsOfType("com.android.email", protocolMap);
protocolMap.clear();
protocolMap.put("eas", getString(R.string.protocol_eas));
protocolMap.put("eas_type", getString(R.string.account_manager_type_exchange));
updateAccountManagerAccountsOfType("com.android.exchange", protocolMap);
// Disable the old authenticators.
disableComponent(LegacyEmailAuthenticatorService.class);
disableComponent(LegacyEasAuthenticatorService.class);
// Disable the upgrade broadcast receiver now that we're fully upgraded.
disableComponent(EmailUpgradeBroadcastReceiver.class);
}
/**
* Handles {@link Intent#ACTION_BOOT_COMPLETED}. Called on a worker thread.
*/

View File

@ -21,20 +21,17 @@ import android.accounts.AccountManagerFuture;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.app.Service;
import android.content.ComponentName;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.database.Cursor;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
@ -57,13 +54,14 @@ import com.android.emailcommon.service.IEmailServiceCallback;
import com.android.emailcommon.service.SearchParams;
import com.android.emailcommon.service.SyncWindow;
import com.android.mail.utils.LogUtils;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -253,47 +251,8 @@ public class EmailServiceUtils {
}
}
private static class UpdateAccountManagerTask extends AsyncTask<Void, Void, Void> {
private final Context mContext;
private final android.accounts.Account mAccount;
private final EmailServiceInfo mOldInfo;
private final EmailServiceInfo mNewInfo;
public UpdateAccountManagerTask(Context context, android.accounts.Account amAccount,
EmailServiceInfo oldInfo, EmailServiceInfo newInfo) {
super();
mContext = context;
mAccount = amAccount;
mOldInfo = oldInfo;
mNewInfo = newInfo;
}
@Override
protected Void doInBackground(Void... params) {
updateAccountManagerType(mContext, mAccount, mOldInfo, mNewInfo);
return null;
}
}
private static class DisableComponentsTask extends AsyncTask<Void, Void, Void> {
private final Context mContext;
public DisableComponentsTask(Context context) {
super();
mContext = context;
}
@Override
protected Void doInBackground(Void... params) {
disableComponent(mContext, LegacyEmailAuthenticatorService.class);
disableComponent(mContext, LegacyEasAuthenticatorService.class);
return null;
}
}
private static void updateAccountManagerType(Context context,
android.accounts.Account amAccount, EmailServiceInfo oldInfo,
EmailServiceInfo newInfo) {
public static void updateAccountManagerType(Context context,
android.accounts.Account amAccount, final HashMap<String, String> protocolMap) {
final ContentResolver resolver = context.getContentResolver();
final Cursor c = resolver.query(Account.CONTENT_URI, Account.CONTENT_PROJECTION,
AccountColumns.EMAIL_ADDRESS + "=?", new String[] { amAccount.name }, null);
@ -310,14 +269,14 @@ public class EmailServiceUtils {
return;
}
// Make sure this email address is using the expected protocol; our query to
// AccountManager doesn't know which protocol was being used (com.android.email
// was used for both pop3 and imap
if (!hostAuth.mProtocol.equals(oldInfo.protocol)) {
final String newProtocol = protocolMap.get(hostAuth.mProtocol);
if (newProtocol == null) {
// This account doesn't need updating.
return;
}
LogUtils.w(Logging.LOG_TAG, "Converting " + amAccount.name + " to "
+ newInfo.protocol);
+ newProtocol);
final ContentValues accountValues = new ContentValues();
int oldFlags = account.mFlags;
@ -331,7 +290,7 @@ public class EmailServiceUtils {
// Change the HostAuth to reference the new protocol; this has to be done before
// trying to create the AccountManager account (below)
final ContentValues hostValues = new ContentValues();
hostValues.put(HostAuth.PROTOCOL, newInfo.protocol);
hostValues.put(HostAuth.PROTOCOL, newProtocol);
resolver.update(ContentUris.withAppendedId(HostAuth.CONTENT_URI, hostAuth.mId),
hostValues, null, null);
LogUtils.w(Logging.LOG_TAG, "Updated HostAuths");
@ -401,14 +360,17 @@ public class EmailServiceUtils {
LogUtils.w(Logging.LOG_TAG, "Deleted old AccountManager account");
// Restore sync keys for contacts/calendar
if (calendarSyncKey != null && calendarSyncKey.length != 0) {
// TODO: Clean up how we determine the type.
final String accountType = protocolMap.get(hostAuth.mProtocol + "_type");
if (accountType != null &&
calendarSyncKey != null && calendarSyncKey.length != 0) {
client = context.getContentResolver()
.acquireContentProviderClient(CalendarContract.CONTENT_URI);
try {
SyncStateContract.Helpers.set(client,
asCalendarSyncAdapter(SyncState.CONTENT_URI, amName,
newInfo.accountType),
new android.accounts.Account(amName, newInfo.accountType),
accountType),
new android.accounts.Account(amName, accountType),
calendarSyncKey);
LogUtils.w(Logging.LOG_TAG, "Set calendar key...");
} catch (RemoteException e) {
@ -417,13 +379,14 @@ public class EmailServiceUtils {
client.release();
}
}
if (contactsSyncKey != null && contactsSyncKey.length != 0) {
if (accountType != null &&
contactsSyncKey != null && contactsSyncKey.length != 0) {
client = context.getContentResolver()
.acquireContentProviderClient(ContactsContract.AUTHORITY_URI);
try {
SyncStateContract.Helpers.set(client,
ContactsContract.SyncState.CONTENT_URI,
new android.accounts.Account(amName, newInfo.accountType),
new android.accounts.Account(amName, accountType),
contactsSyncKey);
LogUtils.w(Logging.LOG_TAG, "Set contacts key...");
} catch (RemoteException e) {
@ -431,17 +394,6 @@ public class EmailServiceUtils {
}
}
if (oldInfo.requiresAccountUpdate) {
EmailServiceProxy service =
EmailServiceUtils.getServiceFromInfo(context, null, newInfo);
try {
service.serviceUpdated(amAccount.name);
LogUtils.w(Logging.LOG_TAG, "Updated account settings");
} catch (RemoteException e) {
// Old settings won't hurt anyone
}
}
// That's all folks!
LogUtils.w(Logging.LOG_TAG, "Account update completed.");
} finally {
@ -456,14 +408,6 @@ public class EmailServiceUtils {
}
}
private static void disableComponent(Context context, Class<?> klass) {
LogUtils.w(Logging.LOG_TAG, "Disabling legacy authenticator " + klass.getSimpleName());
final ComponentName c = new ComponentName(context, klass);
context.getPackageManager().setComponentEnabledSetting(c,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
}
/**
* Parse services.xml file to find our available email services
*/
@ -481,7 +425,9 @@ public class EmailServiceUtils {
final TypedArray ta = res.obtainAttributes(xml, R.styleable.EmailServiceInfo);
info.protocol = ta.getString(R.styleable.EmailServiceInfo_protocol);
info.accountType = ta.getString(R.styleable.EmailServiceInfo_accountType);
// Handle upgrade of one protocol to another (e.g. imap to imap2)
// Protocol upgrades are handled by the upgrade broadcast receiver.
// However, we still create the entry from the old protocol to the new type.
// TODO: Remove the need for this entry.
final String newProtocol =
ta.getString(R.styleable.EmailServiceInfo_replaceWith);
@ -492,16 +438,6 @@ public class EmailServiceUtils {
"Replacement service not found: " + newProtocol);
}
sServiceMap.put(info.protocol, newInfo);
info.requiresAccountUpdate = ta.getBoolean(
R.styleable.EmailServiceInfo_requiresAccountUpdate, false);
final AccountManager am = AccountManager.get(context);
final android.accounts.Account[] amAccounts =
am.getAccountsByType(info.accountType);
for (android.accounts.Account amAccount: amAccounts) {
new UpdateAccountManagerTask(context, amAccount, info, newInfo)
.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
}
continue;
}
info.name = ta.getString(R.styleable.EmailServiceInfo_name);
@ -569,8 +505,6 @@ public class EmailServiceUtils {
sServiceMap.put(info.protocol, info);
}
}
// Disable our legacy components
new DisableComponentsTask(context).executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
} catch (XmlPullParserException e) {
// ignore
} catch (IOException e) {

View File

@ -0,0 +1,17 @@
package com.android.email.service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
/**
* {@link BroadcastReceiver} for app upgrade. This listens to package replacement (for unbundled
* upgrade) and reboot (for OTA upgrade). The code in the {@link EmailBroadcastProcessorService}
* disables this receiver after it runs.
*/
public class EmailUpgradeBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(final Context context, final Intent intent) {
EmailBroadcastProcessorService.processUpgradeBroadcastIntent(context);
}
}