2017年05月30日

「Androidを支える技術U」を読んで その3

3.Androidのライフサイクルの役目

 前回書きましたように、頻繁に起きるメモリ不足によってkillされた多数のActivityが、ユーザーから見て、同時に多数動いているようにみせかける仕組みが「Activityのライフサイクル」という風に、私なりに解釈しました。

 著者の言葉で言うと、Androidが裏に行ったプロセスをkillしたり、それを再作成したりすることをそれほど意識せずに、まるでずっとアプリが立ち上がり続けているかのように開発ができるといのがライフサイクルの考え方です。

 しかし、著者も最後に書かれているように、一度でもアプリを開発した経験がある方であれば、「(実現はそう甘くありませんが)」ではあります(^_^;)何度悩んだことか(T_T)

 以下、著作は、ライフサイクルのもたらすものをユーザー視点と開発者視点から見ています。

(1) ユーザー視点から実現したいこと。

 ユーザーは無制限にアプリを起動して使っていく、そしてシステムが勝手に最近使っていないアプリを終了していき、しかしユーザーがそのアプリにまたやってくると前の状態を復旧する、これが通常のAndroidの想定された使い方です。 このように振る舞うことで ユーザーの端末のメモリリソースを最大限活用して様々なタスクの間を移動したときのレスポンスを機敏なものに保ちつつ、メモリが必要なタスクが動く時にはその分のメモリを自動的にあけようとします。

(2) アプリ開発者の視点から実現したいこと。

 いつ終了されても自動的に再開するコードを書くのは大変です。そこで、開発者が「一定の約束」に従ってコードを書けば、アプリの開発者は自分のプロセスが kill されて再開するときも、killされずにメモリ上にあったままの場合でも対応できるようにしたい。この「一定の約束」が「Activityのライフサイクル」です。

 そこで、開発者に対して具体的に求められるのは、裏に入ったActivityはkillされることがあるというよりは基本的にはkillされるものとして実装しておき、けれどキャッシュとして残っている場合にはそれを再生成する代わりに使い回していると考える方が実装者としては正しい見方となります。

 この結果として、このように裏に入ったActivityを キャッシュとして扱うことで、メモリが贅沢なマシンでは沢山の実体を残しておくことでたくさんのタスク間の移動を機敏に行える一方で、メモリが少ないマシンでも同じコードで自然とメモリを節約して複数タスクの切り替えのパフォーマンスは犠牲にしても、主要なタスクは問題なく動くというシステムを実現しているのが Android ということになります。

 いやー、改めてライフサイクルを意識してコードを書くことの重要性が再認識されます。

(3) Bundleの摩訶不思議

 最後に、ライフサイクルのひとつ、onSaveInstanceStateの中で利用される復旧情報を保存するためのBundleですが、著者は興味深い考察をされています。

 BundleはSystemServerのプロセスのメモリを使用するのでBundleにあまり大きなものを保存してはいけません。SystemServerのメモリが大きくなりすぎるとメモリを開けようとして裏のActivityをkillする頻度が上がるためタスクの切り替えがすごく遅くなったように感じますし、メモリー不足によるアプリの異常終了などが多くなってしまいます。

 しかし、

 Bundleは著者の知る限り ファイルには書き出されず、SystemServerのメモリ上に保持されたままです。個人的にはこれは信じがたいのですが、Bundleを保存してメモリを開放をしている箇所を見つけるべく相当長いことソースコードの中を探してもどうやっても該当箇所が見つけられませんでした。これではBundleにたくさんの値を入れるとSystemServerという 共有資源のメモリが圧迫されてOOMKillerが頻繁に発動するようになってしまう気がするのですが… だそうです。

 けれど、SystemServerはよほどのことがない限りkillされることはないそうですから、著者のおっしゃるように、ほどほどの大きさであれば、Bundleは安全に使えると理解し、ライフサイクルの基本にのっとって、onSaveInstanxeStateを利用していきたいと改めて思いました。

