Watch out for deleted user when exiting async task

Fixes a problem where the async task can take a while to execute
and in the meantime the user can be removed. On exiting the async
task and updating the UI, make sure the user hasn't been deleted.

Bug: 18411181
Change-Id: I1831f3e53084c49e27557cb7aacec78c753a611b
This commit is contained in:
Amith Yamasani
2014-11-19 17:12:46 -08:00
parent 3a84d40133
commit 45f86236e4
3 changed files with 88 additions and 74 deletions

View File

@@ -1023,4 +1023,21 @@ public final class Utils {
return null; return null;
} }
/**
* Queries for the UserInfo of a user. Returns null if the user doesn't exist (was removed).
* @param userManager Instance of UserManager
* @param checkUser The user to check the existence of.
* @return UserInfo of the user or null for non-existent user.
*/
public static UserInfo getExistingUser(UserManager userManager, UserHandle checkUser) {
final List<UserInfo> users = userManager.getUsers(true /* excludeDying */);
final int checkUserId = checkUser.getIdentifier();
for (UserInfo user : users) {
if (user.id == checkUserId) {
return user;
}
}
return null;
}
} }

View File

@@ -58,6 +58,7 @@ import android.widget.Switch;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment; import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.Utils;
import com.android.settings.drawable.CircleFramedDrawable; import com.android.settings.drawable.CircleFramedDrawable;
import java.util.ArrayList; import java.util.ArrayList;
@@ -643,75 +644,81 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen
if (context == null) return; if (context == null) return;
final PackageManager pm = mPackageManager; final PackageManager pm = mPackageManager;
final IPackageManager ipm = mIPm; final IPackageManager ipm = mIPm;
final int userId = mUser.getIdentifier();
// Check if the user was removed in the meantime.
if (Utils.getExistingUser(mUserManager, mUser) == null) {
return;
}
mAppList.removeAll(); mAppList.removeAll();
Intent restrictionsIntent = new Intent(Intent.ACTION_GET_RESTRICTION_ENTRIES); Intent restrictionsIntent = new Intent(Intent.ACTION_GET_RESTRICTION_ENTRIES);
final List<ResolveInfo> receivers = pm.queryBroadcastReceivers(restrictionsIntent, 0); final List<ResolveInfo> receivers = pm.queryBroadcastReceivers(restrictionsIntent, 0);
int i = 0; int i = 0;
if (mVisibleApps.size() > 0) { for (SelectableAppInfo app : mVisibleApps) {
for (SelectableAppInfo app : mVisibleApps) { String packageName = app.packageName;
String packageName = app.packageName; if (packageName == null) continue;
if (packageName == null) continue; final boolean isSettingsApp = packageName.equals(context.getPackageName());
final boolean isSettingsApp = packageName.equals(context.getPackageName()); AppRestrictionsPreference p = new AppRestrictionsPreference(context, this);
AppRestrictionsPreference p = new AppRestrictionsPreference(context, this); final boolean hasSettings = resolveInfoListHasPackage(receivers, packageName);
final boolean hasSettings = resolveInfoListHasPackage(receivers, packageName); p.setIcon(app.icon != null ? app.icon.mutate() : null);
p.setIcon(app.icon != null ? app.icon.mutate() : null); p.setChecked(false);
p.setChecked(false); p.setTitle(app.activityName);
p.setTitle(app.activityName); if (app.masterEntry != null) {
if (app.masterEntry != null) { p.setSummary(context.getString(R.string.user_restrictions_controlled_by,
p.setSummary(context.getString(R.string.user_restrictions_controlled_by, app.masterEntry.activityName));
app.masterEntry.activityName));
}
p.setKey(getKeyForPackage(packageName));
p.setSettingsEnabled((hasSettings || isSettingsApp) && app.masterEntry == null);
p.setPersistent(false);
p.setOnPreferenceChangeListener(this);
p.setOnPreferenceClickListener(this);
PackageInfo pi = null;
try {
pi = ipm.getPackageInfo(packageName,
PackageManager.GET_UNINSTALLED_PACKAGES
| PackageManager.GET_SIGNATURES, mUser.getIdentifier());
} catch (RemoteException e) {
}
if (pi != null && (pi.requiredForAllUsers || isPlatformSigned(pi))) {
p.setChecked(true);
p.setImmutable(true);
// If the app is required and has no restrictions, skip showing it
if (!hasSettings && !isSettingsApp) continue;
// Get and populate the defaults, since the user is not going to be
// able to toggle this app ON (it's ON by default and immutable).
// Only do this for restricted profiles, not single-user restrictions
// Also don't do this for slave icons
if (hasSettings && app.masterEntry == null) {
requestRestrictionsForApp(packageName, p, false);
}
} else if (!mNewUser && isAppEnabledForUser(pi)) {
p.setChecked(true);
}
if (mRestrictedProfile
&& pi.requiredAccountType != null && pi.restrictedAccountType == null) {
p.setChecked(false);
p.setImmutable(true);
p.setSummary(R.string.app_not_supported_in_limited);
}
if (mRestrictedProfile && pi.restrictedAccountType != null) {
p.setSummary(R.string.app_sees_restricted_accounts);
}
if (app.masterEntry != null) {
p.setImmutable(true);
p.setChecked(mSelectedPackages.get(packageName));
}
mAppList.addPreference(p);
if (isSettingsApp) {
p.setOrder(MAX_APP_RESTRICTIONS * 1);
} else {
p.setOrder(MAX_APP_RESTRICTIONS * (i + 2));
}
mSelectedPackages.put(packageName, p.isChecked());
mAppListChanged = true;
i++;
} }
p.setKey(getKeyForPackage(packageName));
p.setSettingsEnabled((hasSettings || isSettingsApp) && app.masterEntry == null);
p.setPersistent(false);
p.setOnPreferenceChangeListener(this);
p.setOnPreferenceClickListener(this);
PackageInfo pi = null;
try {
pi = ipm.getPackageInfo(packageName,
PackageManager.GET_UNINSTALLED_PACKAGES
| PackageManager.GET_SIGNATURES, userId);
} catch (RemoteException e) {
}
if (pi == null) {
continue;
}
if (pi.requiredForAllUsers || isPlatformSigned(pi)) {
p.setChecked(true);
p.setImmutable(true);
// If the app is required and has no restrictions, skip showing it
if (!hasSettings && !isSettingsApp) continue;
// Get and populate the defaults, since the user is not going to be
// able to toggle this app ON (it's ON by default and immutable).
// Only do this for restricted profiles, not single-user restrictions
// Also don't do this for slave icons
if (hasSettings && app.masterEntry == null) {
requestRestrictionsForApp(packageName, p, false);
}
} else if (!mNewUser && isAppEnabledForUser(pi)) {
p.setChecked(true);
}
if (mRestrictedProfile
&& pi.requiredAccountType != null && pi.restrictedAccountType == null) {
p.setChecked(false);
p.setImmutable(true);
p.setSummary(R.string.app_not_supported_in_limited);
}
if (mRestrictedProfile && pi.restrictedAccountType != null) {
p.setSummary(R.string.app_sees_restricted_accounts);
}
if (app.masterEntry != null) {
p.setImmutable(true);
p.setChecked(mSelectedPackages.get(packageName));
}
mAppList.addPreference(p);
if (isSettingsApp) {
p.setOrder(MAX_APP_RESTRICTIONS * 1);
} else {
p.setOrder(MAX_APP_RESTRICTIONS * (i + 2));
}
mSelectedPackages.put(packageName, p.isChecked());
mAppListChanged = true;
i++;
} }
// If this is the first time for a new profile, install/uninstall default apps for profile // If this is the first time for a new profile, install/uninstall default apps for profile
// to avoid taking the hit in onPause(), which can cause race conditions on user switch. // to avoid taking the hit in onPause(), which can cause race conditions on user switch.

View File

@@ -87,7 +87,7 @@ public class RestrictedProfileSettings extends AppRestrictionsFragment
super.onResume(); super.onResume();
// Check if user still exists // Check if user still exists
UserInfo info = getExistingUser(mUser); UserInfo info = Utils.getExistingUser(mUserManager, mUser);
if (info == null) { if (info == null) {
finishFragment(); finishFragment();
} else { } else {
@@ -97,16 +97,6 @@ public class RestrictedProfileSettings extends AppRestrictionsFragment
} }
} }
private UserInfo getExistingUser(UserHandle thisUser) {
final List<UserInfo> users = mUserManager.getUsers(true); // Only get non-dying
for (UserInfo user : users) {
if (user.id == thisUser.getIdentifier()) {
return user;
}
}
return null;
}
@Override @Override
public void startActivityForResult(Intent intent, int requestCode) { public void startActivityForResult(Intent intent, int requestCode) {
mEditUserInfoController.startingActivityForResult(); mEditUserInfoController.startingActivityForResult();