2011年12月31日土曜日

無事暮れまして、お疲れさまでした。

しばらくブログを放置しておりました。ごめんなさい。12月に1個技術な記事を書こうとしたのですが、なんだかアクセス数がすごい事になっていて、怖くなったので、落ち着くまで待とうとか思ってみたりして。ようやくアクセス数も落ち着いてきましたが、もう正直どうなることかとヒヤヒヤものでした。とりあえず、技術のエントリは年明け後落ち着いてから書き直すということで。

さて、今年もあと1日を残すばかりとなりました。

3月の震災では、人生の3分の1を過ごした東北の地に多くの被害があり、連絡のつかない友人も。今もその爪痕が残っており、今年は出だしから心の痛む辛い始まりでした。
このブログにも募金のリンクをはったり、災害情報のリンクをはったりしつつ、心を痛めている余裕も失わせる頻繁な計画停電。23区では全く関係なかったそうなのですが、対象地区でシフト制のため、朝5時起きとか、仕事の途中に4時間抜けて時間つぶしとか、厳しい日々もありました。



また非常に親しくさせていただいた、ある会社の社長さんが42歳で急逝。前日にジンギスカンを食べたいとおっしゃっていて誘いを受けたのですが、ハードな計画停電生活で疲れもあって参加をお断りしたところ、翌朝におおきな鼾をかきはじめ、眠ったまま、逝ってしまわれたそうで。最後の一日にご一緒できなかった事が、今も悔やまれてなりません。
いつも一緒に飲む仲間内だと、危ない下ネタ話に花を咲かせて場を和ませる方でしたが、二人で話す機会があった折、某社の愚痴をこぼしてしまった際には、技術者というもの、仲間というもの、会社というものについて、いろいろご意見やアドバイスをいただきました。特に今在籍している?会社の社長と非常に仲がよく、全くタイプが違うこの二人が組んだら面白い会社になりそうだと思っていたのですが、非常に残念でなりません。

その後、少し間をあけて初の海外出張。読む方は兎も角、英会話には全く自信がなかったものの、退職のためにこちらから契約終了をお願いする形となり、お客様にお詫びと今までの感謝の気持ちもあって引き受けました。無理を言ってすいませんとお客様はおっしゃってくださいましたが、なんとなく、海外でも片言でなんとかなるという驚きと、肌で感じる文化の違いなど、とても良い経験をさせていただきました。まぁ、結果として、ABC 2011 Summerでは、突然の発表キャンセルで、PF部の部長さんには大変ご迷惑をおかけしてしまったことだけが、心残りでしたが。

帰国直後には、待っていてくださったかのような伯母の死。長い事、ガンを煩っていたこともあり、そろそろ危ないとの連絡も入っていたので、どこか覚悟していたことでしたが、人の死には慣れる事ができませんね。急遽生まれ故郷へと伺いました。父と年がだいぶはなれており、戦後の辛く貧しい中を生きてきた逞しい方でした。きつい事をはっきりという方で、幼い頃からちょっと苦手でしたが、何かというときに「がんばんなさい」と背をたたいてくれる、そんな姉御肌の素敵な方でした。葬儀の後、執筆されていた句集等の書籍を数冊頂いて読んだ中には、そんな辛い中で生きてきた思いが綴られており、つまらない事で、くじけたり負けていられないなと決意を新たにさせていただきました。

そして9月末の退職。5年間、辞めたい、辞めるといっては、同僚や上司役の人に引き止められ、お客さんへの迷惑を考えてタイミングを逸し続けながら、粘りに粘ってようやくこぎ着けた決別。まぁ、本当は、紙を1通出せば良いのは知っていたのですが、先に辞めた人達にあきれられながら、お客様や残る人に迷惑をかけないタイミングを探していたらこんなにかかった訳で・・・。

この不景気に、また個人事業主へと逆戻り、ほとんどフリーランスのような立場で、仲間内の小さな会社の名前での再出発です。厳しい綱渡りながらも、充実した日々へと踏み出しました。こういう危ない橋を突っ走る時には、独り身で良かったと思います。クリスマスなんかでうかれやがって、リア充爆・・・なんでもないです。

12月はというと、退職後に忙しくて放置していたのに、誰がはじめたのか、退職エントリーが2ヶ月後にいきなり大ブレイク・・・会う人にはその話をされるし、かなり恥ずかしかったです。2ヶ月もたったら勢いで書いた気持ちも収まって忘れかけてたというのに、蒸し返されてもねぇ・・・。だいたい、一応似非とはいえプログラマ。技術について調べた内容を書いたエントリよりも、よく経営をわかっていないエンジニアの与太話と一刀両断されてもしょうがないエントリの方が人気がでるって・・・。

もともと、某社に残った方で目を通してる物好きさんと、新しく一緒にやっていきましょうという話になっている数名とのために、どこかで同じところにハマりこまないようにエラー処理を考えましょうね、くらいのつもりで書いたんですが。

はてぶやtwitterやGoogle+でいろいろな方がコメントしたりして下さっていたようなのですが、そんなに大仰にするつもりで書いた訳でもないので、ひっそりと見なかった事にしています。ごめんなさい。

強いて挙げるなら

・成長にかかる時間が長すぎない?
・時間ではなく人数で変わると思う
・技術者を一括りに一種類しかいないようにするのは間違っている(俺は変態ではない?)
という意見が、その通りかもしれないなと思いました。

身近で見て、知っている、受託や人売りが中心の、わりとよくある技術系の会社だと、だいたいはあの程度の時間がかかっていて、僕が技術者に区分している周りの技術者は、たいてい変態なので、ああいう記述になったわけで。僕自身、すべての技術者の統計を取っている訳でも、すべての技術会社の推移の調査をしているわけでもないので、この意見はごもっともです。時間軸についてなどは、斬新なアイディアや商品のあてがあり、大きくお金が借りられるような本格的な技術会社だったら、あの時間軸でやってたら、絶対に駄目でしょう。

だから、おそらく、人の数で変遷を見るという意見が正しいです。ま、一応、周囲の例とか、関わった組織の変遷や、今まで読んだ書物、この目で見てきた人とのつきあい方の移り変わりを考えて、なんとか破綻せずに長過ぎず、短すぎずに変遷していける時間軸だとは思っているのですけど。


せっかくだからこのエントリも読んでおこうと、ただ長いだけのこの駄文をここまで読んだという物好きさんにアドバイス。前のエントリにも書いたはずなのですが、あれは「違った未来があったかもしれない」レベルの、会社が育つ時にたぶんエラーチェックをすべき小さなif文のお話しで、間違えなければ成功しただろうという話ではないのです。そこだけは忘れないでくださいね。
ファイルを書き込み権ありでopenできたからといって、writeがすべて成功して無事にファイルができるなんて考えたら、それこそ大事なデータを保存できずに気がつかない深刻なバグが入り込むわけで。

まぁ、ぶっちゃけてしまえば、孟子に天の時、地の利、人の和とはあるけれど、所詮、天の時だけでも勝つ時は勝つし、人の和だけあっても負ける時は負けますよ。たぶん。
ま、天地人のすべてを揃えれば、良い線いけるんじゃないかとも思いますが。

あまり具体的に何があり、どう失敗したのかなんて、実際書くといろいろ問題あるわけではしょって書いていますし、かなり大雑把に人の和を忘れて突き進んだら失敗したね。それじゃ駄目じゃない?という、昔からある、人の和は大事だよねという確認を、ちょっと会社というものの成長を交えて書いただけで、特別な事でもなんでもないはずなんです。それこそ、そんなエントリーに興味をもつような、経営にまで手をだそうかと思う人なら、人の理は、己の道を隠す霧なりということで、自らの信念をもって、どうか自らの理想の形で、生き残りをかけた戦いに出かけてください。

え、僕の理想の形ですか?個人事業主でこの自分の身一つ支えられるかも不安なんですが。第一、経営なんてつまらない事に力を割く時間があるのなら、がしがしコードを書きたいよね?というのが本音です。

まぁ、経営に口を出しはじめたなら、技術者に甘い事ばかりを言う駄目な経営者になりそうだなぁ。技術者には、せめてプロジェクト単位の準個室とか、仕事の速さや顧客の満足度によっては完全な個室を与えて、電話は受付事務の人を必ず通して技術者部屋には音を漏らさない。椅子は20万しようが腰の痛くなりにくい良いものを使い、常に、できるだけ早くコンパイルできるPCと、さくさくWebの見れるネットワーク環境を揃える。各個室には窓があって外を見る事もでき、仮眠室も用意する。いや駄目だ。あっという間に資金つきますねぇ。無理です。

何ともまとまりの無い記事になってきましたので、いい加減ここまでにしましょう。一年を振り返りつつ、どうでも良い話が長くなりすぎました。

そんなこんなで、僕にとっては激動の一年でした。親しい方、憧れていた方を失いながら、涙の多い一年でした。今年心に刻んだのは、一期一会。今までであった出会いも、これから出会う出会いも、その時々をできるだけ大事にして、来年もまたがんばって行きたいなと思います。

という、無駄に長い雑記を、とりあえず奇麗な言葉でまとめたあたりで、この一年の終わりとさせていただきます。それでは、皆様良いお年を。


2011年10月1日土曜日

退職しました

皆様大変お久しぶりです。日本に帰国後、色々と忙しくしていた隠者でございます。
まぁ、ツイートをごらんになった皆様はご存知のように、昨日、常駐先での業務を完了し、同時に退職となりました。

当時、十数人の創業10年目の技術者集団に、2年以上にもわたり勧誘を受け、ぜひ一緒に仕事をしたいという言葉に誘われて、入社を決意したのが2002年末。当時は、「会社なんかいつ無くなっても仕方ない」といい続けてきた技術集団を、きちんとした会社にしなければと感じた最年長の経営にいた技術者が、「ビジョンがある」という営業出身者に代表権が移ってから10年。

結局、会社への変革はできず、技術者の稼ぎから行った投資が実らず、いつの間にか当時の技術者が一人、また一人と去り、かつての技術者が育ててきた親会社の信用を生贄に子会社に従業員全員強制転籍なんて荒業まで行われました。そんな会社で、去り行く人たちを寂しく見送りながら、友のため、お客様のためにと、無駄にあがいてきましたが、ようやく一区切りをつけ自分自身を送り出す事ができました。

そんな流れに身をおきながら、とある経営者の人となんとなく語りあった内容を少し思い出しながら書いてみようかと思います。大して面白い話でもないので、適当に読み捨ててください。


2011年7月24日日曜日

台湾からこんばんは

どうもお久しぶりの隠者でございます。

いやぁ、すっかり留守にしてしまいましたが、皆様いかがお過ごしでしょうか。
隠者はというと、現在台湾出張中です。

久しぶりにBloggerにアクセスすると、なんだか編集画面もすっかり変わっていまして、浦島太郎状態です。

身の回りの出来事としては、退職を決意しまして、会社とも交渉がまとまりました。現在の仕事が一段落ついたところで、客先から撤収し、退職という流れになっています。隠者自身はこの業界に入って客先はいくつか渡り歩いたモノの、一度しか転職をしていません。そのようなわけで、これが2度目の転職となります。まぁ、なんでしょう、人生って色々あるなぁといったそんな気がしています。

さて、本日は、震災の際、多額の寄付を寄せて下さった台湾についてです。
隠者は東北地方で10年以上過ごしており、転勤族の両親に連れられて移動しながら暮らしましたので、一番長く過ごした土地でもあります。

ですので、震災について心痛めていた事もあり、被災者ではないものの、各国の支援の声はとてもありがたく聞いておりました。中でも、台湾については、物価水準からするととんでもなく多額の支援を下さった国です。感謝してもしきれません。

まだ1週間という短い期間ですが、台湾で過ごして思うのは、とても暖かく、親切な人達が多い土地柄だなということです(自動車やバイクに乗っていないときは)。

特に面白く感じているのは、現在の出張先だけしかみていませんが、技術者の現場に女性の数がかなり多くいることです。僕が知るプログラマーの生息地は、たいていが狭く、薄暗く、男臭いというイメージなのですが、こちらは明るい雰囲気です。

