Skip to content

(feat)hugepage: add v10 CMA reservoir management#37

Open
HuJK wants to merge 5 commits into
Droid-VM:masterfrom
HuJK:master
Open

(feat)hugepage: add v10 CMA reservoir management#37
HuJK wants to merge 5 commits into
Droid-VM:masterfrom
HuJK:master

Conversation

@HuJK

@HuJK HuJK commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

搭配 v10 模組,新增 CMA 管理功能,允許把保留池記憶體借給外部 app 用,需要時 acquire 收回
搭配 v11 模組,移除探測步驟,改由 hook 執行移除 CMA 限制

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

拆分为独立提交

Comment on lines +743 to +752
@NonNull
private static String join(@NonNull String... parts) {
var sb = new StringBuilder();
for (var p : parts) {
if (p.isEmpty()) continue;
if (sb.length() > 0) sb.append(' ');
sb.append(p);
}
return sb.toString();
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

放到StringUtils内

Comment on lines +633 to +634
var r = run("chmod 755 %s && timeout %d %s %d",
escapedString(bin), timeoutSec, escapedString(bin), floorMb);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

拆分为两个调用
建议用runList

Comment on lines 201 to 208
private Snapshot(boolean installed, boolean loaded, boolean statsOk, boolean bootEnabled,
long targetIdeal, long built, long free, long lent, long deficit,
boolean acquiring, int acquireMode, boolean hasPoolWant,
boolean softDisabled, @NonNull String state, @NonNull String totalServed,
boolean softDisabled, boolean hasCma, long wantWithCma,
long cmaPool, long availCmaAble, int cmaPbOrder,
@NonNull String state, @NonNull String totalServed,
@NonNull String totalRefilled, @NonNull String activeVms,
@NonNull String acquireStopReason) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

参数过多,请转为空构造器然后逐个赋值。如:

[...]
var s = new Snapshot();
s.installed = installed;
s.loaded = false;
[...]

默认参数等可以写到变量声明。如:

[...]
final long deficit = 0;
@NonNull final String state = "-";
[...]

Comment on lines 285 to 311
boolean hasCma = s.containsKey("pool_want_with_cma");
long wantWithCma = getLong(s, "pool_want_with_cma", 0);
long cmaPool = getLong(s, "pool_cma", 0);
long availCmaAble = getLong(s, "pool_avail_cma_able", -1);
int cmaPbOrder = (int) getLong(s, "cma_pb_order", -1);
// What acquire still has to do, mirroring the module's own "already at
// target" test (acquire_set): it runs when the POOL is short
// (avail + served < pool_want) OR the RESERVOIR is short
// (avail + served + pool_cma < pool_want_with_cma). Those are separate
// shortfalls: raising pool_want while the reservoir already covers the
// total leaves no total deficit, yet acquire must still stage pages in
// from the reservoir to fill the pool. Reporting only the total would
// grey out the acquire buttons exactly then.
long poolDeficit = Math.max(0, want - free - lent);
long reservoirDeficit = wantWithCma > 0
? Math.max(0, wantWithCma - free - lent - cmaPool) : 0;
long deficit = Math.max(poolDeficit, reservoirDeficit);
boolean acquiring = "1".equals(s.get("acquire_active"));
int mode = (int) getLong(s, "acquire_mode", -1);
boolean softDisabled = hasWant && rawWant <= 1;
return new Snapshot(installed, true, statsOk, bootEnabled,
want, built, free, lent, deficit, acquiring, mode, hasWant, softDisabled,
hasCma, wantWithCma, cmaPool, availCmaAble, cmaPbOrder,
s.getOrDefault("state", "-"), s.getOrDefault("total_served", "-"),
s.getOrDefault("total_refilled", "-"), s.getOrDefault("active_vms", "-"),
s.getOrDefault("acquire_stop_reason", "-"));
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个可以放一个独立构造器将s传入Snapshot处理

private Snapshot(Map<String, String> s) {
[...]
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

拆分为独立提交

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

拆分为独立提交

Comment on lines +123 to +151
<cn.classfun.droidvm.ui.widgets.row.TextInputRowWidget
android:id="@+id/input_pool_size"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="@string/hugepage_pool_size"
android:icon="@drawable/ic_resize"
android:inputType="number"
app:ti_max="16GiB"
app:ti_min="0MiB"
app:ti_mode="size"
app:ti_precision="2MiB"
app:ti_unit="GiB" />

<cn.classfun.droidvm.ui.widgets.row.TextInputRowWidget
android:id="@+id/input_cma_size"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="@string/hugepage_cma_pool_size"
android:inputType="number"
android:visibility="gone"
app:ti_max="24GiB"
app:ti_min="0MiB"
app:ti_mode="size"
app:ti_precision="2MiB"
app:ti_unit="GiB"
tools:visibility="visible" />
</LinearLayout>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

可能过于拥挤,需再次确认

Comment on lines +168 to +176
public void setStorage(
@NonNull int[] usedColors, @NonNull float[] usedValues,
@Nullable String[] usedLabels,
float avail, @Nullable String availLabel,
float availNonCma, int availNonCmaColor,
float cmaFree, @Nullable String cmaFreeLabel, int cmaFreeColor,
float cmaOther, @Nullable String cmaOtherLabel, int cmaOtherColor,
int deficitColor, float deficit, @Nullable String deficitLabel,
float want

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

参数过多,请引入独立的存储结构来传递数据(如class)

HuJK and others added 4 commits July 12, 2026 23:51
When no unit fits exactly (findUnit) or is at least the value (findFloatUnit),
fall back to the smallest unit in the *provided* list rather than hardcoding
SizeUnit.B, so a restricted picker (e.g. a GiB-only list) never yields a unit
outside it. For the full list units[0] is B, so the classic behaviour is
unchanged.

Split out of the v10 CMA reservoir work as an independent change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ARourbDczkCYsKUUMC9EFv
FrameLayout.setEnabled alone left the child MaterialSwitch enabled and directly
draggable, so a "disabled" row could still fire its change listener. Override
setEnabled to propagate to the switch, and gate the row's click-to-toggle on
switchView.isEnabled() so a disabled switch can't be toggled by tapping the row.

Split out of the v10 CMA reservoir work as an independent change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ARourbDczkCYsKUUMC9EFv
Two new size-mode options:
  - ti_unit pins the picker to exactly one unit (e.g. "GiB"): values always
    display and are entered in it, no other unit is offered.
  - ti_showUnit hides the picker button in narrow layouts while the fixed/
    derived unit still applies to typed values; setUnitButtonVisible toggles
    it at runtime.

Split out of the v10 CMA reservoir work as an independent change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ARourbDczkCYsKUUMC9EFv
Manage the module's CMA reservoir (pool_want_with_cma) from the hugepage
screen, and fix the pieces of the existing UI that the second target broke.

CMA switch + consumability probe:
  - A switch above "Enable Module" reads cma_probe_result from settings.prop:
    a recorded pass enables directly, anything else offers the probe.
  - The probe raises pool_want_with_cma (never lowers an existing bigger total
    - that would demolish reservoir the device is lending out), then empties
    the pool with a live pool_want=0 so its blocks flip straight into the
    reservoir, and lets a v3 acquire top it up as far as it can.
  - Coming up short is not a distinct failure: the reservoir is assembled out
    of the pool itself, so a fresh boot - unfragmented - simply succeeds.
  - pool_want is only ever written live, so an app killed mid-probe cannot
    leave the pool soft-disabled past a reboot; every exit restores it.
  - A pass pins the pool to 512 MB and keeps the rest as reservoir; a denial or
    unreadable result is put to the user. settings.prop writes became a locked
    read-modify-write so the probe thread and the pool-size save can't wipe
    each other's keys.

Runtime insmod now matches the boot-time one: prefer the module's own load.sh
(single source of truth for the preflight), else reconstruct only v9's
kapi_check ABI guard. insmod args are joined via StringUtils.joinNonEmpty.

Bar and captions: [VMs][available][CMA free][CMA lent][waiting], denominated
by pool_want_with_cma with the reservoir counted as filled. SegmentedBar's
storage bar takes a StorageSpec holder instead of an 18-argument call.

Snapshot parses a refill_stat key=value map in a dedicated constructor, with
field defaults standing in for the not-loaded view.

Acquire gating follows the module's own rule (acquire_set): work exists when
the pool is short OR the reservoir is short. A CMA-era grow kicks v3, not v1.

Pool size is a GiB-only input (ti_unit), split into pool / with-CMA total when
the reservoir is on, two-way linked so the pair keeps
pool_want <= pool_want_with_cma.

VM bar colours are keyed by rank among the live pids rather than by pid.

Co-Authored-By: lateautumn233 <lateautumn233@foxmail.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ARourbDczkCYsKUUMC9EFv
The v11 gh_hugepage_reserve module can open the movable->CMA redirect
directly, so the app no longer needs the balloon consumability probe to
decide whether apps can use the reservoir.

Remove the probe subsystem entirely: runCmaProbe and all of its dialog/worker
plumbing, the balloon runner, the cma_probe_result verdict, and the
reboot-to-finish pending prompt.

New flow when the CMA switch is turned on:
  - if moveable_to_cma_vender_already_allowed reads 1, the vendor kernel
    already redirects movable->CMA: enable directly, no risk;
    otherwise warn, then offer two named actions:
      * "Remove CMA Restriction" arms a lever LIVE ONLY (can crash/reboot the
        phone). On 6.1 the restrict_cma_redirect flag is side-effect-free so it
        is tried first (falling back to the gfp hook); on 6.6/6.12 the same key
        also backs cma_has_pcplist(), so the narrower gfp hook is used directly;
      * "Module CMA" builds the reservoir without arming any lever - no crash
        risk; the reserve still serves VMs via stage-in, and apps consume it
        only where the vendor kernel already allows movable->CMA;
  - once it is running, offer to save the setting to settings.prop for next
    boot. Splitting apply from save is the safety net: a live apply that
    crashes leaves nothing persisted, so the next boot comes up clean. The
    persisted key (cma_movable_lever) is app-owned; a future load.sh reads it.

Disabling reverts whichever lever was armed (the module no-ops these when the
vendor already redirects) and forgets the saved choice.

Pool-size UI: the pool size and the with-CMA total are now two stacked rows
instead of a cramped side-by-side pair; the with-CMA row is greyed and
non-editable while CMA is off.

A stale cma_probe_result from an older app version is cleared on screen load
so the unchanged boot script doesn't keep the module's CMA side cold.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ARourbDczkCYsKUUMC9EFv
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants