diff options
| author | 2023-09-29 22:06:43 +0000 | |
|---|---|---|
| committer | 2023-10-10 19:04:45 +0000 | |
| commit | 8a7d616b967a75154d946f7b534b0b9c96db2c47 (patch) | |
| tree | 909baf6d4d47f8a37656a73209d0c79bacb9ca1d | |
| parent | 042df8f083c3e6e6feec057ac52dc78d4ad3e46b (diff) | |
PinnerService: Update support for pinning anon regions
This change does the following:
* Fixes refresh of anon region pinning - The pinAnonRegion
method was being called multiple times redundantly (e.g., for
different users, or during startup). This resulted in duplicate
pinnings of the same region size, potentially 3-4x the requested
memory after a single boot. This is not safe even for experiments.
Update behavior to listen to config changes and refresh accordingly,
including releasing memory if the experiment flag is reset.
* Changes the mapping from MAP_PRIVATE to MAP_SHARED - This avoids
issues w/ downstream telemetry where rss.anon values (as read from
/proc/*/status) trigger behavior like heap dumps/profiles. The memory
region is still anonymous, and even appears as private dirty in
showmap/dumpsys meminfo (due to the invalidating setMemory() call on
the shared anon buffer), but in perfetto memory accounting, it
falls under `mem.rss.shmem`.
* Renames pin_anon_size to pin_shared_anon_size - As it's not safe to
use the previous flag due to (1), and the semantics are changed
slightly in (2), introduce a different name.
Bug: 294079161
Test: device_config put runtime_native_boot \
pin_shared_anon_size 2000000000
Test: device_config put runtime_native_boot \
pin_shared_anon_size 0
Test: device_config delete runtime_native_boot \
pin_shared_anon_size
Test: showmap `pidof system_server`
Test: cat /proc/`pidof system_server`/status | grep 'Rss'
Change-Id: I7c7c0dc76b9ff04c9cd05de25bfaed65372a56a0
| -rw-r--r-- | services/core/java/com/android/server/PinnerService.java | 62 |
1 files changed, 52 insertions, 10 deletions
diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java index 93dca2f4f192..57ed5a298d9f 100644 --- a/services/core/java/com/android/server/PinnerService.java +++ b/services/core/java/com/android/server/PinnerService.java @@ -41,6 +41,7 @@ import android.net.Uri; import android.os.Binder; import android.os.Build; import android.os.Handler; +import android.os.HandlerExecutor; import android.os.Looper; import android.os.Message; import android.os.RemoteException; @@ -153,6 +154,9 @@ public final class PinnerService extends SystemService { @GuardedBy("this") private ArraySet<Integer> mPinKeys; + private static final String DEVICE_CONFIG_KEY_ANON_SIZE = "pin_shared_anon_size"; + private static final long DEFAULT_ANON_SIZE = + SystemProperties.getLong("pinner.pin_shared_anon_size", 0); private static final long MAX_ANON_SIZE = 2L * (1L << 30); // 2GB private long mPinAnonSize; private long mPinAnonAddress; @@ -180,6 +184,17 @@ public final class PinnerService extends SystemService { } }; + private DeviceConfig.OnPropertiesChangedListener mDeviceConfigListener = + new DeviceConfig.OnPropertiesChangedListener() { + @Override + public void onPropertiesChanged(DeviceConfig.Properties properties) { + if (DeviceConfig.NAMESPACE_RUNTIME_NATIVE_BOOT.equals(properties.getNamespace()) + && properties.getKeyset().contains(DEVICE_CONFIG_KEY_ANON_SIZE)) { + refreshPinAnonConfig(); + } + } + }; + public PinnerService(Context context) { super(context); @@ -206,6 +221,11 @@ public final class PinnerService extends SystemService { registerUidListener(); registerUserSetupCompleteListener(); + + DeviceConfig.addOnPropertiesChangedListener( + DeviceConfig.NAMESPACE_RUNTIME_NATIVE_BOOT, + new HandlerExecutor(mPinnerHandler), + mDeviceConfigListener); } @Override @@ -344,6 +364,8 @@ public final class PinnerService extends SystemService { } } } + + refreshPinAnonConfig(); } /** @@ -560,11 +582,6 @@ 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; } @@ -604,7 +621,6 @@ public final class PinnerService extends SystemService { int key = currentPinKeys.valueAt(i); pinApp(key, userHandle, true /* force */); } - pinAnonRegion(); } /** @@ -689,10 +705,28 @@ public final class PinnerService extends SystemService { } /** + * Handle any changes in the anon region pinner config. + */ + private void refreshPinAnonConfig() { + long newPinAnonSize = + DeviceConfig.getLong( + DeviceConfig.NAMESPACE_RUNTIME_NATIVE_BOOT, + DEVICE_CONFIG_KEY_ANON_SIZE, + DEFAULT_ANON_SIZE); + newPinAnonSize = Math.max(0, Math.min(newPinAnonSize, MAX_ANON_SIZE)); + if (newPinAnonSize != mPinAnonSize) { + mPinAnonSize = newPinAnonSize; + pinAnonRegion(); + } + } + + /** * Pin an empty anonymous region. This should only be used for ablation experiments. */ private void pinAnonRegion() { if (mPinAnonSize == 0) { + Slog.d(TAG, "pinAnonRegion: releasing pinned region"); + unpinAnonRegion(); return; } long alignedPinSize = mPinAnonSize; @@ -700,15 +734,21 @@ public final class PinnerService extends SystemService { alignedPinSize -= alignedPinSize % PAGE_SIZE; Slog.e(TAG, "pinAnonRegion: aligning size to " + alignedPinSize); } - if (mPinAnonAddress != 0 - && mCurrentlyPinnedAnonSize != alignedPinSize) { + if (mPinAnonAddress != 0) { + if (mCurrentlyPinnedAnonSize == alignedPinSize) { + Slog.d(TAG, "pinAnonRegion: already pinned region of size " + alignedPinSize); + return; + } + Slog.d(TAG, "pinAnonRegion: resetting pinned region for new size " + alignedPinSize); unpinAnonRegion(); } long address = 0; try { + // Map as SHARED to avoid changing rss.anon for system_server (per /proc/*/status). + // The mapping is visible in other rss metrics, and as private dirty in smaps/meminfo. address = Os.mmap(0, alignedPinSize, OsConstants.PROT_READ | OsConstants.PROT_WRITE, - OsConstants.MAP_PRIVATE | OsConstants.MAP_ANONYMOUS, + OsConstants.MAP_SHARED | OsConstants.MAP_ANONYMOUS, new FileDescriptor(), /*offset=*/0); Unsafe tempUnsafe = null; @@ -729,7 +769,7 @@ public final class PinnerService extends SystemService { mCurrentlyPinnedAnonSize = alignedPinSize; mPinAnonAddress = address; address = -1; - Slog.e(TAG, "pinAnonRegion success, size=" + mCurrentlyPinnedAnonSize); + Slog.w(TAG, "pinAnonRegion success, size=" + mCurrentlyPinnedAnonSize); } catch (Exception ex) { Slog.e(TAG, "Could not pin anon region of size " + alignedPinSize, ex); return; @@ -744,6 +784,8 @@ public final class PinnerService extends SystemService { if (mPinAnonAddress != 0) { safeMunmap(mPinAnonAddress, mCurrentlyPinnedAnonSize); } + mPinAnonAddress = 0; + mCurrentlyPinnedAnonSize = 0; } /** |