Smart Wireless Headset pro

ソニエリというか、SonyのSmart Wireless Headset proExpansysで購入した。5/31の深夜に注文したら、6/1の昼過ぎには届くという、なんていうAmazon Prime状態。価格は、今のところ、¥10,390。これに、輸送費(今回は、FedEx Priority)で、合計、\12,339。思ったよりも安い。

当然、Xperia acro HDと連携させるのが目的なんだけど、別に今までもMW600使ってたし、ボリューム調整が面倒な以外は、別に困っているわけではなかった。

何を期待していたのかと言えば、Androidならではのアプリによる連携。Google Playに、Smart Wireless Headset proというまんまの名前のアプリがあって、これで、音楽を聴いたり、電話のヘッドセットとして利用したりする以上のことが出来るらしいという話。いろんな通知が来ると便利だよねぇと。

あとは、MW600よりもデザインが好みだなぁと。

FMラジオとか付いているけど、これは海外物のいつものパターンで、どうせ、TOKYO FM (80.0MHz)とかは聴けないのでどうでも良い。

パッケージ

f:id:espresso3389:20120601151753j:plain

音はドイツのwww.testfactory.deっていうところでテストされていて、Sound Quality: excellentなんだそうだ。ふーん。

f:id:espresso3389:20120601151852j:plain

で、英国仕様なので、ACアダプタがでかい奴なんですが、Expansysで買ったので、Expansysが英国仕様のアダプタを変換するプラグと、USB ACアダプタをオマケで付けてくれました。

f:id:espresso3389:20120601152151j:plain

付属品

ACアダプター、microSD 2GB、microSDカードリーダー、ヘッドフォン、クリップ、イヤーピース(予備、サイズ違い)、USB A -> micro A変換ケーブル。

f:id:espresso3389:20120601153026j:plain

本体

"Smart Wireless Headset pro User guide"には、ペアリングすると時計が表示されるとありますが、実際には、一度、Smart Wireless Headset pro側の電源を切って、再接続しないと、時計が出てきませんでした。最初、ペアリングの仕方がAndroid Phone用と、普通のPhone用の両方書かれていたので、時計が出ないのはペアリングがおかしいんだと思って、何度もリセットしたりしながら試行錯誤しました。

f:id:espresso3389:20120601182702j:plain

見て分かるとおり、文字化けしまくりです。これは、今後、日本語版が正式に発売開始された頃にファームウェアアップグレードがあるのか、それともこのまんまなのかは興味深いところです。

f:id:espresso3389:20120601182446j:plain
f:id:espresso3389:20120601182352j:plain

全体的にグロッシーブラックっていう感じではあるんですが、先っちょの色が変わっている部分は、帯で繋がっておりパカッと開きます。帯が一体成形じゃないので、強度的にはどうなんでしょうかとは思いますが、ここの中に、microSDスロットと、USB接続用のmicro USB Aコネクタがあります。

f:id:espresso3389:20120601153725j:plain

で、このUSBコネクタは、充電専用ではなく、microSDが刺さっていると、PC接続時にはマスストレージにもなります。

f:id:espresso3389:20120601153818j:plain

うれしいことに、充電中でも本体は動作するので、電池が足りなくなってきても、充電しながら音楽を聴くことは一応出来ます。そんなことをする必要があるシチュエーションは少ないでしょうが・・・。

付属ヘッドフォン

ちなみに、付属しているヘッドフォンは、普通の3極ステレオミニプラグです。僕は、愛用のBose® IE2があるのでそれで取り替えました。個人的に、オープンエアーじゃないものは疲れるので、音に関しては確認すらしていません。

f:id:espresso3389:20120601182727j:plain

f:id:espresso3389:20120601182747j:plain

いわゆるきしめんケーブルなので、束ねやすくて、絡まりにくいところは評価すべき部分だと思います。

f:id:espresso3389:20120601153338j:plain

付属microSDカードリーダー

SDカードリーダーは、ロゴがソニエリのまんまです。

f:id:espresso3389:20120601153234j:plain
f:id:espresso3389:20120601153310j:plain

ソフト面

ペアリング端末の表示

f:id:espresso3389:20120601175735j:plain

再生中楽曲の情報

<<後からいろいろ分かったので大幅に修正>>

Xperia acro HD(IS12S)に標準で入っている音楽プレイヤーとの連携では、アーティスト名、曲名共に、マルチバイト系の文字が一部というかほとんど表示できないことを除けば、表示できるようになりました。

ちなみに、これは、「松たか子」、「a piece of life」と表示されているところです。

f:id:espresso3389:20120602192044j:plain

ただし、僕はPlayerProという音楽プレイヤーを使っているのですが、これだと曲の情報は何にも表示できません。

f:id:espresso3389:20120601181049j:plain

また、試してみたところ、Galaxy Note SC-05Dでも、標準の音楽プレイヤーと連携できました。

f:id:espresso3389:20120602193212j:plain

AVRCP1.3? on Android

