Merge "Small cleanups around indexOfChild usage."
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index 2aae1de..7392563 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -77,7 +77,7 @@
public static final int FLAG_DISABLED = 0x00000040;
- public static final int NO_PROFILE_GROUP_ID = -1;
+ public static final int NO_PROFILE_GROUP_ID = UserHandle.USER_NULL;
public int id;
public int serialNumber;
@@ -87,6 +87,7 @@
public long creationTime;
public long lastLoggedInTime;
public int profileGroupId;
+ public int restrictedProfileParentId;
/** User is only partially created. */
public boolean partial;
@@ -102,6 +103,7 @@
this.flags = flags;
this.iconPath = iconPath;
this.profileGroupId = NO_PROFILE_GROUP_ID;
+ this.restrictedProfileParentId = NO_PROFILE_GROUP_ID;
}
public boolean isPrimary() {
@@ -206,6 +208,7 @@
dest.writeInt(partial ? 1 : 0);
dest.writeInt(profileGroupId);
dest.writeInt(guestToRemove ? 1 : 0);
+ dest.writeInt(restrictedProfileParentId);
}
public static final Parcelable.Creator<UserInfo> CREATOR
@@ -229,5 +232,6 @@
partial = source.readInt() != 0;
profileGroupId = source.readInt();
guestToRemove = source.readInt() != 0;
+ restrictedProfileParentId = source.readInt();
}
}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index a4e6219..ec0cc6d 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -1038,11 +1038,13 @@
type = "enableDUN";
result = TYPE_MOBILE_DUN;
} else if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL)) {
- type = "enableSUPL";
+ type = "enableSUPL";
result = TYPE_MOBILE_SUPL;
- } else if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)) {
- type = "enableMMS";
- result = TYPE_MOBILE_MMS;
+ // back out this hack for mms as they no longer need this and it's causing
+ // device slowdowns - b/23350688 (note, supl still needs this)
+ //} else if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)) {
+ // type = "enableMMS";
+ // result = TYPE_MOBILE_MMS;
} else if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
type = "enableHIPRI";
result = TYPE_MOBILE_HIPRI;
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 849f5de..64e2505 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -927,6 +927,28 @@
}
/**
+ * Creates a restricted profile with the specified name.
+ *
+ * @param name profile's name
+ * @return UserInfo object for the created user, or null if the user could not be created.
+ * @hide
+ */
+ public UserInfo createRestrictedProfile(String name) {
+ try {
+ if (isSplitSystemUser()) {
+ return mService.createProfileForUser(name, UserInfo.FLAG_RESTRICTED,
+ UserHandle.getCallingUserId());
+ } else {
+ return mService.createProfileForUser(name, UserInfo.FLAG_RESTRICTED,
+ UserHandle.USER_SYSTEM);
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "Could not create a restricted profile", e);
+ }
+ return null;
+ }
+
+ /**
* @hide
* Marks the guest user for deletion to allow a new guest to be created before deleting
* the current user who is a guest.
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index dde9cfa..8bbaf36 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -6522,6 +6522,19 @@
return false;
}
+ /**
+ * Force the window to report its next draw.
+ * <p>
+ * This method is only supposed to be used to speed up the interaction from SystemUI and window
+ * manager when waiting for the first frame to be drawn when turning on the screen. DO NOT USE
+ * unless you fully understand this interaction.
+ * @hide
+ */
+ public void setReportNextDraw() {
+ mReportNextDraw = true;
+ invalidate();
+ }
+
void changeCanvasOpacity(boolean opaque) {
Log.d(TAG, "changeCanvasOpacity: opaque=" + opaque);
if (mAttachInfo.mHardwareRenderer != null) {
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 0579ce7..073a2ad 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -456,7 +456,7 @@
// well, we tried...
}
- if (userHandle == UserHandle.USER_OWNER) {
+ if (userHandle == UserHandle.USER_SYSTEM) {
// Set the encryption password to default.
updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
}
@@ -516,7 +516,7 @@
DevicePolicyManager dpm = getDevicePolicyManager();
// Update the device encryption password.
- if (userId == UserHandle.USER_OWNER
+ if (userId == UserHandle.USER_SYSTEM
&& LockPatternUtils.isDeviceEncryptionEnabled()) {
if (!shouldEncryptWithCredentials(true)) {
clearEncryptionPassword();
@@ -538,7 +538,7 @@
}
private void updateCryptoUserInfo(int userId) {
- if (userId != UserHandle.USER_OWNER) {
+ if (userId != UserHandle.USER_SYSTEM) {
return;
}
@@ -714,7 +714,7 @@
int computedQuality = computePasswordQuality(password);
// Update the device encryption password.
- if (userHandle == UserHandle.USER_OWNER
+ if (userHandle == UserHandle.USER_SYSTEM
&& LockPatternUtils.isDeviceEncryptionEnabled()) {
if (!shouldEncryptWithCredentials(true)) {
clearEncryptionPassword();
@@ -1008,7 +1008,7 @@
setBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, enabled, userId);
// Update for crypto if owner
- if (userId != UserHandle.USER_OWNER) {
+ if (userId != UserHandle.USER_SYSTEM) {
return;
}
@@ -1031,7 +1031,7 @@
*/
public void setVisiblePasswordEnabled(boolean enabled, int userId) {
// Update for crypto if owner
- if (userId != UserHandle.USER_OWNER) {
+ if (userId != UserHandle.USER_SYSTEM) {
return;
}
@@ -1210,7 +1210,7 @@
}
public void setCredentialRequiredToDecrypt(boolean required) {
- if (ActivityManager.getCurrentUser() != UserHandle.USER_OWNER) {
+ if (ActivityManager.getCurrentUser() != UserHandle.USER_SYSTEM) {
Log.w(TAG, "Only device owner may call setCredentialRequiredForDecrypt()");
return;
}
diff --git a/core/jni/android_hardware_camera2_DngCreator.cpp b/core/jni/android_hardware_camera2_DngCreator.cpp
index e10a644..8b69bbd 100644
--- a/core/jni/android_hardware_camera2_DngCreator.cpp
+++ b/core/jni/android_hardware_camera2_DngCreator.cpp
@@ -755,48 +755,31 @@
// ----------------------------------------------------------------------------
/**
- * Given a buffer crop rectangle relative to the pixel array size, and the pre-correction active
- * array crop rectangle for the camera characteristics, set the default crop rectangle in the
- * TiffWriter relative to the buffer crop rectangle origin.
+ * Calculate the default crop relative to the "active area" of the image sensor (this active area
+ * will always be the pre-correction active area rectangle), and set this.
*/
static status_t calculateAndSetCrop(JNIEnv* env, const CameraMetadata& characteristics,
- uint32_t bufWidth, uint32_t bufHeight, sp<TiffWriter> writer) {
+ sp<TiffWriter> writer) {
camera_metadata_ro_entry entry =
characteristics.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
- uint32_t xmin = static_cast<uint32_t>(entry.data.i32[0]);
- uint32_t ymin = static_cast<uint32_t>(entry.data.i32[1]);
uint32_t width = static_cast<uint32_t>(entry.data.i32[2]);
uint32_t height = static_cast<uint32_t>(entry.data.i32[3]);
const uint32_t margin = 8; // Default margin recommended by Adobe for interpolation.
- // Crop based on pre-correction array for pixel array
- uint32_t aLeft = xmin;
- uint32_t aTop = ymin;
- uint32_t aRight = xmin + width;
- uint32_t aBottom = ymin + height;
-
- // 8 pixel border crop for pixel array dimens
- uint32_t bLeft = margin;
- uint32_t bTop = margin;
- uint32_t bRight = bufWidth - margin;
- uint32_t bBottom = bufHeight - margin;
-
- // Set the crop to be the intersection of the two rectangles
- uint32_t defaultCropOrigin[] = {std::max(aLeft, bLeft), std::max(aTop, bTop)};
- uint32_t defaultCropSize[] = {std::min(aRight, bRight) - defaultCropOrigin[0],
- std::min(aBottom, bBottom) - defaultCropOrigin[1]};
-
- // If using buffers with pre-correction array dimens, switch to 8 pixel border crop
- // relative to the pixel array dimens
- if (bufWidth == width && bufHeight == height) {
- defaultCropOrigin[0] = xmin + margin;
- defaultCropOrigin[1] = ymin + margin;
- defaultCropSize[0] = width - margin;
- defaultCropSize[1] = height - margin;
+ if (width < margin * 2 || height < margin * 2) {
+ ALOGE("%s: Cannot calculate default crop for image, pre-correction active area is too"
+ "small: h=%" PRIu32 ", w=%" PRIu32, __FUNCTION__, height, width);
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Pre-correction active area is too small.");
+ return BAD_VALUE;
}
+ uint32_t defaultCropOrigin[] = {margin, margin};
+ uint32_t defaultCropSize[] = {width - defaultCropOrigin[0] - margin,
+ height - defaultCropOrigin[1] - margin};
+
BAIL_IF_INVALID_R(writer->addEntry(TAG_DEFAULTCROPORIGIN, 2, defaultCropOrigin,
TIFF_IFD_0), env, TAG_DEFAULTCROPORIGIN, writer);
BAIL_IF_INVALID_R(writer->addEntry(TAG_DEFAULTCROPSIZE, 2, defaultCropSize,
@@ -1565,17 +1548,24 @@
{
// Set dimensions
- if (calculateAndSetCrop(env, characteristics, imageWidth, imageHeight, writer) != OK) {
+ if (calculateAndSetCrop(env, characteristics, writer) != OK) {
return nullptr;
}
camera_metadata_entry entry =
characteristics.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
- BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_DEFAULTCROPSIZE, writer);
+ BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_ACTIVEAREA, writer);
uint32_t xmin = static_cast<uint32_t>(entry.data.i32[0]);
uint32_t ymin = static_cast<uint32_t>(entry.data.i32[1]);
uint32_t width = static_cast<uint32_t>(entry.data.i32[2]);
uint32_t height = static_cast<uint32_t>(entry.data.i32[3]);
+ // If we only have a buffer containing the pre-correction rectangle, ignore the offset
+ // relative to the pixel array.
+ if (imageWidth == width && imageHeight == height) {
+ xmin = 0;
+ ymin = 0;
+ }
+
uint32_t activeArea[] = {ymin, xmin, ymin + height, xmin + width};
BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_ACTIVEAREA, 4, activeArea, TIFF_IFD_0),
env, TAG_ACTIVEAREA, writer);
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index efacd2c..e00b55e 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -65,6 +65,7 @@
<uses-permission android:name="android.permission.READ_INPUT_STATE" />
<uses-permission android:name="android.permission.SET_ORIENTATION" />
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
+ <uses-permission android:name="android.permission.MOVE_PACKAGE" />
<uses-permission android:name="android.permission.CLEAR_APP_USER_DATA" />
<uses-permission android:name="android.permission.DELETE_CACHE_FILES" />
<uses-permission android:name="android.permission.DELETE_PACKAGES" />
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 12d5f36..6f49fd6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -1461,6 +1461,15 @@
}
mHiding = false;
+ if (mWakeAndUnlocking && mDrawnCallback != null) {
+
+ // Hack level over 9000: To speed up wake-and-unlock sequence, force it to report
+ // the next draw from here so we don't have to wait for window manager to signal
+ // this to our ViewRootImpl.
+ mStatusBarKeyguardViewManager.getViewRootImpl().setReportNextDraw();
+ notifyDrawn(mDrawnCallback);
+ }
+
// only play "unlock" noises if not on a call (since the incall UI
// disables the keyguard)
if (TelephonyManager.EXTRA_STATE_IDLE.equals(mPhoneState)) {
@@ -1474,9 +1483,6 @@
updateActivityLockScreenState();
adjustStatusBarLocked();
sendUserPresentBroadcast();
- if (mWakeAndUnlocking && mDrawnCallback != null) {
- notifyDrawn(mDrawnCallback);
- }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index d0604c5..e26f423 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -24,6 +24,7 @@
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewRootImpl;
import android.view.WindowManagerGlobal;
import com.android.internal.widget.LockPatternUtils;
@@ -533,4 +534,8 @@
public void showBouncerMessage(String message, int color) {
mBouncer.showMessage(message, color);
}
+
+ public ViewRootImpl getViewRootImpl() {
+ return mPhoneStatusBar.getStatusBarView().getViewRootImpl();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
index 6d791bf..0f9dd5c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
@@ -36,6 +36,7 @@
import android.util.Log;
import android.util.SparseArray;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.net.LegacyVpnInfo;
import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnInfo;
@@ -62,8 +63,9 @@
private final IConnectivityManager mConnectivityManagerService;
private final DevicePolicyManager mDevicePolicyManager;
private final UserManager mUserManager;
- private final ArrayList<SecurityControllerCallback> mCallbacks
- = new ArrayList<SecurityControllerCallback>();
+
+ @GuardedBy("mCallbacks")
+ private final ArrayList<SecurityControllerCallback> mCallbacks = new ArrayList<>();
private SparseArray<VpnConfig> mCurrentVpns = new SparseArray<>();
private int mCurrentUserId;
@@ -161,16 +163,20 @@
@Override
public void removeCallback(SecurityControllerCallback callback) {
- if (callback == null) return;
- if (DEBUG) Log.d(TAG, "removeCallback " + callback);
- mCallbacks.remove(callback);
+ synchronized (mCallbacks) {
+ if (callback == null) return;
+ if (DEBUG) Log.d(TAG, "removeCallback " + callback);
+ mCallbacks.remove(callback);
+ }
}
@Override
public void addCallback(SecurityControllerCallback callback) {
- if (callback == null || mCallbacks.contains(callback)) return;
- if (DEBUG) Log.d(TAG, "addCallback " + callback);
- mCallbacks.add(callback);
+ synchronized (mCallbacks) {
+ if (callback == null || mCallbacks.contains(callback)) return;
+ if (DEBUG) Log.d(TAG, "addCallback " + callback);
+ mCallbacks.add(callback);
+ }
}
@Override
@@ -203,8 +209,10 @@
}
private void fireCallbacks() {
- for (SecurityControllerCallback callback : mCallbacks) {
- callback.onStateChanged();
+ synchronized (mCallbacks) {
+ for (SecurityControllerCallback callback : mCallbacks) {
+ callback.onStateChanged();
+ }
}
}
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index f724749..ff02b94 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -1955,10 +1955,12 @@
.setPackage(pkgInfo.packageName);
List<ResolveInfo> hosts = mPackageManager.queryIntentServicesAsUser(
intent, 0, UserHandle.USER_OWNER);
- final int N = hosts.size();
- for (int i = 0; i < N; i++) {
- final ServiceInfo info = hosts.get(i).serviceInfo;
- tryBindTransport(info);
+ if (hosts != null) {
+ final int N = hosts.size();
+ for (int i = 0; i < N; i++) {
+ final ServiceInfo info = hosts.get(i).serviceInfo;
+ tryBindTransport(info);
+ }
}
}
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 8b0e6f2..7aef38d 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -511,10 +511,17 @@
Account[] sharedAccounts = getSharedAccountsAsUser(userId);
if (sharedAccounts == null || sharedAccounts.length == 0) return;
Account[] accounts = getAccountsAsUser(null, userId);
+ int parentUserId = UserManager.isSplitSystemUser()
+ ? mUserManager.getUserInfo(userId).restrictedProfileParentId
+ : UserHandle.USER_SYSTEM;
+ if (parentUserId < 0) {
+ Log.w(TAG, "User " + userId + " has shared accounts, but no parent user");
+ return;
+ }
for (Account sa : sharedAccounts) {
if (ArrayUtils.contains(accounts, sa)) continue;
// Account doesn't exist. Copy it now.
- copyAccountToUser(null /*no response*/, sa, UserHandle.USER_OWNER, userId);
+ copyAccountToUser(null /*no response*/, sa, parentUserId, userId);
}
}
@@ -740,7 +747,7 @@
@Override
public void copyAccountToUser(final IAccountManagerResponse response, final Account account,
- int userFrom, int userTo) {
+ final int userFrom, int userTo) {
int callingUid = Binder.getCallingUid();
if (isCrossUser(callingUid, UserHandle.USER_ALL)) {
throw new SecurityException("Calling copyAccountToUser requires "
@@ -784,7 +791,7 @@
if (result != null
&& result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
// Create a Session for the target user and pass in the bundle
- completeCloningAccount(response, result, account, toAccounts);
+ completeCloningAccount(response, result, account, toAccounts, userFrom);
} else {
super.onResult(result);
}
@@ -851,7 +858,8 @@
}
private void completeCloningAccount(IAccountManagerResponse response,
- final Bundle accountCredentials, final Account account, final UserAccounts targetUser) {
+ final Bundle accountCredentials, final Account account, final UserAccounts targetUser,
+ final int parentUserId){
long id = clearCallingIdentity();
try {
new Session(targetUser, response, account.type, false,
@@ -866,9 +874,9 @@
@Override
public void run() throws RemoteException {
// Confirm that the owner's account still exists before this step.
- UserAccounts owner = getUserAccounts(UserHandle.USER_OWNER);
+ UserAccounts owner = getUserAccounts(parentUserId);
synchronized (owner.cacheLock) {
- for (Account acc : getAccounts(UserHandle.USER_OWNER)) {
+ for (Account acc : getAccounts(parentUserId)) {
if (acc.equals(account)) {
mAuthenticator.addAccountFromCredentials(
this, account, accountCredentials);
@@ -949,27 +957,27 @@
}
sendAccountsChangedBroadcast(accounts.userId);
}
- if (accounts.userId == UserHandle.USER_OWNER) {
- addAccountToLimitedUsers(account);
+ if (getUserManager().getUserInfo(accounts.userId).canHaveProfile()) {
+ addAccountToLinkedRestrictedUsers(account, accounts.userId);
}
return true;
}
/**
- * Adds the account to all limited users as shared accounts. If the user is currently
+ * Adds the account to all linked restricted users as shared accounts. If the user is currently
* running, then clone the account too.
* @param account the account to share with limited users
+ *
*/
- private void addAccountToLimitedUsers(Account account) {
+ private void addAccountToLinkedRestrictedUsers(Account account, int parentUserId) {
List<UserInfo> users = getUserManager().getUsers();
for (UserInfo user : users) {
- if (user.isRestricted()) {
+ if (user.isRestricted() && (parentUserId == user.restrictedProfileParentId)) {
addSharedAccountAsUser(account, user.id);
try {
if (ActivityManagerNative.getDefault().isUserRunning(user.id, false)) {
mMessageHandler.sendMessage(mMessageHandler.obtainMessage(
- MESSAGE_COPY_SHARED_ACCOUNT, UserHandle.USER_OWNER, user.id,
- account));
+ MESSAGE_COPY_SHARED_ACCOUNT, parentUserId, user.id, account));
}
} catch (RemoteException re) {
// Shouldn't happen
@@ -1172,14 +1180,16 @@
new AtomicReference<String>(accountToRename.name));
resultAccount = renamedAccount;
- if (accounts.userId == UserHandle.USER_OWNER) {
+ int parentUserId = accounts.userId;
+ if (canHaveProfile(parentUserId)) {
/*
- * Owner's account was renamed, rename the account for
+ * Owner or system user account was renamed, rename the account for
* those users with which the account was shared.
*/
List<UserInfo> users = mUserManager.getUsers(true);
for (UserInfo user : users) {
- if (!user.isPrimary() && user.isRestricted()) {
+ if (user.isRestricted()
+ && (user.restrictedProfileParentId == parentUserId)) {
renameSharedAccountAsUser(accountToRename, newName, user.id);
}
}
@@ -1191,6 +1201,11 @@
return resultAccount;
}
+ private boolean canHaveProfile(final int parentUserId) {
+ final UserInfo userInfo = mUserManager.getUserInfo(parentUserId);
+ return userInfo != null && userInfo.canHaveProfile();
+ }
+
@Override
public void removeAccount(IAccountManagerResponse response, Account account,
boolean expectActivityLaunch) {
@@ -1304,7 +1319,7 @@
logRecord(accounts, DebugDbHelper.ACTION_CALLED_ACCOUNT_REMOVE, TABLE_ACCOUNTS);
long identityToken = clearCallingIdentity();
try {
- return removeAccountInternal(accounts, account);
+ return removeAccountInternal(accounts, account, callingUid);
} finally {
restoreCallingIdentity(identityToken);
}
@@ -1337,7 +1352,7 @@
&& !result.containsKey(AccountManager.KEY_INTENT)) {
final boolean removalAllowed = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
if (removalAllowed) {
- removeAccountInternal(mAccounts, mAccount);
+ removeAccountInternal(mAccounts, mAccount, getCallingUid());
}
IAccountManagerResponse response = getResponseAndClose();
if (response != null) {
@@ -1360,10 +1375,10 @@
/* For testing */
protected void removeAccountInternal(Account account) {
- removeAccountInternal(getUserAccountsForCaller(), account);
+ removeAccountInternal(getUserAccountsForCaller(), account, getCallingUid());
}
- private boolean removeAccountInternal(UserAccounts accounts, Account account) {
+ private boolean removeAccountInternal(UserAccounts accounts, Account account, int callingUid) {
int deleted;
synchronized (accounts.cacheLock) {
final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
@@ -1376,21 +1391,20 @@
logRecord(db, DebugDbHelper.ACTION_ACCOUNT_REMOVE, TABLE_ACCOUNTS, accountId, accounts);
}
- if (accounts.userId == UserHandle.USER_OWNER) {
- // Owner's account was removed, remove from any users that are sharing
- // this account.
- int callingUid = getCallingUid();
- long id = Binder.clearCallingIdentity();
- try {
+ long id = Binder.clearCallingIdentity();
+ try {
+ int parentUserId = accounts.userId;
+ if (canHaveProfile(parentUserId)) {
+ // Remove from any restricted profiles that are sharing this account.
List<UserInfo> users = mUserManager.getUsers(true);
for (UserInfo user : users) {
- if (!user.isPrimary() && user.isRestricted()) {
+ if (user.isRestricted() && parentUserId == (user.restrictedProfileParentId)) {
removeSharedAccountAsUser(account, user.id, callingUid);
}
}
- } finally {
- Binder.restoreCallingIdentity(id);
}
+ } finally {
+ Binder.restoreCallingIdentity(id);
}
return (deleted > 0);
}
@@ -2707,7 +2721,7 @@
if (r > 0) {
logRecord(db, DebugDbHelper.ACTION_ACCOUNT_REMOVE, TABLE_SHARED_ACCOUNTS,
sharedTableAccountId, accounts, callingUid);
- removeAccountInternal(accounts, account);
+ removeAccountInternal(accounts, account, callingUid);
}
return r > 0;
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 9e878e7..8cec7eb 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -13728,9 +13728,14 @@
libDirRoot = ps.legacyNativeLibraryPathString;
}
if (p != null && (isExternal(p) || p.isForwardLocked())) {
- String secureContainerId = cidFromCodePath(p.applicationInfo.getBaseCodePath());
- if (secureContainerId != null) {
- asecPath = PackageHelper.getSdFilesystem(secureContainerId);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ String secureContainerId = cidFromCodePath(p.applicationInfo.getBaseCodePath());
+ if (secureContainerId != null) {
+ asecPath = PackageHelper.getSdFilesystem(secureContainerId);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
}
}
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 4bfcb90..1924bab 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -61,7 +61,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IAppOpsService;
-import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.XmlUtils;
@@ -102,6 +101,7 @@
private static final String ATTR_GUEST_TO_REMOVE = "guestToRemove";
private static final String ATTR_USER_VERSION = "version";
private static final String ATTR_PROFILE_GROUP_ID = "profileGroupId";
+ private static final String ATTR_RESTRICTED_PROFILE_PARENT_ID = "restrictedProfileParentId";
private static final String TAG_GUEST_RESTRICTIONS = "guestRestrictions";
private static final String TAG_USERS = "users";
private static final String TAG_USER = "user";
@@ -927,7 +927,10 @@
serializer.attribute(null, ATTR_PROFILE_GROUP_ID,
Integer.toString(userInfo.profileGroupId));
}
-
+ if (userInfo.restrictedProfileParentId != UserInfo.NO_PROFILE_GROUP_ID) {
+ serializer.attribute(null, ATTR_RESTRICTED_PROFILE_PARENT_ID,
+ Integer.toString(userInfo.restrictedProfileParentId));
+ }
serializer.startTag(null, TAG_NAME);
serializer.text(userInfo.name);
serializer.endTag(null, TAG_NAME);
@@ -1037,6 +1040,7 @@
long creationTime = 0L;
long lastLoggedInTime = 0L;
int profileGroupId = UserInfo.NO_PROFILE_GROUP_ID;
+ int restrictedProfileParentId = UserInfo.NO_PROFILE_GROUP_ID;
boolean partial = false;
boolean guestToRemove = false;
Bundle restrictions = new Bundle();
@@ -1072,6 +1076,8 @@
lastLoggedInTime = readLongAttribute(parser, ATTR_LAST_LOGGED_IN_TIME, 0);
profileGroupId = readIntAttribute(parser, ATTR_PROFILE_GROUP_ID,
UserInfo.NO_PROFILE_GROUP_ID);
+ restrictedProfileParentId = readIntAttribute(parser,
+ ATTR_RESTRICTED_PROFILE_PARENT_ID, UserInfo.NO_PROFILE_GROUP_ID);
String valueString = parser.getAttributeValue(null, ATTR_PARTIAL);
if ("true".equals(valueString)) {
partial = true;
@@ -1106,6 +1112,7 @@
userInfo.partial = partial;
userInfo.guestToRemove = guestToRemove;
userInfo.profileGroupId = profileGroupId;
+ userInfo.restrictedProfileParentId = restrictedProfileParentId;
mUserRestrictions.append(id, restrictions);
return userInfo;
@@ -1262,6 +1269,7 @@
}
final boolean isGuest = (flags & UserInfo.FLAG_GUEST) != 0;
final boolean isManagedProfile = (flags & UserInfo.FLAG_MANAGED_PROFILE) != 0;
+ final boolean isRestricted = (flags & UserInfo.FLAG_RESTRICTED) != 0;
final long ident = Binder.clearCallingIdentity();
UserInfo userInfo = null;
final int userId;
@@ -1286,6 +1294,24 @@
if (isGuest && findCurrentGuestUserLocked() != null) {
return null;
}
+ // In legacy mode, restricted profile's parent can only be the owner user
+ if (isRestricted && !UserManager.isSplitSystemUser()
+ && (parentId != UserHandle.USER_SYSTEM)) {
+ Log.w(LOG_TAG, "Cannot add restricted profile - parent user must be owner");
+ return null;
+ }
+ if (isRestricted && UserManager.isSplitSystemUser()) {
+ if (parent == null) {
+ Log.w(LOG_TAG, "Cannot add restricted profile - parent user must be "
+ + "specified");
+ return null;
+ }
+ if (!parent.canHaveProfile()) {
+ Log.w(LOG_TAG, "Cannot add restricted profile - profiles cannot be "
+ + "created for the specified parent user id " + parentId);
+ return null;
+ }
+ }
// In split system user mode, we assign the first human user the primary flag.
// And if there is no device owner, we also assign the admin flag to primary
// user.
@@ -1309,11 +1335,22 @@
mUsers.put(userId, userInfo);
writeUserListLocked();
if (parent != null) {
- if (parent.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID) {
- parent.profileGroupId = parent.id;
- scheduleWriteUserLocked(parent);
+ if (isManagedProfile) {
+ if (parent.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID) {
+ parent.profileGroupId = parent.id;
+ scheduleWriteUserLocked(parent);
+ }
+ userInfo.profileGroupId = parent.profileGroupId;
+ } else if (isRestricted) {
+ if (!parent.canHaveProfile()) {
+ Log.w(LOG_TAG, "Cannot add restricted profile - parent user must be owner");
+ }
+ if (parent.restrictedProfileParentId == UserInfo.NO_PROFILE_GROUP_ID) {
+ parent.restrictedProfileParentId = parent.id;
+ scheduleWriteUserLocked(parent);
+ }
+ userInfo.restrictedProfileParentId = parent.restrictedProfileParentId;
}
- userInfo.profileGroupId = parent.profileGroupId;
}
final StorageManager storage = mContext.getSystemService(StorageManager.class);
for (VolumeInfo vol : storage.getWritablePrivateVolumes()) {
@@ -1348,24 +1385,9 @@
return userInfo;
}
- private int numberOfUsersOfTypeLocked(int flags, boolean excludeDying) {
- int count = 0;
- for (int i = mUsers.size() - 1; i >= 0; i--) {
- UserInfo user = mUsers.valueAt(i);
- if (!excludeDying || !mRemovingUserIds.get(user.id)) {
- if ((user.flags & flags) != 0) {
- count++;
- }
- }
- }
- return count;
- }
-
/**
* Find the current guest user. If the Guest user is partial,
* then do not include it in the results as it is about to die.
- * This is different than {@link #numberOfUsersOfTypeLocked(int, boolean)} due to
- * the special handling of Guests being removed.
*/
private UserInfo findCurrentGuestUserLocked() {
final int size = mUsers.size();
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 4aaba14..9ddbcca 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -773,6 +773,13 @@
}
class MyOrientationListener extends WindowOrientationListener {
+ private final Runnable mUpdateRotationRunnable = new Runnable() {
+ @Override
+ public void run() {
+ updateRotation(false);
+ }
+ };
+
MyOrientationListener(Context context, Handler handler) {
super(context, handler);
}
@@ -780,7 +787,7 @@
@Override
public void onProposedRotationChanged(int rotation) {
if (localLOGV) Slog.v(TAG, "onProposedRotationChanged, rotation=" + rotation);
- updateRotation(false);
+ mHandler.post(mUpdateRotationRunnable);
}
}
MyOrientationListener mOrientationListener;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
index 7bd27f2..791d0dd 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
@@ -19,12 +19,14 @@
import android.app.AppGlobals;
import android.app.admin.SystemUpdatePolicy;
import android.content.ComponentName;
+import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.UserInfo;
import android.os.Environment;
-import android.os.PersistableBundle;
import android.os.RemoteException;
+import android.os.UserManager;
import android.util.AtomicFile;
import android.util.Slog;
import android.util.Xml;
@@ -40,13 +42,15 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.io.OutputStream;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.Set;
+import libcore.io.IoUtils;
+
/**
* Stores and restores state for the Device and Profile owners. By definition there can be
* only one device owner, but there may be a profile owner for each user.
@@ -54,21 +58,27 @@
class DeviceOwner {
private static final String TAG = "DevicePolicyManagerService";
- private static final String DEVICE_OWNER_XML = "device_owner.xml";
+ private static final String DEVICE_OWNER_XML_LEGACY = "device_owner.xml";
+
+ private static final String DEVICE_OWNER_XML = "device_owner_2.xml";
+
+ private static final String PROFILE_OWNER_XML = "profile_owner.xml";
+
+ private static final String TAG_ROOT = "root";
+
private static final String TAG_DEVICE_OWNER = "device-owner";
private static final String TAG_DEVICE_INITIALIZER = "device-initializer";
private static final String TAG_PROFILE_OWNER = "profile-owner";
+
private static final String ATTR_NAME = "name";
private static final String ATTR_PACKAGE = "package";
private static final String ATTR_COMPONENT_NAME = "component";
private static final String ATTR_USERID = "userId";
+
private static final String TAG_SYSTEM_UPDATE_POLICY = "system-update-policy";
- private AtomicFile fileForWriting;
-
- // Input/Output streams for testing.
- private InputStream mInputStreamForTest;
- private OutputStream mOutputStreamForTest;
+ private final Context mContext;
+ private final UserManager mUserManager;
// Internal state for the device owner package.
private OwnerInfo mDeviceOwner;
@@ -82,56 +92,41 @@
// Local system update policy controllable by device owner.
private SystemUpdatePolicy mSystemUpdatePolicy;
- // Private default constructor.
- private DeviceOwner() {
- }
-
- @VisibleForTesting
- DeviceOwner(InputStream in, OutputStream out) {
- mInputStreamForTest = in;
- mOutputStreamForTest = out;
+ public DeviceOwner(Context context) {
+ mContext = context;
+ mUserManager = UserManager.get(mContext);
}
/**
- * Loads the device owner state from disk.
+ * Load configuration from the disk.
*/
- static DeviceOwner load() {
- DeviceOwner owner = new DeviceOwner();
- if (new File(Environment.getSystemSecureDirectory(), DEVICE_OWNER_XML).exists()) {
- owner.readOwnerFile();
- return owner;
- } else {
- return null;
+ void load() {
+ synchronized (this) {
+ // First, try to read from the legacy file.
+ final File legacy = getLegacyConfigFileWithTestOverride();
+
+ if (readLegacyOwnerFile(legacy)) {
+ // Legacy file exists, write to new files and remove the legacy one.
+ writeDeviceOwner();
+ for (int userId : getProfileOwnerKeys()) {
+ writeProfileOwner(userId);
+ }
+ if (!legacy.delete()) {
+ Slog.e(TAG, "Failed to remove the legacy setting file");
+ }
+ return;
+ }
+
+ // No legacy file, read from the new format files.
+ new DeviceOwnerReadWriter().readFromFileLocked();
+
+ final List<UserInfo> users = mUserManager.getUsers(); // XXX double check this is the correct profile set.
+ for (UserInfo ui : users) {
+ new ProfileOwnerReadWriter(ui.id).readFromFileLocked(); // XXX double check ID is the right one.
+ }
}
}
- /**
- * Creates an instance of the device owner object with the device owner set.
- */
- static DeviceOwner createWithDeviceOwner(String packageName, String ownerName) {
- DeviceOwner owner = new DeviceOwner();
- owner.mDeviceOwner = new OwnerInfo(ownerName, packageName);
- return owner;
- }
-
- /**
- * Creates an instance of the device owner object with the device initializer set.
- */
- static DeviceOwner createWithDeviceInitializer(ComponentName admin) {
- DeviceOwner owner = new DeviceOwner();
- owner.mDeviceInitializer = new OwnerInfo(null, admin);
- return owner;
- }
-
- /**
- * Creates an instance of the device owner object with the profile owner set.
- */
- static DeviceOwner createWithProfileOwner(ComponentName admin, String ownerName, int userId) {
- DeviceOwner owner = new DeviceOwner();
- owner.mProfileOwners.put(userId, new OwnerInfo(ownerName, admin));
- return owner;
- }
-
String getDeviceOwnerPackageName() {
return mDeviceOwner != null ? mDeviceOwner.packageName : null;
}
@@ -234,10 +229,13 @@
return false;
}
- @VisibleForTesting
- void readOwnerFile() {
+ private boolean readLegacyOwnerFile(File file) {
+ if (!file.exists()) {
+ // Already migrated or the device has no owners.
+ return false;
+ }
try {
- InputStream input = openRead();
+ InputStream input = new AtomicFile(file).openRead();
XmlPullParser parser = Xml.newPullParser();
parser.setInput(input, StandardCharsets.UTF_8.name());
int type;
@@ -295,99 +293,212 @@
}
}
input.close();
- } catch (XmlPullParserException xppe) {
- Slog.e(TAG, "Error parsing device-owner file\n" + xppe);
- } catch (IOException ioe) {
- Slog.e(TAG, "IO Exception when reading device-owner file\n" + ioe);
+ } catch (XmlPullParserException|IOException e) {
+ Slog.e(TAG, "Error parsing device-owner file", e);
}
+ return true;
}
- @VisibleForTesting
- void writeOwnerFile() {
+ void writeDeviceOwner() {
synchronized (this) {
- writeOwnerFileLocked();
+ new DeviceOwnerReadWriter().writeToFileLocked();
}
}
- private void writeOwnerFileLocked() {
- try {
- OutputStream outputStream = startWrite();
- XmlSerializer out = new FastXmlSerializer();
- out.setOutput(outputStream, StandardCharsets.UTF_8.name());
- out.startDocument(null, true);
+ void writeProfileOwner(int userId) {
+ synchronized (this) {
+ new ProfileOwnerReadWriter(userId).writeToFileLocked();
+ }
+ }
- // Write device owner tag
- if (mDeviceOwner != null) {
- out.startTag(null, TAG_DEVICE_OWNER);
- out.attribute(null, ATTR_PACKAGE, mDeviceOwner.packageName);
- if (mDeviceOwner.name != null) {
- out.attribute(null, ATTR_NAME, mDeviceOwner.name);
- }
- out.endTag(null, TAG_DEVICE_OWNER);
- }
+ private abstract static class FileReadWriter {
+ private final File mFile;
- // Write device initializer tag
- if (mDeviceInitializer != null) {
- out.startTag(null, TAG_DEVICE_INITIALIZER);
- out.attribute(null, ATTR_PACKAGE, mDeviceInitializer.packageName);
- if (mDeviceInitializer.admin != null) {
- out.attribute(
- null, ATTR_COMPONENT_NAME, mDeviceInitializer.admin.flattenToString());
- }
- out.endTag(null, TAG_DEVICE_INITIALIZER);
- }
+ protected FileReadWriter(File file) {
+ mFile = file;
+ }
- // Write profile owner tags
- if (mProfileOwners.size() > 0) {
- for (HashMap.Entry<Integer, OwnerInfo> owner : mProfileOwners.entrySet()) {
- out.startTag(null, TAG_PROFILE_OWNER);
- OwnerInfo ownerInfo = owner.getValue();
- out.attribute(null, ATTR_PACKAGE, ownerInfo.packageName);
- out.attribute(null, ATTR_NAME, ownerInfo.name);
- out.attribute(null, ATTR_USERID, Integer.toString(owner.getKey()));
- if (ownerInfo.admin != null) {
- out.attribute(null, ATTR_COMPONENT_NAME, ownerInfo.admin.flattenToString());
+ abstract boolean shouldWrite();
+
+ void writeToFileLocked() {
+ if (!shouldWrite()) {
+ // No contents, remove the file.
+ if (mFile.exists()) {
+ if (!mFile.delete()) {
+ Slog.e(TAG, "Failed to remove " + mFile.getPath());
}
- out.endTag(null, TAG_PROFILE_OWNER);
}
+ return;
}
- // Write system update policy tag
+ final AtomicFile f = new AtomicFile(mFile);
+ FileOutputStream outputStream = null;
+ try {
+ outputStream = f.startWrite();
+ final XmlSerializer out = new FastXmlSerializer();
+ out.setOutput(outputStream, StandardCharsets.UTF_8.name());
+
+ // Root tag
+ out.startDocument(null, true);
+ out.startTag(null, TAG_ROOT);
+
+ // Actual content
+ writeInner(out);
+
+ // Close root
+ out.endTag(null, TAG_ROOT);
+ out.endDocument();
+ out.flush();
+
+ // Commit the content.
+ f.finishWrite(outputStream);
+ outputStream = null;
+
+ } catch (IOException e) {
+ Slog.e(TAG, "Exception when writing", e);
+ if (outputStream != null) {
+ f.failWrite(outputStream);
+ }
+ }
+ }
+
+ void readFromFileLocked() {
+ if (!mFile.exists()) {
+ return;
+ }
+ final AtomicFile f = new AtomicFile(mFile);
+ InputStream input = null;
+ try {
+ input = f.openRead();
+ final XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(input, StandardCharsets.UTF_8.name());
+
+ int type;
+ int depth = 0;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
+ switch (type) {
+ case XmlPullParser.START_TAG:
+ depth++;
+ break;
+ case XmlPullParser.END_TAG:
+ depth--;
+ // fallthrough
+ default:
+ continue;
+ }
+ // Check the root tag
+ final String tag = parser.getName();
+ if (depth == 1) {
+ if (!TAG_ROOT.equals(tag)) {
+ Slog.e(TAG, "Invalid root tag: " + tag);
+ return;
+ }
+ }
+ // readInner() will only see START_TAG at depth >= 2.
+ if (!readInner(parser, depth, tag)) {
+ return; // Error
+ }
+ }
+ } catch (XmlPullParserException | IOException e) {
+ Slog.e(TAG, "Error parsing device-owner file", e);
+ } finally {
+ IoUtils.closeQuietly(input);
+ }
+ }
+
+ abstract void writeInner(XmlSerializer out) throws IOException;
+
+ abstract boolean readInner(XmlPullParser parser, int depth, String tag);
+
+ }
+
+ private class DeviceOwnerReadWriter extends FileReadWriter {
+
+ protected DeviceOwnerReadWriter() {
+ super(getDeviceOwnerFileWithTestOverride());
+ }
+
+ @Override
+ boolean shouldWrite() {
+ return (mDeviceOwner != null) || (mDeviceInitializer != null)
+ || (mSystemUpdatePolicy != null);
+ }
+
+ @Override
+ void writeInner(XmlSerializer out) throws IOException {
+ if (mDeviceOwner != null) {
+ mDeviceOwner.writeToXml(out, TAG_DEVICE_OWNER);
+ }
+ if (mDeviceInitializer != null) {
+ mDeviceInitializer.writeToXml(out, TAG_DEVICE_INITIALIZER);
+ }
if (mSystemUpdatePolicy != null) {
out.startTag(null, TAG_SYSTEM_UPDATE_POLICY);
mSystemUpdatePolicy.saveToXml(out);
out.endTag(null, TAG_SYSTEM_UPDATE_POLICY);
}
- out.endDocument();
- out.flush();
- finishWrite(outputStream);
- } catch (IOException ioe) {
- Slog.e(TAG, "IO Exception when writing device-owner file\n" + ioe);
+ }
+
+ @Override
+ boolean readInner(XmlPullParser parser, int depth, String tag) {
+ if (depth > 2) {
+ return true; // Ignore
+ }
+ switch (tag) {
+ case TAG_DEVICE_OWNER:
+ mDeviceOwner = OwnerInfo.readFromXml(parser);
+ break;
+ case TAG_DEVICE_INITIALIZER:
+ mDeviceInitializer = OwnerInfo.readFromXml(parser);
+ break;
+ case TAG_SYSTEM_UPDATE_POLICY:
+ mSystemUpdatePolicy = SystemUpdatePolicy.restoreFromXml(parser);
+ break;
+ default:
+ Slog.e(TAG, "Unexpected tag: " + tag);
+ return false;
+
+ }
+ return true;
}
}
- private InputStream openRead() throws IOException {
- if (mInputStreamForTest != null) {
- return mInputStreamForTest;
+ private class ProfileOwnerReadWriter extends FileReadWriter {
+ private final int mUserId;
+
+ ProfileOwnerReadWriter(int userId) {
+ super(getProfileOwnerFileWithTestOverride(userId));
+ mUserId = userId;
}
- return new AtomicFile(new File(Environment.getSystemSecureDirectory(),
- DEVICE_OWNER_XML)).openRead();
- }
-
- private OutputStream startWrite() throws IOException {
- if (mOutputStreamForTest != null) {
- return mOutputStreamForTest;
+ @Override
+ boolean shouldWrite() {
+ return mProfileOwners.get(mUserId) != null;
}
- fileForWriting = new AtomicFile(new File(Environment.getSystemSecureDirectory(),
- DEVICE_OWNER_XML));
- return fileForWriting.startWrite();
- }
+ @Override
+ void writeInner(XmlSerializer out) throws IOException {
+ final OwnerInfo profileOwner = mProfileOwners.get(mUserId);
+ if (profileOwner != null) {
+ profileOwner.writeToXml(out, TAG_PROFILE_OWNER);
+ }
+ }
- private void finishWrite(OutputStream stream) {
- if (fileForWriting != null) {
- fileForWriting.finishWrite((FileOutputStream) stream);
+ @Override
+ boolean readInner(XmlPullParser parser, int depth, String tag) {
+ if (depth > 2) {
+ return true; // Ignore
+ }
+ switch (tag) {
+ case TAG_PROFILE_OWNER:
+ mProfileOwners.put(mUserId, OwnerInfo.readFromXml(parser));
+ break;
+ default:
+ Slog.e(TAG, "Unexpected tag: " + tag);
+ return false;
+
+ }
+ return true;
}
}
@@ -407,9 +518,46 @@
this.admin = admin;
this.packageName = admin.getPackageName();
}
+
+ public void writeToXml(XmlSerializer out, String tag) throws IOException {
+ out.startTag(null, tag);
+ out.attribute(null, ATTR_PACKAGE, packageName);
+ if (name != null) {
+ out.attribute(null, ATTR_NAME, name);
+ }
+ if (admin != null) {
+ out.attribute(null, ATTR_COMPONENT_NAME, admin.flattenToString());
+ }
+ out.endTag(null, tag);
+ }
+
+ public static OwnerInfo readFromXml(XmlPullParser parser) {
+ final String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
+ final String name = parser.getAttributeValue(null, ATTR_NAME);
+ final String componentName =
+ parser.getAttributeValue(null, ATTR_COMPONENT_NAME);
+
+ // Has component name? If so, return [name, component]
+ if (componentName != null) {
+ final ComponentName admin = ComponentName.unflattenFromString(componentName);
+ if (admin != null) {
+ return new OwnerInfo(name, admin);
+ } else {
+ // This shouldn't happen but switch from package name -> component name
+ // might have written bad device owner files. b/17652534
+ Slog.e(TAG, "Error parsing device-owner file. Bad component name " +
+ componentName);
+ }
+ }
+
+ // Else, build with [name, package]
+ return new OwnerInfo(name, packageName);
+ }
+
public void dump(String prefix, PrintWriter pw) {
pw.println(prefix + "admin=" + admin);
pw.println(prefix + "name=" + name);
+ pw.println(prefix + "package=" + packageName);
pw.println();
}
}
@@ -426,4 +574,16 @@
}
}
}
+
+ File getLegacyConfigFileWithTestOverride() {
+ return new File(Environment.getSystemSecureDirectory(), DEVICE_OWNER_XML_LEGACY);
+ }
+
+ File getDeviceOwnerFileWithTestOverride() {
+ return new File(Environment.getSystemSecureDirectory(), DEVICE_OWNER_XML);
+ }
+
+ File getProfileOwnerFileWithTestOverride(int userId) {
+ return new File(Environment.getUserSystemDirectory(userId), PROFILE_OWNER_XML);
+ }
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 8788908..00a3c5c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -279,7 +279,7 @@
NotificationManager mNotificationManager;
// Stores and loads state on device and profile owners.
- private DeviceOwner mDeviceOwner;
+ private final DeviceOwner mDeviceOwner;
private final Binder mToken = new Binder();
@@ -1044,6 +1044,7 @@
*/
public DevicePolicyManagerService(Context context) {
mContext = context;
+ mDeviceOwner = new DeviceOwner(mContext);
mUserManager = UserManager.get(mContext);
mHasFeature = context.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_DEVICE_ADMIN);
@@ -1119,10 +1120,8 @@
Slog.w(LOG_TAG, "Tried to remove device policy file for user 0! Ignoring.");
return;
}
- if (mDeviceOwner != null) {
- mDeviceOwner.removeProfileOwner(userHandle);
- mDeviceOwner.writeOwnerFile();
- }
+ mDeviceOwner.removeProfileOwner(userHandle);
+ mDeviceOwner.writeProfileOwner(userHandle);
DevicePolicyData policy = mUserData.get(userHandle);
if (policy != null) {
@@ -1138,7 +1137,7 @@
void loadDeviceOwner() {
synchronized (this) {
- mDeviceOwner = DeviceOwner.load();
+ mDeviceOwner.load();
updateDeviceOwnerLocked();
}
}
@@ -1806,8 +1805,7 @@
Set<Integer> usersWithProfileOwners;
Set<Integer> usersWithData;
synchronized(this) {
- usersWithProfileOwners = mDeviceOwner != null
- ? mDeviceOwner.getProfileOwnerKeys() : new HashSet<Integer>();
+ usersWithProfileOwners = mDeviceOwner.getProfileOwnerKeys();
usersWithData = new HashSet<Integer>();
for (int i = 0; i < mUserData.size(); i++) {
usersWithData.add(mUserData.keyAt(i));
@@ -4137,14 +4135,8 @@
Binder.restoreCallingIdentity(ident);
}
- if (mDeviceOwner == null) {
- // Device owner is not set and does not exist, set it.
- mDeviceOwner = DeviceOwner.createWithDeviceOwner(packageName, ownerName);
- } else {
- // Device owner state already exists, update it.
- mDeviceOwner.setDeviceOwner(packageName, ownerName);
- }
- mDeviceOwner.writeOwnerFile();
+ mDeviceOwner.setDeviceOwner(packageName, ownerName);
+ mDeviceOwner.writeDeviceOwner();
updateDeviceOwnerLocked();
Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED);
@@ -4164,8 +4156,7 @@
return false;
}
synchronized (this) {
- return mDeviceOwner != null
- && mDeviceOwner.hasDeviceOwner()
+ return mDeviceOwner.hasDeviceOwner()
&& mDeviceOwner.getDeviceOwnerPackageName().equals(packageName);
}
}
@@ -4176,11 +4167,8 @@
return null;
}
synchronized (this) {
- if (mDeviceOwner != null && mDeviceOwner.hasDeviceOwner()) {
- return mDeviceOwner.getDeviceOwnerPackageName();
- }
+ return mDeviceOwner.getDeviceOwnerPackageName();
}
- return null;
}
@Override
@@ -4190,7 +4178,7 @@
}
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
synchronized (this) {
- if (mDeviceOwner == null || !mDeviceOwner.hasDeviceOwner()) {
+ if (!mDeviceOwner.hasDeviceOwner()) {
return null;
}
String deviceOwnerPackage = mDeviceOwner.getDeviceOwnerPackageName();
@@ -4232,21 +4220,20 @@
}
synchronized (this) {
clearUserPoliciesLocked(new UserHandle(UserHandle.USER_OWNER));
- if (mDeviceOwner != null) {
- mDeviceOwner.clearDeviceOwner();
- mDeviceOwner.writeOwnerFile();
- updateDeviceOwnerLocked();
- // Reactivate backup service.
- long ident = Binder.clearCallingIdentity();
- try {
- IBackupManager ibm = IBackupManager.Stub.asInterface(
- ServiceManager.getService(Context.BACKUP_SERVICE));
- ibm.setBackupServiceActive(UserHandle.USER_OWNER, true);
- } catch (RemoteException e) {
- throw new IllegalStateException("Failed reactivating backup service.", e);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
+
+ mDeviceOwner.clearDeviceOwner();
+ mDeviceOwner.writeDeviceOwner();
+ updateDeviceOwnerLocked();
+ // Reactivate backup service.
+ long ident = Binder.clearCallingIdentity();
+ try {
+ IBackupManager ibm = IBackupManager.Stub.asInterface(
+ ServiceManager.getService(Context.BACKUP_SERVICE));
+ ibm.setBackupServiceActive(UserHandle.USER_OWNER, true);
+ } catch (RemoteException e) {
+ throw new IllegalStateException("Failed reactivating backup service.", e);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
}
}
@@ -4275,21 +4262,15 @@
synchronized (this) {
enforceCanSetDeviceInitializer(who);
- if (mDeviceOwner != null && mDeviceOwner.hasDeviceInitializer()) {
+ if (mDeviceOwner.hasDeviceInitializer()) {
throw new IllegalStateException(
"Trying to set device initializer but device initializer is already set.");
}
- if (mDeviceOwner == null) {
- // Device owner state does not exist, create it.
- mDeviceOwner = DeviceOwner.createWithDeviceInitializer(initializer);
- } else {
- // Device owner already exists, update it.
- mDeviceOwner.setDeviceInitializer(initializer);
- }
+ mDeviceOwner.setDeviceInitializer(initializer);
addDeviceInitializerToLockTaskPackagesLocked(UserHandle.USER_OWNER);
- mDeviceOwner.writeOwnerFile();
+ mDeviceOwner.writeDeviceOwner();
return true;
}
}
@@ -4313,8 +4294,7 @@
return false;
}
synchronized (this) {
- return mDeviceOwner != null
- && mDeviceOwner.hasDeviceInitializer()
+ return mDeviceOwner.hasDeviceInitializer()
&& mDeviceOwner.getDeviceInitializerPackageName().equals(packageName);
}
}
@@ -4325,7 +4305,7 @@
return null;
}
synchronized (this) {
- if (mDeviceOwner != null && mDeviceOwner.hasDeviceInitializer()) {
+ if (mDeviceOwner.hasDeviceInitializer()) {
return mDeviceOwner.getDeviceInitializerPackageName();
}
}
@@ -4338,7 +4318,7 @@
return null;
}
synchronized (this) {
- if (mDeviceOwner != null && mDeviceOwner.hasDeviceInitializer()) {
+ if (mDeviceOwner.hasDeviceInitializer()) {
return mDeviceOwner.getDeviceInitializerComponent();
}
}
@@ -4367,10 +4347,8 @@
synchronized (this) {
long ident = Binder.clearCallingIdentity();
try {
- if (mDeviceOwner != null) {
- mDeviceOwner.clearDeviceInitializer();
- mDeviceOwner.writeOwnerFile();
- }
+ mDeviceOwner.clearDeviceInitializer();
+ mDeviceOwner.writeDeviceOwner();
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -4389,15 +4367,8 @@
}
synchronized (this) {
enforceCanSetProfileOwner(userHandle);
- if (mDeviceOwner == null) {
- // Device owner state does not exist, create it.
- mDeviceOwner = DeviceOwner.createWithProfileOwner(who, ownerName,
- userHandle);
- } else {
- // Device owner state already exists, update it.
- mDeviceOwner.setProfileOwner(who, ownerName, userHandle);
- }
- mDeviceOwner.writeOwnerFile();
+ mDeviceOwner.setProfileOwner(who, ownerName, userHandle);
+ mDeviceOwner.writeProfileOwner(userHandle);
return true;
}
}
@@ -4412,10 +4383,9 @@
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
synchronized (this) {
clearUserPoliciesLocked(callingUser);
- if (mDeviceOwner != null) {
- mDeviceOwner.removeProfileOwner(callingUser.getIdentifier());
- mDeviceOwner.writeOwnerFile();
- }
+ final int userId = callingUser.getIdentifier();
+ mDeviceOwner.removeProfileOwner(userId);
+ mDeviceOwner.writeProfileOwner(userId);
}
}
@@ -4572,18 +4542,14 @@
}
synchronized (this) {
- if (mDeviceOwner != null) {
- return mDeviceOwner.getProfileOwnerComponent(userHandle);
- }
+ return mDeviceOwner.getProfileOwnerComponent(userHandle);
}
- return null;
}
// Returns the active profile owner for this user or null if the current user has no
// profile owner.
private ActiveAdmin getProfileOwnerAdmin(int userHandle) {
- ComponentName profileOwner =
- mDeviceOwner != null ? mDeviceOwner.getProfileOwnerComponent(userHandle) : null;
+ ComponentName profileOwner = mDeviceOwner.getProfileOwnerComponent(userHandle);
if (profileOwner == null) {
return null;
}
@@ -4785,9 +4751,7 @@
synchronized (this) {
p.println("Current Device Policy Manager state:");
- if (mDeviceOwner != null) {
- mDeviceOwner.dump(" ", pw);
- }
+ mDeviceOwner.dump(" ", pw);
int userCount = mUserData.size();
for (int u = 0; u < userCount; u++) {
DevicePolicyData policy = getUserData(mUserData.keyAt(u));
@@ -6351,7 +6315,7 @@
} else {
mDeviceOwner.setSystemUpdatePolicy(policy);
}
- mDeviceOwner.writeOwnerFile();
+ mDeviceOwner.writeDeviceOwner();
}
mContext.sendBroadcastAsUser(
new Intent(DevicePolicyManager.ACTION_SYSTEM_UPDATE_POLICY_CHANGED),
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DeviceOwnerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DeviceOwnerTest.java
index 7c3014c..8ad7eea 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DeviceOwnerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DeviceOwnerTest.java
@@ -17,11 +17,13 @@
package com.android.server.devicepolicy;
import android.content.ComponentName;
+import android.content.Context;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
+import java.io.File;
/**
* Tests for the DeviceOwner object that saves & loads device and policy owner information.
@@ -32,69 +34,34 @@
*/
public class DeviceOwnerTest extends AndroidTestCase {
- private ByteArrayInputStream mInputStreamForTest;
- private final ByteArrayOutputStream mOutputStreamForTest = new ByteArrayOutputStream();
+ private static class DeviceOwnerSub extends DeviceOwner{
+ private final File mLegacyFile;
+ private final File mDeviceOwnerFile;
+ private final File mProfileOwnerBase;
- @SmallTest
- public void testDeviceOwnerOnly() throws Exception {
- DeviceOwner out = new DeviceOwner(null, mOutputStreamForTest);
- out.setDeviceOwner("some.device.owner.package", "owner");
- out.writeOwnerFile();
+ public DeviceOwnerSub(Context context, File legacyFile, File deviceOwnerFile,
+ File profileOwnerBase) {
+ super(context);
+ mLegacyFile = legacyFile;
+ mDeviceOwnerFile = deviceOwnerFile;
+ mProfileOwnerBase = profileOwnerBase;
+ }
- mInputStreamForTest = new ByteArrayInputStream(mOutputStreamForTest.toByteArray());
- DeviceOwner in = new DeviceOwner(mInputStreamForTest, null);
- in.readOwnerFile();
+ @Override
+ File getLegacyConfigFileWithTestOverride() {
+ return mLegacyFile;
+ }
- assertEquals("some.device.owner.package", in.getDeviceOwnerPackageName());
- assertEquals("owner", in.getDeviceOwnerName());
- assertNull(in.getProfileOwnerComponent(1));
+ @Override
+ File getDeviceOwnerFileWithTestOverride() {
+ return mDeviceOwnerFile;
+ }
+
+ @Override
+ File getProfileOwnerFileWithTestOverride(int userId) {
+ return new File(mDeviceOwnerFile.getAbsoluteFile() + "-" + userId);
+ }
}
- @SmallTest
- public void testProfileOwnerOnly() throws Exception {
- DeviceOwner out = new DeviceOwner(null, mOutputStreamForTest);
- ComponentName admin = new ComponentName(
- "some.profile.owner.package", "some.profile.owner.package.Class");
- out.setProfileOwner(admin, "some-company", 1);
- out.writeOwnerFile();
-
- mInputStreamForTest = new ByteArrayInputStream(mOutputStreamForTest.toByteArray());
- DeviceOwner in = new DeviceOwner(mInputStreamForTest, null);
- in.readOwnerFile();
-
- assertNull(in.getDeviceOwnerPackageName());
- assertNull(in.getDeviceOwnerName());
- assertEquals(admin, in.getProfileOwnerComponent(1));
- assertEquals("some-company", in.getProfileOwnerName(1));
- }
-
- @SmallTest
- public void testDeviceAndProfileOwners() throws Exception {
- DeviceOwner out = new DeviceOwner(null, mOutputStreamForTest);
- ComponentName profileAdmin = new ComponentName(
- "some.profile.owner.package", "some.profile.owner.package.Class");
- ComponentName otherProfileAdmin = new ComponentName(
- "some.other.profile.owner", "some.other.profile.owner.OtherClass");
- // Old code used package name rather than component name, so the class
- // bit could be empty.
- ComponentName legacyComponentName = new ComponentName("legacy.profile.owner.package", "");
- out.setDeviceOwner("some.device.owner.package", "owner");
- out.setProfileOwner(profileAdmin, "some-company", 1);
- out.setProfileOwner(otherProfileAdmin, "some-other-company", 2);
- out.setProfileOwner(legacyComponentName, "legacy-company", 3);
- out.writeOwnerFile();
-
- mInputStreamForTest = new ByteArrayInputStream(mOutputStreamForTest.toByteArray());
-
- DeviceOwner in = new DeviceOwner(mInputStreamForTest, null);
- in.readOwnerFile();
-
- assertEquals("some.device.owner.package", in.getDeviceOwnerPackageName());
- assertEquals("owner", in.getDeviceOwnerName());
- assertEquals(profileAdmin, in.getProfileOwnerComponent(1));
- assertEquals("some-company", in.getProfileOwnerName(1));
- assertEquals(otherProfileAdmin, in.getProfileOwnerComponent(2));
- assertEquals("some-other-company", in.getProfileOwnerName(2));
- assertEquals(legacyComponentName, in.getProfileOwnerComponent(3));
- }
+ // TODO Write tests
}