話によると、朝は8時半には出社するそうですが、夜は20時には帰りなさいという会社のポリシーがあるようで、生活は朝早く夜も早いという雰囲気です。健全ですね。
日本のプログラマーは、朝は遅く夜も極端に遅いというのが常ですから、この辺りが女性進出の鍵なのかもしれませんが・・・。

出勤は車で30分くらいが普通のようです。夜は早いですが、朝も早い分、総合的にはそれほど勤務時間が短いわけではなさそうですね。でも、早い時間に帰れると、少し気分も違ったりしますよね。

食堂や売店は今いる出張先が特殊なのかもしれませんが、非常に良く整っています。お昼休みはお昼寝する習慣があるようで、多くの方々がうたた寝していました。昼休みにもキーボードを打っている隠者は、少し奇妙にうつるようです。

ちなみに、食事の際台湾の方々と一緒でも気にせずに手を合わせての頂きますや、ごちそうさまが癖になっていましたが、夜の食事会でそれは葬式の時にする事だよという話がでていました。日本だとよろしくお願いしますと拝んだり、感謝したり、お祈りしたりと色々使われますが、何気ない仕草が奇異に映ることもあるようなので、この辺は良く学んでおかないといけませんねぇ。まぁ、あえてやっておいて食事時に聞かれたら感謝や祈りの時にするけどと伝えるのも良いのかもしれませんが・・・。

一度海外の職場というモノを見てみると、日本の習慣や、日本の技術者のあり方、日本のメーカーなんかの見え方も少し違って来る所もあったりします。みなさんも、機会があれば、是非一度、仕事でも海外に出て見て下さい。

特に台湾は、反日感情がそれほど強くはない(お年寄りの方々も、それなりに優しく接してくれる)ので、初めての海外としては良い場所のように思います。

2011年6月2日木曜日

MeeGo Porting Guide なんちゃって翻訳(その2) 相変わらず途中まで

はい、前回のMeeGo Porting Guide翻訳のパート2です。

前回の翻訳部分は概要の後、ビルドのツールについての説明に入っていました。

思いっきり要約すると、「MeeGoのコンプライアンスに従い、ABIやAPIを壊すことがないのであれば、HWベンダは独自のソフトのために独自のビルドマシンを使おうと、MeeGoのビルドシステムを使おうとかまわない。ただ、そのためには、MeeGoをビルドしているシステムと同じツールセットを使うことになるだろう」ということで、MeeGoのビルドに使われているツールが列挙されていました。

というわけで、前回に引き続き途中までGoogle翻訳で翻訳を続けていたのですが・・・twitterで、Google Translator Toolkitでないと普通の翻訳は覚えてくれないよ・・・と指摘を受けまして、がっかりです。無駄に浪費時間を返せ!と叫びたい気分です。

というわけで、途中からはかなり投げやりに適当翻訳を行ってますので、ご容赦ください。



ベンダ独自のOBS

したがって、結局のところ、MeeGo OSを実行する実際の製品を作成する場合、ベンダーは独自のOBSビルドシステムを設定する事にになるかもしれません。独自のOBSシステムは新しいハードウェア上でテストするためのMeeGo OSの変更とビルドの柔軟な方法を提供するので、初期のハードウェア/製品開発の段階で有益であるかもしれません。ベンダ独自のOBSシステムはMeeGoから示されたパッケージを扱うためや他のソース、例えば、そのベンダーに固有のクローズドソースのパッケージ等、を扱うリンクをMeeGoOBSにリンクできます。このセットアップの概要図を参照してください。

ベンダーの設定:
  • 独自のOBSシステムを設定する
    OBSシステムの設定に関する手順については、OBS Applicances OpenSUSE OBSのWikiになります。
  • 独自のコンポーネントのため独自のOBS 下のプロジェクトを作成する
  • MeeGoコンポーネント用に独自のOBSをMeeGoOBS へのリンクする
  • 自分のOBSがMeeGoのコンポーネントに試験的なパッチを当てることがあります
    Note : 最終的に完成したMeeGoベースの製品でMeeGoのコンポーネントに必要なすべてのパッチはMeeGo.comにプッシュする必要があります。ただし、これはMeeGoコンプライアンス要件および該当するSWライセンスのルールとして満たされている限り絶対に必須要件になるわけではありません。
    上流のプロジェクト、MeeGo、製品、およびパッチを参照してください

  • OBSで作成されたパッケージからリリースおよびイメージを作成するために必要な機器をセットアップが必要
    この機器は、MeeGoで使用されるツールセットをベースにすることができます(上記参照)

MeeGo.comの下での作業

いくつかの新しいハードウェアにMeeGoを移植するのもう一つの方法は、新しいハードウェアは、1つMeeGoリファレンスハードウェアとして受け入れを取得し、MeeGoビルド機構で通常のMeeGoリリース構築サイクルの一部ハードウェアとしてリファレンス用にビルド作成するものです(リリースタイムラインリリースプロセスを参照してください)。また、この設定ではMeeGoサイド​​のリファレンスハードウェアのQAサポートを含めることができます(クオリティを参照してください)。この文書の執筆時点で、MeeGoの新規リファレンスハードウェアを得るための実際のプロセスはまだ多少は不明瞭です。いずれにせよ、このモデルはMeeGoで、それらのリファレンスハードウェアをサポートする一般的なMeeGo作業ではベンダーから特に積極的に参加する必要があります。

ベンダーの設定:
  • それらのコンポーネントのMeeGo OBS下にあるデバイス/プラットフォーム開発プロジェクトを作成します。オープンソースのコンポーネントは、MeeGoトランクに提出になるでしょう。: 含めるために他のMeeGoコンポーネントのようにテストやレビューを行います。
    MeeGo OBSではいくつかのリファレンスHWのMeeGoをビルド含めるためクローズドソースのバイナリコンポーネントを持つことも可能であることに注意してください。これらは、トランク:non-ossのリポジトリに提出されます。repo.meego.com からミラーやホストができないので、通常、ライセンスはコンポーネントが少なくとも再配布可能性を含むようにする必要があります。
  • 他のMeeGoコンポーネントへのパッチは、必要に応じてMeeGo.comへをプッシュします(上流のプロジェクト、MeeGo、製品、およびパッチを参照)
  • それらのリファレンスHWのイメージを構築するためのMICキックスタートファイルを作成します(または作成をサポートします)
  • 必要に応じて、MeeGoのビルドとインフラストラクチャのリリースツールでそれらのリファレンスハードウェアとソフトウェアコンポーネントのサポートを追加サポートします
