Remove disk access from DeviceAdminReceiver callbacks
* DeviceAdminReceiver is actually a BroadcastReceiver, must follow guidelines to prevent ANR or early process kill. * Remove all uses of AsyncTask from DeviceAdminReceiver * Pass all calls through EmailBroadcastProcessorService * Minor restructuring of EmailBroadcastProcessorService to support this use. Change-Id: Ic6257ea5eff1bd466a736e0f93cb89b1cf8aa73e
This commit is contained in:
parent
5498296287
commit
a2269e84c6
|
@ -20,6 +20,7 @@ import com.android.email.activity.setup.AccountSecurity;
|
|||
import com.android.email.provider.EmailContent;
|
||||
import com.android.email.provider.EmailContent.Account;
|
||||
import com.android.email.provider.EmailContent.AccountColumns;
|
||||
import com.android.email.service.EmailBroadcastProcessorService;
|
||||
|
||||
import android.app.admin.DeviceAdminInfo;
|
||||
import android.app.admin.DeviceAdminReceiver;
|
||||
|
@ -58,12 +59,18 @@ public class SecurityPolicy {
|
|||
private static final int ACCOUNT_SECURITY_COLUMN_ID = 0;
|
||||
private static final int ACCOUNT_SECURITY_COLUMN_FLAGS = 1;
|
||||
|
||||
// Messages used for DevicePolicyManager callbacks
|
||||
private static final int DEVICE_ADMIN_MESSAGE_ENABLED = 1;
|
||||
private static final int DEVICE_ADMIN_MESSAGE_DISABLED = 2;
|
||||
private static final int DEVICE_ADMIN_MESSAGE_PASSWORD_CHANGED = 3;
|
||||
private static final int DEVICE_ADMIN_MESSAGE_PASSWORD_EXPIRING = 4;
|
||||
|
||||
/**
|
||||
* Get the security policy instance
|
||||
*/
|
||||
public synchronized static SecurityPolicy getInstance(Context context) {
|
||||
if (sInstance == null) {
|
||||
sInstance = new SecurityPolicy(context);
|
||||
sInstance = new SecurityPolicy(context.getApplicationContext());
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
|
@ -751,28 +758,14 @@ public class SecurityPolicy {
|
|||
|
||||
/**
|
||||
* Internal handler for enabled->disabled transitions. Deletes all secured accounts.
|
||||
* Must call from worker thread, not on UI thread.
|
||||
*/
|
||||
/*package*/ void onAdminEnabled(boolean isEnabled) {
|
||||
if (!isEnabled) {
|
||||
Utility.runAsync(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
deleteSecuredAccounts(mContext);
|
||||
}});
|
||||
deleteSecuredAccounts(mContext);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal handler for device password expirations.
|
||||
*/
|
||||
private void onPasswordExpiring() {
|
||||
Utility.runAsync(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
onPasswordExpiringSync(mContext);
|
||||
}});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle password expiration - if any accounts appear to have triggered this, put up
|
||||
* warnings, or even shut them down.
|
||||
|
@ -783,7 +776,7 @@ public class SecurityPolicy {
|
|||
* the expiration. In other words, all accounts (that require expiration) will run/stop
|
||||
* based on the requirements of the account with the shortest interval.
|
||||
*/
|
||||
/* package */ void onPasswordExpiringSync(Context context) {
|
||||
private void onPasswordExpiring(Context context) {
|
||||
// 1. Do we have any accounts that matter here?
|
||||
long nextExpiringAccountId = findShortestExpiration(context);
|
||||
|
||||
|
@ -895,9 +888,40 @@ public class SecurityPolicy {
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback from EmailBroadcastProcessorService. This provides the workers for the
|
||||
* DeviceAdminReceiver calls. These should perform the work directly and not use async
|
||||
* threads for completion.
|
||||
*/
|
||||
public static void onDeviceAdminReceiverMessage(Context context, int message) {
|
||||
SecurityPolicy instance = SecurityPolicy.getInstance(context);
|
||||
switch (message) {
|
||||
case DEVICE_ADMIN_MESSAGE_ENABLED:
|
||||
instance.onAdminEnabled(true);
|
||||
break;
|
||||
case DEVICE_ADMIN_MESSAGE_DISABLED:
|
||||
instance.onAdminEnabled(false);
|
||||
break;
|
||||
case DEVICE_ADMIN_MESSAGE_PASSWORD_CHANGED:
|
||||
// TODO make a small helper for this
|
||||
// Clear security holds (if any)
|
||||
Account.clearSecurityHoldOnAllAccounts(context);
|
||||
// Cancel any active notifications (if any are posted)
|
||||
NotificationController nc = NotificationController.getInstance(context);
|
||||
nc.cancelNotification(NotificationController.NOTIFICATION_ID_PASSWORD_EXPIRING);
|
||||
nc.cancelNotification(NotificationController.NOTIFICATION_ID_PASSWORD_EXPIRED);
|
||||
break;
|
||||
case DEVICE_ADMIN_MESSAGE_PASSWORD_EXPIRING:
|
||||
instance.onPasswordExpiring(instance.mContext);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Device Policy administrator. This is primarily a listener for device state changes.
|
||||
* Note: This is instantiated by incoming messages.
|
||||
* Note: This is actually a BroadcastReceiver and must remain within the guidelines required
|
||||
* for proper behavior, including avoidance of ANRs.
|
||||
* Note: We do not implement onPasswordFailed() because the default behavior of the
|
||||
* DevicePolicyManager - complete local wipe after 'n' failures - is sufficient.
|
||||
*/
|
||||
|
@ -908,7 +932,8 @@ public class SecurityPolicy {
|
|||
*/
|
||||
@Override
|
||||
public void onEnabled(Context context, Intent intent) {
|
||||
SecurityPolicy.getInstance(context).onAdminEnabled(true);
|
||||
EmailBroadcastProcessorService.processDevicePolicyMessage(context,
|
||||
DEVICE_ADMIN_MESSAGE_ENABLED);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -916,7 +941,8 @@ public class SecurityPolicy {
|
|||
*/
|
||||
@Override
|
||||
public void onDisabled(Context context, Intent intent) {
|
||||
SecurityPolicy.getInstance(context).onAdminEnabled(false);
|
||||
EmailBroadcastProcessorService.processDevicePolicyMessage(context,
|
||||
DEVICE_ADMIN_MESSAGE_DISABLED);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -933,12 +959,8 @@ public class SecurityPolicy {
|
|||
*/
|
||||
@Override
|
||||
public void onPasswordChanged(Context context, Intent intent) {
|
||||
// Clear security holds (if any)
|
||||
Account.clearSecurityHoldOnAllAccounts(context);
|
||||
// Cancel any active notifications (if any are posted)
|
||||
NotificationController nc = NotificationController.getInstance(context);
|
||||
nc.cancelNotification(NotificationController.NOTIFICATION_ID_PASSWORD_EXPIRING);
|
||||
nc.cancelNotification(NotificationController.NOTIFICATION_ID_PASSWORD_EXPIRED);
|
||||
EmailBroadcastProcessorService.processDevicePolicyMessage(context,
|
||||
DEVICE_ADMIN_MESSAGE_PASSWORD_CHANGED);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -946,7 +968,8 @@ public class SecurityPolicy {
|
|||
*/
|
||||
@Override
|
||||
public void onPasswordExpiring(Context context, Intent intent) {
|
||||
SecurityPolicy.getInstance(context).onPasswordExpiring();
|
||||
EmailBroadcastProcessorService.processDevicePolicyMessage(context,
|
||||
DEVICE_ADMIN_MESSAGE_PASSWORD_EXPIRING);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,8 +19,8 @@ package com.android.email.service;
|
|||
import com.android.email.Email;
|
||||
import com.android.email.ExchangeUtils;
|
||||
import com.android.email.Preferences;
|
||||
import com.android.email.SecurityPolicy;
|
||||
import com.android.email.VendorPolicyLoader;
|
||||
import com.android.email.activity.ActivityHelper;
|
||||
import com.android.email.activity.setup.AccountSettingsXL;
|
||||
|
||||
import android.app.IntentService;
|
||||
|
@ -28,7 +28,6 @@ import android.content.ComponentName;
|
|||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.util.Config;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
|
@ -40,12 +39,22 @@ import android.util.Log;
|
|||
* <li>Even if it does, the Intent that have started it will be re-delivered by the system,
|
||||
* and we can start the process again. (Using {@link #setIntentRedelivery}).
|
||||
* </ul>
|
||||
*
|
||||
* This also handles the DeviceAdminReceiver in SecurityPolicy, because it is also
|
||||
* a BroadcastReceiver and requires the same processing semantics.
|
||||
*/
|
||||
public class EmailBroadcastProcessorService extends IntentService {
|
||||
// Action used for BroadcastReceiver entry point
|
||||
private static final String ACTION_BROADCAST = "broadcast_receiver";
|
||||
|
||||
// Dialing "*#*#36245#*#*" to open the debug screen. "36245" = "email"
|
||||
private static final String SECRET_CODE_ACTION = "android.provider.Telephony.SECRET_CODE";
|
||||
private static final String ACTION_SECRET_CODE = "android.provider.Telephony.SECRET_CODE";
|
||||
private static final String SECRET_CODE_HOST_DEBUG_SCREEN = "36245";
|
||||
|
||||
// This is a helper used to process DeviceAdminReceiver messages
|
||||
private static final String ACTION_DEVICE_POLICY_ADMIN = "com.android.email.devicepolicy";
|
||||
private static final String EXTRA_DEVICE_POLICY_ADMIN = "message_code";
|
||||
|
||||
public EmailBroadcastProcessorService() {
|
||||
// Class name will be the thread name.
|
||||
super(EmailBroadcastProcessorService.class.getName());
|
||||
|
@ -59,30 +68,50 @@ public class EmailBroadcastProcessorService extends IntentService {
|
|||
*/
|
||||
public static void processBroadcastIntent(Context context, Intent broadcastIntent) {
|
||||
Intent i = new Intent(context, EmailBroadcastProcessorService.class);
|
||||
i.setAction(ACTION_BROADCAST);
|
||||
i.putExtra(Intent.EXTRA_INTENT, broadcastIntent);
|
||||
context.startService(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Entry point for {@link com.android.email.SecurityPolicy.PolicyAdmin}. These will
|
||||
* simply callback to {@link
|
||||
* com.android.email.SecurityPolicy#onDeviceAdminReceiverMessage(Context, int)}.
|
||||
*/
|
||||
public static void processDevicePolicyMessage(Context context, int message) {
|
||||
Intent i = new Intent(context, EmailBroadcastProcessorService.class);
|
||||
i.setAction(ACTION_DEVICE_POLICY_ADMIN);
|
||||
i.putExtra(EXTRA_DEVICE_POLICY_ADMIN, message);
|
||||
context.startService(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onHandleIntent(Intent intent) {
|
||||
// This method is called on a worker thread.
|
||||
|
||||
final Intent original = intent.getParcelableExtra(Intent.EXTRA_INTENT);
|
||||
final String action = original.getAction();
|
||||
// Dispatch from entry point
|
||||
final String action = intent.getAction();
|
||||
if (ACTION_BROADCAST.equals(action)) {
|
||||
final Intent broadcastIntent = intent.getParcelableExtra(Intent.EXTRA_INTENT);
|
||||
final String broadcastAction = broadcastIntent.getAction();
|
||||
|
||||
if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
|
||||
onBootCompleted();
|
||||
if (Intent.ACTION_BOOT_COMPLETED.equals(broadcastAction)) {
|
||||
onBootCompleted();
|
||||
|
||||
// TODO: Do a better job when we get ACTION_DEVICE_STORAGE_LOW.
|
||||
// The code below came from very old code....
|
||||
} else if (Intent.ACTION_DEVICE_STORAGE_LOW.equals(action)) {
|
||||
// Stop IMAP/POP3 poll.
|
||||
MailService.actionCancel(this);
|
||||
} else if (Intent.ACTION_DEVICE_STORAGE_OK.equals(action)) {
|
||||
enableComponentsIfNecessary();
|
||||
} else if (SECRET_CODE_ACTION.equals(action)
|
||||
&& SECRET_CODE_HOST_DEBUG_SCREEN.equals(original.getData().getHost())) {
|
||||
AccountSettingsXL.actionSettingsWithDebug(this);
|
||||
// TODO: Do a better job when we get ACTION_DEVICE_STORAGE_LOW.
|
||||
// The code below came from very old code....
|
||||
} else if (Intent.ACTION_DEVICE_STORAGE_LOW.equals(broadcastAction)) {
|
||||
// Stop IMAP/POP3 poll.
|
||||
MailService.actionCancel(this);
|
||||
} else if (Intent.ACTION_DEVICE_STORAGE_OK.equals(broadcastAction)) {
|
||||
enableComponentsIfNecessary();
|
||||
} else if (ACTION_SECRET_CODE.equals(broadcastAction)
|
||||
&& SECRET_CODE_HOST_DEBUG_SCREEN.equals(broadcastIntent.getData().getHost())) {
|
||||
AccountSettingsXL.actionSettingsWithDebug(this);
|
||||
}
|
||||
} else if (ACTION_DEVICE_POLICY_ADMIN.equals(action)) {
|
||||
int message = intent.getIntExtra(EXTRA_DEVICE_POLICY_ADMIN, -1);
|
||||
SecurityPolicy.onDeviceAdminReceiverMessage(this, message);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue