2013年2月28日木曜日

iOSとAndroidの両方を経験したユーザーによる調査結果:「おすすめはiOS、主流になるのはAndroid」

ジャストシステムが運営しているアンケートサービス「Fastask」が、iOS・Androidの両方を経験したユーザーの実感調査結果を公表している。それによると、人などから相談を受けた場合にiOSとAndroidのどちらを勧めるかと質問したところ、78.5%もの人が「iOSを勧める」と回答したとのこと。操作性が良いことが理由であるらしい。

ただ、今後のスマートフォンの主流OSはどちらになるかと聞いた話では、55.0%の人が「Android」と回答。「iOS」は39.0%と少なめの結果になった。Androidを選んだ理由は、「新規ユーザーが増えている」が48.2%、「コストパフォーマンスが高い」が40.9%とのこと。

Eclipse CDT と MinGW (64ビット環境)で JNI のデバッグ

ふと、Eclipse で JNI 呼び出し DLL のデバッグがしたくなった。
つまんない事で嵌ったので、備忘録として書いておく。

検証環境:
  • Windows Vista Business (64ビット) SP2
  • Eclipse classic 3.6.1(64ビット) Build id: M20100909-0800
  • Eclipse CDT 7.0.1.201009141542
  • JDK 1.6.0_16(64ビット)
  • MinGW-w64 (mingw-w64-bin_i686-mingw_20100702_sezero.zip)
  • GDB (x86_64-w64-mingw32-gdb-7.1.90.20100730.zip)
  • Make (make-3.82-20100827.zip)

以前に、CDT の設定をして、うまく動いていたと思ったのに、久しぶりに Eclipse を起動したら、MinGW を認識してくれなった。CDT のアップデートを行ったからだろうか?
しょうがないので、サポート外Toolchain から MinGW を選択した。path に MinGW/bin が設定されていれば、デフォルトの include ディレクトリや lib ディレクトリは自動的に設定されるようだ。
まあ、ここら辺の調査は宿題としておこう。

まあ、何事にも共通するが、初めてやるものは、最小限の状態から試すことが大事。

JNI で Java ソースと C++ のソースを作成済みとする。
プロジェクトは、Java と C++ で分ける必要がある。Java プロジェクトには、JNI インターフェースを作成するソースを格納。これは、そのままテスト駆動用とする。C++ プロジェクトには、JNI インターフェースのヘッダファイルと、ヘッダに定義されている関数の実装を記述したソースを格納。

C++ プロジェクトの設定

C++ プロジェクトのプロパティを開く
「C/C++ Build」−「Settings」で「Tool Settings」タブを開く

「GCC C++ Compiler」で以下を設定
  • 「Preprocessor」の「Defined symbols(-D)」に"_JNI_IMPLEMENTATION_"を追加。これは、jni.h の中に定義されている。未設定でも動いたが、ヘッダの該当箇所あたりに記述してあるメソッドを利用するときは設定する必要があるのかもしれない。
  • 「Includes」の「Include paths(-I)」に JDK をインストールしたディレクトリの include と include/win32 を追加。
  • 「Debugging」の「Debug Level」を"Default(-g)"に設定。

「All options」を見るとこんな感じ
-D_JNI_IMPLEMENTATION_ -I"C:\appli\Java\jdk1.6\include" -I"C:\appli\Java\jdk1.6\include\win32" -O2 -g -Wall -c -fmessage-length=0  


「MinGW C++ Linker」で以下を設定
  • 「Miscellaneous」の「Linker flags」に"-static"と"--kill-at"を追加。static は、静的リンクをしたい場合につける。kill-at はシンボルの後ろに @ を付けたくないときに付ける。両方とも無くてもかまわない。たぶん。
  • 「Shared Library Settings」の「Shared(-shared)」チェックボックスをチェック

「All options」を見るとこんな感じ
-static --kill-at -shared


「Settings」画面の「Build Artifact」タブで以下を設定
  • 「Artifact Type」を"Shared Library"を設定。ただ、この設定がどこに影響があるのか不明。
  • 「Artifact name」を"${ProjName}"に設定。出力ファイルのベースファイル名になる。
  • 「Artifact extension」を"dll"に設定。出力ファイルの拡張子になる
  • 「Output prefix」を空にする。出力ファイル名の先頭に付加される。

以上で C++ プロジェクトへの設定は完了
ビルドすると、Default ディレクトリに dll ファイルが生成されるはず。

Java デバッグの設定
  • DLL 読み込みのために以下のいずれかのように DLL のディレクトリを設定する。
    • 「VM arguments」に"-Djava.library.path=../hello-jni/Default"のように指定。
    • 「Environment」に"PATH"を追加して、"../hello-jni/Default"のように指定。