posted by 【なかま】 at 11:39 | Comment(0) | android

「Androidを支える技術U」を読んで その4

 今回で最後になります。

 第一巻、二巻を通じて、素人の私でもAndroidの凄さ、素晴らしさが少しは理解できたかと思います。

 このような素晴らしい書籍を発行された著者に改めて感謝いたしますm(__)m

4.管理者がいなくても動き続けるシステム

 私が最初に触ったAndroidの端末はサムスンのGalaxy Sでした。この端末は、よくハングして、ひとりでに再起動する不安定な端末でした。ですが、著作を読むと、この再起動は、どうしようもなくなった時に停止することなく再起動するようになっていた訳で、それはそれでよくできたシステムだったのかしれないなと、今は思います。

 最後は、そんなシステムを、著作に従って、電源投入の開始時点から見ていきます。

 まず、以前書きましたが、Androidは一般に言われているようにセキュリティが甘いシステムではありません。著作によれば、Android のブートローダーは通常、端末メーカーのみが知る秘密鍵で署名されているシステムイメージだけをロードします。署名されていないシステムイメージはロードをしません。このようにしてシステムイメージに悪意のあるファイルをこっそり追加したりするのを防いでいます。こうしてルートパーティションやRAMディスクなどは署名されたものと同じであることが保証され、後から変なウイルスなどがこっそり入り込むことができなくなっています。ハードウェアとソフトウェアが独立している PC などでは実現しづらい仕組みだそうです。

 次に、今までに見てきたように、Androidは、勝手にプロセスをkillしていきます。そのため、重要なシステムがkillされることもあるかと思いますが、それでも最近の端末はハングすることなく、ずっと電源を入れたままでも、安定して動いてくれています。

 著書を読んでみると、その背景が理解できます。いや、理解できたつもりかも(^_^;)

 再起動が自動で行われることで、万―OOMKiller(Out Of Memory Killer)などである程度重要なサービスがkillされてしまっても、自動的に再起動されてシステム全体としてはメンテナンスフリーで安定して動き続けます。

 さらに詳細な説明があります。私の頭では半分も理解できませんでしたが、雰囲気で見てください(^_^;)

 異常終了すると通信用のソケットが残ってしまって再帰動時にソケットの作成に失敗してうまく起動しなくなるというのは、出来の悪いデーモンにはありがちなことです。 Android では init が正しく後処理をしてくれるのでそういった心配は必要ありません。各サービスがどのようなソケットを作っているかという情報がすべてinit.rc に記述されているため、あるプロセスが異常終了したときもそのプロセスが持っていたソケットをinitプロセスが正確に把握しているため、正しく後処理を行います。サービスは、oneshotの指定がない限り、異常終了した場合などでも自動的に再起動されます。この機能を実現するためには、そのサービスが使用しているソケットや、そのサービスが再起動する時に一緒に再起動をしなくてはならないサービスの情報などが必要となります。 それぞれのデーモンが自分勝手にソケットなどを管理していると、そのうちの1つがうまく再起動に対応していないだけで全体としてモジュール郡の再起動ができないシステムとなってしまいます。 Android では再起動の時などに問題になりがちなソケットの管理をinitが行うことでこうした出来の悪いサービスができる可能性を減らしているわけです。

 なんか、凄いという気持ちになってくるでしょう?

 結果として、このようにして管理者のいない携帯電話というシステムを家電的に使うことができるわけです。

 …ということで、最近のAndroid端末は、昔に比べると安定してきたなぁとしみじみ思いました。


posted by 【なかま】 at 10:44 | Comment(0) | android

2017年05月10日

iアプリを支えたかった技術 その1

