ラベル Zygote の投稿を表示しています。 すべての投稿を表示
ラベル Zygote の投稿を表示しています。 すべての投稿を表示

2011年2月2日水曜日

Zygoteへの起動要求を出している箇所を探す(その2)

というわけで、先日の続きです。

Zygoteを使って新しいVMプロセスを生成していそうな箇所は
  • android.os.Process.start()を呼び出すコード
  • /system/bin/dvz
の二つにとりあえず絞りました。
というわけで、Process.start()を呼び出していそうな箇所をきちんと探してみたら、あっさり見つかりました。

frameworks/base/services/java/com/android/server/am/ActivityManagerService.java

private final void startProcessLocked(ProcessRecord app, String hostingType, String hostingNameStr) {
        :
        :
    int pid = Process.start("android.app.ActivityThread",
        mSimpleProcessManagement ? app.processName : null, uid, uid,
        gids, debugFlags, null);
        :
        :
}

しかしまぁ、このActivityManagerServiceさんは難敵です。
何せ、メソッドの行数の長いこと・・・・。このコード、なかなか難易度が高いです。
とりあえず、こういうときは焦らず最初から。

横浜PF部の勉強会ではちらりと述べたのですが、Zygoteは起動時に--start-system-serverという引数を受け取っており、プロセス生成後、最初の子プロセスとしてsystem_serverを生成しています。このSystemServerは、内部でServerThreadというスレッドをrunしています。

frameworks/base/services/java/com/android/server/SystemServer.java
public void run() {
        :
        :
    context = ActivityManagerService.main(factoryTest);
        :
        :
}

というわけで、mainが直接呼び出されています。mainはというと

frameworks/base/services/java/com/android/server/am/ActivityManagerService.java
public static final Context main(int factoryTest) {
    AThread thr = new AThread();
    thr.start();
    synchronized (thr) {
        while (thr.mService == null) {
            try {
                thr.wait();
            } catch (InterruptedException e) {
            }
        }
    }
    ActivityManagerService m = thr.mService;
    mSelf = m;
    ActivityThread at = ActivityThread.systemMain();
    mSystemThread = at;
    Context context = at.getSystemContext();

    m.mContext = context;
    m.mFactoryTest = factoryTest;
    m.mMainStack = new ActivityStack(m, context, true);
    m.mBatteryStatsService.publish(context);
    m.mUsageStatsService.publish(context);

    synchronized (thr) {
        thr.mReady = true;
        thr.notifyAll();
    }
    m.startRunning(null, null, null, null);
    return context;
}

まずは、Athreadを生成してrunした後、AThreadのmServiceが設定されるのを待っています。
Athreadとはというと
frameworks/base/services/java/com/android/server/am/ActivityManagerService.java
static class AThread extends Thread {
    ActivityManagerService mService;
    boolean mReady = false;

    public AThread() {
        super("ActivityManager");
    }

    public void run() {
        Looper.prepare();
        android.os.Process.setThreadPriority(
        android.os.Process.THREAD_PRIORITY_FOREGROUND);
        android.os.Process.setCanSelfBackground(false);
        ActivityManagerService m = new ActivityManagerService();
        synchronized (this) {
            mService = m;
            notifyAll();
        }
        synchronized (this) {
            while (!mReady) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        Looper.loop();
    }
}
ということで、Looperのprepareを呼び出した後、ActivityManagerServiceの生成を行いmServiceに設定したうえで、mReadyのフラグが立つのを待っています。
スレッドを生成したmainに処理が戻ると、mServiceのActivityManagerServiceにcontext等を設定した上で、mReadyフラグを立てて、AThreadの処理を実行させた後、AThreadのActivityManagerService#startRunning()を呼び出します。
AThreadの方はというと、Looper.loop()でメッセージループを実行していますね。

一方、startRunning()はというと
public final void startRunning(String pkg, String cls, String action,String data) {
    synchronized(this) {
        if (mStartRunning) {
            return;
        }
        mStartRunning = true;
        mTopComponent = pkg != null && cls != null ? new ComponentName(pkg, cls) : null;
        mTopAction = action != null ? action : Intent.ACTION_MAIN;
        mTopData = data;
        if (!mSystemReady) {
            return;
        }
    }
    systemReady(null);
}

初回起動ですので、systemReady(null)が呼び出されます。
正直な話、真面目に話そうと思うと、PF部の発表時間の枠に収まりませんし、とりあえず、重要そうな処理だけを追いかけます。
public void systemReady(final Runnable goingCallback) {
        :
        :
    Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
    ris = AppGlobals.getPackageManager().queryIntentReceivers(intent, null, 0);
        :
        :
    for (int i=ris.size()-1; i>=0; i--) {
        if ((ris.get(i).activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
            ris.remove(i);
        }
    }
        :
        :

     intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
    ArrayList<ComponentName> lastDoneReceivers = readLastDonePreBootReceivers();


                    final ArrayList<ComponentName> doneReceivers = new ArrayList<ComponentName>();
                    for (int i=0; i<ris.size(); i++) {
                        ActivityInfo ai = ris.get(i).activityInfo;
                        ComponentName comp = new ComponentName(ai.packageName, ai.name);
                        if (lastDoneReceivers.contains(comp)) {
                            ris.remove(i);
                            i--;
                        }
                    }
                  
                    for (int i=0; i<ris.size(); i++) {
                        ActivityInfo ai = ris.get(i).activityInfo;
                        ComponentName comp = new ComponentName(ai.packageName, ai.name);
                        doneReceivers.add(comp);
                        intent.setComponent(comp);
                        IIntentReceiver finisher = null;
                        if (i == ris.size()-1) {
                            finisher = new IIntentReceiver.Stub() {
                                public void performReceive(Intent intent, int resultCode,
                                        String data, Bundle extras, boolean ordered,
                                        boolean sticky) {
                                    mHandler.post(new Runnable() {
                                        public void run() {
                                            synchronized (ActivityManagerService.this) {
                                                mDidUpdate = true;
                                            }
                                            writeLastDonePreBootReceivers(doneReceivers);
                                            systemReady(goingCallback);
                                        }
                                    });
                                }
                            };
                        }
                        Slog.i(TAG, "Sending system update to: " + intent.getComponent());
                        broadcastIntentLocked(null, null, intent, null, finisher,
                                0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID);
                        if (finisher != null) {
                            mWaitingUpdate = true;
                        }
                    }

ということで、詳しいことは置いておいてコードを見る限り
1. PackageManagerからACTION_PRE_BOOT_COMPLETEDのReceiverのリストを取得
2. リストから、FLAG_SYSTEMを持たないものを削除
3. 既にreadLastDonePreBootReceiversで、既に起動済みのものを削除?
4. 残ったリストにintent処理の終了用コードを設定して
5. FLAG_RECEIVER_BOOT_UPGRADEフラグを追加したIntentを送信

といった処理のようですね。
割と込み入っているところを、かなり適当にこんな時間に追いかけているので、何か見落としもありそうですが、とりあえず、この辺りが起動処理に絡んでいそうだという雰囲気です。

追記:
とまぁ、ここまでコードを追いかけてみたもののここが当たりかはちょっと不安を抱いてます。
そもそもActivityManagerServiceとPackageManagerServiceだと、PackageManagerServiceの方が後に生成されたりとかしていますし。
ちょっとログを仕込んでビルドして、実際に動かしてみないと駄目だなぁ・・・。

2011年2月1日火曜日

Zygoteへの起動要求を出している箇所を探す(その1)

週末は病院巡りとQt的なお話で少々忙しかったのでお休みしてました。
で、続き行きます。そろそろ真面目にペースを上げないと、資料作成に入れませんし。

ここまでの調査でZygote(app_process)が、socketを待ち受け、sokectに起動パラメータが来るとそれに従って自身のコピーを使ってJavaアプリの起動を行うという流れまで確認しました。
では、誰がソケットを開いて要求を投げてくるのかを探してみたいなと思っています。

まぁ、まずは待ち受けてるソケットを調べて見るのがセオリーでしょうね。
先日は待ち受けているコードは見つかりました。

private static final String ANDROID_SOCKET_ENV = "ANDROID_SOCKET_zygote";
        :
private static void registerZygoteSocket() {
        :
    String env = System.getenv(ANDROID_SOCKET_ENV);
    fileDesc = Integer.parseInt(env);
    sServerSocket = new LocalServerSocket(createFileDescriptor(fileDesc));
        :
}

でも、環境変数から先がよくわかっていなかったので、とりあえず、実際に動いているエミュレータで当たってみましょう。
とりあえずadb shellでzygoteのプロセス番号をしらべます。
# ps
USER PID PPID VSIZE RSS WCHAN PC NAME
        :
        :
radio 32 1 5412 484 ffffffff afd0bdac S /system/bin/rild
root 33 1 63964 20588 c009b74c afd0b844 S zygote
media 34 1 17212 1364 ffffffff afd0b6fc S /system/bin/mediaserver
        :
        :

続いて、openされているfdを調べます。開いているsocketが2つありますね。
# ls -l /proc/33/fd
lrwx------ root root 2011-01-31 22:51 0 -> /dev/null
lrwx------ root root 2011-01-31 22:51 1 -> /dev/null
lrwx------ root root 2011-01-31 22:51 2 -> /dev/null
l-wx------ root root 2011-01-31 22:51 3 -> /dev/log/main
l-wx------ root root 2011-01-31 22:51 4 -> /dev/log/radio
l-wx------ root root 2011-01-31 22:51 5 -> /dev/log/events
lr-x------ root root 2011-01-31 22:51 6 -> /system/framework/core.jar
lr-x------ root root 2011-01-31 22:51 7 -> /system/framework/bouncycastle.jar
lr-x------ root root 2011-01-31 22:51 8 -> /dev/__properties__ (deleted)
lrwx------ root root 2011-01-31 22:51 9 -> socket:[289]
lr-x------ root root 2011-01-31 22:51 10 -> /system/framework/ext.jar
lr-x------ root root 2011-01-31 22:51 11 -> /system/framework/framework.jar
lr-x------ root root 2011-01-31 22:51 12 -> /system/framework/android.policy.jar
lr-x------ root root 2011-01-31 22:51 13 -> /system/framework/services.jar
lr-x------ root root 2011-01-31 22:51 14 -> /system/framework/core-junit.jar
lr-x------ root root 2011-01-31 22:51 15 -> /system/framework/framework.jar
lr-x------ root root 2011-01-31 22:51 16 -> /system/fonts/DroidSans.ttf
lr-x------ root root 2011-01-31 22:51 17 -> /system/framework/core.jar
lr-x------ root root 2011-01-31 22:51 18 -> /dev/urandom
lr-x------ root root 2011-01-31 22:51 19 -> /system/framework/framework-res.apk
lrwx------ root root 2011-01-31 22:51 20 -> socket:[583]
では、開いているsocketを調べてみましょう。LocalServerなんて名前からもunixかなぁと当て推量で・・・・。
# cat /proc/net/unix
Num RefCount Protocol Flags Type St Inode Path
c5924de0: 00000002 00000000 00010000 0001 01 257 /dev/socket/property_service
c5924960: 00000002 00000000 00010000 0001 01 276 /dev/socket/vold
c59247e0: 00000002 00000000 00010000 0001 01 283 /dev/socket/netd
c5924660: 00000002 00000000 00010000 0001 01 285 /dev/socket/rild-debug
c59244e0: 00000002 00000000 00010000 0001 01 287 /dev/socket/rild
c5924360: 00000002 00000000 00010000 0001 01 289 /dev/socket/zygote
c5b34800: 00000002 00000000 00010000 0001 01 319 @jdwp-control
c59241e0: 00000002 00000000 00010000 0001 01 296 /dev/socket/installd
c5924060: 00000002 00000000 00010000 0001 01 298 /dev/socket/keystore
c5b34e00: 00000002 00000000 00010000 0001 01 305 /dev/socket/qemud
c5b34c80: 00000002 00000000 00010000 0001 01 308 @android:debuggerd
        :
        :
c40fb3c0: 00000003 00000000 00000000 0001 03 613 /dev/socket/qemud
c40fb240: 00000003 00000000 00000000 0001 03 612
c40fb0c0: 00000002 00000000 00000000 0001 03 606
c40fbb40: 00000003 00000000 00000000 0001 03 583 /dev/socket/zygote
c40fbcc0: 00000003 00000000 00000000 0001 03 582
c40fbe40: 00000003 00000000 00000000 0001 03 564
c40716a0: 00000003 00000000 00000000 0001 03 563
c4071520: 00000003 00000000 00000000 0001 03 561
c40713a0: 00000003 00000000 00000000 0001 03 560
c4071220: 00000003 00000000 00000000 0001 03 558 /dev/socket/vold
c40710a0: 00000003 00000000 00000000 0001 03 557
c4071820: 00000003 00000000 00000000 0001 03 550 /dev/socket/netd
c40719a0: 00000003 00000000 00000000 0001 03 549
c4071b20: 00000003 00000000 00000000 0001 03 538 /dev/socket/qemud
c4071ca0: 00000003 00000000 00000000 0001 03 537
c4071e20: 00000003 00000000 00000000 0001 03 317 /dev/socket/installd
c5b34380: 00000003 00000000 00000000 0001 03 523
c5b34200: 00000003 00000000 00000000 0001 03 404 @jdwp-control
c5b34080: 00000003 00000000 00000000 0001 03 402
c5b34500: 00000003 00000000 00000000 0001 03 354 /dev/socket/qemud
c5b34680: 00000003 00000000 00000000 0001 03 353
c5b34980: 00000003 00000000 00000000 0001 03 316
c5b34b00: 00000003 00000000 00000000 0001 03 315
c5924ae0: 00000003 00000000 00000000 0001 03 260
c5924c60: 00000003 00000000 00000000 0001 03 259

どうやら、ビンゴです。/dev/socket/zygoteでUNIXドメインソケットを開いているようですね。肝心の起動要求はというと、いちいちaccept()して読み込んで閉じるという作業を繰り返しているわけですから、エミュレータでは探れません。というわけで、ソースコードに戻ります。

とりあえず、zygoteであることはわかったので、こういう時は"で囲まれた文字列としてのzygoteをコードで検索します。
gingerbread hermit4$ source build/envsetup.sh
gingerbread hermit4$ sgrep \"zygote\"
./cts/tools/device-setup/TestDeviceSetup/src/android/tests/getinfo/RootProcessScanner.java:36: "zygote"
./dalvik/vm/Jni.c:4322: * only be called in "zygote" mode, when we have one thread running.
./dalvik/vm/alloc/HeapDebug.c:87: if (strcmp(buf, "zygote") != 0) {
./dalvik/vm/alloc/HeapDebug.c:88: /* If the process is no longer called "zygote",
./dalvik/vm/hprof/HprofHeap.c:264: nameId = hprofLookupStringId("zygote");
./dalvik/vm/native/dalvik_system_Zygote.c:243: dvmDumpLoaderStats("zygote");
./dalvik/vm/native/dalvik_system_Zygote.c:396: dvmDumpLoaderStats("zygote");
./frameworks/base/cmds/app_process/app_main.cpp:156: setArgv0(argv0, "zygote");
./frameworks/base/cmds/app_process/app_main.cpp:157: set_process_name("zygote");
./frameworks/base/cmds/dumpstate/utils.c:394: if (len <= 0 || !memcmp(data, "zygote", 6)) continue;
./frameworks/base/cmds/rawbu/backup.cpp:707: property_set("ctl.stop", "zygote"); ./frameworks/base/cmds/rawbu/backup.cpp:727: property_set("ctl.start", "zygote"); ./frameworks/base/core/java/android/os/Process.java:46: private static final String ZYGOTE_SOCKET = "zygote";
./frameworks/base/core/java/com/android/internal/os/SamplingProfilerIntegration.java:129: writeSnapshot(dir, "zygote");
./frameworks/base/tools/preload/PrintHtmlDiff.java:44: if (proc.name.equals("zygote")) {
./frameworks/base/tools/preload/Proc.java:79: return parent != null && parent.name.equals("zygote")
./frameworks/base/tools/preload/WritePreloadedClassFile.java:118: addAllClassesFrom("zygote", root, toPreload);
./libcore/dalvik/src/main/java/dalvik/system/Zygote.java:20: * Provides access to the Dalvik "zygote" feature, which allows a VM instance to
./system/core/libcutils/zygote.c:34:#define ZYGOTE_SOCKET "zygote"
./system/core/toolbox/start.c:15: property_set("ctl.start", "zygote");
./system/core/toolbox/stop.c:15: property_set("ctl.stop", "zygote");

すばらしく順調です。それっぽい箇所が2カ所ほど見つかりました。
一カ所は、android.os.Process ですね。
frameworks/base/core/java/android/os/Process.java
private static void openZygoteSocketIfNeeded() throws ZygoteStartFailedEx {
        :
        :
    sZygoteSocket = new LocalSocket();
    sZygoteSocket.connect(new LocalSocketAddress(ZYGOTE_SOCKET,
            LocalSocketAddress.Namespace.RESERVED));

    sZygoteInputStream
        = new DataInputStream(sZygoteSocket.getInputStream());

    sZygoteWriter =
        new BufferedWriter(
            new OutputStreamWriter(
                sZygoteSocket.getOutputStream()),
                256);
        :
        :
}

private static int zygoteSendArgsAndGetPid(ArrayList args) throws ZygoteStartFailedEx {
    int pid;
    openZygoteSocketIfNeeded();
        :
        :
    sZygoteWriter.write(Integer.toString(args.size()));
    sZygoteWriter.newLine();

    int sz = args.size();
    for (int i = 0; i < sz; i++) { 

        String arg = args.get(i); 
        if (arg.indexOf('\n') >= 0) {
            throw new ZygoteStartFailedEx("embedded newlines not allowed");
        }
        sZygoteWriter.write(arg);
        sZygoteWriter.newLine();
    }
     sZygoteWriter.flush();
     // Should there be a timeout on this?
    pid = sZygoteInputStream.readInt();
        :
        :
}


private static int startViaZygote(final String processClass,
                                                  final String niceName,
                                                  final int uid, final int gid,
                                                  final int[] gids,
                                                  int debugFlags,
                                                  String[] extraArgs) throws ZygoteStartFailedEx {
    int pid;
        :
    pid = zygoteSendArgsAndGetPid(argsForZygote);
        :
    return pid;
}

public static final int start(final String processClass,
                                        final String niceName,
                                        int uid, int gid, int[] gids,
                                        int debugFlags,
                                        String[] zygoteArgs)
{
    if (supportsProcesses()) {
        try {
            return startViaZygote(processClass, niceName, uid, gid, gids,
                                                debugFlags, zygoteArgs);
        } catch (ZygoteStartFailedEx ex) {
            Log.e(LOG_TAG,
                "Starting VM process through Zygote failed");
                throw new RuntimeException(
                "Starting VM process through Zygote failed", ex);
        }
    } else {
        // Running in single-process mode

        Runnable runnable = new Runnable() {
            public void run() {
                Process.invokeStaticMain(processClass);
            }
        };

        // Thread constructors must not be called with null names (see spec).
        if (niceName != null) {
            new Thread(runnable, niceName).start();
        } else {
            new Thread(runnable).start();
        }
        return 0;
    }
}

というわけで、一カ所はProcess.start()から始まるようです。が、適当にソースコードを探して見ましたが、呼び出していそうな箇所をまだ見つけられていません。

もう一カ所は、Nativeになります。
system/core/libcutils/zygote.c
int zygote_run_wait(int argc, const char **argv, void (*post_run_func)(int))
{
    int fd;
    int pid;
    int err;
    const char *newargv[argc + 1];

    fd = socket_local_client(ZYGOTE_SOCKET,
                ANDROID_SOCKET_NAMESPACE_RESERVED, AF_LOCAL);

    if (fd < 0) {
         return -1;
     }
    newargv[0] = "--peer-wait";
    memcpy(newargv + 1, argv, argc * sizeof(*argv));
     pid =     send_request(fd, 1, argc + 1, newargv);
     if (pid > 0 && post_run_func != NULL) {
        post_run_func(pid);
    }

    // Wait for socket to close
    do {
        int dummy;
        err = read(fd, &dummy, sizeof(dummy));
    } while ((err < 0 && errno == EINTR) || err != 0);

    do {
         err = close(fd);
    } while (err < 0 && errno == EINTR);
     return 0;
}

int zygote_run_oneshot(int sendStdio, int argc, const char **argv)
{
    int fd = -1;
    int err;
    int i;
    int retries;
    int pid;
    const char **newargv = argv;
    const int newargc = argc;
    for (retries = 0; (fd < 0) && (retries < ZYGOTE_RETRY_COUNT); retries++) {
        if (retries > 0) {
           struct timespec ts;
           memset(&ts, 0, sizeof(ts));
           ts.tv_nsec = ZYGOTE_RETRY_MILLIS * 1000 * 1000;
           do {
               err = nanosleep (&ts, &ts);
           } while (err < 0 && errno == EINTR);
        }
        fd = socket_local_client(ZYGOTE_SOCKET, AF_LOCAL,
                                              ANDROID_SOCKET_NAMESPACE_RESERVED);
    }
    if (fd < 0) {
        return -1;
    }
    pid = send_request(fd, 0, newargc, newargv);
    do {
        err = close(fd);
    } while (err < 0 && errno == EINTR);
    return pid;
}
というわけで、利用されているのは、zygote_run_waitとzygote_run_oneshotの2カ所でした。

zygote_run_waitが使われている箇所を調べると、
dalvik/dvz/dvz.c
int main (int argc, const char **argv) {
    int err;

    if (argc > 1 && 0 == strcmp(argv[1], "--help")) {
        usage(argv[0]);
        exit(0);
    }

    err = zygote_run_wait(argc - 1, argv + 1, post_run_func);

    if (err < 0) {
         fprintf(stderr, "%s error: no zygote process found\n", argv[0]);
         exit(-1);
     }
     exit(0);
}
ということで、/system/bin/dvz にたどり着きました。Usageを見てみると
# dvz --help
Usage: dvz [--help] [-classpath ]
        [additional zygote args] fully.qualified.java.ClassName [args]

Requests a new Dalvik VM instance to be spawned from the zygote
process. stdin, stdout, and stderr are hooked up. This process remains
while the spawned VM instance is alive and forwards some signals.
The exit code of the spawned VM instance is dropped.

というわけで、コマンドラインからクラスを指定してVMプロセスを起動するコマンドです。

もう一方のoneshotの方を探してみると
frameworks/base/cmds/runtime/main_runtime.cpp

extern "C"
int main(int argc, char* const argv[])
{
        :
        :
    if (proc->supportsProcesses()) {
        // If stdio logging is on, system_server should not inherit our stdio
        // The dalvikvm instance will copy stdio to the log on its own
        char propBuf[PROPERTY_VALUE_MAX];
        bool logStdio = false;
        property_get("log.redirect-stdio", propBuf, "");
        logStdio = (strcmp(propBuf, "true") == 0);

        zygote_run_oneshot((int)(!logStdio),
                sizeof(ZYGOTE_ARGV) / sizeof(ZYGOTE_ARGV[0]),
                    ZYGOTE_ARGV);
    } else {
#ifndef HAVE_ANDROID_OS
        QuickRuntime* runt = new QuickRuntime();
        runt->start("com/android/server/SystemServer",
        false /* spontaneously fork system server from zygote */);
#endif
    }
    finish_system_init(proc);
    run(proc);
        :
        :
}
ということですが、このコードをビルドするAndroid.mkを見るとifeq ($(TARGET_SIMULATOR),true)ということで、シミュレータ専用のようですから、とりあえず除外で良いでしょう。

というわけで、本日追いかけた限りでは、可能性があるのは
  • android.os.Process.start()を呼び出すコード
  • /system/bin/dvz
の辺りを攻めると、回答に近づけるかなぁ?といった雰囲気でした。

2011年1月27日木曜日

Zygoteは何をしているのか?

脱線コーナーを抜けて一休み後、とりあえず、続きです。

さて、/system/bin/app_processがZygoteの本体で、JavaのZygoteInit.main()を呼び出すという話を以前の勉強会で出しました。で、前回はそのまま、system_serverプロセスをforkするお話に突入してしまったわけですが、ここからは、その続きの始まりです。ここからは、コードを拾い出して書いて行きますが、かなり大幅に省略していたりしますのでご了承下さい。

public static void main(String argv[]) {
        :
        :
    registerZygoteSocket();
        :
        :
    if (argv[1].equals("true")) {
        startSystemServer();  //前回はここまで
    } else if (!argv[1].equals("false")) {
        throw new RuntimeException(argv[0] + USAGE_STRING);
    }

    Log.i(TAG, "Accepting command socket connections");

    if (ZYGOTE_FORK_MODE) {
        runForkMode();
    } else {
        runSelectLoopMode();
    }

    closeServerSocket();
}
まず先に、registerZygoteSocket()を見ておきます。名前からしてZygoteの必要なソケットの登録とわかります。
        :
        :
private static void registerZygoteSocket() {
    String env = System.getenv(ANDROID_SOCKET_ENV);
    fileDesc = Integer.parseInt(env);
    sServerSocket = new LocalServerSocket(
    createFileDescriptor(fileDesc));

とりあえず、環境変数を取得してLocalServerSocketを生成しています。

続いては前回入り込んだstartSystemServer()では、子プロセスをforkしていましたが、system_serverの生成が終わると、親のプロセスは普通にここまで戻ってきます。続きを見てみると、if文に囲まれた個所が目に入ります。このif文ですが
    private static final boolean ZYGOTE_FORK_MODE = false;
ということで、Gingerbreadさんのコードだと、runSelectLoopMode()に入ります。というわけで処理を追いかけて見ます。
private static void runSelectLoopMode() throws MethodAndArgsCaller {
        :
        :
   while (true) {
       int index;
       /*
       * Call gc() before we block in select().
       * It's work that has to be done anyway, and it's better
       * to avoid making every child do it. It will also
       * madvise() any free memory as a side-effect.
       *
       * Don't call it every time, because walking the entire
       * heap is a lot of overhead to free a few hundred bytes.
       */
       if (loopCount <= 0) {
            gc();
            loopCount = GC_LOOP_COUNT;
        } else {
            loopCount--;
        }
        try {
            fdArray = fds.toArray(fdArray);
            index = selectReadable(fdArray);
        } catch (IOException ex) {
            throw new RuntimeException("Error in select()", ex);
        }
        if (index < 0) {
            throw new RuntimeException("Error in select()");
        } else if (index == 0) {
            ZygoteConnection newPeer = acceptCommandPeer();
            peers.add(newPeer);
            fds.add(newPeer.getFileDesciptor());
        } else {
            boolean done; done = peers.get(index).runOnce();
            if (done) {
                peers.remove(index);
                fds.remove(index);
            }
        }
    }
}

「先生!!なんだか、Zygoteちゃんがgc()呼んでます!」的なコードが見える気がしますが、とりあえず今は無視します。「え〜」って声が聞こえる気はしますが、今回はそこはメインじゃないですし。誰か、ここを追いかけてPF部で発表してくれる人はいないものかな・・・・。

とりあえず進みます。ここでは保持しているfdのリストを元にselectReadable()を呼び出します。selectReadable()は、Nativeコードで、実体は frameworks/base/core/jni/com_android_internal_os_ZygoteInit.cpp にあります。
Jniのためコードがちょっと面倒なので簡単に何をやってるかだけ抜き出すと、引数で渡したfdのArrayをfdsetにFD_SETした後、

do {
    err = select (nfds, &fdset, NULL, NULL, NULL);
} while (err < 0 && errno == EINTR);

とまぁ、select待ちしたうえで、selectを抜けると、Arrayの何番目がFD_ISSETかを判定して返します。

index==0の場合、つまり、最初に待ち受けしているFDに接続要求が来ると
private static ZygoteConnection acceptCommandPeer() {
    try {
        return new ZygoteConnection(sServerSocket.accept());
    } catch (IOException ex) {
        throw new RuntimeException("IOException during accept()", ex);
    }
}

ということで、acceptしたfdを持ったZygoteConnectionを生成しており、それをarrayに追加した後、acceptしたfdをfdsに追加しているわけです。

で、もしも0以外のfd(つまりsServerSocket.accept()でacceptしたfd)がreadableになると、対象となるZygoteConnection#runOnce()を呼び出します。

boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
        :
        :
    args = readArgumentList();
        :
        :
   parsedArgs = new Arguments(args);

    applyUidSecurityPolicy(parsedArgs, peer);
    applyDebuggerSecurityPolicy(parsedArgs);
    applyRlimitSecurityPolicy(parsedArgs, peer);
    applyCapabilitiesSecurityPolicy(parsedArgs, peer);

    int[][] rlimits = null;

    if (parsedArgs.rlimits != null) {
        rlimits = parsedArgs.rlimits.toArray(intArray2d);
    }

    pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid,
                                                        parsedArgs.gids, parsedArgs.debugFlags, rlimits);
        :
        :
    if (pid == 0) {
        // in child
        handleChildProc(parsedArgs, descriptors, newStderr);
        // should never happen
        return true;
    } else { /* pid != 0 */
        // in parent...pid of < 0 means failure
        return handleParentProc(pid, descriptors, parsedArgs);
    }

readArgumentList()は、acceptした時のsocketから引数のリストを読み出しています。何をどう読み込んでパースしているのか、その後のチェック等は後日に回すものとして先に進みます。

取得した引数に従って、まずは子プロセスをforkしています。何となく想像がつくかと思いますが、uid,gid等の設定に従って子プロセスをSpecializeしているわけです。

その後、親プロセスであるZygoteの本体は
private boolean handleParentProc(int pid,FileDescriptor[] descriptors, Arguments parsedArgs) {
        :
        :
    ZygoteInit.setpgid(pid, ZygoteInit.getpgid(peer.getPid()));
        :
        :
    for (FileDescriptor fd: descriptors) {
        ZygoteInit.closeDescriptor(fd);
    }
        :
        :
    mSocketOutStream.writeInt(pid);
        :
        :
    if (parsedArgs.peerWait) {
        mSocket.close();
        return true;
    }
    return false;
}
のように、子プロセスをpeerのプロセスグループへの登録を行った後、descriptorを閉じ、要求をしてきた相手にpidを返した後、peerを維持する必要がなければ、socketを閉じて処理をLoopに戻し、ZygoteConnectionを削除します。

起こされた子プロセスは・・・というと
private void handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors,
                                               PrintStream newStderr) {
    if (parsedArgs.peerWait) {
        ZygoteInit.setCloseOnExec(mSocket.getFileDescriptor(), true);
        sPeerWaitSocket = mSocket;
    } else {
        closeSocket();
        ZygoteInit.closeServerSocket();
    }

    if (descriptors != null) {
        ZygoteInit.reopenStdio(descriptors[0],
        descriptors[1], descriptors[2]);

        for (FileDescriptor fd: descriptors) {
            ZygoteInit.closeDescriptor(fd);
        }
        newStderr = System.err;
    }
サーバー側のFDをcloseした後、
    if (parsedArgs.runtimeInit) {
        RuntimeInit.zygoteInit(parsedArgs.remainingArgs);
    } else {
        ClassLoader cloader;

        if (parsedArgs.classpath != null) {
            cloader
                = new PathClassLoader(parsedArgs.classpath,
                                                        ClassLoader.getSystemClassLoader());
        } else {
            cloader = ClassLoader.getSystemClassLoader();
        }
        String className;
        className = parsedArgs.remainingArgs[0];
        String[] mainArgs = new String[parsedArgs.remainingArgs.length - 1];

        System.arraycopy(parsedArgs.remainingArgs, 1,mainArgs, 0, mainArgs.length);
        ZygoteInit.invokeStaticMain(cloader, className, mainArgs);
    }
}
runtimeInitがどのような場合にtrueになっているのか調べ切れていませんが、後者の処理になった場合、引数で指定されたクラスをロードし、Static Mainを呼び出しているようです。

大ざっぱにまとめると、Zygoteは、socketを生成して待ち受け、要求が来ると、自身のコピーである子プロセスで送信されてきた引数を元にJavaのアプリケーションを起動していると考えて良いかと思います。

とりあえず、今夜の調査はここまでとしておきましょう。

2011年1月26日水曜日

Javaのアプリは本当にZygoteのコピーなのかを示すためのメモ

相変わらず勉強会のための・・・・。



1. psの結果を見せる
# ps
USER     PID   PPID  VSIZE  RSS     WCHAN    PC         NAME
root      1     0     268    180   c009b74c 0000875c S /init
root      2     0     0      0     c004e72c 00000000 S kthreadd
root      3     2     0      0     c003fdc8 00000000 S ksoftirqd/0
root      4     2     0      0     c004b2c4 00000000 S events/0
root      5     2     0      0     c004b2c4 00000000 S khelper
root      6     2     0      0     c004b2c4 00000000 S suspend
root      7     2     0      0     c004b2c4 00000000 S kblockd/0
root      8     2     0      0     c004b2c4 00000000 S cqueue
root      9     2     0      0     c018179c 00000000 S kseriod
root      10    2     0      0     c004b2c4 00000000 S kmmcd
root      11    2     0      0     c006fc74 00000000 S pdflush
root      12    2     0      0     c006fc74 00000000 S pdflush
root      13    2     0      0     c00744e4 00000000 S kswapd0
root      14    2     0      0     c004b2c4 00000000 S aio/0
root      22    2     0      0     c017ef48 00000000 S mtdblockd
root      23    2     0      0     c004b2c4 00000000 S kstriped
root      24    2     0      0     c004b2c4 00000000 S hid_compat
root      25    2     0      0     c004b2c4 00000000 S rpciod/0
root      26    2     0      0     c019d16c 00000000 S mmcqd
root      27    1     248    152   c009b74c 0000875c S /sbin/ueventd
system    28    1     804    260   c01a94a4 afd0b6fc S /system/bin/servicemanager
root      29    1     3916   472   ffffffff afd0bdac S /system/bin/vold
root      30    1     3888   412   ffffffff afd0bdac S /system/bin/netd
root      31    1     664    232   c01b52b4 afd0c0cc S /system/bin/debuggerd
radio     32    1     5412   520   ffffffff afd0bdac S /system/bin/rild
root      33    1     63964  22764 c009b74c afd0b844 S zygote
media     34    1     18236  1412  ffffffff afd0b6fc S /system/bin/mediaserver
root      35    1     812    280   c02181f4 afd0b45c S /system/bin/installd
keystore  36    1     1796   320   c01b52b4 afd0c0cc S /system/bin/keystore
root      38    1     824    316   c00b8fec afd0c51c S /system/bin/qemud
shell     40    1     732    244   c0158eb0 afd0b45c S /system/bin/sh
root      41    1     3364   168   ffffffff 00008294 S /sbin/adbd
system    61    33    125500 31392 ffffffff afd0b6fc S system_server
app_12    111   33    76020  19736 ffffffff afd0c51c S jp.co.omronsoft.openwnn
radio     115   33    88384  21124 ffffffff afd0c51c S com.android.phone
system    116   33    76360  21672 ffffffff afd0c51c S com.android.systemui
app_1     121   33    81328  24320 ffffffff afd0c51c S com.android.launcher
app_3     218   33    85192  18708 ffffffff afd0c51c S com.android.mms
app_9     221   33    75264  19804 ffffffff afd0c51c S android.process.media
app_13    250   33    75620  19768 ffffffff afd0c51c S com.android.email
app_11    264   33    72832  17240 ffffffff afd0c51c S com.android.protips
app_20    276   33    73256  17572 ffffffff afd0c51c S com.android.music
root      279   41    732    344   c003da38 afd0c3ac S /system/bin/sh
app_26    285   33    73852  18392 ffffffff afd0c51c S com.android.quicksearchbox
root      294   279   888    332   00000000 afd0b45c R ps

