Architecture & limitations¶
This document is intended for readers who want to understand implementation details or troubleshoot compatibility issues. For the complete roadmap and target design, see the technical design (Chinese).
Overall structure¶
NestSpace consists of three parts:
- App-level container: Loads the target APK inside the host process and provides a virtualized Android runtime environment for the target app.
- Desktop and space management: Installation, multiple instances, data isolation, icon organization, and system app selection.
- Control channel: Binder-based UI control inside the container, the local AI assistant, and the externally facing MCP Server.
The container is not system-level virtualization; it runs inside NestSpace's own process and simulates the environment the target app needs through ClassLoader, resources, Context, and system service proxies.
Installation and launch¶
Installation¶
- Parse the APK's manifest, resource table, and signature.
- Validate the package name, signature consistency,
minSdk, andREQUIRE_SECURE_ENV. - Copy the APK into the app-private directory and write the installation record; split APKs are merged into a single installation descriptor.
- Create an instance for the app; instance data directories are separated by
data/<package>/<instance>.
Launch¶
- Allocate a slot process from the container process pool by
package@instance. - Load the target code with
DexClassLoader, load target resources withAssetManager, and construct a target-awareContextandResources. - Attach the target Activity to the host window through reflection and drive the full lifecycle.
- The target's
ApplicationexecutesattachBaseContextandonCreate.
Isolation¶
- Each
package@instanceis pinned to an independent host process from:c1to:c16. - An instance's
files,cache,code_cache,databases,getDir, and SharedPreferences use independent namespaces. - Native libraries are extracted by ABI into the instance directory and used as the
librarySearchPathforDexClassLoader; when the same instance is reused, the old process is ended first to avoid sharing JNI global state for.sofiles with the same name. - Target Java exceptions are intercepted and recorded by a crash protection layer; native crashes or
System.exitaffect only the corresponding slot process.
The process pool is managed automatically by default and has a maximum of 16 slots; when memory is tight, background containers are reclaimed in least-recently-used order, and foreground containers are not closed. A fixed slot limit (1–16) can also be set.
Virtualized system capabilities¶
- Activity: Driven through the full callback sequence such as
onCreate → onStart → onRestoreInstanceState → onPostCreate → onResume → onPostResume, supporting in-container Activity navigation, the back stack, splash screens, andstartActivityForResult. - Service / Provider / Broadcast: Target Services are instantiated by the target ClassLoader; Providers are routed by authority; manifest and dynamically registered BroadcastReceivers support normal, ordered, and sticky broadcasts.
- PackageManager: Components, permissions, signatures, UID, labels/icons, resources, and launch Intents for the target package are answered from the APK descriptor; queries across virtual apps in the same space and implicit Intent resolution are also served by the virtual index.
- Notifications: Package name, tag, channel, and group are isolated by virtual package, and the small icon and PendingIntent are automatically rewritten into a form the host accepts.
- JobScheduler: A local scheduler is returned inside the container, target
JobServicecomponents are driven by the target ClassLoader, and delays, periodic execution, backoff, and common constraints are supported. - Permissions: Queries such as
checkSelfPermissiongo through the virtual permission table;requestPermissionsis connected to the host's real permission request, and results are persisted per package. - GMS: Binder transactions to
IGmsServiceBrokerhave the package name andAttributionSourcerewritten, covering common call paths such as WebView/Chimera. - UI control: Inside the container process, Binder is used to observe the view tree, tap, input text, and take screenshots, and to merge windows created by target Activities such as dialogs and bottom sheets; no accessibility service is required.
Control and Agent¶
- Local AI assistant: Supports Claude-compatible and OpenAI-compatible endpoints and operates the
virtual-1space throughspace_*,ui_*, andbrowser_*tools. - Remote MCP: A built-in Streamable HTTP Server that listens only on
127.0.0.1by default, with LAN listening available when explicitly enabled; supports multi-client sessions, SSE heartbeats, and DELETE sessions. - External MCP tools: The local assistant can connect to external MCP Servers; tool names are isolated with an
mcp_<id>_prefix and are not exposed to remote clients. - Browser: A built-in multi-tab WebView; headless tabs are created by the Agent and can be taken over by the visible browser; downloads, uploads, and the proxy are shared with the container tools.
Known limitations¶
- Start with apps you are familiar with; if you run into compatibility issues, it is easier to tell whether the problem is in the app itself or in container adaptation, and it is also easier to report to the project.
- Compatibility depends on the target app's app hardening, native SDKs, dynamic loading, and dependency combination; not every app can run directly, and issues need to be adapted one app at a time.
- At most 16 container processes can run at the same time, and the actual number is also limited by device memory; in automatic mode, when memory is insufficient, the least recently used background container is reclaimed.
- Job, Alarm, and broadcast bridging work only while the container process is alive; after the process is reclaimed by the system, it will not be woken by the system. Full background keepalive still requires a foreground service strategy.
- Cross-virtual-app
startActivitystill falls back to the host and currently mainly supports the query and resolution level; cross-app Provider queries only support the package's own authority. - Android 7.x (API 24–25) does not have
ContentResolver.wrap, so Provider virtualization is disabled on those versions; the other container capabilities remain available. - Standalone processes such as Google Play services validate against the real UID/package name, and only some Binder interfaces are currently proxied; different apps may require additional adaptation.
- Apps containing only arm64 native libraries require an arm64 device; an x86_64 emulator returns
ABI_MISMATCHbefore launch. - A target Activity's
savedInstanceStateis stored in-process and supports same-process recreation, but is not retained across process death. - The synthetic UID is used only for app-layer queries; the system side still sees the host UID.
- Headless launch depends on the background activity launch exemption provided by the overlay permission; without it,
space_launchreturnsLAUNCH_BLOCKED. - LAN MCP uses plaintext HTTP + Bearer Token without TLS and should only be enabled on trusted networks.
- The built-in browser proxy requires Android 10+ and WebView support for
PROXY_OVERRIDE; proxies that require a username/password are not currently supported. - External MCP clients currently support only HTTP POST (with JSON or SSE responses) and Bearer Token.
- The AI assistant is fixed to operate within the
virtual-1space and does not control system-wide apps.