で、Xperiaじゃない機種に接続してみて分かったことですが、この連携にLiveWireマネージャは必須ではないようです。つまり、素のAndroidにそのままBluetoothで接続すれば曲名が出てきます。今まで、曲名表示は、ICSにならないと無理的にAVRCP1.3対応できないから無理っていう話だったのに、一体どんなテクノロジーを使っているのかさっぱり分かりません。

マルチポイント対応

すばらしいのが、二つのデバイスとペアリングして、好きなときに再生するデバイスを自由に切り替えることが出来ること。[|<<]、[>>|]で簡単に切り替えられるのは予想以上に便利です。

f:id:espresso3389:20120602193730j:plain
f:id:espresso3389:20120602193743j:plain

日本語対応状況・・・

どうも、フォントが足らないみたいですね。

一応、電話を検索(電話履歴を表示)と表示したいのだろうけど・・・。これは、この辺の表示情報は、Android側のアプリから転送されてくるようで、この機器の言語設定をEnglishにしたところで、問答無用に日本語になります(つまり、Android側の言語設定が反映される)。

f:id:espresso3389:20120601175106j:plain)

一方で、僕の名前はちゃんと表示される。

f:id:espresso3389:20120601175904j:plain

Twitterは、名前とつぶやきの時刻(?)が表示されて居るっぽいが・・・。

f:id:espresso3389:20120601180221j:plain

f:id:espresso3389:20120601182624j:plain

結論

音質に関しては、僕はそんなにこだわりがないので何ともな部分があるんですが、機能面、操作性どれをとっても、MW600引退確定っていう感じです。
これは日本で発売されたら、おそらくベストバイになるんではなかろうかというクオリティです。

その他

Expansysがオマケで付けてくれたUSB ACアダプターは、付属のUSB A -> micro A変換ケーブルに接続すれば使えます。

f:id:espresso3389:20120601153358j:plain

MUI

Windows Vista以降、Windowsのローカライズの方法に多少の修正が加わって、いわゆる、今までの各国語版というのがなくなった。パッケージとしては残ってはいるものの、システムとしては、ニュートラルなWindowsに対して、言語パックを足せば、何語版にでもなるという構造になった。

そのため、例えば、日本語環境だと、calc.exeに対して、ja-JP\calc.exe.muiというファイルが関連付けられてインストールされるようになった。さらに、英語のGUIが欲しければ、en-US\calc.exe.muiを足せば良いという理屈。

今までも、他言語対応のアプリケーションだったら、

application.exe
lang-0409.dll
lang-0411.dll

みたいな構造でリソースのDLLを足せば良いみたいな形のものはいくらでもあったので、0409みたいなLANGIDの部分が、en-USといった言語タグに取って代わられただけで別に特別に新しい仕組みにも見えないのだけれども、一方で、この新しい仕組みは、Vista以降でサポートされた新しいMUI(ムイって読んで良いらしい)という仕組みに基づいている。

要は、今まではこのリソースDLLを読み込むコードを全部、自分で書かないといけなかったけど、Vista以降では、OS側のフレームワークである程度肩代わりしてくれるよということらしい。

具体的にコードを書くとすれば、エラー処理まで省けば、コードは次の量で済む:

#include <windows.h>
#include <tchar.h>

int APIENTRY _tWinMain(
  HINSTANCE hInstance,
  HINSTANCE hPrevInstance,
  LPTSTR lpCmdLine,
  int nCmdShow)
{
  TCHAR buf[512];
  LoadString(hInstance, 101, buf, 512);
  MessageBox(NULL, buf, _T("muitest"), MB_OK | MB_SYSTEMMODAL);
}

WinMainにくるhInstanceを直接使っている様に見えるけど、これで正解。このhInstanceは、ロードされたMUI(リソース)のDLLとも裏で連携できるようになっていて、あたかも、exeに直接リンクされたリソースをロードしているような感覚でリソースを扱える。

また、一応、下位互換用のライブラリも提供されるようで、muiload.libというライブラリを使って、MUILoadLibrary/MUIFreeLibraryを使えば・・・っていう話もあるけど、FreeLibraryじゃなくて、MUIFreeLibraryを使わないといけないってところにかなりの悲しみを感じます。これじゃ、使いにくいんだよ。Microsoftさん・・・。
結局、下位互換用には従来のコードを使い回した方が良さそう。

MUIのメリット

でも、別に、今までも、

hoge.exe
lang-0409.dll
lang-0411.dll

みたいな構造で事は足りてたのに、なんでこの新しいMUIっていう構造を使わないといけないの?って話になるんだけど、確かにその恩恵はちょっと考えたぐらいでは分からない。

なので、ここでは具体的に僕が前から思っていた事しかかけないんだけど、その一つは、ファイル関連付けのローカライズ。これは、レジストリに書き込む物なので、例えば、

HKEY_CLASSES_ROOT\.hoge
@="hoge.document"

HKEY_CLASSES_ROOT\hoge.document
@="ホゲ文書"

