アーキテクチャと制限¶
この記事は、実装の詳細を知りたい方や互換性の問題を調査したい方を対象としています。完全なロードマップと目標設計については技術設計(中国語)を参照してください。
全体構成¶
NestSpace は 3 つの部分で構成されています。
- アプリレベルのコンテナ:ホストプロセス内で対象の APK を読み込み、対象アプリに仮想化された Android 実行環境を提供します。
- デスクトップとスペース管理:インストール、複製(マルチインスタンス)、データ分離、アイコン整理、システムアプリの選択。
- 制御チャネル:コンテナ内の Binder UI 制御、ローカルの AI アシスタント、外部向けの MCP Server。
コンテナはシステムレベルの仮想化ではありません。NestSpace 自身のプロセス内で動作し、ClassLoader、リソース、Context、システムサービスプロキシを通じて、対象アプリが必要とする環境を模擬します。
インストールと起動¶
インストール¶
- APK のマニフェスト、リソーステーブル、署名を解析します。
- パッケージ名、署名の一致、
minSdk、REQUIRE_SECURE_ENVを検証します。 - APK をアプリ専用ディレクトリにコピーし、インストール記録を書き込みます。split APK は 1 つのインストール記述に統合されます。
- アプリのインスタンスを作成します。インスタンスデータディレクトリは
data/<package>/<instance>で分離されます。
起動¶
package@instanceに従って、コンテナプロセスプールからスロットプロセスを 1 つ割り当てます。DexClassLoaderで対象のコードを読み込み、AssetManagerで対象のリソースを読み込み、対象を認識するContextとResourcesを構築します。- リフレクションを通じて対象の Activity をホストウィンドウに attach し、完全なライフサイクルを駆動します。
- 対象の
ApplicationはattachBaseContextとonCreateを実行します。
分離方式¶
- 各
package@instanceは独立した:c1〜:c16のホストプロセスに固定されます。 - インスタンスの
files、cache、code_cache、databases、getDir、SharedPreferences は独立した名前空間を使用します。 - ネイティブライブラリは ABI ごとにインスタンスディレクトリへ抽出され、
DexClassLoaderのlibrarySearchPathとして使用されます。同じインスタンスを再利用する場合は先に古いプロセスを終了し、同名.soの JNI グローバル状態の混用を避けます。 - 対象の Java 例外はクラッシュ保護レイヤーで捕捉して記録されます。ネイティブクラッシュや
System.exitは、対応するスロットプロセスにのみ影響します。
プロセスプールはデフォルトで最大 16 個のスロットを自動管理します。メモリが逼迫すると、最も長く使われていないバックグラウンドコンテナから回収され、フォアグラウンドのコンテナは終了されません。固定のスロット上限(1〜16)を設定することもできます。
仮想化されるシステム機能¶
- Activity:
onCreate → onStart → onRestoreInstanceState → onPostCreate → onResume → onPostResumeなどの完全なコールバックで駆動し、コンテナ内の Activity 遷移、バックスタック、Splash ページ、startActivityForResultに対応します。 - Service / Provider / Broadcast:対象の Service は対象の ClassLoader でインスタンス化されます。Provider は authority に従ってルーティングされます。マニフェストと動的 BroadcastReceiver は、通常のブロードキャスト、順序付きブロードキャスト、sticky ブロードキャストに対応します。
- PackageManager:対象パッケージのコンポーネント、権限、署名、UID、ラベル/アイコン、リソース、起動 Intent は APK 記述子から返されます。同じスペース内の仮想アプリ間のクエリや暗黙的 Intent の解決も、仮想インデックスによって提供されます。
- 通知:パッケージ名、tag、channel、group は仮想パッケージごとに分離され、small icon と PendingIntent はホストが受け入れ可能な形式に自動的に書き換えられます。
- JobScheduler:コンテナ内ではローカルスケジューラを返し、対象の
JobServiceは対象の ClassLoader で駆動されます。遅延、周期、バックオフ、一般的な制約に対応します。 - 権限:
checkSelfPermissionなどのクエリは仮想権限テーブルを参照します。requestPermissionsはホストの実際の権限申請に接続され、結果はパッケージごとに永続化されます。 - GMS:
IGmsServiceBrokerの Binder トランザクションに対してパッケージ名とAttributionSourceを書き換え、WebView/Chimera などの一般的な呼び出しパスをカバーします。 - UI 制御:コンテナプロセス内で Binder を通じて View ツリーの観察、タップ、入力、スクリーンショットを行い、対象 Activity が独自に作成した Dialog やボトムシートなどのウィンドウも統合します。アクセシビリティサービスには依存しません。
制御と Agent¶
- ローカル AI アシスタント:Claude 互換と OpenAI 互換のインターフェースに対応し、
space_*、ui_*、browser_*ツールを通じてvirtual-1スペースを操作します。 - リモート MCP:Streamable HTTP Server を内蔵し、デフォルトでは
127.0.0.1のみを待ち受けます。LAN 待ち受けを明示的に有効にできます。マルチクライアントセッション、SSE ハートビート、DELETE セッションに対応します。 - 外部 MCP ツール:ローカルアシスタントは外部 MCP Server に接続でき、ツール名は
mcp_<id>_プレフィックスで分離され、リモートクライアントには公開されません。 - ブラウザ:マルチタブ WebView を内蔵し、ヘッドレスタブは Agent が作成し、表示可能なブラウザに引き継ぐことができます。ダウンロード、アップロード、プロキシはコンテナツールと共用されます。
既知の制限¶
- まず自分が使い慣れたアプリをインストールすることをおすすめします。互換性の問題が起きたときに、アプリ自体の問題かコンテナの適応の問題かを判断しやすく、プロジェクトへのフィードバックも容易になります。
- 互換性は対象アプリの加固(パッカー)、ネイティブ SDK、動的ロード、依存関係の組み合わせに依存します。すべてのアプリがそのまま実行できるわけではなく、問題が発生した場合は個別に対応する必要があります。
- 同時に実行できるコンテナプロセスは最大 16 個で、実際の数はデバイスのメモリにも制限されます。自動モードではメモリ不足時に、最も長く使われていないバックグラウンドコンテナが回収されます。
- Job、Alarm、ブロードキャストのブリッジはコンテナプロセスが存続している間のみ有効です。プロセスがシステムに回収されると、システムから起動されることはありません。完全なバックグラウンド維持には、依然としてフォアグラウンドサービスの戦略が必要です。
- 仮想アプリ間の
startActivityはホストにフォールバックし、現在は主にクエリと解決のレベルでサポートされています。アプリ間の Provider クエリは、自パッケージの authority のみをサポートします。 - Android 7.x(API 24〜25)には
ContentResolver.wrapがないため、Provider の仮想化はそのバージョンでは無効になります。その他のコンテナ機能は引き続き使用できます。 - Google Play services などの独立プロセスは実際の UID/パッケージ名で検証され、現在は一部の Binder インターフェースのみを代理しています。アプリによっては追加の対応が必要になる場合があります。
- arm64 のネイティブライブラリのみを含むアプリは arm64 デバイスが必要です。x86_64 エミュレーターでは起動前に
ABI_MISMATCHが返されます。 - 対象 Activity の
savedInstanceStateはプロセス内に保存され、同一プロセス内での再構築には対応しますが、プロセスが強制終了された後はプロセスを跨いで保持されません。 - 合成 UID はアプリ層のクエリにのみ使用され、システム側からは引き続きホスト UID が見えます。
- ヘッドレス起動は、オーバーレイ権限によるバックグラウンド Activity 起動の例外許可に依存します。権限がない場合、
space_launchはLAUNCH_BLOCKEDを返します。 - LAN MCP は平文 HTTP + Bearer Token を使用し、TLS はありません。信頼できるネットワークでのみ有効にしてください。
- 内蔵ブラウザのプロキシは Android 10 以降かつ WebView が
PROXY_OVERRIDEをサポートしている必要があり、ユーザー名/パスワードが必要なプロキシには現在対応していません。 - 外部 MCP クライアントは現在、HTTP POST(JSON または SSE レスポンス)と Bearer Token のみをサポートしています。
- AI アシスタントは
virtual-1スペース内での操作に固定されており、システム全体のアプリを制御することはありません。