2. /procの情報を見せる
# ls -l /proc/111
dr-xr-xr-x app_12 app_12 2011-01-25 02:57 task
dr-x------ app_12 app_12 2011-01-25 02:57 fd
dr-x------ app_12 app_12 2011-01-25 02:57 fdinfo
dr-xr-xr-x app_12 app_12 2011-01-25 02:57 net
-r-------- app_12 app_12 0 2011-01-25 02:57 environ
-r-------- app_12 app_12 0 2011-01-25 02:57 auxv
-r--r--r-- app_12 app_12 0 2011-01-25 02:57 status
-r-------- app_12 app_12 0 2011-01-25 02:57 personality
-r-------- app_12 app_12 0 2011-01-25 02:57 limits
-rw-r--r-- app_12 app_12 0 2011-01-25 02:57 sched
-r--r--r-- app_12 app_12 0 2011-01-25 02:50 cmdline
-r--r--r-- app_12 app_12 0 2011-01-25 02:50 stat
-r--r--r-- app_12 app_12 0 2011-01-25 02:57 statm
-r--r--r-- app_12 app_12 0 2011-01-25 02:57 maps
-rw------- app_12 app_12 0 2011-01-25 02:57 mem
lrwxrwxrwx app_12 app_12 2011-01-25 02:57 cwd -> /
lrwxrwxrwx app_12 app_12 2011-01-25 02:57 root -> /
lrwxrwxrwx app_12 app_12 2011-01-25 02:57 exe -> /system/bin/app_process
-r--r--r-- app_12 app_12 0 2011-01-25 02:57 mounts
-r--r--r-- app_12 app_12 0 2011-01-25 02:57 mountinfo
-r-------- app_12 app_12 0 2011-01-25 02:57 mountstats
--w------- app_12 app_12 0 2011-01-25 02:57 clear_refs
-r--r--r-- app_12 app_12 0 2011-01-25 02:57 smaps
-r-------- app_12 app_12 0 2011-01-25 02:57 pagemap
-r--r--r-- app_12 app_12 0 2011-01-25 02:57 wchan
-r--r--r-- app_12 app_12 0 2011-01-25 02:57 schedstat
-r--r--r-- app_12 app_12 0 2011-01-25 02:57 cgroup
-r--r--r-- app_12 app_12 0 2011-01-25 02:57 oom_score
-rw-r--r-- app_12 app_12 0 2011-01-25 02:57 oom_adj
-rw-r--r-- app_12 app_12 0 2011-01-25 02:57 coredump_filter