1.iアプリで使われていた邪道な技術

 先日、「Androidを支える技術」の感想を書いたところですが、その昔、私がiアプリを開発し公開していた頃、私なりに…というか、野良iアプリ(ドコモの公式サイト以外で配布されていたアプリをこのように言いました。)開発者の間では、それなりの邪道な技術がありました。

  当時のiアプリは、セキュリティが大変厳しく、データ保存などはもってのほか、着信履歴や電話帳の取得なども今のandroidで許されることは、ほとんどできませんでした。特にデータ通信に関しては、自分のアプリをダウンロードして来たサイトにしか接続できないようになっており、そのためか、iアプリを対象としたウィルスは、一部存在していたようですが、ほとんど聞きませんでした。

 そのため、野良アプリ開発者の間では、どうにかしてこれらの制限を回避する方法が、ひたすら探求されていた訳です。

 そこで、今回は、もう誰も振り返らないこれらの技術ですが、「Androidを支える技術」に張り合って(張り合えないって(^_^;))、自分の記憶として書き留めておきたいと思います。

2.画像ファイルを利用したデータ保存

 iアプリにとって、データ保存の方法が正式に存在しないというのは、かなり致命的でした。個人のデータを蓄積するスケジューラアプリなどは、こつこつと書き溜めておいた数カ月の予定が、アプリの不具合や、誤ったアンインストールによって一瞬にして消滅してしまいます。私も何度かデータを失い、バックアップが取れていたらなぁと悔しい思いをした経験があります。

 当時のiアプリがその外部に書き出しを許されていたのは、画像の保存だけでした。カメラアプリでは撮影したデータを保存することができていました。

 そこで、当時の野良アプリ開発者は、ここに目を付けることとなります。

 当時許されていた画像の種類は、GIFとJPGでした。

 GIF画像のフォーマットを研究してみると、そこには、コメントブロックという、画像を作成したアプリ名とか作成時間やカメラの絞りの値とかの情報を書き込めるところがあるのに気が付きます。これを利用できないかと思いました。

 そこで、画像エディタを使い、手始めに1ピクセルのGIF画像を作成してみました。次にこれを byte の配列としてiアプリの内部に保持し、このコメントブロックの位置にそのままiアプリのデータをテキストで書き込んでみました。当初はうまくいきましたが、データが大きくなるにつれ、GIF画像が壊れて作成できなくなりました。

 ここで、GIFの公式ドキュメントをよく見てみました。GIFのコメントブロックのフォーマットは、先頭1バイトが長さ、後に続く1〜255バイトがデータで、最大長255バイトとなっています。つまり、大きなデータは256バイト単位に分割する必要があることがわかりました。

 理屈はわかりましたので、この正式なGIFフォーマットにそってデータを作成し、このコメントブロックにおさめてやればiアプリからGIF画像として書き出すことで、iアプリのデータが外部媒体に保存できるようになりました。

 しかし、当時は、やはり機種によっては正式フォーマットに従っていてもGIF画像作成に失敗することがありました。機種によってはiアプリからGIF画像に書き出すときに、余計なことに、折角書き込んだコメントブロックにカメラの絞りなどの撮影状況を書き込んでしまうものがあったのです。これはどうしようもありませんでした。

 そこで、もうひとつ許されていたJPGは利用できないものかと思いました。これも公式ドキュメントを読んでコメントブロックに書き込もうとしたのですが、野良アプリ作成の先駆者達の情報を探してみると、単に1ピクセルとして作ったJPG画像の後に、テキストデータを付け足すと保存可能とのことでしたので、やってみるとうまくいきました。

 ですので、当時は、あちこちの友人からドコモのガラケーを預かっていろいろとテストしてみました。その結果、GIFが利用できる機種とJPGが利用できる機種、両方利用できる機種があることが判明しました。そこで、iアプリの中では、機種毎に条件分岐して画像の種類を振り分ける方法をとった訳です。

 実は、この機種毎のテストこそ、大変な時間と労力がかかりました。

 今は懐かしい、古き良き時代の話でした(^^)

今も持っているテスト用のガラケー

garakei_list.png
続きを読む
posted by 【なかま】 at 15:15 | Comment(0) | android