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

Commit 21c98807 authored by Tim Murray's avatar Tim Murray Committed by Android (Google) Code Review
Browse files

Merge "PinnerService: add support for pinning empty anon regions" into udc-qpr-dev

parents 7b576a65 3519f5d5
Loading
Loading
Loading
Loading
+75 −0
Original line number Diff line number Diff line
@@ -78,11 +78,14 @@ import java.io.InputStream;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import sun.misc.Unsafe;

/**
 * <p>PinnerService pins important files for key processes in memory.</p>
 * <p>Files to pin are specified in the config_defaultPinnerServiceFiles
@@ -150,6 +153,11 @@ public final class PinnerService extends SystemService {
    @GuardedBy("this")
    private ArraySet<Integer> mPinKeys;

    private static final long MAX_ANON_SIZE = 2L * (1L << 30); // 2GB
    private long mPinAnonSize;
    private long mPinAnonAddress;
    private long mCurrentlyPinnedAnonSize;

    // Resource-configured pinner flags;
    private final boolean mConfiguredToPinCamera;
    private final boolean mConfiguredToPinHome;
@@ -550,6 +558,11 @@ public final class PinnerService extends SystemService {
            pinKeys.add(KEY_ASSISTANT);
        }

        mPinAnonSize = DeviceConfig.getLong(DeviceConfig.NAMESPACE_RUNTIME_NATIVE_BOOT,
                "pin_anon_size",
                SystemProperties.getLong("pinner.pin_anon_size", 0));
        mPinAnonSize = Math.max(0, Math.min(mPinAnonSize, MAX_ANON_SIZE));

        return pinKeys;
    }

@@ -589,6 +602,7 @@ public final class PinnerService extends SystemService {
            int key = currentPinKeys.valueAt(i);
            pinApp(key, userHandle, true /* force */);
        }
        pinAnonRegion();
    }

    /**
@@ -672,6 +686,64 @@ public final class PinnerService extends SystemService {
        }
    }

    /**
     * Pin an empty anonymous region. This should only be used for ablation experiments.
     */
    private void pinAnonRegion() {
        if (mPinAnonSize == 0) {
            return;
        }
        long alignedPinSize = mPinAnonSize;
        if (alignedPinSize % PAGE_SIZE != 0) {
            alignedPinSize -= alignedPinSize % PAGE_SIZE;
            Slog.e(TAG, "pinAnonRegion: aligning size to " + alignedPinSize);
        }
        if (mPinAnonAddress != 0
                && mCurrentlyPinnedAnonSize != alignedPinSize) {
            unpinAnonRegion();
        }
        long address = 0;
        try {
            address = Os.mmap(0, alignedPinSize,
                    OsConstants.PROT_READ | OsConstants.PROT_WRITE,
                    OsConstants.MAP_PRIVATE | OsConstants.MAP_ANONYMOUS,
                    new FileDescriptor(), /*offset=*/0);

            Unsafe tempUnsafe = null;
            Class<sun.misc.Unsafe> clazz = sun.misc.Unsafe.class;
            for (java.lang.reflect.Field f : clazz.getDeclaredFields()) {
                f.setAccessible(true);
                Object obj = f.get(null);
                if (clazz.isInstance(obj)) {
                    tempUnsafe = clazz.cast(obj);
                }
            }
            if (tempUnsafe == null) {
                throw new Exception("Couldn't get Unsafe");
            }
            Method setMemory = clazz.getMethod("setMemory", long.class, long.class, byte.class);
            setMemory.invoke(tempUnsafe, address, alignedPinSize, (byte) 1);
            Os.mlock(address, alignedPinSize);
            mCurrentlyPinnedAnonSize = alignedPinSize;
            mPinAnonAddress = address;
            address = -1;
            Slog.e(TAG, "pinAnonRegion success, size=" + mCurrentlyPinnedAnonSize);
        } catch (Exception ex) {
            Slog.e(TAG, "Could not pin anon region of size " + alignedPinSize, ex);
            return;
        } finally {
            if (address >= 0) {
                safeMunmap(address, alignedPinSize);
            }
        }
    }

    private void unpinAnonRegion() {
        if (mPinAnonAddress != 0) {
            safeMunmap(mPinAnonAddress, mCurrentlyPinnedAnonSize);
        }
    }

    /**
     * @return The maximum amount of bytes to be pinned for an app of type {@code key}.
     */
@@ -1083,6 +1155,9 @@ public final class PinnerService extends SystemService {
                        totalSize += pf.bytesPinned;
                    }
                }
                if (mPinAnonAddress != 0) {
                    pw.format("Pinned anon region: %s\n", mCurrentlyPinnedAnonSize);
                }
                pw.format("Total size: %s\n", totalSize);
                pw.println();
                if (!mPendingRepin.isEmpty()) {