トライアル
上記のプロセスの代わりに、限定的ですが簡単な"try it out"について以下に記述します。

最初の試み
  • まずはあなたのターゲットにもっとも近いすでにビルドされたMeegoのリファレンスのためのrootファイルシステムを入手します。ARMv7の場合、通常N900ハンドセットのイメージで、Atomの場合、Netbookのイメージやハンドセットのイメージになるでしょう。
  • あなたのデバイス向けのLinux kernelをビルドしモジュールを/lib/modulesにインストールします。
  • rootファイルシステムを起動し、コンフィグレーションに手をいれ、デバイスをとめるようなUXをはずします。
  • あなたのポーティング作業について修正したり追加したことを書きとめておいて下さい。

最初のイメージの作成

適切なハードウェアアダプテーションの第二ステップは、あなた自身のイメージをビルドできるようにすることです。この前までの作業がリファレンスデバイスのイメージに基づいているので、手始めにこのイメージを作成することが理にかなっています。MeeGoのイメージは、イメージの内容計画を記述するいわゆる'kickstartファイル'に基づいて構成されます。
  • Meego Image Creator tool(MIC)をインストールします
  • リファレンスデバイスのイメージを見つけたのと同じディレクトリからkickstartファイル(.ks)をダウンロードします。
  • mic-image-creatorを使ってイメージを生成します(should be elaborated)。
  • 前のステップで焼きたてほやほやのイメージを試してみる。

あなたが移植した最初の再生イメージをビルドする
  • MeeGo kernelをダウンロードし、場合によっては新しいデバイスドライバを含むパッチを適用し、カーネルをビルドします(新チップセットをサポートしたMeeGoカーネルの取得方法の記述を参照)
  • Kickstart fileにあなたのカーネルパッケージを含むリポジトリを追加します(to be elaborated)
  • Kickstartファイルからリファレンスデバイス固有の部分を取り除きます
  • %packagesセクションにあなたのカーネルパッケージについての記述を追加します
  • あなたのデバイスに合わせてkickstartファイルの%postセクションに、ビルドしたパッケージやシェルスクリプトの設定を追加変更します。
この方法のバリエーションとして詳細な説明は、ここで見つけられる(もっとよい説明が必要)


MeeGoカーネルの新しいチップセットのサポートを入手する
どのようにMeeGoカーネルを動作させ、新しいハードウェアをサポートするかについてのもっと詳細な情報は、How-Toの 新チップセットをサポートしたMeeGoカーネルの取得方法を参照してください。




というわけで、失意のなかでちらほらとがんばったのですが、全部翻訳するには到底おいついていないわけで、今日も途中までということで。

本日twitterで@kimitake さんが見つけてきてくださった過去MLを超大雑把に翻訳すると、meego.comの翻訳については歓迎するけど、どう載せていくかは、meego.jpのような方法が良いんじゃなかろうかといった意見がある様子。

でも、実は、meego.jpはwikiをもってなくて、独自wikiがあるのはmeego-users.jpなんですよね。

このあたりがこうムズムズするところなんですが、MeeGoというのはもともと、もっとオープンにコミュニティーとして作り上げていこうという趣旨もあって、meego.comにアカウントを作ることもそのwikiを編集することも自由のようです。

ところが、日本の場合は、meego.comの日本版のはずのmeego.jpのほかに、meego-users.jpなんてのもあるんですよね。Androidの場合は、新しい方向性やベースの開発はクローズドに行われているし、OHAとユーザー会とが別にできるのはしょうがないのですけど。

meego.jpとmeego-users.jpの立ち位置とか、ユーザーが何をどこまでどうしていけるのか、もう少し明瞭にしてもらわないと動きにくいような気がしています。

# え、ユーザー会で直接言えって?まぁ、そうかもしれないのだけど、隠者はほら、超小心者ですので・・・・orz

2011年6月1日水曜日

MeeGo Porting Guide なんちゃってGoogle翻訳(途中)

今のGoogle翻訳は使えないとか思っている隠者です。出てくる翻訳結果がねぇ・・・。

ただ、Google翻訳は、自力で訂正を登録できるようなので、もしかしたら頻繁に修正していけば、使い物になるのうになるのかもしれません。というわけで、MeeGo Porting GuideをGoogle翻訳を使いながらちょこちょこ翻訳を手直ししつつ、多少は読める所までを目標に翻訳はじめてみました。です・ます調とである調が混在してますけど、とりあえず半自動翻訳なのでお許し下さい(注:どうしてもうまく文節を認識してもらえないものは分割して翻訳しています)。

本当は meego.jp のwikiにいれたいのだけど、いまいちページの構成とかどう階層付けしたらいいかとかわからないんですよねぇ・・・・。

イントロダクション


MeeGo Porting Guide(MPG)の目標は、(新しい)ハードウェアの上でMeeGo OSを実行し、最終的にMeeGo OSをベースに製品を作成したい人のための貴重な情報と説明を提供することです。 MPGは、移植プロセス、ツール、およびその他の関連する背景情報の概要から始め、移植が実際に個々の技術的/機能的領域において意味することの説明に移ります。

移植ガイドは、厳密に特定のMeeGo OSバージョンまたはデバイスのカテゴリに関連付けていません。代わりに異なるデバイスの種類をカバーするだけでなく、新しいMeeGo OSのバージョンで導入された変更に追従し十分に汎用的であることを目指しています。

異なる技術分野での詳細移植情報は、各MeeGoアーキテクチャに依存しています。いくつかのケースでは、このアーキテクチャでまだ未決定の可能性があり、これについては該当するセクションに記載されています。



フィードバック

これらのページへ投稿はオープンです。すべてのMeeGoコミュニティのメンバーはいつでもこれらのページを向上させる自由があります。また、MeeGo移植メーリングリストにフィードバックをすることができます。

一般的な移植情報/ガイドライン

MeeGo Compliance

おそらく、MPGに関連する背景情報の最も重要な部分は、MeeGoコンプライアンス要件です。MeeGoに準拠することを意図されているデバイスは該当するデバイスのカテゴリのMeeGoコンプライアンス仕様(仕様の最初のバージョンは2010年10月に使用できるようになっている)に記載されている要件を満たす必要があります。要するに、MeeGo準拠のデバイスは以下を満たす必要があります:
  • 該当するデバイスカテゴリの最小ハードウェア性能とコンポーネント要件を満たす
  • MeeGoコアOSを構成するすべてのSWのコンポーネントを含める
  • 該当するデバイスカテゴリにおいて存在するデバイスの必要な、追加ソフトウェアコンポーネントを含む
  • MeeGo由来コンポーネントのいずれのAPI/ ABIも壊さない
  • MeeGo ソフトウェア包装規則に従う
コンプライアンス規則はMeeGo OSそのものとMeeGoアプリケーションが異なる環境(使用される命令セットコンパイラバージョン、コンパイラオプションなど)でコンパイルされる方法に関してCPUアーキテクチャ固有の要件を指定します。

デバイスの製造元は、MeeGoコンプライアンスを壊さしない限り、それらのデバイスの追加機能をハードウェアコンポーネントとSWのコンポーネントを含むことができる。ベンダーはパッチがMeeGoコンプライアンスを壊さない場合、MeeGo OSのコンポーネントにパッチを当てる事ができる。それら該当するソフトウェアライセンスにより設定されている規則に準拠する限り、デバイスベンダー独自のソフトウェアコンポーネントは、オープンソースやクローズドソースののコンポーネントにすることができます。

MeeGo Porting Guideの観点から、コンプライアンスの要件は-存在する必要のあるソフトウェアコンポーネントとハードウェアコンポーネントを定義している-デバイスのベンダで移植するための必要な作業最小セットとMeeGo OS側からの関連するソフトウェアコンポーネントを効果的に定義しています。

移植プロセスとツール

概要

ベンダーのデバイスが上記で定義したMeeGoに準拠している場合に限り、彼らが、デバイスのためのSWをどのようにビルドするのかは基本的にはベンダー次第です。ベンダーは、彼らの所有するビルドのマシンやMeeGoでも使用されるOBSビルドシステムをセットアップして使用することができます。ベンダーのビルドシステムが、何であるかに関係なく、それはMeeGoビルドインフラストラクチャと統合するするには、少なくともビルドのためにMeeGoソースパッケージを取得するだけでなく、MeeGoコンポーネントがMeeGoビルドシステムで構築される同じ方法(同じコンパイラおよびコンパイラオプションを使用してなど)で、それぞれのビルドをする必要があります。いずれにせよ、MeeGoにおいては、任意のハードウェアまたはソフトウェアのベンダーが、効率的なSWの作成に使用できるオープンなツールセットを提供し使用しています。MeeGoと同じツールセットを使用することでMeeGoビルドインフラストラクチャとベンダー独自のビルドシステムを統合する最も簡単な方法を提供できるでしょう。

MeeGoビルドインフラストラクチャおよびツールセットの主要な成分:

  • MeeGo Gitorious
    様々なMeeGo固有SWコンポーネントとツールのソースファイルのバージョン管理システム
  • MeeGo OBS
    ソースからMeeGoパッケージ(RPM)を構築するために使用されているビルドシステム
  • MeeGo Repository
    ビルドされたMeeGoリリース、すなわちMeeGoパッケージとイメージが格納されている場所
  • MeeGo Image Creator
    ハードウェアにフラッシュ/インストールできるMeeGoイメージをビルドするために使用するツール
  • MeeGo release tools
    repo.meego.comの下でMeeGoリリースの作成に使用されているBOSSとREVSのようなのツール

関連情報を参照するには、ビルドインフラストラクチャリリースインフラストラクチャおよびリリースエンジニアリングを参照してください。

MeeGoの移植プロセスの別の概要については、ハードウェアの有効化プロセスを参照してください。


2011年5月30日月曜日

Wazze Mark-IVについて調べてみました

ずいぶん長い間 Blogを放置してしまった隠者です。
いや、ちょうど書こうと思ってた時期にBloggerの調子が悪くて・・・と少しだけ言い訳をしてみたり。

今回はWazze Mark-Ⅳ関連の自分用のメモ書きです。

1) Linux for Tegraの現状について

Tegra2のグラフィカル周りのドライバはソースコードが公開されておらず、すべてはnVidiaさんのバイナリ提供のドライバ公開にかかっています。
ところが、nVidiaさんが公開していたはずのL4T(Linux for Tegra)が公開停止になっています。


nVidia DEVELOPER ZONEのフォーラムに2010年2月に以下のような発言がありました。
We have removed the L4T downloads from the site due to some bugs and while we prepare for a forthcoming release. Please continue to report if you are having issues (or successes).

で、3ヶ月ほど経過した現在はというと、downloadページのどこにもL4Tの復活は見られませんでした。

終了

まぁ、少ないリソースは売れるAndroidにフォーカスしたいというのはわかるのですけど・・・・。本気でお願いします・・・nVidiaさん。

2) Wazze Mark-IV のLinux kernelについて
Wazze Mark-IV自体は、カーネルを公開していないようですが、同ハードの機種であるAdvent Vega向けのkernelは公開されていました。まぁ、Android向けなんですけどね・・・。

https://github.com/paulobrien/android_kernel_advent_vega


ちなみに、nVidiaさんのTegra2向けのkernelは以下にあるようです。Androidに関してはやる気満々ですね。

http://nv-tegra.nvidia.com/gitweb/?p=linux-2.6.git;a=summary


公式の方のバージョン更新のほうが早いようですが、Wazze用のドライバなどが不足していると思われます。現在この辺を調査中です。

3) Wazze Mark-IV のUbuntu 11.04の動作について
これも、Wazze自体のというより、Advent Vega向けに行われている成果でしたけど、すでに動かされている方がいるようです。

http://android.modaco.com/content/advent-vega-vega-modaco-com/332887/ubuntu-linux-11-04-natty-on-vega-update-13-4/

公開されているバイナリを使い、手順の通りに焼くだけで普通に動きました。

Cool な hybr1d8 氏に心からの感謝を述べたいと思います。

4) Wazze Mark-IV のMeeGoの動作について

Martin Brook(vgrade) さんが今年の初め頃に動作させたときの記録をwikiに残されていました。

http://wiki.meego.com/ARM/TEGRA2

ただし、非常に残念ながら、すでにMIC2用のリンクは切れてしまっていて、ビルドのときの条件とかは不明な状況のようです。一応、Filesystem Imageを残してくださってはいるのですが・・・・素直に動いてくれずに苦労しました。

一応、あちこち調べながら何とか画面が出る、触ってしばらく待つと反応が返る「まだ動いているとは言えない」レベルでの動作は確認できましたけれど・・・・。
手順については、もう少しきちんと確立できたら公開します。

なお、 vgrade さんはおそらく、快適に動かそうとずいぶんとがんばってたのではないかと思われます。フォーラムでも


We have the resources in the to assist your engineers bulding your driver against later Xorg versions.
We would provide a development environment (virtual box virtual machine) whcih would allow the tegra_drv.so driver to be easily built ready for MeeGo.
Please can you pass offer to your team.

と、アピールしているのですが、nVidiaさんの応答だと

I appreciate the offer, but I believe our core linux team is already looking at best approaches to supporting multiple ABI generation, and we have one devtech trying to support Meego efforts in the background.  But again, I simply don't have a specific ETA on such work as resources are focused at this time on getting customer products out the door. 

ということで、自分たちのLinuxコアチームが、複数のABI生成のためのサポート方法を探してると思いますという解答で、結局nVidiaさんの成果待ちの様子です。

というわけで、ざっと調べた限り、Android以外の用途としては、nVidiaさんの対応がいまいちといったところでしょうか。
グラフィック周りはいろいろノウハウの塊で、バイナリでしか公開できないのかもしれませんが、だとしたら、その部分をフォローできるだけのリソースをそろえて対応してもらえるとありがたいのですけどねぇ・・・。

まぁ、早いところ、L4Tの公開再開が行われることを祈りたいところです。

2011年4月13日水曜日

Wazze Mark−Ⅳを手にとってみた

久しぶりの技術ブログな隠者でございます。

こっそり3Dゲーマーで、最近でこそRadeon系を使っているものの、かなりの期間GeForce派だったので、前々からTegraには興味深々だったのですが、なかなか手を出せずにいたところ、Tegra2搭載のタブレット「Wazze Mark-IV」をお借りすることができました。



主なスペックは、


  • CPUTegra2Dual Cortex-A91GHz
  • RAMDDR2667MHz 512MB
  • ROMNAND Flash 512MB
  • カメラ 1.3MFor video conference)
  • LCD10.1” 1024x600, LEDバックライト
  • タッチパネル:静電容量タイプ
  • Micro-SD:最大32GB
  • Wi-Fi802.11 b/g
  • Bluetooth2.1 + EDR
  • 3軸加速度センサ 
  • USBHOST1
  • 外部ディスプレイ:HDMI 1.3
  • 3.5 ヘッドフォンジャック
  • ステレオスピーカー内蔵
  • マイク内蔵
  • スイッチ
    • 電源、ボリューム、ロック、リターン
  • バッテリ
    • 動画再生 4.5時間
    • スタンバイ(LCDオン) 7.5時間
    • オーディオ再生(LCDオフ) 16時間
    • スリープ 98時間
  • 大きさ:275 ×178 × 13.6
  • 重さ730g

とのこと。なかなか高性能な製品です。
これは、もともと、P10AN01という型番で知られる中国製の製品でして、いくつかの国で色々名前を変え、カスタマイズされて売られているようです。
  • Wazze Mark-IV
  • XVision
  • Advent Vega
  • DreamBook ePad P10 3Dui
  • Mobii Tegra Tablet 10.2
Wazze Mark-IVは、タブレット向けにカスタマイズされたSimejiさんと、Adobe Flashとをプレインストールした物にとの事です。


ちなみに、ハードウェア上部には、マイク、電源ボタン、ロックボタン、戻るボタンが



右脇には、ACアダプタソケット、HDMI端子、USB端子、microSDスロット、イヤフォン、音量のハードキーが

下部には、おそらくクレドール用の端子が用意されているようです。

ちなみに、大きさは、FSS rebootと比べるとこんなものです。え・・・・余計に分かりにくいって?それは、書店に行ってFSS rebootを買ってくるときっとわかります。1巻は、Amazonでは売り切れて値段をふっかける業者しか残ってませんが、まだ地方の書店ではそこそこの冊数が積まれているのを見かけていますので、頑張って探して下さい。


いや、ちょっと脱線しました。というわけで、今日からしばらく、Wazze Mark-IVでのお遊びについて、ちらほら書いて行きたいなと思います。

   



2011年4月2日土曜日

心からの感謝と静かな祈りを

立て続けに技術情報ではない日記を書いている隠者でございます。
もう一つ、このエントリーだけ・・・。

先週の木曜日、個人的に交友のあったある技術会社の社長さんが亡くなられました。享年41歳。

もともとずいぶん昔から退職を考えていて、色々相談させていただいてる方に一度合わせるよと言われてお会いしたのが1年ちょっと前くらいでしたでしょうか。初めての飲み会は平日の夜23時スタートという異例の飲み会で、翌朝まで飲んでいました。
結局始発まではもたずに、朝一番にタクシーに乗せられて自宅まで戻り、シャワーを浴びて出社・・・なんて事になったわけですが、それはそれなりに、非常に楽しい時間で、それ以来、その時のお二人には何度もごちそうになり、毎度のように、いつでも受け入れるよとおっしゃっていただいてきました。

文系出身のたいして学のないエンジニアで、今まで一つのお客さんのところで長く仕事をしており、関わった仕事の種類も少ないため、お役に立てるのか不安な所だったんですが、色々と話をしているうちに、ずいぶんと高く買って下さっていまして。
今のお客さんはとても大事なお客様なので、おふたりとも、もう少しだけ待ってください・・・と言っている間にこの世を去ってしまわれました。