C++ アタッチデバッグの設定
  • C++ プロジェクトをクリックして、選択状態にする。
  • 「Run」メニューから「Debug Configurations...」を選択。
  • 「C/C++ Attach to Application」 を右クリックして、コンテキストメニューから「New」を選択。
  • 作成されたデバッグ設定をクリック。
  • 「Main」タブの「C/C++ Application」が"Default\ DLL ファイル名"、「Project」がC++ プロジェクト名になっていることを確認。
  • 「Close」ボタンを押す。

デバッグ開始


デバッグを開始する手順は次のようにする。
  • Javaのソースにブレイクポイントを設定。ただし、 System.loadLibrary で 作成した DLL のロード後の場所に設定すること。
  • Java のデバッグを開始。
  • C++ のデバッグを開始。アタッチするプロセス ID を設定するダイアログが開くので、上で実行したプロセス(javaw.exe)の ID を tasklist コマンドか、タスクマネージャで調べて入力する。javaw.exe プロセスは、eclipse 本体もあるので、間違って eclipse 本体のプロセスを指定しないこと。
  • C++ ソースにブレイクポイントを設定する。ここ重要、必ず C++ デバッグ開始直後の状態(GDB が起動して、一時停止の状態)でブレイクポイントを設定すること。ブレイクポイントを解除しなくても無効にして有効にすれば問題ない。ブレイクポイントのマークをよく見ると、有効な場合は、丸の上にチェックが付いている。無効な場合には、丸だけ。さらに、ソース上のブレイクポイント行に!マークが付き"Breakpoint attribute problem: installation failed"と表示される。
  • C++ デバッグを再開(Resume(F8))する。再開後に C++ のブレイクポイントの設定はできない。C++ のブレイクポイントで一時停止した状態にならないとブレイクポイントの設定はできない。
  • Java デバッグを再開すると C++ のブレイクポイントで停止する。はず。


いろいろやってると、eclipse が反応しなくなるときがある。そんなときは、GDB のプロセスが残ってる場合があるので、taskkill コマンドかタスクマネージャから gdb.exe プロセスを停止するといい。

Loading 32 or 64 bit JNI Library in Java

In my Java application I need a JNI library which is available for 32 bit and 64 bit. I don't want to ship two different versions of my application so I want to ship the application with both libraries and the application must determine itself which library to load (foobar32.so or foobar64.so). How do I do that?

I thought about trying to load the first one and if this throws an exception then I load the second one but this sounds ugly.

Is there some system property I could check instead to determine if a 32 bit Java or a 64 bit Java is used to run my application? I know there is some os.arch property but the return value seems to be pretty unpredictable according to this answer.

So what is the best way to let the application decide if to load the 32 or 64 bit JNI library?

==>

Why unpredictable? You want only to detect if it is 32 bit system, and in this case it will be always x86 (of course for x86 processors), everything else means 64 bit.

Problems starts if you know that your code may be executed also on PPC or other non x86 processors. But in this case you may use ugly hack with exception driven flow control, and use try {} catch () to "detect" such situations.

IMHO os.arch will be the best solution.

Java Native Interface (JNI)

JNI (Java Native Interface)は、Java仮想マシンとネイティブアプリケーションを組み合わせるための標準プログラミングインタフェースです。

Java VM の動作に影響を及ぼすので、JNI関数の中ではシグナルハンドラを設定してはいけません。J2SDK v1.4からシグナル連鎖機能がサポートされ、シグナルハンドラが使用できるようになった。

Javaから呼び出されているネイティブライブラリをデバッガで動作させる

Javaから呼び出されているネイティブライブラリをデバッガで動作させるには、環境変数DEBUG_PROGにデバッガを定義します。そしてJavaを実行させるとデバッガが起動されますので、stop dlopenコマンドでデバッグするライブラリのパスを指定します。runコマンドで実行すると、libxxx.soが呼び出されると停止するので、ブレークポイントを設定して実行を継続します。

$ setenv DEBUG_PROG dbx
$ java
(dbx) stop dlopenn ライブラリのパス
(dbx) run Test.Test_0
(dbx) file operate.c
(dbx) stop at 行番号
(dbx) cont

JNIを使ってC言語からJavaのメソッドを呼ぶ

JNIを使うと、ネイティブ・コード(C言語やC++など)からJavaのクラスを利用したり、メソッドを呼ぶことができる。

C言語のサンプル・コードを次に示す。