3. map情報を比較してみる?
# cat /proc/33/maps
00008000-00009000 r-xp 00000000 1f:00 321 /system/bin/app_process
00009000-0000a000 rwxp 00001000 1f:00 321 /system/bin/app_process
0000a000-001ab000 rwxp 0000a000 00:00 0 [heap]
40000000-40008000 r-xs 00000000 00:0a 197 /dev/__properties__ (deleted)
40008000-40009000 r-xp 40008000 00:00 0
40009000-4054b000 rwxp 00000000 00:07 355 /dev/ashmem/dalvik-heap (deleted)
4054b000-41009000 ---p 00542000 00:07 355 /dev/ashmem/dalvik-heap (deleted)
41009000-41049000 rwxp 00000000 00:07 356 /dev/ashmem/dalvik-bitmap-1 (deleted)
41049000-41089000 rwxp 00000000 00:07 357 /dev/ashmem/dalvik-bitmap-2 (deleted)
41089000-410aa000 rwxp 00000000 00:07 358 /dev/ashmem/dalvik-card-table (deleted)
410aa000-410ad000 rwxp 410aa000 00:00 0
410ad000-410ae000 ---p 00000000 00:07 359 /dev/ashmem/dalvik-LinearAlloc (deleted)
410ae000-41289000 rwxp 00001000 00:07 359 /dev/ashmem/dalvik-LinearAlloc (deleted)
41289000-415ad000 ---p 001dc000 00:07 359 /dev/ashmem/dalvik-LinearAlloc (deleted)
415ad000-415ae000 r-xs 00002000 1f:00 467 /system/framework/core-junit.jar
415ae000-415b4000 r-xp 00000000 1f:01 283 /data/dalvik-cache/system@framework@core-junit.jar@classes.dex
415be000-415bf000 r-xs 001c6000 1f:00 480 /system/framework/core.jar
415bf000-419e7000 r-xp 00000000 1f:01 277 /data/dalvik-cache/system@framework@core.jar@classes.dex
419e7000-41a26000 rwxp 419e7000 00:00 0
41a26000-41a27000 r-xs 00046000 1f:00 479 /system/framework/bouncycastle.jar
41a27000-41ad4000 r-xp 00000000 1f:01 278 /data/dalvik-cache/system@framework@bouncycastle.jar@classes.dex
41ad4000-41ad5000 r-xs 0007d000 1f:00 476 /system/framework/ext.jar
41ad5000-41c0a000 r-xp 00000000 1f:01 279 /data/dalvik-cache/system@framework@ext.jar@classes.dex
41c0a000-41c0b000 r-xs 002c8000 1f:00 472 /system/framework/framework.jar
41c0b000-422b0000 r-xp 00000000 1f:01 280 /data/dalvik-cache/system@framework@framework.jar@classes.dex
422b0000-4233c000 rwxp 422b0000 00:00 0
4233c000-4233d000 r-xs 00015000 1f:00 475 /system/framework/android.policy.jar
4233d000-4236b000 r-xp 00000000 1f:01 281 /data/dalvik-cache/system@framework@android.policy.jar@classes.dex
4236b000-4236c000 r-xs 00097000 1f:00 473 /system/framework/services.jar
4236c000-424ba000 r-xp 00000000 1f:01 282 /data/dalvik-cache/system@framework@services.jar@classes.dex
424ba000-42a77000 r-xs 00000000 1f:00 519 /system/usr/icu/icudt44l.dat
42a88000-42ab7000 r-xs 00000000 1f:00 261 /system/fonts/DroidSans.ttf
42ab7000-42b32000 r-xs 00000000 1f:00 508 /system/usr/share/zoneinfo/zoneinfo.dat
42b32000-42b6a000 r-xs 00606000 1f:00 478 /system/framework/framework-res.apk
42b6a000-42dbc000 r-xs 003b5000 1f:00 478 /system/framework/framework-res.apk
42dbc000-42dcf000 rwxp 42dbc000 00:00 0
42de0000-42e01000 rwxp 42de0000 00:00 0
80000000-80003000 r-xp 00000000 1f:00 597 /system/lib/liblog.so
80003000-80004000 rwxp 00003000 1f:00 597 /system/lib/liblog.so
80100000-8010e000 r-xp 00000000 1f:00 557 /system/lib/libcutils.so
8010e000-8010f000 rwxp 0000e000 1f:00 557 /system/lib/libcutils.so
8010f000-8011e000 rwxp 8010f000 00:00 0
80200000-80228000 r-xp 00000000 1f:00 633 /system/lib/libutils.so
80228000-80229000 rwxp 00028000 1f:00 633 /system/lib/libutils.so
80300000-80314000 r-xp 00000000 1f:00 592 /system/lib/libz.so
80314000-80315000 rwxp 00014000 1f:00 592 /system/lib/libz.so
80400000-80422000 r-xp 00000000 1f:00 621 /system/lib/libbinder.so
80422000-80428000 rwxp 00022000 1f:00 621 /system/lib/libbinder.so
80500000-8057f000 r-xp 00000000 1f:00 594 /system/lib/libandroid_runtime.so
8057f000-80587000 rwxp 0007f000 1f:00 594 /system/lib/libandroid_runtime.so
80587000-80588000 rwxp 80587000 00:00 0
80600000-80613000 r-xp 00000000 1f:00 559 /system/lib/libexpat.so
80613000-80615000 rwxp 00013000 1f:00 559 /system/lib/libexpat.so
80700000-8072e000 r-xp 00000000 1f:00 583 /system/lib/libnativehelper.so
8072e000-80731000 rwxp 0002e000 1f:00 583 /system/lib/libnativehelper.so
80800000-808bc000 r-xp 00000000 1f:00 574 /system/lib/libcrypto.so
808bc000-808cc000 rwxp 000bc000 1f:00 574 /system/lib/libcrypto.so
808cc000-808ce000 rwxp 808cc000 00:00 0
80900000-809fb000 r-xp 00000000 1f:00 618 /system/lib/libicui18n.so
809fb000-80a00000 rwxp 000fb000 1f:00 618 /system/lib/libicui18n.so
80a00000-80ac8000 r-xp 00000000 1f:00 549 /system/lib/libicuuc.so
80ac8000-80ad0000 rwxp 000c8000 1f:00 549 /system/lib/libicuuc.so
80ad0000-80ad3000 rwxp 80ad0000 00:00 0
80b00000-80b4e000 r-xp 00000000 1f:00 625 /system/lib/libsqlite.so
80b4e000-80b50000 rwxp 0004e000 1f:00 625 /system/lib/libsqlite.so
80c00000-80c2b000 r-xp 00000000 1f:00 612 /system/lib/libssl.so
80c2b000-80c2f000 rwxp 0002b000 1f:00 612 /system/lib/libssl.so
80d00000-80d04000 r-xp 00000000 1f:00 560 /system/lib/libnetutils.so
80d04000-80d05000 rwxp 00004000 1f:00 560 /system/lib/libnetutils.so
80e00000-80e31000 r-xp 00000000 1f:00 551 /system/lib/libui.so
80e31000-80e34000 rwxp 00031000 1f:00 551 /system/lib/libui.so
80f00000-80f09000 r-xp 00000000 1f:00 585 /system/lib/libEGL.so
80f09000-80f0a000 rwxp 00009000 1f:00 585 /system/lib/libEGL.so
80f0a000-80f0c000 rwxp 80f0a000 00:00 0
81000000-8101a000 r-xp 00000000 1f:00 613 /system/lib/libpixelflinger.so
8101a000-8101c000 rwxp 0001a000 1f:00 613 /system/lib/libpixelflinger.so
81100000-81104000 r-xp 00000000 1f:00 569 /system/lib/libhardware_legacy.so
81104000-81105000 rwxp 00004000 1f:00 569 /system/lib/libhardware_legacy.so
81200000-81202000 r-xp 00000000 1f:00 553 /system/lib/libwpa_client.so
81202000-81203000 rwxp 00002000 1f:00 553 /system/lib/libwpa_client.so
81300000-81301000 r-xp 00000000 1f:00 558 /system/lib/libhardware.so
81301000-81302000 rwxp 00001000 1f:00 558 /system/lib/libhardware.so
81400000-8140a000 r-xp 00000000 1f:00 607 /system/lib/libgui.so
8140a000-8140c000 rwxp 0000a000 1f:00 607 /system/lib/libgui.so
81500000-81518000 r-xp 00000000 1f:00 637 /system/lib/libsurfaceflinger_client.so
81518000-8151b000 rwxp 00018000 1f:00 637 /system/lib/libsurfaceflinger_client.so
81600000-81611000 r-xp 00000000 1f:00 641 /system/lib/libcamera_client.so
81611000-81614000 rwxp 00011000 1f:00 641 /system/lib/libcamera_client.so
81700000-8170a000 r-xp 00000000 1f:00 608 /system/lib/libskiagl.so
8170a000-8170b000 rwxp 0000a000 1f:00 608 /system/lib/libskiagl.so
81800000-81914000 r-xp 00000000 1f:00 609 /system/lib/libskia.so
81914000-81918000 rwxp 00114000 1f:00 609 /system/lib/libskia.so
81918000-8191b000 rwxp 81918000 00:00 0
81a00000-81a02000 r-xp 00000000 1f:00 578 /system/lib/libemoji.so
81a02000-81a03000 rwxp 00002000 1f:00 578 /system/lib/libemoji.so
81b00000-81b32000 r-xp 00000000 1f:00 567 /system/lib/libjpeg.so
81b32000-81b33000 rwxp 00032000 1f:00 567 /system/lib/libjpeg.so
81c00000-81c05000 r-xp 00000000 1f:00 570 /system/lib/libGLESv1_CM.so
81c05000-81c06000 rwxp 00005000 1f:00 570 /system/lib/libGLESv1_CM.so
81d00000-81da2000 r-xp 00000000 1f:00 572 /system/lib/libdvm.so
81da2000-81da9000 rwxp 000a2000 1f:00 572 /system/lib/libdvm.so
81da9000-81dab000 rwxp 81da9000 00:00 0
81e00000-81e04000 r-xp 00000000 1f:00 634 /system/lib/libGLESv2.so
81e04000-81e05000 rwxp 00004000 1f:00 634 /system/lib/libGLESv2.so
81f00000-81f02000 r-xp 00000000 1f:00 619 /system/lib/libETC1.so
81f02000-81f03000 rwxp 00002000 1f:00 619 /system/lib/libETC1.so
82000000-82051000 r-xp 00000000 1f:00 547 /system/lib/libsonivox.so
82051000-82052000 rwxp 00051000 1f:00 547 /system/lib/libsonivox.so
82052000-82057000 rwxp 82052000 00:00 0
82100000-82159000 r-xp 00000000 1f:00 561 /system/lib/libmedia.so
82159000-82168000 rwxp 00059000 1f:00 561 /system/lib/libmedia.so
82200000-82201000 r-xp 00000000 1f:00 636 /system/lib/libnfc_ndef.so
82201000-82202000 rwxp 00001000 1f:00 636 /system/lib/libnfc_ndef.so
82300000-8230c000 r-xp 00000000 1f:00 591 /system/lib/libmedia_jni.so
8230c000-8230d000 rwxp 0000c000 1f:00 591 /system/lib/libmedia_jni.so
82400000-8255d000 r-xp 00000000 1f:00 639 /system/lib/libstagefright.so
8255d000-82567000 rwxp 0015d000 1f:00 639 /system/lib/libstagefright.so
82567000-82568000 rwxp 82567000 00:00 0
82600000-8261c000 r-xp 00000000 1f:00 600 /system/lib/libvorbisidec.so
8261c000-8261d000 rwxp 0001c000 1f:00 600 /system/lib/libvorbisidec.so
82700000-8270c000 r-xp 00000000 1f:00 640 /system/lib/libstagefright_amrnb_common.so
8270c000-8270d000 rwxp 0000c000 1f:00 640 /system/lib/libstagefright_amrnb_common.so
82800000-82801000 r-xp 00000000 1f:00 615 /system/lib/libstagefright_enc_common.so
82801000-82802000 rwxp 00001000 1f:00 615 /system/lib/libstagefright_enc_common.so
82900000-82905000 r-xp 00000000 1f:00 614 /system/lib/libstagefright_avc_common.so
82905000-82906000 rwxp 00005000 1f:00 614 /system/lib/libstagefright_avc_common.so
82a00000-82a09000 r-xp 00000000 1f:00 568 /system/lib/libstagefright_foundation.so
82a09000-82a0a000 rwxp 00009000 1f:00 568 /system/lib/libstagefright_foundation.so
82b00000-82b03000 r-xp 00000000 1f:00 647 /system/lib/libstagefright_color_conversion.so
82b03000-82b04000 rwxp 00003000 1f:00 647 /system/lib/libstagefright_color_conversion.so
82c00000-82c09000 r-xp 00000000 1f:00 632 /system/lib/libexif.so
82c09000-82c0a000 rwxp 00009000 1f:00 632 /system/lib/libexif.so
82c0a000-82c0c000 rwxp 82c0a000 00:00 0
82d00000-82d06000 r-xp 00000000 1f:00 598 /system/lib/libsoundpool.so
82d06000-82d07000 rwxp 00006000 1f:00 598 /system/lib/libsoundpool.so
82e00000-82e3a000 r-xp 00000000 1f:00 554 /system/lib/libstlport.so
82e3a000-82e3c000 rwxp 0003a000 1f:00 554 /system/lib/libstlport.so
83000000-83415000 r-xp 00000000 1f:00 628 /system/lib/libwebcore.so
83415000-8346f000 rwxp 00415000 1f:00 628 /system/lib/libwebcore.so
8346f000-83471000 rwxp 8346f000 00:00 0
afb00000-afb20000 r-xp 00000000 1f:00 595 /system/lib/libm.so
afb20000-afb21000 rwxp 00020000 1f:00 595 /system/lib/libm.so
afc00000-afc01000 r-xp 00000000 1f:00 623 /system/lib/libstdc++.so
afc01000-afc02000 rwxp 00001000 1f:00 623 /system/lib/libstdc++.so
afd00000-afd40000 r-xp 00000000 1f:00 588 /system/lib/libc.so
afd40000-afd43000 rwxp 00040000 1f:00 588 /system/lib/libc.so
afd43000-afd4e000 rwxp afd43000 00:00 0
b0001000-b0009000 r-xp 00001000 1f:00 293 /system/bin/linker
b0009000-b000a000 rwxp 00009000 1f:00 293 /system/bin/linker
b000a000-b0013000 rwxp b000a000 00:00 0
bef58000-bef6d000 rw-p befeb000 00:00 0 [stack]