実は、亡くなられる前日も、社員と一緒に呑むから来ないかと誘われていたのですが、納期の事や、友人たちの安否の不安もあるなか、度重なる余震のために寝付きも悪く、さらには停電対策のために、朝5時起きで会社にでかけたかと思うと、午後から夜まで仕事だったりと、不安定な生活が続いていたため、断ってしまいました。

そして翌日の電話で・・・急逝されたとの連絡があったのです。

非常に気さくなうえに、いつも笑顔が絶えない方で、そのうえ技術的にもしっかりしたものをお持ちの方でした。愚痴をこぼす時すら笑顔で冗談交じり。物腰が穏やかな、裏表のない方でした。

何度か二人で話をする機会もあったのですが、よく話されていたのが、日本の技術者は冷遇されすぎているという事でした。日本ではなかなか技術者がそれなりの立場につくこと無く、文系の人たちに支配され過ぎていると。技術者にももっとスポットライトが当り、より良い環境で仕事が出来るようにできないものかと話していらっしゃいました。

勉強会の話をした時には、そういうの良いよね、技術者が人前にたつのも、技術者同士が積極的に交流をする機会というのも重要で、縁とは不思議なものだから、どんな付き合いも、好き嫌いや損得を超えて、まっすぐに向きあってごらんというような事をおっしゃって頂いたものです。

実は、先週のQt勉強会の日がお通夜で、勉強会での発表を断って通夜から伺おうかと思っていたのですが、なんとなく、自分も時間が取れれば勉強しにいきたいと以前おっしゃっていましたから、通夜の前にこっそりおいでになるかもなぁ、なんて思いながら、勉強会に参加しておりました。

お通夜は、その人となりを表すかのように、もう人が入りきらないくらいにごった返していて、身動きも取れない程だったと、告別式の日に伺いました。

僕はもともと人との付き合いが苦手な人間で、数回勉強会で発表した今でも、人前で話すのも実はかなり怖かったりするんですけどね。なんとなく、背中を押されて、引くなと言われた気がしています。
本当なら今年の後半には、ぜひ一緒に仕事をしていたいと考えていたのですが、もう少し急ぐべきだったでしょうか・・・。本当に残念でなりません。

告別式から明日で一週間。なんとか落ち着いて色々思いだせるようになりました。今日はこれまでのお付き合いとお言葉に心からの感謝と静かな祈りを捧げたいと思います。

今はまだ、冷静を装い、カラ元気な処も少しありますが、ご心配をおかけしないよう、しっかりと自分に出来ることをやっていきたいなと、そう思います。

2011年4月1日金曜日

できることから・・・

大変お久しぶりな隠者でございます。
皆様、ご無事に過ごしておられるでしょうか。今日は、技術日記をお休みして、すこしばかり仙台についてを書きたいと思います。

もともと、納期が間近で3月は忙しかった所に、突然古巣の宮城近郊を大地震が襲いました。人生の3分の1を仙台で過ごし、大学も仙台で通っていたものですから、友人、知人の消息が気になってしまって。自宅の近郊や職場では何度か停電もしているため、仕事も先に進まずですが、色々と心配事も重なって、少々きつい日々を送っていました。

特に、就職して仙台を離れる直前までは、若林区に住んでいたこともあり、その惨状には心が痛む日々です。数人の友人たちとは連絡が取れましたが、大学時代にお世話になった方々や、気仙沼、福島近郊で職についた方々とは連絡が取れず、馴染みだったあの店の現状等も、わからないまま今日に至っています。

大学卒業後は仙台を離れてしまい、忙しい仕事に追われるようにして暮らしていたため、すっかり疎遠になってしまっていたので、こうなってしまうと連絡の取りようもない状況です。連絡が取れていない方々も、なんとか無事にいて欲しい、そう思うばかりです。

そんな中、本日届いた仙台在住の友人からのメールには、概ねこんなことが書かれていました。

  • 基本的に物資が全く足りていません
  • ガソリンは2時間〜6時間並んで買うような状態。場所によってはリッター200円
  • お店の中はがらんとして品物がほとんどない
  • 沿岸部では、ちぎれて転がった遺体、電柱や木にひっかかった遺体、目を見開いたまま車のなかで発見される遺体等、地獄絵図です
  • 空港も新幹線もなくガソリンもなくて車が使えないので帰省も難しい
  • 自宅にはまだガスが戻っておらず、震災以後、シャワーのみの生活です
もちろん、同じ市内でも被害の大小はあり、品はなくても普通に近い生活を始めてる方もいるとのことですが、映像にもならず報道されない現実が、やはりそこにはあるようです。

友人は不動産関連のお仕事ですから、おそらく、管理している建物を回るため、市内を色々見てらっしゃるのかと思います。毎日苦情が大量にきて気が狂いそうだと書きながらも、自分はまだ大丈夫、まだまだ困っている人もいますから、ほんの少しでも構わないので、被災地にできることがあればご協力下さいと締めくくられておりました。

エイプリルフールだよって最後に書いてないかなと、すこしばかり不謹慎な希望ももちましたが、これが、被災地の現状です。

僕も含めて日本人の欠点として、今、報道で一番流れる話題には興味をもつけれど、少し古くなった事を忘れてしまう所があります。原発の事、計画停電の事、関東に住んでいてもきついこともあるけれど、できれば、現地のことを思い、できるご協力はぜひお願いしたいと思います。日本赤十字社さんが義援金を受け付けています。

僕自身、何かできることがあればと、幾許かの義援金を送ったり、こちらへの転居を考えてる知人の相談に乗ったりもしてきました。ただ、どうにもそれが精一杯でして。
体力のないプログラマ。被災地に駆けつけて何かをするなんていう勇気を持たない、この上なく情けない身の上ですから、関東で何かできることはないだろうかと考えた結果、停電の苦労があろうが、仕事のては止めず、税金や義援金に回せるお金を少しでもつくりながら、良いアイディアがあればコードを書こうかと考えています。

アイディアはあるけど、プログラムはできないという方がいらっしゃったら、ぜひ声をかけてみてください。

2011年3月3日木曜日

MeeGo勉強会に参加してきました

納期が近い @hermit4 です。先月半ば頃から結構忙しくて大変です。そんなわけで、相変わらずブログの更新が止まってます(三日坊主じゃないんだからね!)。

さて、そんな忙しい最中なんですが、@himamura さんにぜひ来て!と呼ばれてしまったので、巣鴨にあるCQ出版さんのセミナールームでMeeGo勉強会参加してきました。

MeeGoユーザー会勉強会&OSCボランティア募集


日時:2011年3月3日(木) 18時~
定員:30人
会場:CQ出版社セミナールーム
       東京都豊島区巣鴨1-14-2 炭七ビル1階
料金:無料

正直なところ、都内とはいえ外れの方から1時間半近くかかる場所に18時はきつかったです。仕事を下さっているお客様には、忙しい最中なのにごめんなさいと心の中で土下座しつつ、遊び勉強に出向きました。

ちなみに、今回会場を貸して下さったCQ出版さんのInterface 2011年3月号には「Linuxベースの開発プラットホームMeeGoの基礎知識」という記事が掲載されているとの事。ご興味のある方は急ぎ購入されることをおすすめします(というか、つい先ほどぽちりました。最近書店で見かけてトップの記事に興味があるときしか買ってないです。ごめんなさい)。



さて、今まで参加してきた勉強会の多くは、発表者が数名スライドを用意してきて、それについて質問や意見等を忌憚なくぶつけてみるというものなんですが、今回は特にそういうこともなく、それぞれ思い思いに話す感じでした。

最初は自己紹介タイム
Nokiaの端末が好きな方、Qtを仕事にしていて興味を持った方から、仕事でMeeGoを始めた方、暗い話の多い仕事だから、何か新しく楽しいことをやりたいと思ってという方まで、色々な方がいらっしゃいました。

IntelさんからNokiaさんの発表について
Intelの今別府さんからは、WMCの目前、丁度1年目という正直時期の悪い発表でしたけど、Intelとしてはスタンスにもリソースにも変更はなしとのこと。このままMeeGo続けますよとの発言がありました。
上層部は知っていたのかもしれないですが、かなりサプライズ的な発表でしたとの事。
かなり各所への火消しが大変だったみたいですけど、それでも中にはNokiaさんがデバイスの主軸から外した事で逆に電話に使いやすくなるかもなぁ的な意見もあったようです。
まぁ、Intel色が強くなりすぎる事に懸念をしめしている方々もいるとの事でしたけど。

ユーザー会の盛り上げ方について
@himamura さんからAndroidのユーザー会の活発な活動についての紹介とMeeGoユーザー会に対する意見があったので、 MeeGoユーザー会の現状について、ちょっと不満に思っていた辺りを意見してきました。

MeeGoユーザー会なんですが、参加したもののあまり盛り上がりのないフォーラムがWebにあるだけで、勉強会も参加者が誰なのかよくわからない状態。
昨今の勉強会は、Google Groups等で、参加者の概要がわかったり、イベントもATND等で募集して、誰が参加しているのか見えやすい。そういったユーザー同士のつながりが今のMeeGoユーザー会では作られにくいという事をもっと開放的な組織になるようにしないと駄目なのではないかなということで述べて来ました。

という話をしていた辺りで、MeeGoユーザー会の事務局の人や、Nokiaの佐相さん登場。

Nokiaさんのスタンスと今回WMCの話
色々噂話も出てるのだけどという前置きで色々話をしていただきました。
今回の発表は、MeeGoからの完全撤収という話ではなくて、主軸の製品から外れてしまって実験的なものになってしまっただけとの事。MeeGoへの貢献は続けて行きたいとの事でした。

Nokiaさんが抜けるとARMをやる人がいなくなるのでは的な話には、元々、Nokiaとしても、Intelさんのチップでという考えもあって、実はわりとIntel寄りだったとの事。
人材流出が始まっているとの話は、その多くがMeeGo主軸にとがんばってきていて、このままMeeGoをやっていきたいと思っている人のようです。Intelさんへ転職されて続けようという人もいるようですね。
Qtについても、もう終わりだ的な発言をする人がいるけれど、WMCへのQtに関する出展もストップはかからなかったし、まだ首にはなりそうもないとの事でした。

WMCについては、MeeGoのコーナーもあったとの事。発表直後だけあって、Intelさんのブースには近寄りにくかったそうですけど、色々な種類のデバイスが展示してあったそうです。
Androidのピンバッチについては、高いお金払って(一般参加だと結構お金かかるそうですね)来てるのに、バッチ集めで良いのかなぁ?・・・との事。冷静だなぁ。
あれはあれで、収集癖を刺激する良い方法な気もしますけど、バッチを集め歩いた人たちの今の心境を聞いてみたくなりました。


ちなみに、Qt大好きプログラマとしては、今後のNokiaさんの動向が気になるものの、実際のところは、LGPL化されており、サポートが途絶えたとしても、オープンソースの世界で生き残れるだろうと思っているため、悲観的な感想は持っていません。

Nokiaさんの中には、Trolltech時代からQtをやってきたQtエンジニアの方々も相当数いるでしょうし、今回の発表でリソースや予算の面では、今までよりは厳しい状況がくるのかもしれませんけど、Qt側の人たちには何とかがんばって欲しいなと思います。


そんなあれこれな、お話の間に、WeTABにMeeGoを入れたものを回して頂いて触ってみました。正直な感想を言わせてもらうと・・・もう少しユーザーにとって使いやすそうなインターフェースにできないかなという感触。
iPadをまねれば良いというものでもないですけど、なんでしょうね、こう、まだ萌えが足りない感じでした。まぁ、まだまだやるべき事が一杯ある、丁度Androidの最初の頃のような印象でした。

雑談ちっくな勉強会の話しの中で、Qtに関するプログラマーのイベントについてのお話が出ました。

・NokiaさんのN8向けのアプリを作って懸賞金総額10億円!

N8だからSymbianですかね。でもアプリはQtで組めるので、もってなくてもいけるか・・・?!とまぁ、さすがに厳しいかなぁとも思いつつ。

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