include "jni.h"    int main()  {      JNIEnv  *env;      JavaVM  *jvm;      int     res;      jclass  clazz;      jmethodID mid;        JavaVMOption options[3];      options[0].optionString = "-Xmx128m";      options[1].optionString = "-verbose:gc";      options[2].optionString = "-Djava.class.path=/home/yajima/class";        JavaVMInitArgs vm_args;      vm_args.version = JNI_VERSION_1_6;      vm_args.options = options;      vm_args.nOptions = 3;        /* Java VM の作成 */      res = JNI_CreateJavaVM(&jvm, (void **)&env, &vm_args);      if (res < 0) {          fprintf(stderr, "JNI_CreateJavaVM error\n");          return -1;      }        /* Javaクラスの検索 */      clazz = (*env)->FindClass(env, "Hello");      if (clazz == 0) {          fprintf(stderr, "FindClass error\n");          return -1;      }        /* メソッド識別子の取得 */      mid = (*env)->GetStaticMethodID(env, clazz, "main",          "([Ljava/lang/String;)V");      if (mid == 0) {          fprintf(stderr, "GetStaticMethodID error\n");          return -1;      }        /* Hello#main の呼び出し */      (*env)->CallStaticVoidMethod(env, clazz, mid, NULL);        /* Java VM の破棄 */      (*jvm)->DestroyJavaVM(jvm);        return 0;  }  

C言語から呼び出されるJavaのサンプル・コードを次に示す。

public class Hello {      public static void main(String args[]) {          System.out.println("Hello!");      }  }  

jni.h のインクルード

C言語/C++ のプログラムで、ヘッダファイル jni.h をインクルードする必要がある。jni.h は JDK_HOME/include ディレクトリに含まれているので、このディレクトリをインクルードファイルのディレクトリとしてコンパイラに指定する。

jni.h の中では jni_md.h をインクルードしている。jni_md.h にはプラットフォームに依存する内容が含まれている。そのため、jni_md.h が存在するディレクトリはプラットフォームにより異なる。このディレクトリもインクルードファイルのディレクトリとしてコンパイラに指定する。

jni_md.h が存在するディレクトリの一例を次に示す。

jni_md.hのディレクトリ
OS パス
Windows include\win32
Linux include/linux
Solaris include/solaris

JNI変数型のマッピング

Javaとネイティブ変数型(C言語)のマッピングを次の表に示す。

JNI変数型のマッピング
Java変数型 ネイティブ変数型
jboolean unsigned char
jbyte signed char
jchar unsigned short
jshort short
jnit int
jlong long long __int64
jfloat float
jdouble double

Java VMの生成

Java VMをロードして初期化するには、JNI_CreateJavaVM()関数を呼び出す。

_JNI_IMPORT_OR_EXPORT_ jint JNICALL
JNI_CreateJavaVM(JavaVM **pvm, void **penv, void *args);

引数pvmには、呼び出しAPI関数テーブルのポインタ (JavaVM *) を格納する領域へのポインタを渡す。

呼び出しAPI関数テーブルには、次に示す関数へのポインタが格納される。

  • DestroyJavaVM
  • AttachCurrentThread
  • DetachCurrentThread
  • GetEnv
  • AttachCurrentThreadAsDaemon

引数argsには、JavaVMInitArgs構造体を参照するポインタを指定する。

JavaVM型

JavaVM は、JNIInvokeInterface_ 構造体へのポインタ型である。

#ifdef __cplusplus  typedef JavaVM_ JavaVM;  #else  typedef const struct JNIInvokeInterface_ *JavaVM;  

64ビットJNI

64ビット版のEclipseをインストールしてふと疑問が。

EclipseってSWTだから、PureJavaじゃなくて、JNIでDLL呼び出してるよなあ。どうやって作るんだろうか。

早速試してみます。なかなか難しい。

試行錯誤した結果、以下の手順で一応できることが分かりました(実用性がほぼ無くなるほどの制約がつきます。後述)。

以下、jdkのバージョンは1.6.0_13、VCのバージョンは、9.0 (2008)です。もちろん、両方とも64ビット版です。

(1) TestJNI.javaを作成。

(2) 「javac TestJNI.java」
これにより、TestJNI.classが作成される。

(3) 「javah -jni TestJNI」
これにより、TestJNI.hが作成される。

(4) TestJNI.cを作成。

(5) 「Visual Studio 2008 x64 Win64コマンドプロンプト」で、「cl /I"c:¥Program Files¥Java¥jdk1.6.0_13¥include" /I"c:¥Program Files¥Java¥jdk1.6.0_13¥include¥win32" /MT /LD TestJNI.c」
これにより、TestJNI.dllが作成される。

ここで重要なのは、/MTオプション。(これにたどり着くのに2時間かかりました。)

(6) テスト。「java TestJNI」

上で「実用性がほぼ無くなるほどの制約」と言っているのは、VC 2008の場合に必ず動的リンクなってしまうDLLが呼び出せないこと(たとえば、printf()を利用すると、msvcr90.dllへのリンクが作られます)。

java.exeからこのDLLをロードしない限り、それを利用するDLLも「java.lang.UnsatisfiedLinkError」ではねられてしまうのですが、その方法が分かりません。

中途半端な結果ですが、とりあえず今日はここまで。