みたいにしてしまうと、.hogeの説明が常に日本語になってしまう。ローカライズしたいなぁと思うと、固定値は不味い。リソースDLLから読みたい。

なので、これを回避するために、FriendlyTypeNameというものが導入された。これだと、

HKEY_CLASSES_ROOT\.hoge
@="hoge.document"

HKEY_CLASSES_ROOT\hoge.document
@="ホゲ文書"
"FriendlyTypeName"="@C:\Program Files\....\hoge-0411.dll,-101"

(hoge-0411.dllのID=101のテキストを設定すると言うこと)ってやりたいなぁ・・・って、これだと、やっぱり日本語になってしまう。あれれれ、解決になってない。

そこで、今回のMUIを使うと、そもそも、EXEにしろ、DLLにしろ、

hoge.exe
en-US/
hoge.exe.mui
ja-JP/
hoge.exe.mui

というレイアウトになって、一応、主体としては、hoge.exeを考える事が出来るようになる。なので、こういうレジストリに対しては、

HKEY_CLASSES_ROOT\.hoge
@="hoge.document"

HKEY_CLASSES_ROOT\hoge.document
@="Hoge Document"
"FriendlyTypeName"="@C:\Program Files\....\hoge.exe,-101"

って書けば良くなる。後は、各言語用にmuiファイル群を作っていけば良い。

hoge.exeに対して、hoge.exe.muiを作る

そして、ここからが本題なんだけど、これが実は著しく面倒な上に難解。
今まで通りにリソースDLLを作って、名前だけ変えて配置という分けにはいかない。
hoge.exeとhoge.exe.muiはディレクトリ構造と名前さえ一致してくれればロードしてくれる・・・っていうわけじゃなくて、チェックサムで結ばれていて、ちゃんと設定しないと、勝手にロードしてくれるようにはなりません。

一応、概要というか、全部、

Resource Utilities - MSDN

Using Multilingual User Interface - MSDN

Getting started with Win32 MUI development

に書いてある。けど、これは分からない。強烈に何がしたいのか分からない。

というか、さっきのMUIのメリットさえ無視できるんだったら、今までのリソースDLLのやり方に執着した方が数百倍楽だし。その辺の読み手の欲求を完全に無視しているとしか思えない文書構成。

なので、ここでは、既に、

hoge.exe
lang-0409.dll
lang-0411.dll

という構造を作れる大本が手元にあることを前提で話をする。この構造の成果物があるということは、普通に考えれば、

lang-0409.rc
lang-0411.rc
resource.h

があるということだ。ここでは、話を簡単にするために、普通は、hoge.exeにリンクされるであろう、アイコンやらバージョンリソースの話は無視する。resource.hは、lang-XXXX.hの付属品だと思ってください。

全体のフローは、

Vista Win32 MUI Application Developmentによると、

f:id:espresso3389:20120309183407p:image

といった感じ。リソース側から"Compiled LN resources"という物をアプリ側にリンクさせてあげるということ。

rcconfigファイル

で、最初にやることは、

lang-0409.rc
lang-0411.rc

から、不純物を取り除くこと。これがわかりにくい。
簡単に言えば、lang-XXXX.rcは、本来、ローカライズされるべき部分と、何となく付随してしまっている物が混ざっている。

例えば、文字列は間違いなく、言語毎にローカライズされなければならないけども、普通は、アイコンとかカーソルぐらいは言語間で共有されても良いかもしれない(宗教上の理由などで国別に変えないといけない場合もあるだろうけど)。

そのために、どの種類のリソースは、言語DLL側に残して、どこの部分は全言語で共有するか(つまり、hoge.exe側に持たせる)という判断をすることになる。

これをやるのがrcconfigファイル。説明は、一応、

Preparing a Resource Configuration File - MSDN

に書かれているが、やはりピントがつかめない文書。天下り的に答えを書くと、下みたいなファイルになる。

<?xml version="1.0" encoding="utf-8"?>
<localization>
  <resources>
    <win32Resources fileType="Application">
      <localizedResources>
        <resourceType typeNameId="#1"/> <!-- CURSOR -->
        <resourceType typeNameId="#2"/> <!-- BITMAP -->
        <resourceType typeNameId="#3"/> <!-- ICON -->
        <resourceType typeNameId="#4"/> <!-- MENU -->
        <resourceType typeNameId="#5"/> <!-- DIALOG -->
        <resourceType typeNameId="#6"/> <!-- STRING -->
        <resourceType typeNameId="#9"/> <!-- ACCELERATORS -->
        <resourceType typeNameId="#10"/> <!-- RCDATA -->
        <resourceType typeNameId="#241"/> <!-- TOOLBAR -->
      </localizedResources>
    </win32Resources>
  </resources>
</localization>

typeNameIdの後ろに書いてあるのは、リソースタイプに割り振られたID。これは、上にあるページよりも、

Resource Types - MSDN

の方が網羅性が高い。しかし、やはり、TOOLBARに該当するIDが書いてなかったりするが、Community Additionsに、親切な人が、TOOLBARのIDを書いてくれている。241らしい。