# cat /proc/111/maps
00008000-00009000 r-xp 00000000 1f:00 321 /system/bin/app_process
00009000-0000a000 rwxp 00001000 1f:00 321 /system/bin/app_process
0000a000-001d2000 rwxp 0000a000 00:00 0 [heap]
10000000-10001000 ---p 10000000 00:00 0
10001000-10100000 rwxp 10001000 00:00 0
40000000-40008000 r-xs 00000000 00:0a 197 /dev/__properties__ (deleted)
40008000-40009000 r-xp 40008000 00:00 0
40009000-405fb000 rwxp 00000000 00:07 355 /dev/ashmem/dalvik-heap (deleted)
405fb000-41009000 ---p 005f2000 00:07 355 /dev/ashmem/dalvik-heap (deleted)
41009000-41049000 rwxp 00000000 00:07 356 /dev/ashmem/dalvik-bitmap-1 (deleted)
41049000-41089000 rwxp 00000000 00:07 357 /dev/ashmem/dalvik-bitmap-2 (deleted)
41089000-410aa000 rwxp 00000000 00:07 358 /dev/ashmem/dalvik-card-table (deleted)
410aa000-410ad000 rwxp 410aa000 00:00 0
410ad000-410ae000 ---p 00000000 00:07 359 /dev/ashmem/dalvik-LinearAlloc (deleted)
410ae000-41294000 rwxp 00001000 00:07 359 /dev/ashmem/dalvik-LinearAlloc (deleted)
41294000-415ad000 ---p 001e7000 00:07 359 /dev/ashmem/dalvik-LinearAlloc (deleted)
415ad000-415ae000 r-xs 00002000 1f:00 467 /system/framework/core-junit.jar
415ae000-415b4000 r-xp 00000000 1f:01 283 /data/dalvik-cache/system@framework@core-junit.jar@classes.dex
415b4000-415bd000 rwxp 415b4000 00:00 0
415bd000-415be000 r-xs 00000000 00:07 409 /dev/ashmem/SurfaceFlinger read-only heap (deleted)
415be000-415bf000 r-xs 001c6000 1f:00 480 /system/framework/core.jar
415bf000-419e7000 r-xp 00000000 1f:01 277 /data/dalvik-cache/system@framework@core.jar@classes.dex
419e7000-41a26000 rwxp 419e7000 00:00 0
41a26000-41a27000 r-xs 00046000 1f:00 479 /system/framework/bouncycastle.jar
41a27000-41ad4000 r-xp 00000000 1f:01 278 /data/dalvik-cache/system@framework@bouncycastle.jar@classes.dex
41ad4000-41ad5000 r-xs 0007d000 1f:00 476 /system/framework/ext.jar
41ad5000-41c0a000 r-xp 00000000 1f:01 279 /data/dalvik-cache/system@framework@ext.jar@classes.dex
41c0a000-41c0b000 r-xs 002c8000 1f:00 472 /system/framework/framework.jar
41c0b000-422b0000 r-xp 00000000 1f:01 280 /data/dalvik-cache/system@framework@framework.jar@classes.dex
422b0000-4233c000 rwxp 422b0000 00:00 0
4233c000-4233d000 r-xs 00015000 1f:00 475 /system/framework/android.policy.jar
4233d000-4236b000 r-xp 00000000 1f:01 281 /data/dalvik-cache/system@framework@android.policy.jar@classes.dex
4236b000-4236c000 r-xs 00097000 1f:00 473 /system/framework/services.jar
4236c000-424ba000 r-xp 00000000 1f:01 282 /data/dalvik-cache/system@framework@services.jar@classes.dex
424ba000-42a77000 r-xs 00000000 1f:00 519 /system/usr/icu/icudt44l.dat
42a77000-42a83000 rwxp 42a77000 00:00 0
42a88000-42ab7000 r-xs 00000000 1f:00 261 /system/fonts/DroidSans.ttf
42ab7000-42b32000 r-xs 00000000 1f:00 508 /system/usr/share/zoneinfo/zoneinfo.dat
42b32000-42b6a000 r-xs 00606000 1f:00 478 /system/framework/framework-res.apk
42b6a000-42dbc000 r-xs 003b5000 1f:00 478 /system/framework/framework-res.apk
42dbc000-42dcf000 rwxp 42dbc000 00:00 0
42dcf000-42dd9000 r-xs 00286000 1f:00 426 /system/app/OpenWnn.apk
42de0000-42e01000 rwxp 42de0000 00:00 0
42e01000-42e02000 ---p 42e01000 00:00 0
42e02000-42f01000 rwxp 42e02000 00:00 0
42f01000-42f02000 ---p 42f01000 00:00 0
42f02000-43001000 rwxp 42f02000 00:00 0
43001000-43002000 ---p 43001000 00:00 0
43002000-43101000 rwxp 43002000 00:00 0
43101000-43102000 ---p 43101000 00:00 0
43102000-43201000 rwxp 43102000 00:00 0
43201000-432ff000 r-xp 00000000 00:0a 61 /dev/binder
432ff000-43300000 ---p 432ff000 00:00 0
43300000-433ff000 rwxp 43300000 00:00 0
433ff000-43400000 ---p 433ff000 00:00 0
43400000-434ff000 rwxp 43400000 00:00 0
434ff000-43509000 r-xs 00286000 1f:00 426 /system/app/OpenWnn.apk
43509000-43544000 r-xp 00000000 1f:01 444 /data/dalvik-cache/system@app@OpenWnn.apk@classes.dex
43544000-43555000 r-xs 00276000 1f:00 426 /system/app/OpenWnn.apk
43555000-435d5000 r-xp 00000000 00:07 700 /dev/ashmem/dalvik-jit-code-cache (deleted)
435d5000-43609000 rwxp 435d5000 00:00 0
80000000-80003000 r-xp 00000000 1f:00 597 /system/lib/liblog.so
80003000-80004000 rwxp 00003000 1f:00 597 /system/lib/liblog.so
80100000-8010e000 r-xp 00000000 1f:00 557 /system/lib/libcutils.so
8010e000-8010f000 rwxp 0000e000 1f:00 557 /system/lib/libcutils.so
8010f000-8011e000 rwxp 8010f000 00:00 0
80200000-80228000 r-xp 00000000 1f:00 633 /system/lib/libutils.so
80228000-80229000 rwxp 00028000 1f:00 633 /system/lib/libutils.so
80300000-80314000 r-xp 00000000 1f:00 592 /system/lib/libz.so
80314000-80315000 rwxp 00014000 1f:00 592 /system/lib/libz.so
80400000-80422000 r-xp 00000000 1f:00 621 /system/lib/libbinder.so
80422000-80428000 rwxp 00022000 1f:00 621 /system/lib/libbinder.so
80500000-8057f000 r-xp 00000000 1f:00 594 /system/lib/libandroid_runtime.so
8057f000-80587000 rwxp 0007f000 1f:00 594 /system/lib/libandroid_runtime.so
80587000-80588000 rwxp 80587000 00:00 0
80600000-80613000 r-xp 00000000 1f:00 559 /system/lib/libexpat.so
80613000-80615000 rwxp 00013000 1f:00 559 /system/lib/libexpat.so
80700000-8072e000 r-xp 00000000 1f:00 583 /system/lib/libnativehelper.so
8072e000-80731000 rwxp 0002e000 1f:00 583 /system/lib/libnativehelper.so
80800000-808bc000 r-xp 00000000 1f:00 574 /system/lib/libcrypto.so
808bc000-808cc000 rwxp 000bc000 1f:00 574 /system/lib/libcrypto.so
808cc000-808ce000 rwxp 808cc000 00:00 0
80900000-809fb000 r-xp 00000000 1f:00 618 /system/lib/libicui18n.so
809fb000-80a00000 rwxp 000fb000 1f:00 618 /system/lib/libicui18n.so
80a00000-80ac8000 r-xp 00000000 1f:00 549 /system/lib/libicuuc.so
80ac8000-80ad0000 rwxp 000c8000 1f:00 549 /system/lib/libicuuc.so
80ad0000-80ad3000 rwxp 80ad0000 00:00 0
80b00000-80b4e000 r-xp 00000000 1f:00 625 /system/lib/libsqlite.so
80b4e000-80b50000 rwxp 0004e000 1f:00 625 /system/lib/libsqlite.so
80c00000-80c2b000 r-xp 00000000 1f:00 612 /system/lib/libssl.so
80c2b000-80c2f000 rwxp 0002b000 1f:00 612 /system/lib/libssl.so
80d00000-80d04000 r-xp 00000000 1f:00 560 /system/lib/libnetutils.so
80d04000-80d05000 rwxp 00004000 1f:00 560 /system/lib/libnetutils.so
80e00000-80e31000 r-xp 00000000 1f:00 551 /system/lib/libui.so
80e31000-80e34000 rwxp 00031000 1f:00 551 /system/lib/libui.so
80f00000-80f09000 r-xp 00000000 1f:00 585 /system/lib/libEGL.so
80f09000-80f0a000 rwxp 00009000 1f:00 585 /system/lib/libEGL.so
80f0a000-80f0c000 rwxp 80f0a000 00:00 0
81000000-8101a000 r-xp 00000000 1f:00 613 /system/lib/libpixelflinger.so
8101a000-8101c000 rwxp 0001a000 1f:00 613 /system/lib/libpixelflinger.so
81100000-81104000 r-xp 00000000 1f:00 569 /system/lib/libhardware_legacy.so
81104000-81105000 rwxp 00004000 1f:00 569 /system/lib/libhardware_legacy.so
81200000-81202000 r-xp 00000000 1f:00 553 /system/lib/libwpa_client.so
81202000-81203000 rwxp 00002000 1f:00 553 /system/lib/libwpa_client.so
81300000-81301000 r-xp 00000000 1f:00 558 /system/lib/libhardware.so
81301000-81302000 rwxp 00001000 1f:00 558 /system/lib/libhardware.so
81400000-8140a000 r-xp 00000000 1f:00 607 /system/lib/libgui.so
8140a000-8140c000 rwxp 0000a000 1f:00 607 /system/lib/libgui.so
81500000-81518000 r-xp 00000000 1f:00 637 /system/lib/libsurfaceflinger_client.so
81518000-8151b000 rwxp 00018000 1f:00 637 /system/lib/libsurfaceflinger_client.so
81600000-81611000 r-xp 00000000 1f:00 641 /system/lib/libcamera_client.so
81611000-81614000 rwxp 00011000 1f:00 641 /system/lib/libcamera_client.so
81700000-8170a000 r-xp 00000000 1f:00 608 /system/lib/libskiagl.so
8170a000-8170b000 rwxp 0000a000 1f:00 608 /system/lib/libskiagl.so
81800000-81914000 r-xp 00000000 1f:00 609 /system/lib/libskia.so
81914000-81918000 rwxp 00114000 1f:00 609 /system/lib/libskia.so
81918000-8191b000 rwxp 81918000 00:00 0
81a00000-81a02000 r-xp 00000000 1f:00 578 /system/lib/libemoji.so
81a02000-81a03000 rwxp 00002000 1f:00 578 /system/lib/libemoji.so
81b00000-81b32000 r-xp 00000000 1f:00 567 /system/lib/libjpeg.so
81b32000-81b33000 rwxp 00032000 1f:00 567 /system/lib/libjpeg.so
81c00000-81c05000 r-xp 00000000 1f:00 570 /system/lib/libGLESv1_CM.so
81c05000-81c06000 rwxp 00005000 1f:00 570 /system/lib/libGLESv1_CM.so
81d00000-81da2000 r-xp 00000000 1f:00 572 /system/lib/libdvm.so
81da2000-81da9000 rwxp 000a2000 1f:00 572 /system/lib/libdvm.so
81da9000-81dab000 rwxp 81da9000 00:00 0
81e00000-81e04000 r-xp 00000000 1f:00 634 /system/lib/libGLESv2.so
81e04000-81e05000 rwxp 00004000 1f:00 634 /system/lib/libGLESv2.so
81f00000-81f02000 r-xp 00000000 1f:00 619 /system/lib/libETC1.so
81f02000-81f03000 rwxp 00002000 1f:00 619 /system/lib/libETC1.so
82000000-82051000 r-xp 00000000 1f:00 547 /system/lib/libsonivox.so
82051000-82052000 rwxp 00051000 1f:00 547 /system/lib/libsonivox.so
82052000-82057000 rwxp 82052000 00:00 0
82100000-82159000 r-xp 00000000 1f:00 561 /system/lib/libmedia.so
82159000-82168000 rwxp 00059000 1f:00 561 /system/lib/libmedia.so
82200000-82201000 r-xp 00000000 1f:00 636 /system/lib/libnfc_ndef.so
82201000-82202000 rwxp 00001000 1f:00 636 /system/lib/libnfc_ndef.so
82300000-8230c000 r-xp 00000000 1f:00 591 /system/lib/libmedia_jni.so
8230c000-8230d000 rwxp 0000c000 1f:00 591 /system/lib/libmedia_jni.so
82400000-8255d000 r-xp 00000000 1f:00 639 /system/lib/libstagefright.so
8255d000-82567000 rwxp 0015d000 1f:00 639 /system/lib/libstagefright.so
82567000-82568000 rwxp 82567000 00:00 0
82600000-8261c000 r-xp 00000000 1f:00 600 /system/lib/libvorbisidec.so
8261c000-8261d000 rwxp 0001c000 1f:00 600 /system/lib/libvorbisidec.so
82700000-8270c000 r-xp 00000000 1f:00 640 /system/lib/libstagefright_amrnb_common.so
8270c000-8270d000 rwxp 0000c000 1f:00 640 /system/lib/libstagefright_amrnb_common.so
82800000-82801000 r-xp 00000000 1f:00 615 /system/lib/libstagefright_enc_common.so
82801000-82802000 rwxp 00001000 1f:00 615 /system/lib/libstagefright_enc_common.so
82900000-82905000 r-xp 00000000 1f:00 614 /system/lib/libstagefright_avc_common.so
82905000-82906000 rwxp 00005000 1f:00 614 /system/lib/libstagefright_avc_common.so
82a00000-82a09000 r-xp 00000000 1f:00 568 /system/lib/libstagefright_foundation.so
82a09000-82a0a000 rwxp 00009000 1f:00 568 /system/lib/libstagefright_foundation.so
82b00000-82b03000 r-xp 00000000 1f:00 647 /system/lib/libstagefright_color_conversion.so
82b03000-82b04000 rwxp 00003000 1f:00 647 /system/lib/libstagefright_color_conversion.so
82c00000-82c09000 r-xp 00000000 1f:00 632 /system/lib/libexif.so
82c09000-82c0a000 rwxp 00009000 1f:00 632 /system/lib/libexif.so
82c0a000-82c0c000 rwxp 82c0a000 00:00 0
82d00000-82d06000 r-xp 00000000 1f:00 598 /system/lib/libsoundpool.so
82d06000-82d07000 rwxp 00006000 1f:00 598 /system/lib/libsoundpool.so
82e00000-82e3a000 r-xp 00000000 1f:00 554 /system/lib/libstlport.so
82e3a000-82e3c000 rwxp 0003a000 1f:00 554 /system/lib/libstlport.so
82f00000-82f0b000 r-xp 00000000 1f:00 630 /system/lib/libwnndict.so
82f0b000-82f0c000 rwxp 0000b000 1f:00 630 /system/lib/libwnndict.so
83000000-83415000 r-xp 00000000 1f:00 628 /system/lib/libwebcore.so
83415000-8346f000 rwxp 00415000 1f:00 628 /system/lib/libwebcore.so
8346f000-83471000 rwxp 8346f000 00:00 0
83800000-83801000 r-xp 00000000 1f:00 593 /system/lib/libWnnJpnDic.so
83801000-83948000 rwxp 00001000 1f:00 593 /system/lib/libWnnJpnDic.so
83a00000-83a01000 r-xp 00000000 1f:00 646 /system/lib/libWnnEngDic.so
83a01000-83b23000 rwxp 00001000 1f:00 646 /system/lib/libWnnEngDic.so
afb00000-afb20000 r-xp 00000000 1f:00 595 /system/lib/libm.so
afb20000-afb21000 rwxp 00020000 1f:00 595 /system/lib/libm.so
afc00000-afc01000 r-xp 00000000 1f:00 623 /system/lib/libstdc++.so
afc01000-afc02000 rwxp 00001000 1f:00 623 /system/lib/libstdc++.so
afd00000-afd40000 r-xp 00000000 1f:00 588 /system/lib/libc.so
afd40000-afd43000 rwxp 00040000 1f:00 588 /system/lib/libc.so
afd43000-afd4e000 rwxp afd43000 00:00 0
b0001000-b0009000 r-xp 00001000 1f:00 293 /system/bin/linker
b0009000-b000a000 rwxp 00009000 1f:00 293 /system/bin/linker
b000a000-b0013000 rwxp b000a000 00:00 0
bef58000-bef6d000 rw-p befeb000 00:00 0 [stack]