--- TestJNI.java ここから ---
public class TestJNI {
 public native void hello();
 static { System.loadLibrary("TestJNI"); }
 public static void main(String[] args) {
  new TestJNI().hello();
 }
}
--- TestJNI.java ここまで ---

--- TestJNI.c ここから ---
#include <jni.h>
#include "testJNI.h"
/*#include <stdio.h> */
JNIEXPORT void JNICALL Java_TestJNI_hello
(JNIEnv *env, jobject obj)
{
 /*printf("hello¥n");*/
 return;
}
--- TestJNI.c ここまで ---

2013年2月27日水曜日

キーボード レイアウトを 日本語 106/109 配列に設定する

以下、マイクロソフト社のサポートラインHPからの抜粋です。

http://support.microsoft.com/kb/418323/ja

キーボード レイアウトを 日本語 106/109 配列に設定するには、次の手順で操作します。

1. [スタート] ボタンをクリックし、[コントロール パネル] をクリックします。
2. [システム] アイコンをダブルクリックして、[システムのプロパティ] を開きます。
3. [ハードウェア] タブをクリックして、[デバイス マネージャ] をクリックします。
4. [デバイス マネージャ] のメニュー バーの [表示] から [デバイス (種類別)] をクリックします。
5. デバイスの一覧から [キーボード] をダブルクリックして、変更する 101/102 配列のキーボード デバイス表示をダブルクリックします。
6. [ドライバ] タブをクリックし、[ドライバの更新] をクリックして、[ハードウェアの更新ウィザード] を開始します。
7. [一覧または特定の場所からインストールする (詳細)] をクリックして、[次へ] をクリックします。
8. 検索とインストールのオプションを選択する画面で [検索しないで、インストールするドライバを選択する] をクリックして、[次へ] をクリックします。
9. デバイス ドライバを選択する画面で [互換性のあるハードウェアを表示] チェック ボックスをオフにし、以下のモデルをクリックします。
1. 製造元: [(標準キーボード)]
2. モデル: [日本語 PS/2 キーボード (106/109 キー Ctrl + 英数)]
注意 : 以下のモデルを選択しないでください。これらのモデルでドライバを更新した場合、システムの再起動後に PS/2 サービスが無効となり PS/2 ポートに接続されているすべてのデバイス (キーボードおよびマウスなどのポインティング デバイス) が機能しなくなることが確認されています。
* Microsoft USB Internet Keyboard
* Microsoft USB Internet Keyboard Pro
* Microsoft USB Natural Keyboard
* Microsoft USB Natural Keyboard Pro
10. [次へ] をクリックして、画面の指示に従います。
11. Windows XP を再起動します。

2013年2月26日火曜日

Intel Announces Clover Trail+ Atom Platform For Smartphones and Tablets

Today, Intel announced the follow-on to their Medfield Atom platform for smartphones, code-named Clover Trail+. Clover Trail is powering a few Windows 8 Pro tablets currently. However, Clover Trail+, Intel's new performance and feature-optimized version of Clover Trail for smartphones and tablets, has a long row to hoe versus incumbents like Qualcomm, Samsung and NVIDIA, at least in the highly competitive handset arena. What's interesting this time around is that Clover Trail+ seems to really have the chops (at least on paper) to keep pace with the performance of current, best-of-class ARM-based architectures that have been so dominant in smartphones. Clover Trail+ is another 32nm design and Intel has beefed up almost every major functional block on the platform. From its now dual-core, 4-thread capable Atom CPU, to its new PowerVR SGX 544MP2 graphics engine, 2GB of LPDDR2 1066 DRAM, up to 256GB of NAND storage, a higher resolution 16MP camera and Intel's XMM 6360 HSPA+ 42Mbps modem, with LTE support from their XMM 7160 radio moving forward; Intel's Clover Trail+ smartphone reference design brings a lot more to the table than Medfield ever did.

2013年2月25日月曜日

18 Carriers Sign Up for Firefox OS Phones

Several readers sent word of a Mozilla announcement that 18 carriers have committed to launching phones running Firefox OS. The carriers are primarily from markets in South America and Europe. They include Deutsche Telekom, Telefonica, and Sprint. The devices running Firefox OS will be made by LG, ZTE, Huawei, and Alcatel, and all will be powered by a Qualcomm Snapdragon chipset. The new mobile operating system is built to allow HTML5 apps to run directly on the device, a solution Mozilla thinks will give it an edge when playing catch-up to all the software available for Android and iOS devices. "Developers are busy and don't have time to learn a new programming language. We believe that the only remaining eco-system is the web and there are more developers for the web than for any other platform in the world," said Jay Sullivan. According to Reuters, "Mozilla will initially look to compete in so-called 'emerging economies' in Latin America, Eastern Europe and Asia, where many people still use older phone models and have yet to upgrade to more expensive smartphones that feature touchscreens and high-speed Internet connections."