で、さっき書いたように、ここには、言語DLL側に残したいもののIDを書いていく。つまり、アイコンとか、ビットマップは言語間で共有してもいいやと思えば、#2とか、#3は削除する。

さて、次に、これによってrcファイルを処理する。これには、Windows SDK 6以降のrc.exeが必要らしい。平たく言うと、

C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin
C:\Program Files\Microsoft SDKs\Windows\v7.0A\Bin

あたりにあるrc.exeを使う。VS2010の奴ならいけるんじゃないだろうか(自分のマシンはいろいろ入っていて良く分からない)。一応、rc /?って実行して、オプション一覧に、

C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin>rc /?

Microsoft (R) Windows (R) Resource Compiler Version 6.1.7600.16385
Copyright (C) Microsoft Corporation. All rights reserved.

Usage: rc [options] .RC input file
Switches:
/r Emit .RES file (optional)
/v Verbose (print progress messages)
/d Define a symbol
/u Undefine a symbol
/fo Rename .RES file
/l Default language ID in hex
/i Add a path for INCLUDE searches
/x Ignore INCLUDE environment variable
/c Define a code page used by NLS conversion
/w Warn on Invalid codepage in .rc (default is an error)
/y Don't warn if there are duplicate control ID's
/n Append null's to all strings in the string tables
/fm Localizable resource only dll file name
/q RC Configuration file for the resource only DLL
/g Specify the ultimate fallback language ID in hex
/g1 Specify if version only MUI file can be created
/g2 Specify the custom file version for checksum in MUI creation
/nologo Suppress startup logo
Flags may be either upper or lower case

みたいに、/fmやら、/qというオプションが見つかればOK。

で、さっきのrcconfigがhoge.rcconfigという名前だとすると、このrcを使って、

rc /focommon.res /fmlang-0409.res /q hoge.rcconfig lang-0409.rc

とする。ヘッダ関連のディレクトリとかは適当に設定してくださいな。

そうすると、中間成果物として、

common.res (言語間で共有する奴)
lang-0409.res (英語のリソースDLLに入る奴)

というのができる。これを開いてみると、上のrcconfigで指定したとおりにリソースが選り分けられているだけじゃなくて、"MUI"という良く分からないものが出来ているのがわかる。ここにチェックサムとやらが入っているらしい。

f:id:espresso3389:20120309183408p:image
f:id:espresso3389:20120309183409p:image

で、あとは、

  • common.resはhoge.exe側にリンクしてしまう
  • lang-0409.resはDLLとしてen-US\hoge.exe.muiにする

でやること完了。一応、lang-0409.resはDLLとしてen-US\hoge.exe.muiの手順を書いておくと、こんな感じで良い:

link /out:en-US\hoge.exe.mui /nodefaultlib /noentry /dynamicbase /nxcompat /dll lang-0409.res

/nodefaultlibとか、/noentryは無駄なゴミが入らないように付けている。


他の言語に対しても同じ事をやると、当然、全部に対してcommon.resができちゃうんだけど、いらないので、こっちに関しては捨ててOK。
もちろん、common.resはいらないので、本当は、日本語(0411/ja-JP)だと、

rc /fmlang-0411.res /q hoge.rcconfig lang-0411.rc

で良い。これだと、無駄なファイルが出来ない。

で、重要なステップを忘れちゃいけないんだけど、

lang-0411から、ja-JP\hoge.exe.muiを作ったら、その後に、MUIRCTを使って、

muirct -c hoge.exe -e ja-JP\hoge.exe.mui

として、hoge.exeから、ja-JP\hoge.exe.muiに対して、チェックサム情報を反映してあげる。これをしないと、ja-JP\hoge.exe.muiが正しいmuiのファイルとして認識されない。

Seasonic 660W 80PLUS GOLD SS-660KM

先日、メインマシンの電源が入らなくなり、いろいろと調べたところ、電源が逝かれてしまったことが判明したので、急遽、新しい電源ユニットを購入することになりました。友人曰く、冬は電源が死にやすいらしい。というか、基本、常時稼働のマシンだったので、ほとんど電源を落とすことがなかったのですが、たまたま、電源を落としてしまったところ、二度と電源が入らなくなってしまうという・・・。

で、購入したのが、Seasonic 660W 80PLUS GOLD SS-660KM。

オウルテック シーソニック電源 660W 80PLUS GOLD SS-660KM

オウルテック シーソニック電源 660W 80PLUS GOLD SS-660KM

以前の電源ユニットは、SilverStone SST-ST45NF 400Wという、ファンレス電源だったのですが、ファンレスだったが故に弱ってたという仮説も成り立つので、今回は、あえてファン付きにしました。80PLUS GOLDなので、効率は良いはずで無駄な発熱がなさそうなこと、さらに、ネットでの評判では、かなり静かということでこいつにしました。

f:id:espresso3389:20120211184821j:image
f:id:espresso3389:20120211181725j:image

評判通り、音はかなり静か。深夜の家で耳を澄ましても何も聞こえない・・・というより、ファン、回ってないんじゃ?っていう話です。

効率的なメモリブロックサイズ

とっても環境依存で実装依存な事なんですが、一方で、メモリ効率っていうのは非常に大事なファクターです。
特に小さな構造体をメモリにたくさん配置するような場合、メモリのアラインメント(データをCPUが効率的にアクセスできるきりの良いアドレスに配置すること、16バイトとか、32バイトといった単位になることが多い)のため、メモリが無駄になることが多いです。

例えば、現状のIntel x86系で32-bit OSだと、6バイトのメモリを確保するなんてことをすると、アラインメント単位がおそらく、16バイトなので、10バイト分が利用されることなく無駄な領域として残されることになります。ただし、一般的に、mallocやnewで確保されるメモリブロックには管理領域という領域が確保されるので、

char* p = new char[10];

っていう処理が果たして何バイトの領域を必要として、結果、どれだけの領域を確保するのかは実際に試してみないといけません(コードを読んでも良いんですが、それだと環境毎にソースを読まないといけないので、簡単なコードを実行する方が楽です)。

ということで、実験コード。テスト用コードなのでメモリを解放していません。

// memalign.cpp
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char* argv[])
{
  if(argc < 3)
  {
    printf("%s BLOCK_SIZE COUNT\n", argv[0]);
    return -1;
  }
  
  size_t blockSize = atoi(argv[1]);
  size_t count = atoi(argv[2]);
  
  for(size_t i = 0; i < count; i++)
  {
    unsigned char *p = new unsigned char[blockSize];
    printf("%u\t%p\n", i, p);
  }
}

32ビット環境でのテスト

これを、Visual Studio 2010 SP1の32ビット版コンパイラ

Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86

でビルドしてテストしてみます。最初に、10バイトのブロックを10個確保してみます。

C:\work>memalign 10 20
0       00793C08
1       00791A00
2       00791A18
3       00791A30
4       00791A48
5       00791A60
6       00791A78
7       00791A90
8       00791AA8
9       00791AC0

そうすると、最初の奴は無視するとして、メモリブロックの間隔が、0x18(24)バイト単位で推移していることになります。つまり、10バイト確保すると、実際には、24バイトが消費されているわけです!
次は、8バイトを確保する実験。

C:\work>memalign 8 10
0       00963C08
1       00961A00
2       00961A10
3       00961A20
4       00961A30
5       00961A40
6       00961A50
7       00961A60
8       00961A70
9       00961A80

綺麗に16バイトずつ確保されているのが分かります。結論から言うと、この環境においては、管理ブロックが8バイトで、さらに、メモリブロックの先頭が8バイトに揃うようにメモリが確保されているわけです。つまり、1〜8バイトのメモリ確保は、結果的には、16バイトのメモリを消費するということです。16バイトのメモリ確保は、32バイトのメモリ消費です。メモリがもったいないと思って、メモリ確保のサイズをケチるときにはこの事実をキッチリと頭に入れておく必要があります。実装依存ですけど。

1バイトを確保してみると、

C:\work>memalign 1 10
0       00513C10
1       00511A00
2       00511A10
3       00511A20
4       00511A30
5       00511A40
6       00511A50
7       00511A60
8       00511A70
9       00511A80

やっぱり16バイト持って行かれます。無駄すぎる。

64ビット環境でのテスト

次に、Visual Studio 2010 SP1の64ビット版コンパイラ:

Microsoft (R) C/C++ Optimizing Compiler Version 16.00.40219.01 for x64

で試します。最初は、さっきと同じで、10バイトのブロックを10個確保してみます。

C:\work>memalign 10 10
0       00000000004A8520
1       00000000004A8540
2       00000000004A8560
3       00000000004A8580
4       00000000004A85A0
5       00000000004A85C0
6       00000000004A85E0
7       00000000004A8600
8       00000000004A8620
9       00000000004A8640

64ビットなのでアドレス表記が16桁になっています。今回はアドレスの間隔が32バイト。
つまり、10バイト確保する毎に、32バイトを消費しています。
試しに1バイト確保してみると、

C:\work>memalign 1 10
0       0000000000538E30
1       0000000000538E50
2       0000000000538E70
3       0000000000538E90
4       0000000000538EB0
5       0000000000538ED0
6       0000000000538EF0
7       0000000000538F10
8       0000000000538F30
9       0000000000538F50

やっぱりというかなんというか、32バイト確保しています!32ビット版に輪を掛けてもったいなさ過ぎ!
32バイトというのは64ビット環境での最小ブロック単位なわけです。
テストすれば分かりますが、こっちは、24バイト確保すると32バイト消費し、25バイト確保すると、48バイト消費します。
つまり、管理領域は、8バイト。32ビット版と管理領域のサイズが同じなので、よく考えるとお得かも知れません。

Mac OS X 10.7 + g++ 4.2.1

OS X 10.7での結果。

