Loading core/java/android/accounts/Account.java +7 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import android.util.ArraySet; import android.util.Log; import com.android.internal.annotations.GuardedBy; import java.util.Objects; import java.util.Set; /** Loading Loading @@ -80,6 +81,12 @@ public class Account implements Parcelable { if (TextUtils.isEmpty(type)) { throw new IllegalArgumentException("the type must not be empty: " + type); } if (name.length() > 200) { throw new IllegalArgumentException("account name is longer than 200 characters"); } if (type.length() > 200) { throw new IllegalArgumentException("account type is longer than 200 characters"); } this.name = name; this.type = type; this.accessId = accessId; Loading services/core/java/com/android/server/accounts/AccountManagerService.java +11 −0 Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ import android.app.admin.DeviceAdminInfo; import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyManagerInternal; import android.content.BroadcastReceiver; import android.content.ClipData; import android.content.ComponentName; import android.content.Context; import android.content.Intent; Loading Loading @@ -1777,6 +1778,11 @@ public class AccountManagerService + ", skipping since the account already exists"); return false; } if (accounts.accountsDb.findAllDeAccounts().size() > 100) { Log.w(TAG, "insertAccountIntoDatabase: " + account + ", skipping since more than 50 accounts on device exist"); return false; } long accountId = accounts.accountsDb.insertCeAccount(account, password); if (accountId < 0) { Log.w(TAG, "insertAccountIntoDatabase: " + account Loading Loading @@ -4734,6 +4740,11 @@ public class AccountManagerService * supplied entries in the system Settings app. */ protected boolean checkKeyIntent(int authUid, Intent intent) { // Explicitly set an empty ClipData to ensure that we don't offer to // promote any Uris contained inside for granting purposes if (intent.getClipData() == null) { intent.setClipData(ClipData.newPlainText(null, null)); } intent.setFlags(intent.getFlags() & ~(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION Loading services/core/java/com/android/server/pm/PackageInstallerService.java +41 −4 Original line number Diff line number Diff line Loading @@ -119,6 +119,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub { private static final long MAX_ACTIVE_SESSIONS = 1024; /** Upper bound on number of historical sessions for a UID */ private static final long MAX_HISTORICAL_SESSIONS = 1048576; /** Destroy sessions older than this on storage free request */ private static final long MAX_SESSION_AGE_ON_LOW_STORAGE_MILLIS = 8 * DateUtils.HOUR_IN_MILLIS; private final Context mContext; private final PackageManagerService mPm; Loading Loading @@ -218,18 +220,26 @@ public class PackageInstallerService extends IPackageInstaller.Stub { } private void reconcileStagesLocked(String volumeUuid, boolean isEphemeral) { final File stagingDir = buildStagingDir(volumeUuid, isEphemeral); final ArraySet<File> unclaimedStages = newArraySet( stagingDir.listFiles(sStageFilter)); final ArraySet<File> unclaimedStages = getStagingDirsOnVolume(volumeUuid, isEphemeral); // Ignore stages claimed by active sessions for (int i = 0; i < mSessions.size(); i++) { final PackageInstallerSession session = mSessions.valueAt(i); unclaimedStages.remove(session.stageDir); } removeStagingDirs(unclaimedStages); } private ArraySet<File> getStagingDirsOnVolume(String volumeUuid, boolean isEphemeral) { final File stagingDir = buildStagingDir(volumeUuid, isEphemeral); final ArraySet<File> stagingDirs = newArraySet( stagingDir.listFiles(sStageFilter)); return stagingDirs; } private void removeStagingDirs(ArraySet<File> stagingDirsToRemove) { // Clean up orphaned staging directories for (File stage : unclaimedStages) { for (File stage : stagingDirsToRemove) { Slog.w(TAG, "Deleting orphan stage " + stage); synchronized (mPm.mInstallLock) { mPm.removeCodePathLI(stage); Loading @@ -237,6 +247,33 @@ public class PackageInstallerService extends IPackageInstaller.Stub { } } /** * Called to free up some storage space from obsolete installation files */ public void freeStageDirs(String volumeUuid, boolean internalVolume) { final ArraySet<File> unclaimedStagingDirsOnVolume = getStagingDirsOnVolume(volumeUuid, internalVolume); final long currentTimeMillis = System.currentTimeMillis(); synchronized (mSessions) { for (int i = 0; i < mSessions.size(); i++) { final PackageInstallerSession session = mSessions.valueAt(i); if (!unclaimedStagingDirsOnVolume.contains(session.stageDir)) { // Only handles sessions stored on the target volume continue; } final long age = currentTimeMillis - session.createdMillis; if (age >= MAX_SESSION_AGE_ON_LOW_STORAGE_MILLIS) { // Aggressively close old sessions because we are running low on storage // Their staging dirs will be removed too session.abandon(); } else { // Session is new enough, so it deserves to be kept even on low storage unclaimedStagingDirsOnVolume.remove(session.stageDir); } } } removeStagingDirs(unclaimedStagingDirsOnVolume); } public void onPrivateVolumeMounted(String volumeUuid) { synchronized (mSessions) { reconcileStagesLocked(volumeUuid, false /*isInstant*/); Loading services/core/java/com/android/server/pm/PackageInstallerSession.java +14 −1 Original line number Diff line number Diff line Loading @@ -703,6 +703,19 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } /** * Check if the caller is the owner of this session. Otherwise throw a * {@link SecurityException}. */ @GuardedBy("mLock") private void assertCallerIsOwnerOrRootOrSystemLocked() { final int callingUid = Binder.getCallingUid(); if (callingUid != Process.ROOT_UID && callingUid != mInstallerUid && callingUid != Process.SYSTEM_UID) { throw new SecurityException("Session does not belong to uid " + callingUid); } } /** * If anybody is reading or writing data of the session, throw an {@link SecurityException}. */ Loading Loading @@ -1489,7 +1502,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @Override public void abandon() { synchronized (mLock) { assertCallerIsOwnerOrRootLocked(); assertCallerIsOwnerOrRootOrSystemLocked(); if (mRelinquished) { Slog.d(TAG, "Ignoring abandon after commit relinquished control"); Loading services/core/java/com/android/server/pm/PackageManagerService.java +3 −0 Original line number Diff line number Diff line Loading @@ -4762,6 +4762,9 @@ public class PackageManagerService extends IPackageManager.Stub InstantAppRegistry.DEFAULT_UNINSTALLED_INSTANT_APP_MIN_CACHE_PERIOD))) { return; } // 11. Clear temp install session files mInstallerService.freeStageDirs(volumeUuid, internalVolume); } else { try { mInstaller.freeCache(volumeUuid, bytes, 0, 0); Loading
core/java/android/accounts/Account.java +7 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import android.util.ArraySet; import android.util.Log; import com.android.internal.annotations.GuardedBy; import java.util.Objects; import java.util.Set; /** Loading Loading @@ -80,6 +81,12 @@ public class Account implements Parcelable { if (TextUtils.isEmpty(type)) { throw new IllegalArgumentException("the type must not be empty: " + type); } if (name.length() > 200) { throw new IllegalArgumentException("account name is longer than 200 characters"); } if (type.length() > 200) { throw new IllegalArgumentException("account type is longer than 200 characters"); } this.name = name; this.type = type; this.accessId = accessId; Loading
services/core/java/com/android/server/accounts/AccountManagerService.java +11 −0 Original line number Diff line number Diff line Loading @@ -46,6 +46,7 @@ import android.app.admin.DeviceAdminInfo; import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyManagerInternal; import android.content.BroadcastReceiver; import android.content.ClipData; import android.content.ComponentName; import android.content.Context; import android.content.Intent; Loading Loading @@ -1777,6 +1778,11 @@ public class AccountManagerService + ", skipping since the account already exists"); return false; } if (accounts.accountsDb.findAllDeAccounts().size() > 100) { Log.w(TAG, "insertAccountIntoDatabase: " + account + ", skipping since more than 50 accounts on device exist"); return false; } long accountId = accounts.accountsDb.insertCeAccount(account, password); if (accountId < 0) { Log.w(TAG, "insertAccountIntoDatabase: " + account Loading Loading @@ -4734,6 +4740,11 @@ public class AccountManagerService * supplied entries in the system Settings app. */ protected boolean checkKeyIntent(int authUid, Intent intent) { // Explicitly set an empty ClipData to ensure that we don't offer to // promote any Uris contained inside for granting purposes if (intent.getClipData() == null) { intent.setClipData(ClipData.newPlainText(null, null)); } intent.setFlags(intent.getFlags() & ~(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION Loading
services/core/java/com/android/server/pm/PackageInstallerService.java +41 −4 Original line number Diff line number Diff line Loading @@ -119,6 +119,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub { private static final long MAX_ACTIVE_SESSIONS = 1024; /** Upper bound on number of historical sessions for a UID */ private static final long MAX_HISTORICAL_SESSIONS = 1048576; /** Destroy sessions older than this on storage free request */ private static final long MAX_SESSION_AGE_ON_LOW_STORAGE_MILLIS = 8 * DateUtils.HOUR_IN_MILLIS; private final Context mContext; private final PackageManagerService mPm; Loading Loading @@ -218,18 +220,26 @@ public class PackageInstallerService extends IPackageInstaller.Stub { } private void reconcileStagesLocked(String volumeUuid, boolean isEphemeral) { final File stagingDir = buildStagingDir(volumeUuid, isEphemeral); final ArraySet<File> unclaimedStages = newArraySet( stagingDir.listFiles(sStageFilter)); final ArraySet<File> unclaimedStages = getStagingDirsOnVolume(volumeUuid, isEphemeral); // Ignore stages claimed by active sessions for (int i = 0; i < mSessions.size(); i++) { final PackageInstallerSession session = mSessions.valueAt(i); unclaimedStages.remove(session.stageDir); } removeStagingDirs(unclaimedStages); } private ArraySet<File> getStagingDirsOnVolume(String volumeUuid, boolean isEphemeral) { final File stagingDir = buildStagingDir(volumeUuid, isEphemeral); final ArraySet<File> stagingDirs = newArraySet( stagingDir.listFiles(sStageFilter)); return stagingDirs; } private void removeStagingDirs(ArraySet<File> stagingDirsToRemove) { // Clean up orphaned staging directories for (File stage : unclaimedStages) { for (File stage : stagingDirsToRemove) { Slog.w(TAG, "Deleting orphan stage " + stage); synchronized (mPm.mInstallLock) { mPm.removeCodePathLI(stage); Loading @@ -237,6 +247,33 @@ public class PackageInstallerService extends IPackageInstaller.Stub { } } /** * Called to free up some storage space from obsolete installation files */ public void freeStageDirs(String volumeUuid, boolean internalVolume) { final ArraySet<File> unclaimedStagingDirsOnVolume = getStagingDirsOnVolume(volumeUuid, internalVolume); final long currentTimeMillis = System.currentTimeMillis(); synchronized (mSessions) { for (int i = 0; i < mSessions.size(); i++) { final PackageInstallerSession session = mSessions.valueAt(i); if (!unclaimedStagingDirsOnVolume.contains(session.stageDir)) { // Only handles sessions stored on the target volume continue; } final long age = currentTimeMillis - session.createdMillis; if (age >= MAX_SESSION_AGE_ON_LOW_STORAGE_MILLIS) { // Aggressively close old sessions because we are running low on storage // Their staging dirs will be removed too session.abandon(); } else { // Session is new enough, so it deserves to be kept even on low storage unclaimedStagingDirsOnVolume.remove(session.stageDir); } } } removeStagingDirs(unclaimedStagingDirsOnVolume); } public void onPrivateVolumeMounted(String volumeUuid) { synchronized (mSessions) { reconcileStagesLocked(volumeUuid, false /*isInstant*/); Loading
services/core/java/com/android/server/pm/PackageInstallerSession.java +14 −1 Original line number Diff line number Diff line Loading @@ -703,6 +703,19 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } /** * Check if the caller is the owner of this session. Otherwise throw a * {@link SecurityException}. */ @GuardedBy("mLock") private void assertCallerIsOwnerOrRootOrSystemLocked() { final int callingUid = Binder.getCallingUid(); if (callingUid != Process.ROOT_UID && callingUid != mInstallerUid && callingUid != Process.SYSTEM_UID) { throw new SecurityException("Session does not belong to uid " + callingUid); } } /** * If anybody is reading or writing data of the session, throw an {@link SecurityException}. */ Loading Loading @@ -1489,7 +1502,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @Override public void abandon() { synchronized (mLock) { assertCallerIsOwnerOrRootLocked(); assertCallerIsOwnerOrRootOrSystemLocked(); if (mRelinquished) { Slog.d(TAG, "Ignoring abandon after commit relinquished control"); Loading
services/core/java/com/android/server/pm/PackageManagerService.java +3 −0 Original line number Diff line number Diff line Loading @@ -4762,6 +4762,9 @@ public class PackageManagerService extends IPackageManager.Stub InstantAppRegistry.DEFAULT_UNINSTALLED_INSTANT_APP_MIN_CACHE_PERIOD))) { return; } // 11. Clear temp install session files mInstallerService.freeStageDirs(volumeUuid, internalVolume); } else { try { mInstaller.freeCache(volumeUuid, bytes, 0, 0);