Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a0085ebf authored by Automerger Merge Worker's avatar Automerger Merge Worker
Browse files

Merge "Add a limit on how much data an app can acquire a lease on." into...

Merge "Add a limit on how much data an app can acquire a lease on." into rvc-dev am: cd629dd3 am: 78a5f4ba

Change-Id: I345dbebc9a646e0d6483d7e99f46bf3385aa4a7c
parents a6b70111 78a5f4ba
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -242,7 +242,7 @@ class BlobMetadata {
        return hasOtherLeasees(null, uid);
        return hasOtherLeasees(null, uid);
    }
    }


    private boolean isALeasee(@Nullable String packageName, int uid) {
    boolean isALeasee(@Nullable String packageName, int uid) {
        synchronized (mMetadataLock) {
        synchronized (mMetadataLock) {
            // Check if the package is a leasee of the data blob.
            // Check if the package is a leasee of the data blob.
            for (int i = 0, size = mLeasees.size(); i < size; ++i) {
            for (int i = 0, size = mLeasees.size(); i < size; ++i) {
+98 −0
Original line number Original line Diff line number Diff line
@@ -15,12 +15,23 @@
 */
 */
package com.android.server.blob;
package com.android.server.blob;


import static android.provider.DeviceConfig.NAMESPACE_BLOBSTORE;
import static android.text.format.Formatter.FLAG_IEC_UNITS;
import static android.text.format.Formatter.formatFileSize;
import static android.util.TimeUtils.formatDuration;

import android.annotation.NonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.content.Context;
import android.os.Environment;
import android.os.Environment;
import android.provider.DeviceConfig;
import android.provider.DeviceConfig.Properties;
import android.util.DataUnit;
import android.util.Log;
import android.util.Log;
import android.util.Slog;
import android.util.Slog;


import com.android.internal.util.IndentingPrintWriter;

import java.io.File;
import java.io.File;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeUnit;


@@ -55,6 +66,76 @@ class BlobStoreConfig {
     */
     */
    public static final long SESSION_EXPIRY_TIMEOUT_MILLIS = TimeUnit.DAYS.toMillis(7);
    public static final long SESSION_EXPIRY_TIMEOUT_MILLIS = TimeUnit.DAYS.toMillis(7);


    public static class DeviceConfigProperties {
        /**
         * Denotes how low the limit for the amount of data, that an app will be allowed to acquire
         * a lease on, can be.
         */
        public static final String KEY_TOTAL_BYTES_PER_APP_LIMIT_FLOOR =
                "total_bytes_per_app_limit_floor";
        public static final long DEFAULT_TOTAL_BYTES_PER_APP_LIMIT_FLOOR =
                DataUnit.MEBIBYTES.toBytes(300); // 300 MiB
        public static long TOTAL_BYTES_PER_APP_LIMIT_FLOOR =
                DEFAULT_TOTAL_BYTES_PER_APP_LIMIT_FLOOR;

        /**
         * Denotes the maximum amount of data an app can acquire a lease on, in terms of fraction
         * of total disk space.
         */
        public static final String KEY_TOTAL_BYTES_PER_APP_LIMIT_FRACTION =
                "total_bytes_per_app_limit_fraction";
        public static final float DEFAULT_TOTAL_BYTES_PER_APP_LIMIT_FRACTION = 0.01f;
        public static float TOTAL_BYTES_PER_APP_LIMIT_FRACTION =
                DEFAULT_TOTAL_BYTES_PER_APP_LIMIT_FRACTION;

        static void refresh(Properties properties) {
            if (!NAMESPACE_BLOBSTORE.equals(properties.getNamespace())) {
                return;
            }
            properties.getKeyset().forEach(key -> {
                switch (key) {
                    case KEY_TOTAL_BYTES_PER_APP_LIMIT_FLOOR:
                        TOTAL_BYTES_PER_APP_LIMIT_FLOOR = properties.getLong(key,
                                DEFAULT_TOTAL_BYTES_PER_APP_LIMIT_FLOOR);
                        break;
                    case KEY_TOTAL_BYTES_PER_APP_LIMIT_FRACTION:
                        TOTAL_BYTES_PER_APP_LIMIT_FRACTION = properties.getFloat(key,
                                DEFAULT_TOTAL_BYTES_PER_APP_LIMIT_FRACTION);
                        break;
                    default:
                        Slog.wtf(TAG, "Unknown key in device config properties: " + key);
                }
            });
        }

        static void dump(IndentingPrintWriter fout, Context context) {
            final String dumpFormat = "%s: [cur: %s, def: %s]";
            fout.println(String.format(dumpFormat, KEY_TOTAL_BYTES_PER_APP_LIMIT_FLOOR,
                    formatFileSize(context, TOTAL_BYTES_PER_APP_LIMIT_FLOOR, FLAG_IEC_UNITS),
                    formatFileSize(context, DEFAULT_TOTAL_BYTES_PER_APP_LIMIT_FLOOR,
                            FLAG_IEC_UNITS)));
            fout.println(String.format(dumpFormat, KEY_TOTAL_BYTES_PER_APP_LIMIT_FRACTION,
                    TOTAL_BYTES_PER_APP_LIMIT_FRACTION,
                    DEFAULT_TOTAL_BYTES_PER_APP_LIMIT_FRACTION));
        }
    }

    public static void initialize(Context context) {
        DeviceConfig.addOnPropertiesChangedListener(NAMESPACE_BLOBSTORE,
                context.getMainExecutor(),
                properties -> DeviceConfigProperties.refresh(properties));
        DeviceConfigProperties.refresh(DeviceConfig.getProperties(NAMESPACE_BLOBSTORE));
    }

    /**
     * Returns the maximum amount of data that an app can acquire a lease on.
     */
    public static long getAppDataBytesLimit() {
        final long totalBytesLimit = (long) (Environment.getDataSystemDirectory().getTotalSpace()
                * DeviceConfigProperties.TOTAL_BYTES_PER_APP_LIMIT_FRACTION);
        return Math.max(DeviceConfigProperties.TOTAL_BYTES_PER_APP_LIMIT_FLOOR, totalBytesLimit);
    }

    @Nullable
    @Nullable
    public static File prepareBlobFile(long sessionId) {
    public static File prepareBlobFile(long sessionId) {
        final File blobsDir = prepareBlobsDir();
        final File blobsDir = prepareBlobsDir();
@@ -123,4 +204,21 @@ class BlobStoreConfig {
    public static File getBlobStoreRootDir() {
    public static File getBlobStoreRootDir() {
        return new File(Environment.getDataSystemDirectory(), ROOT_DIR_NAME);
        return new File(Environment.getDataSystemDirectory(), ROOT_DIR_NAME);
    }
    }

    public static void dump(IndentingPrintWriter fout, Context context) {
        fout.println("XML current version: " + XML_VERSION_CURRENT);

        fout.println("Idle job ID: " + IDLE_JOB_ID);
        fout.println("Idle job period: " + formatDuration(IDLE_JOB_PERIOD_MILLIS));

        fout.println("Session expiry timeout: " + formatDuration(SESSION_EXPIRY_TIMEOUT_MILLIS));

        fout.println("Total bytes per app limit: " + formatFileSize(context,
                getAppDataBytesLimit(), FLAG_IEC_UNITS));

        fout.println("Device config properties:");
        fout.increaseIndent();
        DeviceConfigProperties.dump(fout, context);
        fout.decreaseIndent();
    }
}
}
+70 −14
Original line number Original line Diff line number Diff line
@@ -188,7 +188,9 @@ public class BlobStoreManagerService extends SystemService {


    @Override
    @Override
    public void onBootPhase(int phase) {
    public void onBootPhase(int phase) {
        if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
        if (phase == PHASE_ACTIVITY_MANAGER_READY) {
            BlobStoreConfig.initialize(mContext);
        } else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
            synchronized (mBlobsLock) {
            synchronized (mBlobsLock) {
                final SparseArray<SparseArray<String>> allPackages = getAllPackages();
                final SparseArray<SparseArray<String>> allPackages = getAllPackages();
                readBlobSessionsLocked(allPackages);
                readBlobSessionsLocked(allPackages);
@@ -381,6 +383,11 @@ public class BlobStoreManagerService extends SystemService {
                throw new IllegalArgumentException(
                throw new IllegalArgumentException(
                        "Lease expiry cannot be later than blobs expiry time");
                        "Lease expiry cannot be later than blobs expiry time");
            }
            }
            if (getTotalUsageBytesLocked(callingUid, callingPackage)
                    + blobMetadata.getSize() > BlobStoreConfig.getAppDataBytesLimit()) {
                throw new IllegalStateException("Total amount of data with an active lease"
                        + " is exceeding the max limit");
            }
            blobMetadata.addLeasee(callingPackage, callingUid,
            blobMetadata.addLeasee(callingPackage, callingUid,
                    descriptionResId, description, leaseExpiryTimeMillis);
                    descriptionResId, description, leaseExpiryTimeMillis);
            if (LOGV) {
            if (LOGV) {
@@ -391,6 +398,18 @@ public class BlobStoreManagerService extends SystemService {
        }
        }
    }
    }


    @VisibleForTesting
    @GuardedBy("mBlobsLock")
    long getTotalUsageBytesLocked(int callingUid, String callingPackage) {
        final AtomicLong totalBytes = new AtomicLong(0);
        forEachBlobInUser((blobMetadata) -> {
            if (blobMetadata.isALeasee(callingPackage, callingUid)) {
                totalBytes.getAndAdd(blobMetadata.getSize());
            }
        }, UserHandle.getUserId(callingUid));
        return totalBytes.get();
    }

    private void releaseLeaseInternal(BlobHandle blobHandle, int callingUid,
    private void releaseLeaseInternal(BlobHandle blobHandle, int callingUid,
            String callingPackage) {
            String callingPackage) {
        synchronized (mBlobsLock) {
        synchronized (mBlobsLock) {
@@ -1236,8 +1255,10 @@ public class BlobStoreManagerService extends SystemService {
            }
            }


            synchronized (mBlobsLock) {
            synchronized (mBlobsLock) {
                if (dumpArgs.shouldDumpAllSections()) {
                    fout.println("mCurrentMaxSessionId: " + mCurrentMaxSessionId);
                    fout.println("mCurrentMaxSessionId: " + mCurrentMaxSessionId);
                    fout.println();
                    fout.println();
                }


                if (dumpArgs.shouldDumpSessions()) {
                if (dumpArgs.shouldDumpSessions()) {
                    dumpSessionsLocked(fout, dumpArgs);
                    dumpSessionsLocked(fout, dumpArgs);
@@ -1248,6 +1269,14 @@ public class BlobStoreManagerService extends SystemService {
                    fout.println();
                    fout.println();
                }
                }
            }
            }

            if (dumpArgs.shouldDumpConfig()) {
                fout.println("BlobStore config:");
                fout.increaseIndent();
                BlobStoreConfig.dump(fout, mContext);
                fout.decreaseIndent();
                fout.println();
            }
        }
        }


        @Override
        @Override
@@ -1260,14 +1289,16 @@ public class BlobStoreManagerService extends SystemService {
    }
    }


    static final class DumpArgs {
    static final class DumpArgs {
        private static final int FLAG_DUMP_SESSIONS = 1 << 0;
        private static final int FLAG_DUMP_BLOBS = 1 << 1;
        private static final int FLAG_DUMP_CONFIG = 1 << 2;

        private int mSelectedSectionFlags;
        private boolean mDumpFull;
        private boolean mDumpFull;
        private final ArrayList<String> mDumpPackages = new ArrayList<>();
        private final ArrayList<String> mDumpPackages = new ArrayList<>();
        private final ArrayList<Integer> mDumpUids = new ArrayList<>();
        private final ArrayList<Integer> mDumpUids = new ArrayList<>();
        private final ArrayList<Integer> mDumpUserIds = new ArrayList<>();
        private final ArrayList<Integer> mDumpUserIds = new ArrayList<>();
        private final ArrayList<Long> mDumpBlobIds = new ArrayList<>();
        private final ArrayList<Long> mDumpBlobIds = new ArrayList<>();
        private boolean mDumpOnlySelectedSections;
        private boolean mDumpSessions;
        private boolean mDumpBlobs;
        private boolean mDumpHelp;
        private boolean mDumpHelp;


        public boolean shouldDumpSession(String packageName, int uid, long blobId) {
        public boolean shouldDumpSession(String packageName, int uid, long blobId) {
@@ -1286,18 +1317,41 @@ public class BlobStoreManagerService extends SystemService {
            return true;
            return true;
        }
        }


        public boolean shouldDumpAllSections() {
            return mSelectedSectionFlags == 0;
        }

        public void allowDumpSessions() {
            mSelectedSectionFlags |= FLAG_DUMP_SESSIONS;
        }

        public boolean shouldDumpSessions() {
        public boolean shouldDumpSessions() {
            if (!mDumpOnlySelectedSections) {
            if (shouldDumpAllSections()) {
                return true;
                return true;
            }
            }
            return mDumpSessions;
            return (mSelectedSectionFlags & FLAG_DUMP_SESSIONS) != 0;
        }

        public void allowDumpBlobs() {
            mSelectedSectionFlags |= FLAG_DUMP_BLOBS;
        }
        }


        public boolean shouldDumpBlobs() {
        public boolean shouldDumpBlobs() {
            if (!mDumpOnlySelectedSections) {
            if (shouldDumpAllSections()) {
                return true;
            }
            return (mSelectedSectionFlags & FLAG_DUMP_BLOBS) != 0;
        }

        public void allowDumpConfig() {
            mSelectedSectionFlags |= FLAG_DUMP_CONFIG;
        }

        public boolean shouldDumpConfig() {
            if (shouldDumpAllSections()) {
                return true;
                return true;
            }
            }
            return mDumpBlobs;
            return (mSelectedSectionFlags & FLAG_DUMP_CONFIG) != 0;
        }
        }


        public boolean shouldDumpBlob(long blobId) {
        public boolean shouldDumpBlob(long blobId) {
@@ -1334,11 +1388,11 @@ public class BlobStoreManagerService extends SystemService {
                        dumpArgs.mDumpFull = true;
                        dumpArgs.mDumpFull = true;
                    }
                    }
                } else if ("--sessions".equals(opt)) {
                } else if ("--sessions".equals(opt)) {
                    dumpArgs.mDumpOnlySelectedSections = true;
                    dumpArgs.allowDumpSessions();
                    dumpArgs.mDumpSessions = true;
                } else if ("--blobs".equals(opt)) {
                } else if ("--blobs".equals(opt)) {
                    dumpArgs.mDumpOnlySelectedSections = true;
                    dumpArgs.allowDumpBlobs();
                    dumpArgs.mDumpBlobs = true;
                } else if ("--config".equals(opt)) {
                    dumpArgs.allowDumpConfig();
                } else if ("--package".equals(opt) || "-p".equals(opt)) {
                } else if ("--package".equals(opt) || "-p".equals(opt)) {
                    dumpArgs.mDumpPackages.add(getStringArgRequired(args, ++i, "packageName"));
                    dumpArgs.mDumpPackages.add(getStringArgRequired(args, ++i, "packageName"));
                } else if ("--uid".equals(opt) || "-u".equals(opt)) {
                } else if ("--uid".equals(opt) || "-u".equals(opt)) {
@@ -1397,6 +1451,8 @@ public class BlobStoreManagerService extends SystemService {
            printWithIndent(pw, "Dump only the sessions info");
            printWithIndent(pw, "Dump only the sessions info");
            pw.println("--blobs");
            pw.println("--blobs");
            printWithIndent(pw, "Dump only the committed blobs info");
            printWithIndent(pw, "Dump only the committed blobs info");
            pw.println("--config");
            printWithIndent(pw, "Dump only the config values");
            pw.println("--package | -p [package-name]");
            pw.println("--package | -p [package-name]");
            printWithIndent(pw, "Dump blobs info associated with the given package");
            printWithIndent(pw, "Dump blobs info associated with the given package");
            pw.println("--uid | -u [uid]");
            pw.println("--uid | -u [uid]");
+1 −0
Original line number Original line Diff line number Diff line
@@ -9131,6 +9131,7 @@ package android.provider {
    field public static final String NAMESPACE_ATTENTION_MANAGER_SERVICE = "attention_manager_service";
    field public static final String NAMESPACE_ATTENTION_MANAGER_SERVICE = "attention_manager_service";
    field public static final String NAMESPACE_AUTOFILL = "autofill";
    field public static final String NAMESPACE_AUTOFILL = "autofill";
    field public static final String NAMESPACE_BIOMETRICS = "biometrics";
    field public static final String NAMESPACE_BIOMETRICS = "biometrics";
    field public static final String NAMESPACE_BLOBSTORE = "blobstore";
    field public static final String NAMESPACE_CONNECTIVITY = "connectivity";
    field public static final String NAMESPACE_CONNECTIVITY = "connectivity";
    field public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture";
    field public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture";
    field @Deprecated public static final String NAMESPACE_DEX_BOOT = "dex_boot";
    field @Deprecated public static final String NAMESPACE_DEX_BOOT = "dex_boot";
+8 −0
Original line number Original line Diff line number Diff line
@@ -110,6 +110,14 @@ public final class DeviceConfig {
    @TestApi
    @TestApi
    public static final String NAMESPACE_AUTOFILL = "autofill";
    public static final String NAMESPACE_AUTOFILL = "autofill";


    /**
     * Namespace for blobstore feature that allows apps to share data blobs.
     *
     * @hide
     */
    @SystemApi
    public static final String NAMESPACE_BLOBSTORE = "blobstore";

    /**
    /**
     * Namespace for all networking connectivity related features.
     * Namespace for all networking connectivity related features.
     *
     *
Loading