$ ./memalign 16 10
0	0x10df00a00
1	0x10df00a10
2	0x10df00a20
3	0x10df00a30
4	0x10df00a40
5	0x10df00a50
6	0x10df00a60
7	0x10df00a70
8	0x10df00a80
9	0x10df00a90

素敵なことに、メモリのブロックには管理ブロックは付きません。綺麗に、16バイト単位で並んでいます。

Ubuntu 11.10 (GNU/Linux 3.0.0-13-server x86_64) + g++ 4.6.1

$ ./memalign 1 10
0	0x1186010
1	0x1186030
2	0x1186050
3	0x1186070
4	0x1186090
5	0x11860b0
6	0x11860d0
7	0x11860f0
8	0x1186110
9	0x1186130

$ ./memalign 24 10
0	0x1045010
1	0x1045030
2	0x1045050
3	0x1045070
4	0x1045090
5	0x10450b0
6	0x10450d0
7	0x10450f0
8	0x1045110
9	0x1045130

$ ./memalign 28 10
0	0x1a5d010
1	0x1a5d040
2	0x1a5d070
3	0x1a5d0a0
4	0x1a5d0d0
5	0x1a5d100
6	0x1a5d130
7	0x1a5d160
8	0x1a5d190
9	0x1a5d1c0

1バイトでも32バイトを消費してくれます。24バイト確保と28バイト確保の結果から、管理領域は、8バイト。Windows 64ビット版と大きくは変わらないようですね。

参考文献

x64 Software Conventionsについてっぽいので、32ビットについては微妙だけど、mallocは16バイトアラインメントと書いてある。
malloc Alignment - Visual Studio .2010


glibcのアラインメントは、8の倍数(64ビットなら、16の倍数)
3.2.2.7 Allocating Aligned Memory Blocks - The GNU C Library


Mac OS Xのアラインメント(というかメモリ粒度)は16バイト。
Tips for Allocating Memory - Mac OS X Developer Library

追記

誤解を招くといけないので、追記しておきますが、

int *p = new int[10];

が10*16バイト消費したりするわけではありません。この場合、ブロックの先頭は16バイト単位にアラインメントされますが、32ビットのintの値は継ぎ目なく確保されるので、この場合は、おそらく、4*10+8=48バイトしか消費しません。
あくまでも、malloc/newした時のメモリ確保の最小単位が16バイトで、管理ブロックのサイズが8バイトだということです。

MapView用のAPI Keyを署名から自動判別したい

Android上で、MapViewを使おうとすると、API Keyをlayout.xmlに書き込まないといけない。
さらに、このAPI Keyはアプリの署名から生成されるので、デバッグ用の署名(debug.keystore)とリリース用の署名で別々のモノを使わないといけない。
そうすると、リリース時にAPI Keyを入れ替えるだけのためにコードを修正しないといけなくなるわけで、スゲーめんどくさいし、間違えて、リリース用のAPI Keyをリポジトリにcommitしちゃったりして周りに迷惑を掛けたりして・・・みたいな事になる。
これに関して、

Android ApiキーをRelease版とDebug版で切り替える方法

の様なことをやっている方もいるのだけども、正直、android:debuggableを見るのも微妙な気がする。というか、android:debuggable使ってない・・・。

ので、apkの署名で使うAPI Keyを切り替えようと考えました。

要は、アプリ上で、

MapView mapView = new MapView(this, getMapApiKey());

のような感じで署名に対応したAPI Keyを自動的に返してくれるといいなぁと。

元ネタは、たまたま、この記事を見つけたから。

「アプリケーション(.apk)の自己署名を検証する」

今回は、apkの署名がデバッグ用とリリース用で違うから問題なわけで、それを検出して、対応するAPI Keyを貰えれば良い。で、Google様から貰えるAPI Keyは、署名に対応しているので、署名を文字列化したものを直接コードに挿入したいところなんだけど、署名をそのまま書き込むのは気が引けるのと、そもそも、文字列としては極めてでかいことなど、どうなんだろうという感じなので、

Sign Up for the Android Maps API

にあるように署名のMD5で比較するようにする。

ということで、ほぼ丸ままコピペ出来るコード。例外処理はいい加減ですが。コード中の、XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XXの部分は、Google様からAPI Keyを貰うときに渡したフィンガープリントの文字列をそのまま書いて貰って、その下のAPI Keyの部分は対応するキーに。複数のプロジェクトで共有しているモジュールの場合は、全部のプロジェクト用の対応をここに追加してもいいかもしれない。

// パッケージ署名に対応するAPI Keyを返す
String getMapApiKey() {
  PackageManager pm = getPackageManager();
  try {
    PackageInfo pi = pm.getPackageInfo(getPackageName(), PackageManager.GET_SIGNATURES);
    for (Signature sig : pi.signatures) {
      String key = getMapApiKey(sig);
      if (key != null)
        return key;
    }
  } catch (NameNotFoundException e) {
    e.printStackTrace();
  }
  return null;
}