* 差分
1c1
< # cat maps --- > # cat /proc/111/maps
4c4,6
< 0000a000-001ab000 rwxp 0000a000 00:00 0 [heap] --- > 0000a000-001d2000 rwxp 0000a000 00:00 0 [heap]
> 10000000-10001000 ---p 10000000 00:00 0
> 10001000-10100000 rwxp 10001000 00:00 0
7,8c9,10
< 40009000-4054b000 rwxp 00000000 00:07 355 /dev/ashmem/dalvik-heap (deleted) < 4054b000-41009000 ---p 00542000 00:07 355 /dev/ashmem/dalvik-heap (deleted) --- > 40009000-405fb000 rwxp 00000000 00:07 355 /dev/ashmem/dalvik-heap (deleted)
> 405fb000-41009000 ---p 005f2000 00:07 355 /dev/ashmem/dalvik-heap (deleted)
14,15c16,17
< 410ae000-41289000 rwxp 00001000 00:07 359 /dev/ashmem/dalvik-LinearAlloc (deleted) < 41289000-415ad000 ---p 001dc000 00:07 359 /dev/ashmem/dalvik-LinearAlloc (deleted) --- > 410ae000-41294000 rwxp 00001000 00:07 359 /dev/ashmem/dalvik-LinearAlloc (deleted)
> 41294000-415ad000 ---p 001e7000 00:07 359 /dev/ashmem/dalvik-LinearAlloc (deleted)
17a20,21
> 415b4000-415bd000 rwxp 415b4000 00:00 0
> 415bd000-415be000 r-xs 00000000 00:07 409 /dev/ashmem/SurfaceFlinger read-only heap (deleted)
32a37
> 42a77000-42a83000 rwxp 42a77000 00:00 0
37a43
> 42dcf000-42dd9000 r-xs 00286000 1f:00 426 /system/app/OpenWnn.apk
38a45,62
> 42e01000-42e02000 ---p 42e01000 00:00 0
> 42e02000-42f01000 rwxp 42e02000 00:00 0
> 42f01000-42f02000 ---p 42f01000 00:00 0
> 42f02000-43001000 rwxp 42f02000 00:00 0
> 43001000-43002000 ---p 43001000 00:00 0
> 43002000-43101000 rwxp 43002000 00:00 0
> 43101000-43102000 ---p 43101000 00:00 0
> 43102000-43201000 rwxp 43102000 00:00 0
> 43201000-432ff000 r-xp 00000000 00:0a 61 /dev/binder
> 432ff000-43300000 ---p 432ff000 00:00 0
> 43300000-433ff000 rwxp 43300000 00:00 0
> 433ff000-43400000 ---p 433ff000 00:00 0
> 43400000-434ff000 rwxp 43400000 00:00 0
> 434ff000-43509000 r-xs 00286000 1f:00 426 /system/app/OpenWnn.apk
> 43509000-43544000 r-xp 00000000 1f:01 444 /data/dalvik-cache/system@app@OpenWnn.apk@classes.dex
> 43544000-43555000 r-xs 00276000 1f:00 426 /system/app/OpenWnn.apk
> 43555000-435d5000 r-xp 00000000 00:07 700 /dev/ashmem/dalvik-jit-code-cache (deleted)
> 435d5000-43609000 rwxp 435d5000 00:00 0
138a163,164
> 82f00000-82f0b000 r-xp 00000000 1f:00 630 /system/lib/libwnndict.so
> 82f0b000-82f0c000 rwxp 0000b000 1f:00 630 /system/lib/libwnndict.so
141a168,171
> 83800000-83801000 r-xp 00000000 1f:00 593 /system/lib/libWnnJpnDic.so
> 83801000-83948000 rwxp 00001000 1f:00 593 /system/lib/libWnnJpnDic.so
> 83a00000-83a01000 r-xp 00000000 1f:00 646 /system/lib/libWnnEngDic.so
> 83a01000-83b23000 rwxp 00001000 1f:00 646 /system/lib/libWnnEngDic.so