// 与えられた署名に対応するAPI Keyを返す
static String getMapApiKey(Signature sig) {
  String sigStr = getSignatureFingerPrint(sig);
  
  // デバッグ用署名(debug.keystore)に対応するAPI Key
  if (sigStr.equals("XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX"))
    return "<<デバッグ用署名用のAPI Keyをここに挿入>>";
  
  // リリース用署名に対応するAPI Key
  if (sigStr.equals("XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX"))
    return "<<リリース用署名用のAPI Keyをここに挿入>>";

  // その他の署名とAPI Keyの対応など
  // ...

  return null;
}

// 署名のMD5を文字列形式で返す
static String getSignatureFingerPrint(Signature sig) {
  try {
    MessageDigest md = MessageDigest.getInstance("MD5");
    md.update(sig.toByteArray());
    return hex(md.digest());
  } catch (NoSuchAlgorithmException e) {
    e.printStackTrace();
    return null;
  }
}

// バイト列の16進文字列化
static String hex(byte[] bin) {
  StringBuilder sb = new StringBuilder(bin.length * 3 - 1);
  for (int i = 0; i < bin.length; i++) {
    sb.append(String.format("%02X", bin[i]));
    if (i + 1 < bin.length)
      sb.append(':');
  }
  return sb.toString();
}

ndk-buildを使わないでプログラムをビルドする

普段は、ndk-buildでビルドをしているのが楽だし、便利なんですが、時に、外部のライブラリがconfigureとか使ってて、自前でAndroid.mkとかを作るのが面倒なことがあります。というか、試しに自前で作ってみようとしたけど、新旧の情報が錯綜しており、また、C++を使った場合のリンク方法がさっぱりとか、とりあえず、root化した端末でコマンドラインベースのコードを動かしてみたいけど・・・な場合にどうやれば良いのか全く分かりませんでした。

結局、当たり前ながら、じゃぁ、ndk-buildは何をやってるんでございましょうということになるんですが、これを見てみるために凄く簡単なサンプルを作ってみます。


sample/
jni/
Application.mk
Android.mk
sample.cpp

というディレクトリ構造で、

# Application.mk
APP_ABI := armeabi-v7a

# RTTI、例外を使うためにstatic GNU STLを利用する
APP_STL := gnustl_static
# Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE := sample
LOCAL_CFLAGS :=
LOCAL_SRC_FILES += sample.cpp
LOCAL_STATIC_LIBRARIES += gnustl_static

include $(BUILD_EXECUTABLE)
// sample.cpp
#include <iostream>
#include <vector>

int main(int argc, char* argv[])
{
  // 単にSTLが使えているかどうかをチェックしたい
  std::vector<int> v(256);
  std::cout << "Hello, world." << v.size() << std::endl;
}

っていうのを作って、jni/ディレクトリで

ndk-build -n

とやると(ちなみに、/opt/android-ndk-r7にAndroid NDK r7をインストールしている)、

rm -f /somewhere/sample/libs/armeabi/lib*.so /somewhere/sample/libs/armeabi-v7a/lib*.so /somewhere/sample/libs/x86/lib*.so
rm -f /somewhere/sample/libs/armeabi/gdbserver /somewhere/sample/libs/armeabi-v7a/gdbserver /somewhere/sample/libs/x86/gdbserver
rm -f /somewhere/sample/libs/armeabi/gdb.setup /somewhere/sample/libs/armeabi-v7a/gdb.setup /somewhere/sample/libs/x86/gdb.setup
mkdir -p /somewhere/sample/obj/local/armeabi-v7a/objs/helloworld/
echo """Compile++ thumb""  : helloworld <= sample.cpp"
ccache /opt/android-ndk-r7/toolchains/arm-linux-androideabi-4.4.3/prebuilt/darwin-x86/bin/arm-linux-androideabi-g++ -MMD -MP -MF /somewhere/sample/obj/local/armeabi-v7a/objs/helloworld/sample.o.d -fpic -ffunction-sections -funwind-tables -fstack-protector -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__  -Wno-psabi -march=armv7-a -mfloat-abi=softfp -mfpu=vfp -fno-exceptions -fno-rtti -mthumb -Os -fomit-frame-pointer -fno-strict-aliasing -finline-limit=64 -I/opt/android-ndk-r7/sources/cxx-stl/gnu-libstdc++/include -I/opt/android-ndk-r7/sources/cxx-stl/gnu-libstdc++/libs/armeabi-v7a/include -I/opt/android-ndk-r7/sources/cxx-stl/gnu-libstdc++/include -I/opt/android-ndk-r7/sources/cxx-stl/gnu-libstdc++/libs/armeabi-v7a/include -I/somewhere/sample/jni -DANDROID  -Wa,--noexecstack -fexceptions -frtti -fexceptions -frtti  -O2 -DNDEBUG -g -fexceptions -frtti  -I/opt/android-ndk-r7/platforms/android-3/arch-arm/usr/include -c  /somewhere/sample/jni/sample.cpp -o /somewhere/sample/obj/local/armeabi-v7a/objs/helloworld/sample.o 
mkdir -p /somewhere/sample/obj/local/armeabi-v7a/
echo "Prebuilt       : libgnustl_static.a <= <NDK>/sources/cxx-stl/gnu-libstdc++/libs/armeabi-v7a/"
cp -f /opt/android-ndk-r7/sources/cxx-stl/gnu-libstdc++/libs/armeabi-v7a/libgnustl_static.a /somewhere/sample/obj/local/armeabi-v7a/libgnustl_static.a
mkdir -p /somewhere/sample/obj/local/armeabi-v7a/
echo "Executable     : helloworld"
/opt/android-ndk-r7/toolchains/arm-linux-androideabi-4.4.3/prebuilt/darwin-x86/bin/arm-linux-androideabi-g++ -Wl,--gc-sections -Wl,-z,nocopyreloc --sysroot=/opt/android-ndk-r7/platforms/android-3/arch-arm  /somewhere/sample/obj/local/armeabi-v7a/objs/helloworld/sample.o   /somewhere/sample/obj/local/armeabi-v7a/libgnustl_static.a /somewhere/sample/obj/local/armeabi-v7a/libgnustl_static.a /opt/android-ndk-r7/toolchains/arm-linux-androideabi-4.4.3/prebuilt/darwin-x86/bin/../lib/gcc/arm-linux-androideabi/4.4.3/libgcc.a    -Wl,--fix-cortex-a8  -Wl,--no-undefined -Wl,-z,noexecstack  -lc -lm -o /somewhere/sample/obj/local/armeabi-v7a/helloworld
echo "Install        : helloworld => libs/armeabi-v7a/helloworld"
mkdir -p /somewhere/sample/libs/armeabi-v7a
install -p /somewhere/sample/obj/local/armeabi-v7a/helloworld /somewhere/sample/libs/armeabi-v7a/helloworld
/opt/android-ndk-r7/toolchains/arm-linux-androideabi-4.4.3/prebuilt/darwin-x86/bin/arm-linux-androideabi-strip --strip-unneeded  /somewhere/sample/libs/armeabi-v7a/helloworld

という感じのことをやっている事が分かる。

つまり、まとめると、コンパイル、リンク、リンク後処理として、

# コンパイル
/opt/android-ndk-r7/toolchains/arm-linux-androideabi-4.4.3/prebuilt/darwin-x86/bin/arm-linux-androideabi-g++ \
	-MMD -MP -MF \
	/somewhere/sample/obj/local/armeabi-v7a/objs/helloworld/sample.o.d \
	-fpic \
	-ffunction-sections -funwind-tables -fstack-protector \
	-D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__  \
	-Wno-psabi \
	-march=armv7-a -mfloat-abi=softfp -mfpu=vfp \
	-fno-exceptions -fno-rtti \
	-mthumb \
	-Os \
	-fomit-frame-pointer \
	-fno-strict-aliasing \
	-finline-limit=64 \
	-I/opt/android-ndk-r7/sources/cxx-stl/gnu-libstdc++/include \
	-I/opt/android-ndk-r7/sources/cxx-stl/gnu-libstdc++/libs/armeabi-v7a/include \
	-I/somewhere/sample/jni \
	-DANDROID \
	-Wa,--noexecstack \
	-O2 -DNDEBUG -g \
	-I/opt/android-ndk-r7/platforms/android-3/arch-arm/usr/include \
	-c  /somewhere/sample/jni/sample.cpp \
	-o /somewhere/sample/obj/local/armeabi-v7a/objs/helloworld/sample.o 
# リンク
/opt/android-ndk-r7/toolchains/arm-linux-androideabi-4.4.3/prebuilt/darwin-x86/bin/arm-linux-androideabi-g++ \
	-Wl,--gc-sections \
	-Wl,-z,nocopyreloc \
	--sysroot=/opt/android-ndk-r7/platforms/android-3/arch-arm \
	/somewhere/sample/obj/local/armeabi-v7a/objs/helloworld/sample.o \
	/somewhere/sample/obj/local/armeabi-v7a/libgnustl_static.a \
	/opt/android-ndk-r7/toolchains/arm-linux-androideabi-4.4.3/prebuilt/darwin-x86/lib/gcc/arm-linux-androideabi/4.4.3/libgcc.a \
	-Wl,--fix-cortex-a8 \
	-Wl,--no-undefined \
	-Wl,-z,noexecstack \
	-lc -lm \
	-o /somewhere/sample/obj/local/armeabi-v7a/helloworld
# デバッグ情報の除去
/opt/android-ndk-r7/toolchains/arm-linux-androideabi-4.4.3/prebuilt/darwin-x86/bin/arm-linux-androideabi-strip \
	--strip-unneeded \
	/somewhere/sample/libs/armeabi-v7a/helloworld

ということが分かる(一部、重複など簡略化済み)。
あとは、この辺を配慮した上でconfigure様に、CC/CXX/LD/CFLAGS/LDFLAGSなどを設定してあげれば良い感じみたいだ。