プログラムメモ



2018/09/19 Android NDK r18
Android NDK r18 がリリース。




2018/09/06 Android NDK r17c
Android NDK r17c がリリース。

変化点は1点だけ?
・Issue 112611166: Fixed "min" value in meta/platforms.json.




2018/08/23 Android NDK r18 beta2
Android NDK r18 beta2 がリリース。

Changes
・Added APP_STRIP_MODE and LOCAL_STRIP_MODE to ndk-build.
・Issue 749: The libc++_shared.so in the NDK is no longer stripped of debug info.
 Debugging libc++ is now possible.
 Gradle will still strip the library before packaging it in an APK.

他、不具合修正。




2018/08/04 アニメーションのZオーダー
Android の画面切り替えアニメーションは切り替え先が手前に表示される。
finish() で終了した場合は終了した画面が手前から消え、裏側画面が表示される。

アプリの実装上、finish() ではなく intent で前の画面に戻りたい場合に問題が発生する。

intent だと切り替え先と認識されるので表示中の画面が手前ではなく
裏側でアニメーションしてしまうので見た目がおかしくなる。

この動作に気付けたのでなんとか解決策がみつかった。

アニメーションには簡素なZオーダー指定があってそれを使えばいい。
android:zAdjustment="0"

数字の意味は normal(0), top(1), bottom(-1) となる。




2018/07/30 Android NDK r18 beta1
Android NDK r18 beta1 がリリース。

Announcements
・gcc は削除した。
・LLD をテスト用に使用できるようにした。
 AOSP はデフォルトで LLD を使用するように切り替えた。
・gnustl, gabi++ および stlport は削除した。
・ICS (android-14 and android-15) のサポートは削除した。
 PIE形式の違いを考慮する必要がなくなった。
・2019年8月からPlayストアに登録する apk は64ビットサポートが必須になります。


Changes
・Clang を r328903 ベースの build 4751641 に更新した。
 Issue 573 が修正されて、-Oz のデフォルト最適化モードは thumb 命令になりました。
・libc++ を r334917 に更新した。
・ndk-build に clang-tidy のサポートを追加した。
・Issue 490:ndk-build と CMake は android-23(Marshmallow)以上をターゲットにすると
 ARM 用 NEON 命令をデフォルトで使用するようになりました。
・その他、不具合修正。




2018/07/28 乱数の初期化
乱数の初期化を時間関連の値で行っていると起きる問題。

コードはこんな感じ。
srand(GetTickCount());

レアケースなんだけど、バッチ処理等で同じアプリを複数起動すると、
1ミリ秒以下で複数起動されるので乱数のシードが全て同じになってしまう。

よって各アプリの rand() で得られる値が全て同じになる…




2018/07/22 Android Studio で NDK
Android Studio に NDK を使った eclipse プロジェクトをインポートしてみた。

やっぱり NDK 部分でエラーが出た。

Error:Execution failed for task ':app:compileDebugNdk'.
> Error: Your project contains C++ files but it is not using a supported native build system.
Consider using CMake or ndk-build integration with the stable Android Gradle plugin:
https://developer.android.com/studio/projects/add-native-code.html
or use the experimental plugin:
http://tools.android.com/tech-docs/new-build-system/gradle-experimental.

build.gradle に記述していなくても android.mk があると上記のエラーが出るみたい。

対処としては SDK Maneger で CMAKE を追加ダウンロード。
cmakelists.txt 作成して android.mk と置き換えればいい。

そのまま android.mk を使いたい場合は gradle.properties を作成して

android.useDeprecatedNdk=true

を記述すれば、build.gradle で android.mk を指定してビルドできる。

ただし、android.mk は将来的にサポートされなくなるので
CMAKE に移行する事が勧められている。




2018/06/16 VC カスタムビルドの nasm でエラー
カスタムビルドで nasm を使ったVCプロジェクトを移動してビルドしたらエラーになった。

nasm: error: more than one input file specified

入力ファイルが異常だと言われているみたいだけど…

移動後のフォルダ名にスペースが入っているのでファイル名解析で失敗してるっぽい。

nasmw -dWIN32 -f win32 -o "$(IntDir)\$(InputName).obj" "$(InputDir)/$(InputName).asm"

ダブルクォーテーションで囲んだら解決した。




2018/06/13 Android NDK r17b
NDK r17b がリリース。
バグ修正がメインかなー。

Issue 480: Fixed libc++ header issues with _FILE_OFFSET_BITS=64.
Issue 692: Fixed ASAN for standalone toolchains with static STLs.
Issue 697: Pulled documentation updates for simpleperf.
Issue 702: Updated sysroot to fix missing libc symbols.
Issue 704: Updated shaderc/vulkan-validation-layers sources.
Issue 708: Fixed introduced API tag for pthread_cond_timedwait_monotonic_nmp to make it available on ICS.




2018/06/02 Android Studio で NDK を試してみる
Android Studio でも NDK を問題なく使用できる。

Eclipse 時代のソースもビルド出来るけど問題なのはメイクファイル。
今までと互換性が無い CMAKE が採用されている。

一応、build.gradle で android.mk をビルドできるけど、
細かい事をやろうとすると面倒そうだし、将来使えなくなる可能性もあるので
CMAKE に対応して置いた方が良さそう。

なんとなく android.mk と cmakelists.txt を一緒にビルドを
試してみたけど混合はビルドできないみたい。




2018/05/28 Android Studio 3.1 のバグ?
某所より Android Studio 用のプロジェクトをダウンロードしてインポートしたら
ツリーに build.gradle (project名) が表示されていない…

いろいろ調べた結果、.idea/modules.xml に記述されるパスが正しくない。
正:fileurl="file://$PROJECT_DIR$/TestProject.iml" filepath="$PROJECT_DIR$/TestProject.iml"

誤:fileurl="file://$PROJECT_DIR$/.idea/TestProject.iml" filepath="$PROJECT_DIR$/.idea/TestProject.iml"

なぜか .idea フォルダにプロジェクトの iml が生成されるようになっているので
プロジェクトルートにある build.gradle を参照しなくなっているのが原因だった。
手動で .idea/modules.xml を修正して直ったけど、これってバグだよね?




2018/05/09 Android NDK r17
突然 Android NDK r17 がリリース。




2018/05/06 Proguardで難読化されたログから名称を復元する
難読化しているとスタックトレースのどこで例外が発生したのかわからない。

どうやら難読化したログを mapping.txt として保存してるらしく、
このファイルから元の名称を復元できるらしい。

Android SDK 中にある tools/proguard/bin/retrace.bat を使って復元する。
※Windows 以外の環境だと retrace.sh を使う。

やり方は難読化前の名称にしたいスタックトレースを stacktrace.txt として保存して
下記コマンドを実行すればクラス名やメソッド名に置き換えてくれる。

retrace.bat (パス)\app\build\outputs\mapping\release\mapping.txt stacktrace.txt

完全では無いけど解析が楽になったかな。




2018/05/01 また CreateProcess か…
Android アプリを ndk でビルドしたらまた訳の分からないエラーが出た…

make (e=87): パラメーターが間違っています。

なんでも CreateProcess の第二引数(またか!)に制限があるらしく、
32,768 文字を超えるとダメらしい。

プロジェクト側で生成されるメイクコマンドを修正して対応するしかない。

パスをロングネーム(通常)ではなくショートネーム(DOS用等)で
扱う事によって文字数を減らす事ができるので設定を変更する。

Application.mk に次の1行を追記する。
APP_SHORT_COMMANDS := true

Android.mk に次の1行を追記する。
LOCAL_SHORT_COMMANDS := true

この2つを追記してビルドが通るようになった。




2018/04/27 Proguard でスタックサイズエラー
Proguard を有効にすると解決が面倒な事ばかり起きる…。

訳のわからないエラーが発生したのでいろいろ調べた。
Stack size becomes negative after instruction [23] invokestatic #58 in [com/google/android/gms/internal/zzap.zzf(Ljava/lang/String;)J]

解決方法は2つあった。

対策1:-dontoptimize を指定して最適化を無効にする。

対策2:Log 出力を削除対象としない。
Log クラスのメソッド呼び出しを削除していると部分をコメントアウト。
#-assumenosideeffects public class android.util.Log {
# public static *** v(...);
# public static *** d(...);
# public static *** i(...);
# public static *** w(...);
# public static *** e(...);
# public static *** wtf(...);
#}

google のライブラリが最適化を非推奨としているなんて情報もあってビミョー。
Android の ART 動作なら java を中間オブジェクトで処理していないハズなので
java バイナリの最適化をしなくても最適化されるのかも知れないけどね…。




2018/04/26 CreateProcess でハマる
久しぶりに Windows アプリを組んでみた。

CreateProcessA だと問題ないのに CreateProcessW だと落ちる。

原因不明だったけどなんとか解決した。
CreateProcessW に渡す第二引数が (TCHAR* p) だと落ちるが
(TCHAR p[]) だと落ちない事が判明。

これって VC 以外のコンパイラでも発生するのかな?
気になるけどわざわざアセンブラで確認するのは面倒だなー。




2018/04/21 NumberPicker を使う
NumberPicker の EditText で IME を表示しないようにする。

xml の表記。
android:descendantFocusability="blocksDescendants"

java で実装する。
numberPicker.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS);



2018/04/19 ImageView を固定色で塗りつぶし
ImageView を固定色で塗りつぶしてみた。

とりあえず。
int color = getResources().getColor(R.color.colorWhite);
imageView.setColorFilter(color);

とすると次に setImageBitmap しても表示が変わらない。
imageView.setColorFilter(null);
で無効にしないと画像が表示されない。


これだと扱いが面倒なので違う方法を探す。
int color = getResources().getColor(R.color.colorWhite);
imageView.setImageDrawable(new ColorDrawable(color));

これだと setImageBitmap して表示が変化する。

setColorFilter はマスク的な使い方、
setImageDrawable は画像無しの場合に使のがいいのかも知れない。



2018/04/17 Android NDK r17 beta2
NDK r17 beta2 がひっそりリリース(笑)

Announcements
・libc++ は標準 STL として使われている。
 もし他の STL を使っている場合は libc++ に移行する事を勧める。
・gnustl と stlport は非推奨となり NDK r18 で削除される。
・ARMv5 (armeabi), MIPS, and MIPS64 のサポートを削除した。
・ICS (android-14 and android-15) のサポートは R18 で削除される。
・2019年8月からPlayストアに登録するには apk に 64bit対応が必要。
 その時が来る前に 64bit へ移植を始めてください。

Changes
・Clang を r316199 をベースにした build 4691093 に更新。
・更新 gtest to upstream revision 0fe96607d85cf3a25ac40da369db62bbee2939a5.
・libandroid のサポートは長くない。
・プラットフォーム静的ライブラリ(libc.a、libm.aなど)を更新。
・NDK のリビジョンは CMAKE で次のように固定される。
 ・ANDROID_NDK_REVISION: The full string in the source.properties file.
 ・ANDROID_NDK_MAJOR: The major revision of the NDK. For example: the 16 in r16b.
 ・ANDROID_NDK_MINOR: The minor revision of the NDK. For example: the b (represented as 1) in r16b.
 ・ANDROID_NDK_BUILD: The build number of the NDK. This is 0 in the case of a local development build.
 ・ANDROID_NDK_BETA: The beta version of the NDK. This is 0 for a stable release.
・ndk-build に APP_WRAP_SH のサポートが追加された。



2018/03/20 依存関係(gradle Ver 4 系)
Android Studio 3 にプロジェクトを移行してみた。

compile が deprecated になってて書き換える必要が…。

implementation → モジュールに展開され結合される。
api → 従来の compile と同じ動作。
compileOnly → 従来の provided と同じ動作。
runtimeOnly → この依存関係は実行時にのみ、モジュールとその使用側で利用できる。



2018/03/12 Android NDK r17 beta1
2回のリリース延期を経て、beta1 がリリース。

clang の更新とか。バグフィックス。



2018/02/27 エディットテキストの下線の色を変える
とりあえずスタイルを記述する。

<style name="MyCustomEditTextTheme" parent="Theme.AppCompat.Light.NoActionBar">
  <item name="colorControlNormal">#0000ff</item>
</style>

style="@style/MyCustomEditTextTheme" だけだと colorControl が
適用されないので app:theme="@style/MyCustomEditTextTheme" にも設定する。
(style と app:theme の両方に設定する。)
app:theme を使うには android.support.v7.widget.AppCompatEditText を
使う必要がある。



2018/02/14 XML で強制的に警告を表示しない方法
出来る限り使用するべきでは無いけど…必要な場合もある。
tools:ignore に無視したい警告の種別を記述する。

xmlns:tools="http://schemas.android.com/tools"
tools:ignore="MissingPrefix"



2018/01/26 フォルダとファイル名が長いとエラーが出る
新しくプロジェクトをインポートしたらエラーが出てビルドできない…。

Error:com.android.builder.internal.aapt.AaptException
調べると com.google.android.gms の内部で使われている
common_google_signin_btn_icon_light_focused.9
が正しくない場合に出るエラーらしいが…何かが違う。

Windows の文字数限界 240 文字にフォルダ名が達して発生していたようで、
プロジェクトのフォルダ階層を減らしてインポートし直したらビルドが通った。



2018/01/20 ListView のアイテムにボタン配置すると onItemClick が呼ばれない
ListView のアイテムにボタンを配置した xml を指定すると
アイテム本体のタップが反応しなくなる。
(onItemClick が呼ばれなくなる。)

回避策としてアイテムの xml の親 Layout (ViewGroup) に下記の記述をすると解決する。

android:descendantFocusability="blocksDescendants"



2018/01/19 CheckedTextView を使う。
CheckedTextView の android:checkMark に設定できる値。

?android:attr/listChoiceIndicatorSingle
?android:attr/listChoiceIndicatorMultiple
?android:attr/textCheckMark



2018/01/06 Spinner を使う。
リスト展開した時のリソース変更。

adapter.setDropDownViewResource(R.layout.item_spinner_radio_dropdown);



2018/01/02 TextInputLayout
android.support.design.widget.TextInputLayout

テキストのヒントを常時表示する為のパーツ。



2017/12/24 View からはみ出して表示する
子 View を親 View からはみ出して表示するには
clipChildren と clipToPadding を使用する。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
 xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:padding="40dp"
 android:clipChildren="false"
 android:clipToPadding="false"
 android:background="@color/white">

 <LinearLayout
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:background="@color/colorPrimary">

  <!-- はみだしたい View -->
  <TextView
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:layout_marginLeft="-20dp"
   android:text="Hello World!"
   android:padding="12dp"
   android:background="@color/colorAccent"/>

 </LinearLayout>
</RelativeLayout>



2017/12/08 Android NDK r16b
Android NDK r16b がリリースされた。

・コンパイルのデフォルトを -Oz に戻した。

更新内容これだけ?



2017/11/19 Android NDK r17
リリース予定。

Beta 1 December 2017
Beta 2 Late January 2018
Release February 2018



2017/11/15 Android NDK r16
Beta2 でしばらく止まっていた Android NDK r16 がリリースされた。

・古いヘッダーは削除され、共通化されたヘッダーはシンプルになった。
・gcc は削除されていないが対応しない。バックポートも受け入れない。
 r18 で libc++,gnustl 関連が安定した場合には不要な STL と共には削除される。
・libc++ はβ版が終わり、使用が好まれる。r17 ではデフォルトSTLになる。
 手動で異なる STL を選択するよりも libc++ で使う事を強く勧める。
・ARMv5(armeabi)、MIPS、およびMIPS64のサポートは非推奨になる。
 これらは r17 で取り除かれる。
・ndk-build と CMake は標準で libatomic をリンクする。
 もう手動の追加 -latomic は必要ない。
・ndk-build の clang コンパイラは静的解析をサポートした。
・Clang の標準を -Oz から -Os に変更した。gcc よりもサイズを小さくする。
・GCC はデフォルトでもう -Bsymbolic を使わない。
 多くの公開されたシンボルはあなたのバイナリサイズを大きくする。
・binutils を 2.27 に更新。aarch64 のミスコンパイルを防ぐ。
・CMake の互換性が向上した。
・ndk-stack は arm64 上の Darwin で動作する。
・Android O MR1 のネイティブ API を追加した。
・他、バグ修正。



2018/01/10 AppCompatActivity の判定
AppCompatActivity を判定する方法。

 public static AppCompatActivity getAppCompActivity(Context context) {
  if (context == null) return null;
   if (context instanceof AppCompatActivity) {
    return (AppCompatActivity) context;
   } else if (context instanceof ContextThemeWrapper) {
    return getAppCompActivity(((ContextThemeWrapper) context).getBaseContext());
  }
  return null;
 }



2017/01/09 AppCompat 系の widget
AppCompatActivity を使うと各パーツは初期化で自動的に置き換えられている。

AppCompatAutoCompleteTextView
AppCompatButton
AppCompatCheckBox
AppCompatCheckedTextView
AppCompatEditText
AppCompatImageButton
AppCompatImageView
AppCompatMultiAutoCompleteTextView
AppCompatRadioButton
AppCompatRatingBar
AppCompatSeekBar
AppCompatSpinner
AppCompatTextView



2017/10/07 自動生成される activity ソース
eclipse でプロジェクトを作成していて気が付いた。

プロジェクト作成時に自動生成される activity ソースは
「Minimum Required SDK」と「Target SDK」が異なると AppCompatActivity。
同じだと Activity になる。

これによって style 関連の自動生成結果も変わってくる。



2017/09/20 Release 版のログ出力
Android Studio でリリース版にするとログ出力が見えなくなる対策。

adb から直接拾うと見れる。
adb logcat




2017/09/18 リストの末端アニメーション
リストの先頭と最後に到達したと時のアニメーションを無効にする方法。

java コードから制御する。API Level 9 から使える。
listView.setOverScrollMode(View.OVER_SCROLL_NEVER);

ViewCompat にもある。
ViewCompat.setOverScrollMode(viewPager, ViewCompat.OVER_SCROLL_NEVER);

xml から制御する方法。
android:overScrollMode="never"



2017/09/01 NDK で端末の API Level を取得する
NDK で API Level を取得できないか調べてみた。

java 側の API を呼ぶ方法。

buildClass = (*env)->FindClass( env,"android/os/Build$VERSION" );
if( buildClass != NULL )
{
    sdkIntFieldID = (*env)->GetStaticFieldID( env,buildClass, "SDK_INT","I" );
    sdk_int = (*env)->GetStaticIntField( env,buildClass,sdkIntFieldID );
    (*env)->DeleteLocalRef( env,buildClass );
}
LOGI( "build.sdk_int : %d\n",sdk_int );


システム情報から文字列で取得する。
#include <sys/system_properties.h>
int len;
char str[128];

// シリアルナンバーを読む
len = __system_property_get(“ro.serialno”, str);
// 機種を読み取る
len = __system_property_get(“ro.product.model”, str);
// sdkバージョンを読み取る
len = __system_property_get(“ro.build.version.sdk”, str);
len = __system_property_get("ro.build.version.release", str);

こっちは古い API らしく Deprecated になっている。
#include <cutils/properties.h>
char str[128];

// sdkバージョンを読み取る
property_get(“ro.build.version.sdk”, str , "0" );

NativeAcitivy の方法。
#include <android/configuration.h>
// sdkバージョンを読み取る
int sdk_int = AConfiguration_getSdkVersion( app->config );
LOGI( "build.sdk_int : %d",sdk_int );



2017/08/11 Android のスレッドID
java と NDK で互換性のあるスレッドIDを取得する。

java 側のスレッドIDを取得する方法。
int tid = android.os.Process.myTid();

NDK の場合は Linux の tid の取得する方法を使う。
#include <unistd.h>
pid_t tid = gettid();

取得した tid でプライオリティの変更が出来る。



2017/08/04 Android NDK r15c
Android NDK r15c がリリースされた。

・_FILE_OFFSET_BITS=64 に関係する API を修正。(64bitファイルアクセス)
・termios.h の API を古い API として修正。(非推奨?)
・互換性を維持する為に ffs を追加した。ただし非推奨。
・過去のリリースとの互換性を取る為に古い pthread API を追加した。



2017/07/04 Android NDK r15b
Android NDK r15b がリリースされた。

・libsync のヘッダーとライブラリの不整合を修正。
・他のシステムとの互換性を高める為に libc ヘッダーを更新した。



2017/06/28 Android SDK 更新
eclpse でのサポートが無くなり Android アプリ開発がやりづらくなってるけど
そんな事を気にせず、 android SDK の更新してみた。

とりあえずコンパイルは問題なさそう。次はデバッグ実行を…

あれ?…エラーが出て実行できない。ついでに apk も作成できない…

Dex Loader] Failed to load C:\android_sdk\build-tools\26.0.0\lib\dx.jar
TestApp] Unknown error: Unable to build: the file dx.jar was not loaded from the SDK folder!

いくつか素行錯誤したけど改善せず。

追加された Build Tools が悪さしてるみたいだから 26.0.0 を削除して eclipse を再起動!
お…動いた。とりあえず 25.0.3 までは大丈夫みたい。

eclipse だと最新の 26.0.0 は使えないのかな?
ADT を最新(配布終了?)に更新してれば動くなのかなぁ…?



2017/06/12 Android NDK r15
Android NDK r15 がリリースされた。

Gingerbread (android-9) はサポートしない。
最小の API level は Cream Sandwich (android-14) になる。
x86 and x86-64 用のアセンブラ YASM を CMake toolchain で対応。

・Android O.で追加された API を知って欲しい。
 AAudio API
 Hardware Buffer API
 Shared Memory API
・awk はもう長く使わない。Python に置き換えられる。
・Clang を build 4053586 に更新。元になったのは Clang 5.0 SVN r300080。
・Clang は OpenMP に今対応した。(MIPS/MIPS64を除く)
・libc++ の信頼性を高める為に libandroid_support を改善し、サイズダウンを行う。
・その他、バグ修正。



2017/06/10 Android の UIPageControl
iPhone には UIPageControl というページ状態を表す UI パーツがあるけど、
Android には存在しない。でも使ってるのは良く見かける。
(ViewPager なんかと合わせて使う「・●・・・」みたいなやつ。)

Android ではアプリがみんな独自に実装してるっぽい。
こういうのをデザインサポートライブラリに入れればいいのにねぇ。



2017/06/07 Android の UITableView
iPhone には UITableView を使ってリストの項目を左にスワイプすると
「削除」が出てきたりするけど、Androind には当然そんな UI パーツはない。
たまに Android でも使ってるのは見かけるけど、気が付かないよね。コレ。

Android では iPhone をマネしてアプリが独自に実装してるっぽい。
こういうのをデザインサポートライブラリに入れればいいのにねぇ。



2017/04/12 Android NDK r14b
Android NDK r14b がリリースされた。
少数のバグ修正リリース。

今後の gcc サポートは長くない。

・XSIので『strerror_r』 統合されたヘッダーを持つアンドロイド23まで入手可能ではないのを修正。?
・Windows版の toolchains で __ANDROID_API__ が追加されていなかったのを修正。?
・mips32のためのスタンドアロンのtoolchainsによってgnustlヘッダーを見つけることができないのを修正。?
・偶然露出されたnon-NDK API Vulkanヘッダーを削除。
 非APIヘッダー自身の機能は暴露されなかった。従って、これらはとにかく使用可能ではなかった。
・RTTIと例外は、デフォルトで現在オンである。
 これは、高められた互換性のために既存のCMakeプロジェクトによってされた。



2017/04/10 Android NDK r14
Android NDK r14 がリリースされた。


2017/03/20 singleLine は本当にいらない?
Deprecated になった singleLine の変わりとしてよく紹介されている
項目の値を設定をしても期待した動作にならない事が多くて困る。

android:lines="1"
android:maxLines="1"
android:minLines="1"
android:scrollHorizontally="true"

singleLine を呼ぶと内部で何かのフラグを立てるらしいけど、
他の設定に置き換えてもそのフラグが立たないらしい。それが原因?
どうにかならないのかなぁ。



2017/03/17 TextView#setText で落ちる
Android 2.3 の端末だと問題ないのに 4.4 と 5.0 だと
TextView#setText を実行して落ちる。

java.lang.ArrayIndexOutOfBoundsException: length=49; index=-1
    at android.text.StaticLayout.calculateEllipsis(StaticLayout.java:679)
    at android.text.StaticLayout.out(StaticLayout.java:643)
    at android.text.StaticLayout.generate(StaticLayout.java:427)
    at android.text.StaticLayout.(StaticLayout.java:144)
    at android.widget.TextView.makeSingleLayout(TextView.java:6484)
    at android.widget.TextView.makeNewLayout(TextView.java:6330)
    at android.widget.TextView.checkForRelayout(TextView.java:6869)
    at android.widget.TextView.setText(TextView.java:4086)
    at android.widget.TextView.setText(TextView.java:3944)
    at android.widget.TextView.setText(TextView.java:3919)

ソースを確認してもおかしい部分はない…。
calculateEllipsis って出てるから省略文字の計算で失敗してる?

とりあえずググったら singleLine を入れろとあったので試してみた。

android:lines="1"
android:ellipsize="start"
android:singleLine="true"

落ちなくなった…これってOSの不具合なんじゃないかと。

singleLine は Deprecated なんだけど、使わないと正常に動かないケース多過ぎ。



2017/02/26 NDK の sprintf で SJIS が使えない
新しい端末が手に入ったのでアプリを動かしたら文字列が表示されないバグを発見。

原因を調べると sprintf が 0 を返して文字列をバッファに入れていなかった。
Android 5.0 以降では sprintf で文字列に SJIS が含まれると処理を中断するように
なっていたようだ。

対策としてはソースを UTF-8 にすること。
何らかの理由で取得するデータが SJIS の場合は UTF-8 に変換してから
sprintf に渡して文字列を形成する。

かなり面倒だけど sprintf を自作する方法もある。



2017/02/16 Android Studio 2.2.3
Android Studio 2.2.3 で「Instant Run」を使ってアプリ作成してて気づいた。
たまに実行しても修正内容が反映されて無い時がある…

どうも xml の修正は反映されないっぽい?

そんな時は端末の USB ケーブルを抜き差しすると改善されるけど面倒だなぁ。



2017/02/06 リスト選択のアニメーション
ListView の項目をタップした時のアニメーションを他のパーツに適用する方法。

android:background="@android:drawable/list_selector_background"

これは OS 側で用意されている設定なので Android のソースを参照すれば中身が見れる。
frameworks/base/core/res/res/drawable/

アニメーションだとこっちのパス。
/frameworks/base/core/res/res/anim/

当然だけど参照するソースの Android バージョンによって内容が違う可能性がある。


ListView の標準の Selecter はこれらしい。
「android:background="?android:attr/activatedBackgroundIndicator"」



2017/01/27 onActivityResult の引数
Android では前の画面から戻ってきた場合に onActivityResult が呼ばれる。

@Override
void onActivityResult(int requestCode, int resultCode, Intent intent)

requestCode は startActivityForResult(intent,REQUEST_CODE) の第二引数を返す。
resultCode は setResult(RESULT_OK,intent) の第一引数を返す。
intent は setResult(RESULT_OK,intent) の第二引数を返す。

resultCode は下記の値(int 型)が使用できる。

RESULT_CANCELED 0 キャンセルされた
RESULT_FIRST_USER 1 自分で定義する結果コードの最初の値
RESULT_OK -1 結果成功

独自の値も定義して使用できる。

final int RESULT_YES = RESULT_FIRST_USER + 0
final int RESULT_NO = RESULT_FIRST_USER + 1
final int RESULT_RETRY = RESULT_FIRST_USER + 2




2017/01/22 Android Studio のビルド切り替え
Android Studio でビルド (Debug, Release) を切り替えるにはウインドウの
左側にある縦型タブの下側にある「Build Variants」をクリックする。
これでデバッグとリリースを切り替えれるウインドウが表示される。

もしくはメニューの「Build」→「Select Build Variant...」を
選択しても切り替えウインドウが表示される。

また、build.gradle を修正して Build Variant を増やせる。

android {
  ...(省略)

  productFlavors {
    develop {
      applicationId "com.develop.testapp"
      versionName "1.0.0 (dev)"
    }
    products {
      applicationId "com.products.testapp"
      versionName "1.0.0"
    }
  }
}

上記修正を加えると Build Variant は4つに増える。
developDebug
developRelease
productsDebug
productsRelease

ソースも別々に読み込ませることも可能になる。
※ただし、AndroidManifest.xml だけは結合されるので注意すること!
src\main\  共通のソースコード
src\main\develop  develop 用のソースコード
src\main\products  products 用のソースコード

直接パスを記述する事も可能。
android {
  ...(省略)

  sourceSets {
    main {
      java.srcDirs = ['src/main/java']
      res.srcDirs = ['src/main/res']
    }
    develop {
      java.srcDirs = ['src/demo/java']
      res.srcDirs = ['src/demo/res']
    }
  }
}



2016/12/29 Android.mk のパスを指定する
ndk-build を実行すると jni フォルダの中にある Android.mk が処理される。

Android.mk 以外のファイルを指定したい場合や jni フォルダ以外を対象にもできる。

パッケージ名が TestApp ならこんな感じ。
ndk-build APP_BUILD_SCRIPT=$(APP_PROJECT_PATH)/TestApp/jni/Android.mk

これは最初に読み込むメイクファイルを指定する方法なので、
include $(call all-subdir-makefiles) を使ってサブフォルダを検索するケースでは
サブフォルダ内の Android.mk 以外を指定する事はできない。



2016/11/01 Android NDK r13b
Android NDK r13b がリリースされた。
少数のバグ修正リリース。

今後の gcc サポートは長くない。

・simpleperf を追加した。これは Android 用の CPU プロファイラ。
・__cxa_bad_cast の間違いを修正。



2016/10/07 Android NDK r13
Android NDK r13 がリリースされた。
ビルド環境の移行および修正。

今後の gcc サポートは長くない。

・NDK_TOOLCHAIN_VERSION の標準を Clang に変更した。
・libc++ を r263688 にアップデートした
・make-standalone-toolchain.sh は Python 版をラップした簡単なもの。
・サポートしないABIのライブラリを削除。(mips64r2, mips32r6, mips32r2, 32bitMIPS)

C++ライブラリの例外補足は ARM の Gingerbread および Ice Cream Sandwichで
動作しない。これらは Marshmallow and N で提供される?



2016/09/14 Android で低レイテンシの再生
特に興味は無いんだけど Android 4.2 から低レイテンシの再生に対応していたらしい。

ただし、低遅延で動作させるには条件があり、ハード側(端末)だけでなく
ソフト側でも下記条件を考慮する必要がある。

1. 指定されたサンプリング周波数で再生する。(最近だと 48KHz)
2. 指定されたサンプル数の倍数でバッファを構成する。
3. エフェクトを使用しない。

端末や OS バージョンに依存するかも知れないけど、
1と3は必須で考慮しなければ低遅延の動作モードにならない。
 ※48KHz の場合に 44.1KHz を使うのは NG。未確認だけど 96KHz は OK らしい。
2に関しては守れば+αで低遅延になるっぽい。影響度は低い。

AudioManager の getProperty から上記に関連する値を取得できる。
 ※文字列での取得になるので整数型への変換が必要。
AudioManager am;
String str;
am = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
str = am.getProperty(AudioManager.OUTPUT_SAMPLE_RATE);
str = am.getProperty(AudioManager.OUTPUT_FRAMES_PER_BUFFER);

OpenSL ES の場合は3を考慮する為に CreateAudioPlayer で
SL_IID_ANDROIDSIMPLEBUFFERQUEUE, SL_IID_PLAY だけを指定する。
SL_IID_EQUALIZER を追加すると低遅延モードにならない。



2016/07/02 Android NDK r12b
NDK r12b がリリースされた。
小規模なバグ修正。

・ndk-gdb.py を修正。
・NdkCameraMetadataTags.h を更新。
・ndk-build のバグで libc++ 使用時の正しくない警告を修正。
・android-24 の OpenSLES ヘッダを更新。

ARM Hard Float ABI Removal
https://android.googlesource.com/platform/ndk/+/ndk-r12-release/docs/HardFloatAbi.md



2016/07/01 Android NDK r12 検証2
google の NDK ダウンロードの x86 と x64 が逆なのがやっと直ってた。

前回の e=216 の原因はツールチェインの指定が原因だった…。

Application.mk から次の2行を消す。
APP_ABI := armeabi-v7a-hard
NDK_TOOLCHAIN_VERSION=clang

これでビルドが通るようになった。



2016/06/20 Android NDK r12 検証
google の NDK ダウンロードのファイルが x86 と x64 が逆になってる…
とりあえず 64bit の方の x86 をダウンロード。

armeabi-v7a-hard のビルドチェック。
やっぱりエラーになった。

Android NDK: armeabi-v7a-hard is no longer supported. Use armeabi-v7a.
Android NDK: See https://android.googlesource.com/platform/ndk/+/master/docs/Har
dFloatAbi.md
Android NDK: NDK Application 'local' targets unknown ABI(s): armeabi-v7a-hard

Android NDK: Please fix the APP_ABI definition in C:/eclipse/workspace/testjni2/
jni/Application.mk
c:/android_ndk/build//../build/core/setup-app.mk:120: *** Android NDK: Aborting

とりあえず armeabi-v7a-hard を外すとまたしてもエラー。

[armeabi-v7a] Compile thumb : testjni <= testjni.c
process_begin: CreateProcess(ほにゃらら) failed.
make (e=216): Error 216
make: *** [C:/eclipse/workspace/core/dw_plug/obj/local/armeabi-v7a/objs/testjni/
testjni.o] Error 216

これって x86 パッケージの中に x64 バイナリが混ざっているってことじゃないかと。
NDK r12a が出るのは確定ですか。



2016/06/18 Android NDK r12
NDK r12 がリリースされた。
今回の修正内容は互換性にも大きく影響する。

・Clang を 3.8svn (r256229, build 2812033) に更新。
・Clang が標準になって、次回リリースより gcc は削除される。
・make-standalone-toolchain.sh は削除される。
 代わりに make_standalone_toolchain.py を使って欲しい。
・armeabi-v7a-hard ABI は削除された。詳しくはドキュメント参照。
・Android 2.3.3 (API Level 10) は削除された。
・使用できない ARM (non-thumb)用の STL libraries は削除された。
・android-24 で Vulkan サポート。
・android-24 で Choreographer API サポート。
・libcamera2 APIs は INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED を
 サポートした機器用。詳しくは CameraCharacteristics を参照。
・その他いろいろ。


Android 2.2 (API Level 8) 以下のサポートが無くなったので古いアプリのビルドは不可。
Android 2.3.1 (API Level 9) は残っている。



2016/04/02 Android NDK r11c
今回も変更は少なくてスクリプト系の修正。
Windows-32bit環境のツールチェインパスが修正されたのでビルドエラーが直った。



2016/03/26 Android NDK r11b
変更は少なくてスクリプト系の修正。



2016/03/12 Android NDK r11 のバグ?
早速 Android NDK r11 を使ってみると問題が発生。

ビルドを実行するとなぜかエラーになる。
failed.
make (e=3): wウスpXェゥツゥワケB

どうも参照しているパスが存在しないっぽい。
ndk-build で gcc の参照しているパス
C:\android-ndk-r11\toolchains\arm-linux-androideabi-4.9\prebuilt\windows-x86

実際のパス構成
C:\android-ndk-r11\toolchains\arm-linux-androideabi-4.9\prebuilt\windows

とりあえず参照パスと同じになるようにフォルダ名に -x86 を
付けたらビルドが失敗しないようになった。

Clang の場合はこちら。
C:\android_ndk\toolchains\llvm\prebuilt\windows-x86

64bit環境だと -x64 になるのかなぁ?



2016/03/10 Android NDK r11
Android 6.0 発表の時はスルーされたけど、N 発表でやっとNDKが更新された。

コンパイラは GCC ではなく Clang が推奨らしい。
バグがあったら報告してくれだそうな。

・Clang を 3.8svn (r243773, build 2481030) に更新。
・GCC は非推奨。5.0 にはアップデートしない。バックポートもしない。
・GCC 4.8 を削除。GCC 4.9 だけ使用可能。
・android-23 に tracing API, multinetwork API を追加。
・Vulkan のヘッダとライブラリ (API level N.)
・ドキュメントは含まれないので Web サイトを参照。
・その他いろいろ



2016/02/09 Android Studio 2.0 Beta
2015/11 に発表された Android Studio 2.0 Preview 版が
Android Studio 2.0 Beta になってダウンロード可能に。

差分ビルド&実機転送で高速に実行できる「Instant Run」が特徴なのは変わらず
Preview 版からの新規の追加機能は特に無いみたい。

Android のエミュレータは新しくなっているらしい。

Ver 1.x は安定しているように思えなかったから使うのはパスしたけど、
正式版になったらまた試してみようかなー。



2016/01/02 printf を使うとエラーになる
Visual Studio 2013/2012 で sprintf を使うとセキュリティの問題があるとエラーになる。

VS2010 以前では警告が出るだけでエラーにはならなかったのに…。

対処としてはセキュリティ強化版の sprintf_s を使うか、設定変更をする。
設定は「構成プロパティ」→「C/C++」→「SDLチェック」を
「いいえ (/sdl-)」に変更するとエラーではなく警告に変化する。



2015/12/20 Android NDK の ShiftJIS 対応
Android NDK で ShiftJIS のビルド実験。

ダメ文字「"表"、"ソ"」を含まなければビルドには問題ない。

ダメ文字を含んだ状態でビルドする為に Android.mk に追記。

LOCAL_CFLAGS += --input-charset=cp932

これでビルドするとエラーが出る。

cc1plus.exe: error: no iconv implementation, cannot convert from cp932 to UTF-8

このエラーは gcc が iconv に対応しないビルドで生成されると出るらしい。
NDK の gcc を iconv 対応でリビルドすれば対応可能なのかも知れない。

※Windows 版の NDK で発生する問題で Linux 版では発生しないらしい。



2015/12/11 Android 静的ライブラリのリンク
NDK で jpeglib と libpng をビルドして普通にリンク。

Android.mk の静的ライブラリのリンク指定は2種類ある。

LOCAL_STATIC_LIBRARIES += libjpeg libpng



LOCAL_WHOLE_STATIC_LIBRARIES += libjpeg libpng

の2種類がある。

LOCAL_WHOLE_STATIC_LIBRARIES を使うと生成されるバイナリのサイズが大きくなる。
この指定は未使用関数も全てリンクするオプションっぽい。



2015/11/29 Android スリープ中の定期動作
スリープ中にタイマーは動作しない?インテントは受け取れない?
でもスレッドは動作している。

ググると PendingIntent と AlarmManager とサービスを使う方法が紹介されている。
setInexactRepeating に AlarmManager.RTC_WAKEUP を指定して第3引数に
インターバルを指定すればできるっぽい。




2015/11/02 Assets からアプリ領域にコピー
Assets は専用 API で読み出し可能だが、書き換え不可やサイズ制限があるので
必要容量が大きくなってしまうがアプリ領域にコピーしてしまえば
これらの制限は無くなり、扱いやすくなる。

で、コピーするコードをいくつか作ってみたけど、失敗したのを紹介。

InputStream input = am.open( "data/" + arrStrPath[i] );
fcout = (new FileOutputStream(file)).getChannel();
ReadableByteChannel ch = Channels.newChannel(input);
fcout.transferFrom( ch,0,Long.MAX_VALUE );

ファイルは作成されるが、途中で例外が発生してサイズ0?

さらにもう一つ。

AssetFileDescriptor afd = null;
afd = am.openFd( "data/" + arrStrPath[i] );
file.createNewFile();
FileChannel src = new FileInputStream(afd.getFileDescriptor()).getChannel();
FileChannel dst = new FileOutputStream(file).getChannel();
long size = src .size();

size が Assets の全体サイズになる。コピーは Assets の塊ファイル。

普通に InputStream と OutputStream でコピーするのが安全。

input = am.open( strAssetsPath );
byte[] buffer = new byte[4096];
int read;
while( (read = input.read(buffer)) != 0 )
{
    output.write( buffer,0,read );
}



2015/10/22 Android setFlags と addFlags
setFlags と addFlags の違いが気になったので Android のソースを見てみた。

/frameworks/base/core/java/android/view/Window.java
public void addFlags(int flags) {
    setFlags(flags, flags);
}

結局、setFlags が呼ばれるので結果は同じだった。




2015/10/21 Android GPU アクセラレーション有効確認。
設定の「 GPU アクセラレーション」が無効の状態でアプリから
GPU アクセラレーションを使用にするのは3つの方法がある。

1. AndroidManifest.xml に記述する。
2. Window に FLAG_HARDWARE_ACCELERATED を設定する。
3. View に View.LAYER_TYPE_HARDWARE を設定する。

「GPU アクセラレーション」が有効か確認する API として
View#isHardwareAccelerated と Canvas#isHardwareAccelerated がある。

View#isHardwareAccelerated は Window の FLAG_HARDWARE_ACCELERATED が
有効にされているかどうかで true,false を返す。

よって、View.LAYER_TYPE_HARDWARE を設定したり、設定「GPU アクセラレーション」、
AndroidManifest.xml のGPU設定を有効にしても true にはならない。

Canvas#isHardwareAccelerated は常に false になる。
隠し API や API Lv 23 の lockHardwareCanvas を使うと true になるらしい。

AndroidManifest.xml で有効にしたのを確認するには ActivityInfo を使う。
PackageManager pm = getPackageManager();
ActivityInfo info = pm.getActivityInfo( getComponentName(),0 );
if( (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) > 0 )
    return true;



2015/10/17 Android Bitmap 拡大縮小
Bitmap を拡大縮小して Canvas に描画する方法は複数ある。

これが一般的?
Bitmap bitmap = 生成;
Paint paint = new Paint();
Rect rs = new Rect( 0,0,BMP_WIDTH,BMP_HEIGHT );
Rect rd = new Rect( px,py,scale_width+px,scale_height+py );
canvas.drawBitmap( bitmap,rs,rd,paint );

Matrix を使う方法。
Bitmap bitmap = 生成;
Paint paint = new Paint();
Matrix matrix = new Matrix();
matrix.setTranslate( px,py );
matrix.setScale( scale,scale );
canvas.drawBitmap( bitmap,matrix,paint );

BitmapDrawable を使う方法。
この拡大縮小にはアンチエイリアスが適用されるが処理が非常に重い。
必要に応じて drawable.setFilterBitmap( false ) で無効にする。
Bitmap bitmap = 生成;
BitmapDrawable drawable = new BitmapDrawable( bitmap );
drawable.setBounds( px,py,scale_width+px,scale_height+py );
drawable.draw( canvas );



2015/10/12 Android のナビゲーションバー非表示
ナビゲーションバー(Back,Home,Task のボタン領域)を非表示にする方法を探してみた。
Android 4.x 系で非表示に出来るけど画面タッチすると強制的に再表示される。
動画プレイヤーアプリとかならこれでも良いかも知れないけど…。
Android 5.x 系なら完全非表示が可能だとか。

View view = getWindow().getDecorView();
view.setSystemUiVisibility( View.SYSTEM_UI_FLAG_HIDE_NAVIGATION );

試してみたけど Android 4.0 端末で非表示にならない…。
でも Android 4.3 端末では非表示になるのでコードは間違っていないみたい。

API Level 14 ってなってるけど実際に使えるのは 15 なのかな?

バージョン API Level コードネーム
Android 3.2 13 Honeycomb MR2
Android 4.0 14 Ice Cream Sandwich
Android 4.0.1
Android 4.0.2
Android 4.0.3 15 Ice Cream Sandwich MR1
Android 4.1 16 Jelly Bean




2015/10/10 Android NDK の SLresult
Android NDK で OpenSL が使えるようになったのは Android 2.3(API Lv 9) から。
その時の SLresult の定義は unsigned long だった。

OpenSLES_Platform.h
typedef unsigned long sl_uint32_t;

SLES/OpenSLES.h
typedef sl_uint32_t SLuint32;
typedef SLuint32 SLresult;

それがいつの頃からか API Level 14 以降で定義が変更になり
typedef unsigned long sl_uint32_t;
typedef signed long sl_int32_t;

から

typedef unsigned int /*long*/ sl_uint32_t;
typedef signed int /*long*/ sl_int32_t;

に変更された。

int か long かの違いは 64bit 環境では 4byte,8byte と大きな違いがあるので
コンパイラのチェックが厳しくなっている。古いコードを新しい API Level に
変更すると警告が出てきたりと結構面倒。

NDK の更新忘れのような気もするけど…。



2015/09/06 android sdk build-tools
Android SDK 22 からビルドツールが分離された。

アップデートで問題があっても古いビルドツールが使えるようになっている。
project.properties に build-tools のバージョンを指定する。

sdk.buildtools=18.1.1



2015/09/05 Android API 21
Android 5.0 用のアプリを作ろうかと Android SDK Manager で
API Level 21 (5.0.1) を追加したけどエラーが出て APK が生成できない。

'Loading data for Android 5.0.1' has encountered a problem.
Parsing Data for android-21 failed
unsupported major.minor version 51.0

なんでも JAVA SDK を JDK 1.8 を入れないとダメらしい。
初期の頃は古い JDK 1.6 が推奨だったので少し驚き。

JDK 1.8 を入れたら問題なく動いた。



2015/08/16 デフォルトライブラリがリンク出来ない
VS2008 からランタイムライブラリの「シングルスレッド」が無くなり、
必ずマルチスレッドになるようになった。

これによって古いVCでビルドした「シングルスレッド」の
スタティックライブラリを VS2008 で使おうとすると
「LINK : fatal error LNK1104: ファイル 'LIBC.lib' を開くことができません。」
が発生してしまう。

VS2008 の プロジェクト → プロパティ → 構成プロパティ → リンカ から

入力 の「特定の既定のライブラリの無視」に「LIBC.lib」 を指定すると回避できる。



2015/07/26 targetSdkVersion
AndroidManifest に記述した targetSdkVersion で動作や見た目が変わる。

Android OS バージョンによってデフォルトのテーマ(背景色等)が異なる場合があるが、
targetSdkVersion が設定されていればバージョンが変わっても古いバージョンの
テーマが使用される。
targetSdkVersion が 8(Ver2.2) だとナビゲーションバーにメニューボタンが現れる。

また、GC の動作が古い処理に置き換えられる事もあるらしい。



2015/07/02 eclipse のヒープサイズ
eclipse は java で動作しているので java で確保されたヒープ内で動作する。
その為、巨大なリソースを扱うプロジェクトではヒープが足りなくなり、
操作中に eclipse が突然、強制終了される事になる。

そんな時は eclipse をインストールしたフォルダにある eclipse.ini を書き換える。

-XX:PermSize=48m
-XX:MaxPermSize=512m
-Xms256m
-Xmx1024m
-Xms は起動時に確保するヒープサイズ。
-Xmx はヒープが足りなくなった場合の拡大可能な最大サイズになる。
-XX:PermSize は起動時に確保するパーマネントサイズ。
-XX:MaxPermSize はパーマネントが足りなくなった場合の拡大可能な最大サイズになる。

パーマネントはクラスファイルをメモリ上に展開する為の領域。

eclipse が確保するメモリが足りないとGCが頻発して遅くなるが、
足りている場合は増やしても速くなる訳ではない。

32bit版 Java で設定可能なヒープサイズは約 1.5GB でこれより大きな値を
指定すると起動しなくなる。64bit版ならこの制限は無い。



2015/07/01 Android 端末のヒープサイズ
Android 2.x 端末は1つのアプリに割り当てる最大ヒープサイズは大抵 24MB。
カメラで撮影した高解像の画像を扱うと大量のメモリを扱うので
Bitmap クラスや ImageView が「Out of Memory」を起こしやすくなる。
画像処理アプリはヒープサイズが小さいと作るのも使うのも難しい。

Android 4.x の最大ヒープサイズは 24〜72MB と端末によって大きく異なる。

メモリが少ない場合は Android 3.0 から追加された LARGE_HEAP を使うと
ヒープサイズは 128〜256MB と激増する。



2015/06/19 Android タッチイベント
タッチイベントの初回は最上位の親 ViewGroup (RelativeLayout 等のレイアウト)の
dispatchTouchEvent から開始される。

dispatchTouchEvent が呼ばれると ViewGroup の中にある配置的に優先度の高い
View もしくは ViewGroup から順番にイベントを渡していく。
対象が View なら onTourchEvent が呼ばれ、
ViewGroup なら dispatchTouchEvent が呼ばれる。

ViewGroup の中の全ての View,ViewGroup が true を返さなければ
ViewGroup 自身の onTourchEvent が呼ばれる。

true を返すか、View が無くなるまでこの処理を繰り返す。



2015/06/04 Android Timer のスレッドタイプ
Timer クラスのコンストラクタにはスレッドタイプを指示する boolean がある。
true ならデーモンススレッド、false ならユーザースレッドで動作する。

デーモンスレッドはメインスレッドが終了したら強制的に終了、
ユーザースレッドはメインスレッドが終了しても動作する。

Android では onDestroy が呼ばれても即プロセスは終了しないので、
指定がデーモンスレッド動作だとしてもタイマーは止まらない。

スレッドタイプに関わらず終了時にタイマーは止めた方が安全。



2015/05/29 activity 起動時に IME が出ないようにする
UI が画面に納まらないので ScrollView を使うように変更したら
起動時に EditText にフォーカスが当たって IME が表示されるようになった。

画面位置も EditText まで勝手にスクロールしてしまうのですごく邪魔。
対策方法は無いのかとググってみると focusable と focusableInTouchMode を
制御する方法があるらしいがなんか面倒な実装に思える。

別の方法が無いかと探してみるとやっぱりあるじゃない。
getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);

注意点は setContentView の前に呼ぶ必要があるのと、LayoutParams は
WindowManager の LayoutParams を使うこと。
import android.view.WindowManager.LayoutParams;

これで起動時に IME が表示されなくなるし、
EditText をタップすれば IME がちゃんと表示される。



2015/05/17 Android NDK r10e リリース
Android の「次期バージョンMが出るよー」とアナウンスがあったので
NDK が更新されそうだなと思っていたらやっぱり更新されてた。

主な変更点はこんな感じ。
・Cortex-A53 のエラッタ修正。
・Clang 3.6 を追加。(デフォルト使用)
・Clang 3.4 削除。
・GCC 4.6 削除。
・ld.gold を使ったマルチスレッド対応。--threadsオプションで有効になる。
・GDB/gdbserver を 7.7 に更新。
・Mac OS の 32bit NDKパッケージを今回から削除。
・細かいバグ修正が多数。

Mac OS は 64bit 環境だけ対応することになったみたい。



2015/05/05 SDカードの読み込み権限
Android 4.4 以降では SDカードの読み込みにも権限が必要になった。
これによってSDカードのファイルを読み込む古いアプリは動作しなくなる。

ただし、書き込み権限(WRITE_EXTERNAL_STORAGE)を設定しているアプリは
読み込み権限も同時に与えられるのでこの問題は発生しない。

開発対象が古い Android でも SDカードを読み込む必要があるのであれば
READ_EXTERNAL_STORAGE
を AndroidManifest.xml に記述しておく事をお勧めする。

READ_EXTERNAL_STORAGE を設定したアプリを 4.4 未満の端末に入れても動作する。
権限の要求を確認すると読み込み権限の表示は出ない。




2015/04/27 android デバッグドライバ
Android のドライバが無い場合は google 汎用ドライバの android_winusb.inf に
デバイスマネージャのプロパティからから確認できるハードウェアIDを
追記すれば使えるようになる事がある。
(特に中国製タブレット。)
C:\<Android SDK のパス>\extras\google\usb_driver
フォルダが存在しない場合は Android SDK Manager で
Google USB Driver をダウンロードする。

メーカーから提供されているドライバを入れても認識しないケースは
ユーザープロファイル(ログイン名)のパスにある
c:\<ユーザープロファイル>\.android\adb_usb.ini
にベンダーIDを書き加えると認識する場合がある。
このファイルの改行は LF(0x0a) なので CR-LF にしか対応していないエディタで
編集すると書き換えが有効にならない可能性があるので注意する。

本来、adb_usb.ini は自動生成されるファイルなので直接書き換えるのは良くない。
addon に端末の情報を記述した manifest.ini を作成し、下記のコマンドを実行する。
c:\<Android SDK のパス>\tools\android.bat update adb
これを実行しても adb_usb.ini が更新されない場合は
直接書き換えるしかない。

後はサーバーを再起動して端末を認識しているか確認。
adb kill-server
adb start-server
adb devices

これでデバイスIDが表示されて右に device と表示されれば完了。

device 以外が表示された場合の対処法。
unauthorized (権限が無い?)→ 端末を抜き差ししてサーバー再起動。
offline (認識したけど使用不可)→ Android SDK が極端に古いなら最新に更新。



2015/04/16 文字列の余白
Android で文字列を扱うとサイズが想定したドット数よりも大きくなる事が多い。

TextView で上下に余白が入らないようにする。
android:bufferType="spannable"
android:includeFontPadding="false"

EditText と Button はデフォルトでパディングが入っているので
パディング0を試してから値を設定するといいかもしれない。




2015/03/10 CRT の errno はスレッドセーフ
CRT の関数はエラー値をグローバル変数 errno に設定する。
コレってマルチスレッドでエラー値が正しく取れないケースがあるのでは?
と思って調べてみた。

とりあえず古い VC のヘッダを見てみた。
#if (defined(_MT) || defined(_DLL)) && !defined(_MAC)
_CRTIMP extern int * __cdecl _errno(void);
#define errno (*_errno())
#else
_CRTIMP extern int errno;
#endif

プロジェクトの設定で CRT を「シングルスレッド」にしていると
errno はグローバルな int 型だが、設定が「マルチスレッド」や「DLL」だと
_errno() の戻り値のポインタ参照先を返すマクロになっている。

このポインタの領域はスレッド毎に異なるスレッドローカルストレージを使っているので
複数スレッドで errno を書き変わる関数を実行しても各スレッドで正しい値が取れる。

Linux の errno もスレッド毎に異なる領域が割り当てられるのでスレッドセーフらしい。



2015/02/22 Android SDK の ADB コマンド
パッケージ:com.hoge.hallo
パス:c:\workspace\hallo.apk

アプリのインストール(新規)
adb install c:\workspace\hallo.apk

アプリの上書きインストール(インストール済み)
adb install -r c:\workspace\hallo.apk

アプリのアンインストール
adb uninstall com.hoge.hallo

アプリのアンインストール(データ、ディレクトリ保持)
adb shell pm uninstall -k com.hoge.hallo

インストールされたアプリの確認
adb shell pm list packages

アプリのプロセス停止(要ルート権限)
adb shell kill プロセスID

アプリの起動
adb shell am start -n com.hoge.hallo

アプリの強制停止
adb shell am force-stop com.hoge.hallo

ファイルの送信
adb push 送りたいファイルのパス(PC) 受け取りパス(Android)

ファイルの受信
adb pull 取り出したいファイルのパス(Android) 受け取りパス(PC)

ログの受信(CTRL-Cで解除するまで常時更新される)
adb logcat

ログの受信(バッファ済みのみ表示)
adb logcat -d



2015/02/01 NewGlobalRef と NewLocalRef
NewLocalRef は JNI 関数の呼び出し中だけ有効な参照カウンタらしい。
これって DeleteLocalRef でカウンタを減少する意味があまり無いような。

関数内で大量の参照カウンタが発生する場合は DeleteLocalRef を使用しないと
メモリが不足するかも知れないけど数回なら大丈夫なんじゃないかと思ってしまう。

NewGlobalRef は名前からわかるように長期的な参照カウンタ増加になる。
JNI 側でグローバル変数にJAVAオブジェクトを保持する場合に必要。

java でこんな感じのコードを書くなら JNI 側で参照カウンタを増加させないと
次の GC でクラスインスタンスが破棄される事になる。
setCallback( new CallbackSub() );

そんな時は NewGlobalRef を使用する。
jcls = (*env)->GetObjectClass( env,obj );
g_jcls = (jclass*) (*env)->NewGlobalRef( env,jcls );

Android 5.0 の ART でも大丈夫かな…



2015/01/19 メインスレッド以外からの描画
Android ではメインスレッド以外からの描画は出来ない制限がある。

一般的な回避策としてメインスレッドで生成した Handler に post する方法。
これであればメインスレッドで描画処理が実行できる。
Handler mHandler;
mHandler = new Handler(); // UIスレッドで生成すること!

// 別スレッドから post する。
mHandler.post( new runDrawClass() );

メインスレッドで Handler を生成するのが面倒な場合は
getMainLooper() でメインスレッドを指定して生成する方法もある。
import android.os.Looper;

handler = new Handler(Looper.getMainLooper());

他にも方法が無いのかと探してみると Activity#runOnUiThread があった。
Activity のインスタンスにアクセスできるクラスなら便利。

void runOnUiThread(Runnable action)

単純に描画要求だけなら invalidate() ではなく postInvalidate() を使う。



2015/01/16 Android SurfaceView の VSync
SurfaceView のチラツキが気になったので調べて見た。

Android 4.1(Jelly Bean) のバージョンアップの変更点で
・16msの垂直同期に合わせる
・トリプルバッファリング
とあったので Android 4.0.x までは VSync に合わせる事はしていなかったようだ…。

垂直同期は unlock のタイミングで合わせているらしい。
canvas = holder.lockCanvas();
// 描画処理
holder.unlockCanvasAndPost( canvas ); // 同期待ち発生?

Android 4.1 以降では描画処理がギリギリだと処理落ちする可能性が高いかも。



2015/01/09 カスタムView のコンストラクタ Lint エラー
古いプロジェクトを引っ張り出して apk を作成しようとしたら
コンストラクタでエラーが出た。

どうやら必要な public のコンストラクタが無いと言われているらしい。
This class should be public (com.testOpenGL.GLSView)

文法に問題は無く、古い開発環境だとこのエラーは発生しない。

原因を調べると xml でカスタム View を貼り付けた場合に、
貼り付けた View のコンストラクタで Lint がエラーを出しているのを確認した。
<com.testOpenGL.GLSView
  android:id="@+id/surfaceView1"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
/>

他のプロジェクトも GLSurfaceView を継承して作成したクラスを
xml に貼り付けるとエラーになっていた。
でもなぜか SurfaceView だと発生しない。はて?

もっとも簡単な対処方法は Lint のエラーを発生しないように変更すること。
プロジェクトを右クリック → Properties を選択、
Android Lint Preferences の項目から「Instantiatable」を選択、
「Fatal」を「Warning」に変更する
これで警告に変更される。


コード修正で直すなら GLSurfaceView を直接 xml に貼り付けて、
レンダラだけを登録する方法。
<android.opengl.GLSurfaceView
  android:id="@+id/surfaceView1"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
/>

Activity はこんな感じ。
_renderer = new EntryRenderer();
_surface = (GLSurfaceView) findViewById( R.id.surfaceView1 );
_surface.setRenderer( _renderer );

この方法だとタッチ処理を GLSurfaceView 継承クラスで行っていた場合に
Activity 側にタッチ処理を移動する必要があるので注意。



2015/01/05 Android SDK のレイアウト互換性2
レイアウトのUIパーツの id は重複しても構わない。
古い開発環境では同じファイル内で重複IDがあってもエラーにならない。

状態 古い開発環境 最新の開発環境
ファイル内の重複ID 許可 エラー
異なるファイルでの重複ID 許可 許可

重複IDは使い方を誤るとバグの原因となる可能性もあるが、
onCreate の setContentView で読み込むレイアウトを可変にしても
ID が全て同じであれば Java コードを変更する必要が無い。

端末の解像度に合わせてレイアウトを複数持つケースでも役に立つ。



2015/01/04 Android SDK のレイアウト互換性
古いプロジェクトを最新の環境でビルドするとエラーは出ないが
apk パッケージを作成しようとするとエラーで弾かれた。

どうやらレイアウトの XML でエラーが出ている。
android id definitions *must* be of the form @+id/name

古い開発環境ではこのエラーは発生せず apk を作成できる。

UIパーツの ID を id 以外に割り振るとエラーが出る。
android:id="@+idsub/txtValue"

調べてみると google が id 以外に割り振れたのが SDK のバグと言ってる感じがする。

解決策は開発環境を古いものに戻すか、全てのコードで id に修正する。
android:id="@+id/sub_txtValue"

これ、修正するとなると Java コードも修正だから面倒だよね。



2014/12/28 Android Studio 1.0 を試す。
Android Studio に eclipse からプロジェクトをインポートしてみる。
コメント行やコードの日本語が文字化け。

Android Studio の設定で使用する標準フォントを日本語対応のフォントに
変更しても効果なし。

ソースコードの文字コードが ShiftJIS なのが怪しいので
文字コードを UTF-8 に変換してからインポートすると、問題は発生しなかった。

ShiftJIS のまま扱うには Android Studio 起動時の初回メニューから
インポートの設定を ShiftJIS に変更してからインポートを行う。

ビルドするとこんな感じでエラーが出る。
Error:(27, 8) 繧ィ繝ゥ繝シ: 縺薙?ョ譁?蟄励?ッ縲√お繝ウ繧ウ繝シ繝?繧」繝ウ繧ーUTF-8縺ォ繝槭ャ繝励〒縺阪∪縺帙s

さらに環境変数で Javaコンパイラが ShiftJIS でコンパイルするように変更する。



2014/12/10 Android NDK r10d がリリース。
Android 公式の新しい開発環境 Android Studio 1.0 がリリース。
さらに Android NDK r10d もリリースされてた。

変更点はバグ修正がメインみたい。いろいろ修正されている。
後は gcc 4.6 がツールチェインから削除されたくらいか。



2014/12/01 LibFlac 1.3.1
LibFlac が Version 1.3.1 にアップデート。
主な変更点はこんな感じ。

・デコードの量子化処理の改善、特に24bit時のx86。
・SSE、AVXを使った高速なエンコード。
・新しいエンコード処理の追加、それのプリセット追加。
・デコード機能の脆弱性を修正。

stream_decoder.c にはスタックベースのバッファオーバーフローの脆弱性が存在し、
Version 1.3.1 未満の全バージョンにこの問題があるとのこと。

なお、LibFlac 1.3.0 で 2GB 超えに対応した時に古いコンパイラへの対応が
無くなっているので古いソフトのアップデートには新しい開発環境が必要になるかも。



2014/10/22 Android NDK r10c
最近、Android 5 の正式発表があったので思った通りアップデートされてた。

前回 r10b までは 32bit と 64bit で異なっていたパッケージが ndk r10c では
1つに統合されて配布形式が 7zip の自己解凍形式に変更された。
(圧縮率を高くする為に 7zip にしたけどメジャーじゃないから自己解凍形式?)

今回のパッケージ名 ndk r10b の時のパッケージ名
android-ndk-r10c-windows-x86.exe android-ndk32-r10-windows-x86.zip
android-ndk64-r10-windows-x86.zip
android-ndk-r10c-windows-x86_64.exe android-ndk32-r10-windows-x86_64.zip
android-ndk64-r10-windows-x86_64.zip

ndk r10 32bit の解凍後は約4万ファイルの 1.5GB だったのが
今回は 64bit が統合されて約5万ファイルの 3.4GB まで増えている。

主な変更はこんな感じ。
・32bit , 64bit のヘッダ、ライブラリの統合。
・platforms に android-21 を追加。
・コンパイラの変更
 ・32bit でも 64bit と同じ gcc 4.9 を追加。
 ・gcc 4.6 は今後削除予定。
 ・clang 3.5 を追加。(clang のデフォルトも 3.5 に変更)
 ・clang 3.3 を削除。
・Android 5.0 の ART Debug に対応。
・バグ修正。



2014/10/20 Android 5.0 の互換性
Android L は正式に Android 5.0 となったみたい。
そして Android 5.0 は 64bit で動作するけど既存のアプリは動くのか?

JAVA でアプリを作ってるから「32bit,64bit なんて関係ないだろ」と
思うかもしれないけど、実は JAVA コードを解析実行する部分に変更が入っている。

Android の JAVA コード処理には Dalvik が使われてきたが 5.0 ではこれが
Android RunTime (ART) に変更されていて 100% の互換性があるかは不明。

Dalvik は実行時によく使われる部分をネイティブコードに変換して実行する。
ネイティブコードは保存されないので実行時に変換処理が毎回発生する。

ART ではアプリのインストール時に全てをネイティブコードに変換して
結果をストレージに保存して置くので初回のみ変換処理が発生する。

ART のメリットはアプリ全体を最適化できるのと実行時の変換負荷が無いこと。
また、GC の方式が改良されて効率が良くなっているらしい。
デメリットはインストール時の時間増加と容量増大。

実は Android 4.4 も開発者向けにお試し実装されていて
開発者オプション→「ランタイムを変更」→「ARTを使用する」
で ART を使用したアプリの実行が試せるらしい。
ART では JNI を使ったアプリが動かないとのウワサも。

ART に変更すると端末が再起動され、インストール済みアプリの
ネイティブコード変換が行われて実行可能になる。



2014/09/27 「GPUレンダリング使用」の制限
開発者向けオプションの「GPUレンダリング使用」をONにすると
画像処理が速くなる可能性がある。
ただし、一部のアプリでは正常に描画が行われない可能性があるので注意する。

この問題は拡大縮小をGPUのテクスチャ機能を使って行うので
画像サイズがハードウェアの限界サイズを超えると問題が発生する。

テクスチャの限界サイズを超えるとログに出力される。
W/OpenGLRenderer(4048): Bitmap too large to be uploaded into a texture (1800x2400, max=2048x2048)

Android OS は最低でも 2048x2048 のテクスチャを扱えることをハードウェアの
必須条件にしているので 2048x2048 まではどの端末でも問題ない。

「GPUレンダリング使用」がOFFの場合はCPUで全て処理するので
画像サイズに制限は無く、 2048x2048 以上も扱える。



2014/09/16 Android NDK r10b
Android NDK r10 がアップデートされてた。
変更内容は主に Android L (64bit) の問題修正。
従来の 32bit 環境向けはほとんど更新が無いように思える。

遅い気もするけど今回注意事項としてパッケージに512MBの制限があるから
Android L 用のヘッダや gcc4.9 は ndk64 にしか入れてないよとあった。

「ファイルが入ってない」と r10 リリースの時に問い合わせが多かったのかも。



2014/09/15 gcc の浮動少数からのキャスト
マイナスの浮動少数値を符号なし整数にキャストすると VC と gcc で結果が異なる。

double a = -1.0;
unsigned int b = (unsigned int)a;

printf( "b = %d",b );

VC だと結果は 0xffffffff (-1) になるが gcc だと 0 になる。



2014/09/06 OpenSL の再生終了通知
OpenSL で BufferQueue を使わずに直接ファイル (正確には URI や FileDescriptor) を
指定した再生で再生終了通知を得るには SLPlayItf インターフェースを使用する。

通知時に呼び出されるコールバック関数を用意して登録する。

static void PlayCallback(SLPlayItf caller, void *pContext, SLuint32 event)
{
 switch( event )
 {
  case SL_PLAYEVENT_HEADATEND:
  LOGI( "PlayerObject->Callback(SL_PLAYEVENT_HEADATEND)\n" );
  break;
 }
}

void reg_end_callback()
{
 SLresult result;
 // register callback on the PlayerObject
 result = (*fdPlayerPlay)->RegisterCallback( fdPlayerPlay,PlayCallback,NULL );
 result = (*fdPlayerPlay)->SetCallbackEventsMask( fdPlayerPlay,SL_PLAYEVENT_HEADATEND );
}

SetCallbackEventsMask で通知して欲しい種別を指定する。
SL_PLAYEVENT_HEADATEND
SL_PLAYEVENT_HEADATMARKER
SL_PLAYEVENT_HEADATNEWPOS
SL_PLAYEVENT_HEADMOVING
SL_PLAYEVENT_HEADSTALLED



2014/09/02 OpenSL の繰り返し再生
OpenSL で BufferQueue を使わずに直接ファイル (正確には URI や FileDescriptor) を
指定して繰り返し再生するケースでは SLSeekItf インターフェースを使用する。

(*fdPlayerSeek)->SetLoop( fdPlayerSeek,SL_BOOLEAN_TRUE,0,SL_TIME_UNKNOWN );

C++ではなくC言語なので第1引数は self を指定する。
次の引数から「有効無効、ループ開始位置(ミリ秒)、ループ終了位置(ミリ秒)」となる。
終了位置を最後にする場合は SL_TIME_UNKNOWN を指定する。



2014/08/29 OpenSL の圧縮ファイル再生開始の硬直
OpenSL で BufferQueue を使わずに直接ファイル (正確には URI や FileDescriptor) を
指定して OggVorbis を再生開始すると一瞬硬直してしまう。
(サイズ-1秒,圧縮時11KB,解凍時88KB-44KHz,16bit,mono)

BGMであれば画面が切り替わった時に再生するのでそれほど問題にならないが
効果音だと再生タイミングが不定な場合が多く都合が悪い。

FileDescriptor を指定してインターフェースを生成した時なら対処もできるが…
(*engineEngine)->CreateAudioPlayer( ... );

硬直するのは再生開始のタイミング…どうしましょ。
(*fdPlayerPlay)->SetPlayState( fdPlayerPlay,SL_PLAYSTATE_PLAYING );

自前で LibOgg,LibVorbis を利用してバッファキュー再生するしかないか。



2014/08/27 OpenSL で複数同時再生
移植で DirectSound や DirectAudio のコードを置き換える場合とか。

OpenSL を使って BGM と複数の効果音を同時に再生するには
SLObjectItf (AudioPlayer) を必要な分だけ複数生成すれば可能になる。

生成可能な個数は端末依存と思われる。16個くらいなら古い端末でも平気かも。

#define AUDIO_IF_NUM 10
static SLObjectItf g_engineObject;
static SLEngineItf g_engineEngine;
static SLObjectItf g_outputMixObject;
static SLObjectItf bqPlayerObject[AUDIO_IF_NUM];
static SLPlayItf bqPlayerPlay[AUDIO_IF_NUM];
static SLEffectSendItf bqPlayerEffectSend[AUDIO_IF_NUM]; //必須では無い
static SLMuteSoloItf bqPlayerMuteSolo[AUDIO_IF_NUM]; //必須では無い
static SLVolumeItf bqPlayerVolume[AUDIO_IF_NUM]; //必須では無い
static SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue[AUDIO_IF_NUM];

PCM の再生フォーマットが全て同じなら複数必要な IF を for 文で回して生成する。
バッファーキューのコールバックはどれから呼ばれても動作するようにするか、
個別にコールバック関数を用意するようにする。



2014/08/15 Android NDK r10 のパッケージ
NDK r10 から配布パッケージに Android L 用が追加された。

パッケージ名 開発環境 開発ターゲット
android-ndk32-r10-windows-x86.zip 32bit の Windows 系 OS Android 〜4.4
android-ndk32-r10-windows-x86_64.zip 64bit の Windows 系 OS Android 〜4.4
android-ndk64-r10-windows-x86.zip 32bit の Windows 系 OS Android L (64bit)
android-ndk64-r10-windows-x86_64.zip 64bit の Windows 系 OS Android L (64bit)

NDK r10 の変更内容は ndk32 と ndk64 の2つを合わせて記載しているので
新規追加したヘッダやライブラリが ndk32 に無くて ndk64 には入っている場合がある。



2014/07/22 Android NDK r10 で clang のバージョン
clang 3.4 でgccコンパイラ用のバージョンマクロを使うと…

sprintf( buf,"gcc ver %d.%d.%d\n",
__GNUC__,
__GNUC_MINOR__,
__GNUC_PATCHLEVEL__ );
LOGI( "%s",buf );

結果はなぜか古いバージョンが設定されている。

gcc ver 4.2.1

調べてみると clang 専用にバージョンマクロがあった。

記述 備考
__VERSION__ gcc なら "4.8"
clang 3.4 なら "4.2.1 Compatible Clang 3.4"
__clang__ gcc なら定義されないのでこれで判別できる。
clang なら値が 1 で定義される
__clang_major__ clang 3.4 なら値が 3 で定義される
__clang_minor__ clang 3.4 なら値が 4 で定義される
__clang_patchlevel__ clang 3.4 なら値が 0 で定義される
__clang_version__ clang 3.4 なら値が "3.4"



2014/07/21 Android NDK r10 で単体実行ファイル
NDK r10 でコンパイラを clang にして単体実行ファイルをビルドすると実行時に

[1] Segmentation fault /data/local/ndkexe

とセグメント例外で落ちるので調べてみた。

とりあえずコンパイラを gcc にすると発生しない。
clang のデフォルトは 3.4 なので clang3.3 を指定してみると問題ない。
単体実行ファイルを clang3.4 で作るとダメらしい。



2014/07/19 Android NDK r10 のコンパイラ選択
NDK で使用するコンパイラは Application.mk で指定可能だけど何が指定できるか
わからない時は NDK を展開したフォルダの toolchains を参照すればわかる。

NDK r10 の toolchains に存在するフォルダ一覧。
arm-linux-androideabi-4.6
arm-linux-androideabi-4.8
arm-linux-androideabi-clang3.3
arm-linux-androideabi-clang3.4
llvm-3.3
llvm-3.4
mipsel-linux-android-4.6
mipsel-linux-android-4.8
mipsel-linux-android-clang3.3
mipsel-linux-android-clang3.4
renderscript
x86-4.6
x86-4.8
x86-clang3.3
x86-clang3.4

フォルダ名の最後の -(ハイフン) より後ろの名前を Application.mk の
NDK_TOOLCHAIN_VERSION に指定するとそのコンパイラが使用される。

何も指定しない場合は NDK のデフォルト値が使われる。
NDK r10 では 4.8 (gcc 4.8.3) が使われる。

NDK_TOOLCHAIN_VERSION=4.6

とした場合は gcc 4.6 が使われる。

NDK_TOOLCHAIN_VERSION=clang3.3

とした場合は clang3.3 が使われる。

NDK_TOOLCHAIN_VERSION=clang

この場合は NDK r10 でデフォルトに設定されている clang3.4 が使われる。



2014/07/17 Android NDK r10
先日発表された Android L に対応。
変更内容を見ると64ビットアプリにも対応しているようなので
Android L は 64bit で動作するのかも。

仕様が確定していないのか API Level の表記が API Level L 。
ちなみに Android 4.4 (KitKat) は Level 19 。

Android L (64bit) 向けのコンパイラは gcc 4.9 がデフォルト。
従来の API Level 19 までは gcc 4.8 がデフォルトになり、
clang を選択した場合のデフォルトは 3.4 になった。

ドキュメントには platforms/Android-L/ を追加したって記述があるけど
android-ndk32-r10-windows-x86.zip には入ってない…リリース漏れ?

サンプルに Level 19 用の native-codec が追加されてた。
これは MediaCodec の NDK 版かも。

修正内容を確認すると wchar_t に修正があった。
オプションで wchar_t を2バイトにできるっぽい。

○Fixed WCHAR_MIN and WCHAR_MAX so that they they take appropriate
signs according to the architecture they're running on:
・X86/MIPS: signed.
・ARM: unsigned.
・To force X86/MIPS to default to unsigned, use -D__WCHAR_UNSIGNED__.
・To force wchar_t to be 16 bits, use -fshort-wchar.

NDK r9d であった LibVorbis の hardfp 動作不良も起きなくなっている。



2014/06/02 Android NDK の wchar_t 宣言
Windows 用のコード移植で wchar_t を使っている場合は注意が必要。

LOGI( "sizeof(wchar_t) == [%d]\n",sizeof(wchar_t) );

sizeof の結果はになる。

Windows だと wchar_t は2バイト なので wcscpy を使ったコードを無理やり
ビルドすると文字列終端を発見できずにアクセス例外が発生する可能性がある。

追記 2014/07/17
NDK r10 以降では -fshort-wchar で2バイトに変更できる。



2014/05/21 gcc のプロトタイプ宣言有無
プロトタイプ宣言の警告の相違。
通常の状態でプロトタイプ宣言が無い場合に出る警告。

warning: implicit declaration of function 'printf'

gcc の C99 規格オプションでコンパイルすると
gcc -std=c99

警告が次のように変わる。

warning: implicit declaration of function 'printf' is invalid in C99

Android NDK でビルドすると後者の警告が出る。



2014/05/12 Android NDK で単体実行ファイル作成。
実は共有ライブラリだけでなく単体実行ファイルも動作する。

Android.mk はこんな感じ。
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := ndkexe
LOCAL_SRC_FILES := ndkexe.c
LOCAL_LDLIBS := -llog
include $(BUILD_EXECUTABLE)

ソース
#include <stdio.h>
#include <android/log.h>
int main()
{
 printf("hello.\n");
 __android_log_print(ANDROID_LOG_INFO,"tag","hello.\n");
 return 0;
}

printf は実行したコマンドプロントに出力される。
__android_log_print は eclipse の logcat に出力される。

転送と実行を行うバッチファイル
@echo off
path %Path%;C:\android\platform-tools
adb -d push C:\workspace\ndk-exe\libs\armeabi/ndkexe /data/local
adb -d shell chmod 755 /data/local/ndkexe
adb -d shell /data/local/ndkexe
pause

実機のフォルダは /data/ 下以外では権限の問題で実行できない。
(/data/local/ 等のサブフォルダでも実行可能。)

SDCard をマウントしたフォルダには push で転送できても
chmod で権限による失敗が発生してエラーが表示される。

Operation not permitted

chmod が成功すれば作成したファイルを実行する事が出来る。



2014/05/03 clang の ShiftJIS ダメ文字
clang で ShiftJIS のダメ文字をコンパイルすると正常に動作しないっぽい。

※ "能" のコードは { 0x94,0x5c } で 0x5c を含むのでダメ文字。
char *p = "能力";
printf( "%s\n",p );

上記のコードをビルドしてバイナリのデータ部分をダンプで確認すると、
{0x94,0x5c,0x97,0xcd,0x00}; となるべきが
{0x94,0x97,0xcd,0x00}; と 0x5c が抜けた状態になってしまう。

これだと表示がおかしくなるのでコードを書き換える。

static unsigned char __damemoji[] = {0x94,0x5c,0x97,0xcd,0x00};
char *p = (char*)__damemoji;
printf( "%s\n",p );

ただしコメント行の途中にダメ文字を記述するのは問題ないみたい。怖いけど。
文字コードを UTF-8 にすればこんな問題は起きないんだけど…



2014/05/02 clang の ShiftJIS コンパイル
clang で文字コードが ShiftJIS のソースをコンパイルすると
文字コードに問題があると警告が出る。(gcc だと出ない。)

printf("ハローワールド。\n");

こんなコードを記述すると警告が。

warning: illegal character encoding in string literal
[-Winvalid-source-encoding]
printf("<83>n<83><8D><81>[<83><8F><81>[<83><8B><83>h<81>B\n");

ソースコードを UTF-8 で保存するのが一番なんだけど
Windows 環境だといろいろと面倒な事が多くてなぁ。



2014/05/01 Android NDK r9d clang の警告
gcc 4.8 でコードをビルドすると警告が出ないのに
clang に切り替えてビルドすると大量に警告が発生した。

type_defs.h:100:13: warning:warning:
redefinition of typedef 'int32_t' is a C11 feature [-Wtypedef-redefinition]
typedef int int32_t;
types_def.h:55:13:note: previous definition is here
typedef int int32_t;

int32_t が C11 では予約キーワードになっていて再定義された?かと思ったが、
よく見ると単なる typedef の再定義警告だった。
原因は似たような名称の2つのファイルで次のように記述していたこと。

#ifndef int32_t
typedef int int32_t;
#endif

確かに再定義になってしまうので #define を使うように修正。

#ifndef int32_t
#define int32_t int
#endif

あまり良いコードとは思えないが警告は出なくなった。



2014/04/19 Android NDK r9d の hardfp
Android NDK r9b で限定的サポートのような扱いだった ARM の
-mhard-float が NDK r9d では正式サポートされたようだ。
これは関数の引数が浮動小数だった場合に直接FPレジスタに値を入れて
受け渡すようにする高速化オプション。

NDK 側のライブラリは softfp のままらしいので自分でコンパイルするソースに
浮動小数を使った関数呼び出しが多い場合に効果がある。

NDK r9b では clang 非対応だったが NDK r9d では特に記述が無く、
clang でも使えるようなので試してみた。

APP_ABI=armeabi-v7a-hard

あれ… LibVorbis の実行結果がおかしくなった。

最適化オプションを弱めに設定しても変化なし。
hardfp を切ると正常な実行結果に戻った…。

追記 2014/07/17
NDK r10 以降ではこの問題が改善された。



2014/04/18 Android 4.x のメディア機能
Android 4.x (API Level 14) 以降では NDK で MP4 のデコードが可能みたいな話が
あったので調べてみた。

NDK では OMXAL/OpenMAXAL.h が該当する。
OpenMAX は 2006 年に Khronos で策定された規格で結構昔からあったようだ。

OpenMAX は3つのソフトウェア層で構成されていて上からこんな感じ。

OpenMAX AL (Application Layer) high-level playback and recording
OpenMAX IL (Integration Layer) media conponent
OpenMAX DL (Development Layer) media primitives and concerrency constructs

各層の機能は次のような感じらしい。

AL は DirectShow ような再生、停止といった高レベルな API。
IL は DirectShow Filter (transform) のようなコーデック API。
DL は動画や音声のデコード、エンコードを行うドライバ API。

NDK から使える機能は AL だけで動画の場合は
JAVA 側から Surface を受け取り NativeWindow に関連付けする。

// for native window JNI
#include <android/native_window_jni.h>
ANativeWindow* ANativeWindow_fromSurface(JNIEnv* env, jobject surface);

後はファイルを読み込んでバッファキューに詰める OpenSL のような
実装をすれば動画再生が可能になる。



2014/04/12 Android NDK r9d と ndk-build
Android NDK r9 のドキュメントに記載がある ndk-build のオプション一覧。
オプションは組み合わせて使うことも可能。

記述 備考
clean 生成物の除去
V=1 gcc へ渡すコマンドを表示する。
-B 強制的にリビルドする。
NDK_LOG=1 NDK 内部のログを表示する。
NDK_DEBUG=1 デバッグモードでビルドする。
NDK_DEBUG=0 リリースモードでビルドする。
NDK_HOST_32BIT=1 64bit 環境でも 32bit の toolchain を使う。
NDK_APPLICATION_MK=[file] application.mk の代わりに[file]を使用してビルドする。
-C [project] [project] で指定されたパスをビルドする。

デフォルトはこんな感じだと思われる。

ndk-build V=0 NDK_LOG=0 NDK_DEBUG=1



2014/04/08 Android NDK r9d のマルチスレッドビルド
Windows 以外の環境だと動作していたっぽいマルチスレッドビルド。
NDK ドキュメントには記載が無い。

Android NDK r8b でマルチスレッドビルドを試した時は Error 3 が表示されて
MAKE コマンドが失敗していたのが Android NDK r9d では正常動作している。

ndk-build -j 4

もしくは

ndk-build --jobs=4

CPU のコア数と同じ数にすれば高速化されるのを確認。
ただし、ハイパースレッティングな CPU ではスレッド数に合わせても
速くなるかは不明。AMD の Bulldozer 系なら速くなるかも。



2014/04/03 Android NDK r9d と C++ ライブラリ
Android NDK r9d でサポートする C++ ライブラリ。

library Exceptions RTTI STL 備考
system × × × default minimal system C++ runtime library
gabi++_static
gabi++_shared
× × GAbi++ runtime as a library
stlport_static
stlport_shared
STLport runtime as a library
gnustl_static
gnustl_shared
GNU Standard C++ Library
(a.k.a. libstdc++-v3)
GNU STL as a library

ライブラリのソースやヘッダは以下のパスで確認出来る。

(NDKをインストールしたパス)\sources\cxx-stl\system\include
(NDKをインストールしたパス)\sources\cxx-stl\stlport\stlport
(NDKをインストールしたパス)\sources\cxx-stl\gnu-libstdc++\4.8\include
(NDKをインストールしたパス)\sources\cxx-stl\gabi++\include



2014/04/02 Android NDK r9d で STL
標準状態では #include <string> のビルドが通らなかった。
当然 #include <vector> もビルドが通らない。
.h 無しヘッダ非対応かと思えば #include <cstring> は通る…。はて?

C++ ヘッダや STL が使えないか NDK のドキュメントを見てみると、
NDK デフォルトライブラリの system は必要最低限の最小構成で
C++ の機能として Exception, RTTI, STL は使えないらしい。

ただし、STL が使える C++ ライブラリを Application.mk で
指定すれば使えそうなので試してみた。
(注意事項で Android.mk に書いても意味は無いとあった。)
とりあえず GPL 系は避けたいので STLport を使う事にした。

Application.mk に APP_STL を記述する。

APP_STL := stlport_shared

今度は例外処理でビルドエラーが出たので Android.mk に

LOCAL_CPP_FEATURES += exceptions

を記述してビルドするとエラーが出なくなった。

これでビルドは通ったけど、
libs\armeabi-v7a\libstlport_shared.so (374,076byte)
がコピーされていた。

実機の Android OS 側で保持された共有ライブラリじゃなくて
apk に含めて使うって事なのか…。共有ライブラリの意味が無いような…。
でも、この方法なら Android バージョンに依存しないメリットがあるか。

次に Application.mk をスタティックリンクに書き換えてみた。

APP_STL := stlport_static

スタティックリンクだと libstlport_shared.so はコピーされず、
本体が 20kbyte 程度増えるだけで済んだのでスタティックリンクにする事にした。



2014/03/27 NDK r9 NativeActivity 書き換え
NativeActivity でアプリを作成するとエントリーポイントは

(NDKをインストールしたパス)\sources\android\native_app_glue\
android_native_app_glue.c

void ANativeActivity_onCreate()

になる。

このままだと困るので JNIEXPORT を付け加える。

422: JNIEXPORT void ANativeActivity_onCreate(ANativeActivity* activity,




2014/02/14 gcc の警告抑制
基本的にはコンパイルした時に警告が出ないソースコードがベストだけど
そうもいかない時もある。

gcc でも pragma で ON/OFF の切り替えが可能。
VC 等、他のコンパイラとの文法に互換性は無い。

例えば、使用していない変数の警告は -Wunused なので

変数の警告を無効にする場合
#pragma GCC diagnostic ignored "-Wunused"

変数の警告を有効にする場合
#pragma GCC diagnostic warning "-Wunused"

とソースコードの先頭に記述すれば、警告設定が変更される。

また、ソースコードの一部のみに適用することも可能。

#pragma GCC diagnostic push // 現在の警告設定を保存する
#pragma GCC diagnostic ignored "-Wunused"
void test1()
{
 int a; // 警告が出ない
}
#pragma GCC diagnostic pop // 警告設定を復帰する

void test2()
{
 int b; // 警告が出る
}



2014/01/07 Win64 で追加された型
Win64 で追加されたサイズ指定の型。

備考
DWORD32 32 ビット符号なし整数
DWORD64 64 ビット符号なし整数
INT32 32 ビット符号付き整数
INT64 64 ビット符号付き整数
LONG32 32 ビット符号付き整数
LONG64 64 ビット符号付き整数
UINT32 符号なし INT32
UINT64 符号なし INT64
ULONG32 符号なし LONG32
ULONG64 符号なし LONG64

Win64 で追加されたポインタに関係する型

DWORD_PTR ポインタ精度の符号なし LONG 型
HALF_PTR ポインタの半分のサイズで、1 つのポインタと
2つの小さな領域が含まれる構造体で使用します
INT_PTR ポインタ精度の符号付き integer 型
LONG_PTR ポインタ精度の符号付き LONG 型
SIZE_T ポインタが参照できる最大バイト数
(ポインタのすべての範囲に対応する必要がある
カウントで使用します)
SSIZE_T 符号付き SIZE_T
UHALF_PTR 符号なし HALF_PTR
UINT_PTR 符号なし INT_PTR
ULONG_PTR 符号なし LONG_PTR



2013/12/22 OS と IE のバージョン
Windows のサポートする Internet Explorer のバージョン。

バージョン 標準 最終 備考
Windows 8.1 11.0 - 最新の IE 11.0 が使用可能。
Windows 8 10.0 10.0 -
Windows 7 8.0 - 最新の IE 11.0 が使用可能。
Windows Vista 7.0 9.0 -
Windows XP 6.0 8.0 -
Windows 2000 5.0 6.0 -
Windows NT4 無し 6.0 -
Windows ME 5.5 6.0 -
Windows 98SE 4.0 6.0 -
Windows 98 4.0 6.0 -
Windows 95 OSR2〜 3.0 5.5 -
Windows 95 無し 5.5 -




2013/12/21 OS と MediaPlayer のバージョン
Windows のサポートする Media Player のバージョン。

バージョン 標準 最終 備考
Windows 8.1 12 - -
Windows 8 12 - -
Windows 7 12 - -
Windows Vista 11 11 -
Windows XP XP(8相当) 11 11 は Service Pack2 以降が必要。
Windows 2000 6 9 -
Windows NT4 無し 6.4 -
Windows ME 7 9 -
Windows 98SE 4.1 9 -
Windows 98 4.1 7.1 -
Windows 95 OSR2〜 4.0 6.4 7のサポートは無いがインストール可能。
Windows 95 4.0 6.4 -




2013/12/20 OS と DirectX のバージョン
Windows のサポートする DirectX のバージョン。

バージョン 標準 最終 備考
Windows 8.1 11.2 - -
Windows 8 11.1 - -
Windows 7 - 11.0 -
Windows Vista 9.0Ex 11.0 -
Windows XP 8.1 9.0c -
Windows 2000 7 9.0c -
Windows NT4 無し 3相当 ServicePack6 で DirectX3 が提供される。
ただし、3D機能のHAL無し版。
Windows ME 7.1 9.0c -
Windows 98SE 6.1 9.0c -
Windows 98 5.2 9.0c -
Windows 95 OSR2〜 無し 8.0a -
Windows 95 無し 8.0a NEC PC-9800シリーズ用の最終は7。




2013/12/19 OS のバージョン
GetVersionEx で取得した Windows のバージョン。

バージョン Major Minor Build 備考
Windows 8.1 6 3 9600 マニフェストの記述が無い場合は
Windows8 のバージョンを返す。
Windows 8 6 2 9200 -
Windows 7 6 1 7600 -
Windows Vista 6 0 6002 -
Windows XP x64 5 2 3790 -
Windows XP 5 1 2600 -
Windows 2000 5 0 2195 -
Windows NT4 4 0 1381 -
Windows ME 4 10 3000 -
Windows 98SE 4 10 2222 -
Windows 98 4 10 1998 -
Windows 95 OSR2〜 4 0 1111
1212
-
Windows 95 4 0 950 -




2013/12/06 OFN_ALLOWMULTISELECTのバッファサイズ
OPENFILENAME::Flags に OFN_ALLOWMULTISELECT を指定して
GetOpenFileName を呼び出すと複数のファイルが選択できるようになる。

OFN_ALLOWMULTISELECT 使用時のバッファサイズは下記のようにする。
(指定ファイル数 * (MAX_PATH + 1) + 1) * sizeof(TCHAR);

※TCHAR は ShiftJIS(ASCII) なら 1byte。 unicode なら 2byteになる。

バッファには下記のように格納される。
path\0name\0name\0name\0\0

OFN_ALLOWMULTISELECT 使用時はパスとファイル名が分離されるので
ファイル名で MAX_PATH を埋め尽くす事はほとんど無く、指定ファイル数以上に
選択する事は可能。

一部で「バッファサイズの限界はドキュメントに 2048 が限界と記載してあるが
実際には 2048 を超えても問題が無い」と言われているので調べてみると…

The MFC documentation for CFile-Dialog contains the following strange warning:

When the user allocates their own buffer to accommodate OFN_ALLOWMULTISELECT,
the buffer can't be larger than 2048 or else everything gets corrupted
(2048 is the maximum size).

The limitation in question existed in Windows 95 and
was fixed in Windows NT 4 and Windows 98,
so the remarks do not apply to any modern version of Windows.

問題の制限はWindows 95に存在しWindows NT 4および
Windows 98に固定されました。したがって、
発言はウィンドウズのどんな現代版にも当てはまりません。

※エキサイト翻訳

この問題は Windows95 の制限で Windows98/NT4 以降では修正されているらしい。



2013/12/02 WM_USER の注意点
ダイアログを使ったソフトの動作が不安定だったので調べてみた。
どうやら予期せぬタイミングで WM_USER が発生している事を突き止めた。

ダイアログの定義で確かに WM_USER を使っているのを確認。
#define DM_GETDEFID (WM_USER+0)
#define DM_SETDEFID (WM_USER+1)
#define DM_REPOSITION (WM_USER+2)

とりあえず、(WM_USER+10) に書き換えてダイアログのメッセージと
重複しないようにしたら動作が安定した。

どうしてこんな問題があるのか調べてみると…

WM_USER はコントロール(ボタン等も含む)で使う為の定義らしい。
コントロールを扱う側は WM_APP を使うのが正しいらしい。



2013/11/20 シェーダーモデル
シェーダーモデル と API バージョン。

バージョン DirectX OpenGL 備考
1.0 8.0 1.5+EXT vertex 1.0〜1.1 , pixel 1.0〜1.4
2.0 9.0 2.0 -
2.0a 9.0b 2.0 nVIDIA 拡張
2.0b 9.0b 2.0 ATI 拡張
3.0 9.0c 2.1 -
4.0 10.x 3.x -
5.0 11.x 4.x -




2013/11/19 DXGI
DirectX グラフィックス インフラストラクチャー (DXGI) は
DirectX 10 以降に搭載された機能。

DirectX 9 までは解像度の切り替え(フルスクリーン化)やデバイス列挙等の
低レベル制御は DirectX Runtime が行っていたので DirectX がバージョンアップすると
I/F が変わって(ソースコードの)互換性が無くなると言うことがあった。

でも DirectX 10 以降はこの低レベル制御の部分を別コンポーネント化したから
毎回、開発者が最新機能を使う為にこの部分を作り直す必要が無いよってことらしい。

DXGI は DirectX Runtime とドライバ階層の間に入っていて、
Vista 以降の OS で実装されているらしい。



2013/10/19 Android (x86) とARM用アプリの互換性
最新の Android (x86) には NDK で ARM 用のバイナリしか
作っていないアプリでもほとんど動作するらしい。

なんでも Intel 製の「Houdini Binary Translator」と呼ばれるソフトが
Android に組み込まれていて、ARM 用のバイナリを x86 に変換している。
これにより約9割の ARM 専用のアプリが動作すると言われている。

「Houdini Binary Translator」はOS内部に組み込まれているようで、
一般ユーザーは意識することなく利用している状態になっている。
その為、「Houdini Binary Translator」を存在を知らない人も多いと思われる。

国外製の安価な Android(x86) タブレットに「Houdini Binary Translator」が
組み込まれているかは不明。



2013/05/04 Android のファイルへのデータ保存
簡単にデータを保存するには Serializable を implements してシリアライズ化した
クラスを用意する。

そのクラスを ObjectOutputStream の writeObject メソッドに指定すると
メンバの値はファイルに保存される。
ただし、static や transient 宣言していると保存対象にはならない。

class SaveData implements Serializable
{
 // シリアライズID
 static final long serialVersionUID = 123456;
 // 保存するメンバ
 public int _nDataVer;
 public String _strLastPath;
 public int _nNumber;
 public transient int _format; // 非シリアライズ変数は保存されない
 public static int _type; // 静的変数は保存されない
}

FileOutputStream から ObjectOutputStream を生成してクラスを保存する。

SaveData data;
data._nDataVer = 1;
data._strLastPath = "save";
data._number = 100;

try
{
 //FileOutputStream fos = new FileOutputStream(_SD_EXT_FULLPATH);
 FileOutputStream fos = context.openFileOutput(_FILENAME,Context.MODE_PRIVATE);
 ObjectOutputStream oos = new ObjectOutputStream(fos);
 oos.writeObject(data);
 oos.close();
}
catch( Exception e )
{
}

保存したデータの読み込みは FileInputStream から ObjectInputStream を
生成して Serializable したクラスのインスタンスを復帰させる。

SaveData data;
try
{
 //FileInputStream fis = new FileInputStream(_SD_EXT_FULLPATH);
 FileInputStream fis = context.openFileInput(_FILENAME);
 ObjectInputStream ois = new ObjectInputStream(fis);
 data = (Serializable) ois.readObject();
 ois.close();
}
catch( Exception e )
{
}

保存したファイルにはクラス名とメンバ名をキーに値が保存されるので
保存メンバを変更すると読み込み時に例外が発生する。
順番を変えずに追加する場合には発生しないっぽい。

これにより ProGuard を使っていると ON/OFF でクラス名とメンバ名に
相違が発生しデータが正しく読み込めない事になる。
また、ProGuard の難読化は変数の順番が異なると生成される名称も異なるので
この場合もデータが正しく読み込めない事になる。

この問題は Serializable を implements したクラスは難読化を抑制するように
proguard-project.txt に追記して対策可能。

-keep class * implements Serializable
{
 <fields>;
}

シリアライズ化したクラスを全て抑制したくない場合は該当クラスを
個別で全て記述すればいい。



2013/04/16 Android のファイルサイズ限界
PC からのコード移植で気が付いた。
Android NDK で 2GB を超えるファイルにアクセス出来ない…。

ファイルシステム的には 2GB を超えるファイルは存在可能なんだけど、
2GB を超えていると fopen() の時点で失敗するらしい。

32bit(4 byte) なら 4GB まで操作出来そうだけど fseek は現在位置からマイナス方向に
移動指定が可能なので符号ビットが必要になり、2GB までしか扱えないってことか。

fseek の 位置指定は long 型。特に #if も無いので変化しそうにない。
NDK の platforms レベル19のヘッダを参照しても long。
sizeof(long) として確認したけど 32bit 環境なので当然 4 byte。

fseeko があるので off_t を調べたけどこれも 4 byte …。
fseeko64 は MinGW 専用っぽいのでこれも無理。
fseeki64 は VC 専用っぽいのでこれも無理。

32bit Linux 環境用のマクロ定義
#define _LARGEFILE64_SOURCE
#define _FILE_OFFSET_BITS 64
#include <stdio.h>
これも変化無し。

NDK のヘッダを検索していると lseek64 を発見した。
これは 「Linux 用でCRT間の移植性が落ちるからあまり使わないでね」と
注意があったけど、使えるなら構わない。
lssek64 は NDK r6 には無い。NDK r8 にはあった。

Android のソースを確認すると隠し関数?の __llseek を呼び出しているだけだった。

2GB 超えファイルを open() で開くと失敗して errno に EOVERFLOW が設定される。
open() の引数に O_LARGEFILE を設定すれば失敗しない。

Windows 環境の open() とは引数に使う定義の互換性が無いので注意。

#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
fd = open( filename.O_RDONLY|O_LARGEFILE,666 );
if( fd < 0 )return;
size64 = lseek64( fd,0,SEEK_END );

これでファイルサイズが正常に取得出来れば 2GB 超え対応の完了。
Android 2.3 系でも動作した。



2013/04/01 SJIS ダメ文字
2byte 文字の 2byte 目が 0x5c ("\") だと 1byte の "\" と誤認してしまう文字。
UNICODE (UTF8,UTF-16) ではこの問題は発生しない。

これは VC から GCC に移植するケースやパス処理で問題になる。

SJIS を認識しない C/C++ コンパイラでダメ文字 "表" を記述すると…
// ID一覧表
static int id[]={20,40,50};
v = id[0];

"表" が "\" と解釈されてコメント行に連結されてしまう。
// ID一覧表static int id[]={20,40,50};
v = id[0];

変数 id は存在しない事になり、コンパイルエラーになる。

日本語コメントは /**/ にするか、最後に適当な文字を追加すれば対策可能。
/* ID一覧表 */
// ID一覧表-

Microsoft 系OSはパスの区切りに "\" を使うのでフルパスからファイル名を
単純に "\" で抽出するプログラムコードを作成すると下記のようなパスで

c:\data\制御ソフト.txt

"ソ"がダメ文字なので「フト.txt」で抽出されてしまう可能性がある。
mbs 系の文字列操作関数を使えば対策出来る。

ダメ文字の一覧。
文字 ShiftJIS 備考
0x815c -
0x835c -
Ы 0x845c -
0x895c -
0x8a5c -
0x8b5c -
0x8c5c -
0x8d5c -
0x8e5c -
0x8f5c -
0x905c -
0x915c -
0x925c -
0x935c -
0x945c 注意コメント //性能 、//分解能 、//知能
0x955c 注意コメント //一覧表
0x965c 注意文字 //暴れる 、//暴走
0x975c 注意文字 //予約 、//予定 、//予報
0x985c -
0x985c -
- 0x??5c 喀 媾 彌 拿 杤 歃 濬 畚 秉 綵 臀 藹 觸 軆 鐔 饅 鷭 x x

Perl だと "|" (0x7c) で同様の問題が発生する。



2013/01/07 テキストのスクロール設定
TextView でサイズから文字がはみ出た場合の処理を android:ellipsize で
指定が出来るとあったのでスクロールを設定する事にした。

android:ellipsize="marquee"

を試してみたが改行されて2行になってしまう。

調べてみると行数の設定をすれば良いとあったので試してみる…
android:singleLine="true"
android:scrollHorizontally="true"

1行になっただけで、はみ出した文字列は動く様子がない。

バージョンがダメなのかと調べてみたけど Android 2.x でも使えるみたい。

さらに調べてみるとフォーカスも設定しているケースがあったので
これを試してみるとスクロールしてくれた。

android:focusable="true"
android:focusableInTouchMode="true"

何回もスクロールする必要は無いのでスクロール回数を指定して完了。

android:marqueeRepeatLimit="1"



2012/12/10 セキュリティ強化関数
VS2005 以降で文字列操作系の関数を使うとセキュリティに問題が無い、
新しい関数を使ってくれと警告が出る。

これらの関数は不正なデータを使ってバッファ領域を超えて
他のメモリ領域が書き換えられる可能性がある。

VS2003 以前 VS2005 以降 問題点
sprintf sprintf_s バッファサイズをチェックしていない
strcpy strcpyf_s バッファサイズをチェックしていない
strcat strcat_s バッファサイズをチェックしていない
fopen fopen_s CRT が保持するポインタを返す。
localtime localtime_s CRT が保持するポインタを返す。

「バッファ管理はしっかりやっているので大丈夫です。」という人は
#define _CRT_SECURE_NO_DEPRECATE
として警告が出ないようにしても良いかも。


ちなみに新関数でバッファオーバーを検知すると失敗するのではなく
アサートが発生してプログラムが強制停止させられる。



2012/12/01 64ビット環境の変数サイズ
Microsoft 系 64bit コンパイラは LLP64 モデル。
gcc 系の 64bit コンパイラは LP64 モデル。

定義 16 ILP32 LP64 LLP64
char 1 1 1 1
short 2 2 2 2
int 2 4 4 4
long 4 4 8 4
long long (*1) - 8 8 8
__int64 (*2) - 8 8 8
ポインタ 2 4 8 8

(*1) 古いコンパイラは対応していない。
(*2) Microsoft の独自拡張。gcc は対応していない。



2012/11/02 環境の判別方法

定義済みマクロ 意味
__GNUC__ コンパイラは gcc
__clang__ コンパイラは clang
_MSC_VER コンパイラは Visual C/C++
__ANDROID__ ターゲット環境は Android
__linux__ ターゲット環境は Linux
__x86_64__ ターゲット環境は 64bit OS (gcc系?)
_WIN32 ターゲット環境は Windows 32bit
_WIN64 ターゲット環境は Windows 64bit



2012/10/14 Linux のマルチスレッド関数
マルチスレッドで使いそうな関数。

pthread_create() : スレッドの生成。
pthread_join() : スレッドの終了待ち。
pthread_mutex_init() : 排他処理の初期化。
pthread_mutex_lock() : 排他処理のロック開始。
pthread_mutex_trylock() : 排他処理の条件ロック開始。
pthread_mutex_unlock() : 排他処理のロック終了。
pthread_mutex_destroy() : 排他処理の開放。
pthread_cond_init() : 条件付き休止の初期化。
pthread_cond_signal() : 条件付き休止の解除(単体スレッド)。
pthread_cond_broadcast() : 条件付き休止の初期化(複数スレッド)。
pthread_cond_wait() : 条件付き休止の開始。
pthread_cond_timedwait() : 条件付き休止の開始。
pthread_cond_destroy() : 条件付き休止の開放。

sleep() : 1 を指定すると1秒休止する。
usleep() : 1000000 を指定すると1秒休止する。



2012/10/07 NDK の static library リンク
別のプロジェクトで生成したスタティックライブラリをリンクする。

指定されたフォルダを作成してライブラリとヘッダをコピーする。
jni/external/include
jni/external/lib

後は android.mk を書き換える。

ライブラリ名は先頭に lib を付ける必要があるが、自動的に付与されるので
android.mk では lib を省略して記述する。

libxfile.a をリンクする場合。
LOCAL_C_INCLUDES := $(LOCAL_PATH)/external/include
LOCAL_LDLIBS := -llog -lGLESv1_CM
LOCAL_LDLIBS += -Lexternal/lib/ -lxfile

と記述したら以下の警告が出た。

Android NDK: WARNING:jni/Android.mk:name: non-system libraries in linker flags: -lname
Android NDK: This is likely to result in incorrect builds. Try using LOCAL_STATIC_LIBRARIES
Android NDK: or LOCAL_SHARED_LIBRARIES instead to list the library dependencies of the
Android NDK: current module

指定のライブラリはシステム(CRT?)には存在しない。
LOCAL_STATIC_LIBRARIES か LOCAL_SHARED_LIBRARIES を
試してみてくれってことらしい。

一応、リンクは成功してビルドは正常に完了している。

LOCAL_STATIC_LIBRARIES := xfile

を追加してみたけど変化は無かった。

ググっても警告だから無視して問題ないみたいと書かれていた。



2012/10/06 NDK gcc のバージョン指定
NDK のバージョンによっては toolchains フォルダに複数の gcc が入っている。
最新のコンパイラを使用したい場合や逆に古いNDKと互換性が欲しい場合などに
Application.mk に設定すればいい。

#use gcc 4.6
NDK_TOOLCHAIN_VERSION=4.6



2012/09/08 NDK の API Level 指定方法
OpenSL のコードを書いたらヘッダが無いとエラーになった。

error SLES/OpenSLES.h: No such file or directory

NDK のフォルダを検索すると andoroid-8 以前には無いが andoroid-9 にはある。

API Level の指定が間違っているとわかったので eclipse のプロジェクト設定を
変更してからビルドしたけど効果なし。

ググったらコマンドプロンプトから入力を試せとあったので
ndk-build TARGET_PLATFORM=android-9

実行してみると確かにビルドが通る。

NDK のサンプルはこんな事しなくてもビルドが通るので調べてみたら
Application.mk に記述してあった。

# The ARMv7 is significanly faster due to the use of the hardware FPU
#APP_ABI := armeabi-v7a

# CPU NEON code
#LOCAL_ARM_NEON := true

# target ANDROID 2.3.1
APP_PLATFORM := android-9



2012/09/02 NDK でログ出力
ログ出力するコードを作ったらエラーが出てビルドが通らない。

jni/xx.c:100: undefined referance to `__android_log_print'

エラーに行数が出ていたのでコンパイルエラーと思っていたが
調べてみるとリンクエラーだった…

LOCAL_LDLIBS += -llog

で解決した。

VC のリンクエラーはソースの該当行数を表示しないので
gcc も同じだと勘違いしていた。



2012/08/26 Android の ネイティブから使える機能
Android バージョン別の NDK から使える機能。

func / ver 1.6 2.0 2.2 2.3.1 2.3.3 3.0 4.0
API Level 4 5 8 9 10 11 14
JNI
NativeActivity - - -
OpenGL ES 1.1
OpenGL ES 2.0 -
OpenSL ES - - -
Sensor/Touch - - -
Media Dec/Enc - - - - - -



2012/07/26 Android SurfaceView の破棄されるタイミング
SurfaceView は終了時だけでなく、画面向き変更時やスリープ移行時等の
画面が切り替わるタイミングでも破棄される。

このタイミングを検知するには SurfaceHolder.Callback の
surfaceDestroyed をオーバライドで可能になる。
public abstract void surfaceDestroyed (SurfaceHolder holder)
Added in API level 1

いろいろ解説サイトを見ていると surfaceDestroyed は
サーフェイスが破棄された後に呼ばれると記述されている事が多い。
だとしたら描画スレッドで不正なアクセスが多発するハズだが、あまり聞かない。

Android の公式サイトで API の解説を探してみると
This is called immediately before a surface is being destroyed.
After returning from this call, you should no longer try to access this surface.
If you have a rendering thread that directly accesses the surface,
you must ensure that thread is no longer touching the Surface before returning from this function.

表面が破壊されるすぐ前に、これは呼ばれる。
この呼び出しから戻った後に、あなたはもうこの表面にアクセスしようとするべきではない。
もしあなたが、表面に直接アクセスするスレッドを持っているならば、
あなたは、この機能から戻る前にもうスレッドが表面に触れないことを保証しなければならない。

※エキサイト翻訳

やっぱりサーフェイスが破棄される前に呼ばれるようだ。
API 側の要求としては surfaceDestroyed の終わりに達する時には
描画スレッドが停止していること。
サンプルコードの大半は surfaceDestroyed でスレッドを停止させているが
スレッドが完全に停止した事を確認しているものはほとんど無い。

サンプルのようにスレッドの処理が軽い場合には問題は発生しないが
スレッドで重い処理を行っていた場合はスレッドの停止処理が間に合わず
サーフェイスにアクセスしてしまう事も考えられるので注意が必要。



2012/07/20 Deprecated Thread methods are not supported
Java でマルチスレッドを Thread.stop() を使って停止させると例外が発生する。

Deprecated Thread methods are not supported.
java.lang.UnsupportedOperationException
at java.lang.VMThread.stop(VMThread.java:85)
at java.lang.Thread.stop(Thread.java:1280)

Deprecated なので使えるけど非推奨になってるらしい。
スレッドが強制終了されるので状態があいまいになる可能性があるとのこと。

スレッド終了フラグを参照して無限ループを抜けて run メソッドの最後に
行き着くようなプログラムを作り、終了フラグを有効にしてもスレッドが終了しない
場合に最終手段として Thread.stop() を使うのが理想なのかも知れない。

メインスレッド以外のスレッドが1つしか無いのなら Thread.interrupt() を
使うのも良いかもしれない。

do
{
 //スレッドで行う処理

 //ウエイト前に確認する
 life = Thread.interrupted();
 if( ! life )
 {
  break;
 }

 //sleepでウエイトを入れる
 try
 {
  Thread.sleep( 100 );
 }
 catch (InterruptedException e)
 {
  Log.i( _TAG,"InterruptedException()\n" );
  Thread.interrupted(); // フラグクリアする
  life = false;
 }
}
while( life );



2012/07/15 android ログの種類
Android のログ出力はレベルを指定して出力する事が出来る。
eclipse を使用しているならば logcat の文字列に色が付く。

コード 種別 eclipse
logcat
意味、用途
Log.v(_TAG,"verbose"); verbose 冗長な表示(詳細)
Log.d(_TAG,"debug"); debug デバッグ
Log.i(_TAG,"info"); info 情報
Log.w(_TAG,"warning"); warning 警告
Log.e(_TAG,"error"); error エラー


NDK でも同様に android/log.h でレベルが定義されている。

typedef enum android_LogPriority {
 ANDROID_LOG_UNKNOWN = 0,
 ANDROID_LOG_DEFAULT, /* only for SetMinPriority() */
 ANDROID_LOG_VERBOSE,
 ANDROID_LOG_DEBUG,
 ANDROID_LOG_INFO,
 ANDROID_LOG_WARN,
 ANDROID_LOG_ERROR,
 ANDROID_LOG_FATAL,
 ANDROID_LOG_SILENT, /* only for SetMinPriority(); must be last */
} android_LogPriority;




2012/07/14 android アプリ連続起動の問題
onPause() の後、onStop() が呼ばれる前に再度アプリが起動されると
onCreate() が呼ばれた後に onStop() 、onDestroy() が呼ばれる。
しかも onDestroy() が呼ばれているのにアプリは終了しない。

結果、インスタンスの無いクラスにアクセスして落ちる…

●プロセスが存在しない状態から起動
00:40:59.716: D/Life:(13469): constructor()
00:40:59.716: D/Life:(13469): onCreate()
00:40:59.796: D/Life:(13469): onStart()
00:40:59.796: D/Life:(13469): onResume()
00:40:59.836: D/Life:(13469): onWindowFocusChanged(true)

●BACKキーで終了
00:41:44.816: D/Life:(13469): onUserInteraction()
00:41:44.816: D/Life:(13469): onKeyDown(4)
00:41:44.996: D/Life:(13469): onUserInteraction()
00:41:45.006: D/Life:(13469): onPause()
00:41:46.407: D/Life:(13469): onStop() ←1秒以上の空き時間がある。
00:41:46.407: D/Life:(13469): onDestroy()

●BACKキーで終了後、1秒以内にアプリを起動する
00:47:39.032: D/Life:(13469): onUserInteraction()
00:47:39.032: D/Life:(13469): onKeyDown(4)
00:47:39.122: D/Life:(13469): onUserInteraction()
00:47:39.132: D/Life:(13469): onPause()
00:47:39.172: D/Life:(13469): onWindowFocusChanged(false)
00:47:40.223: D/Life:(13469): onCreate()
00:47:40.243: D/Life:(13469): onStart()
00:47:40.243: D/Life:(13469): onResume()
00:47:40.293: D/Life:(13469): onWindowFocusChanged(true)
00:47:40.423: D/Life:(13469): onStop()
00:47:40.423: D/Life:(13469): onDestroy()

この現象は android 2.3.3 で確認してるが
他のバージョンでも発生するのだろうか…。

連続起動した場合にプロセスも変わっていないので
(コンストラクタが呼ばれていない)
プロセスを使った判別は無理と思われる。

↓の2つの前提条件が正しいと仮定して
・onPause() と onResume() は対になっている。
・onStop() 、onDestroy() は onPause() の後にしか呼ばれない。

1. static なフラグを用意する。
2. onPause() でフラグを true に設定。
3. onResume() でフラグを false に設定。
4. フラグが false なら onStop() 、onDestroy() は処理しない。
(フラグに関係なく super は実行する。)

で回避できた。

さらに onStop() もしくは onDestroy() でデータ保存してると

onPause()
onCreate() ←保持データの読み込み、変更が起動時に戻る。
onStart()
onResume()
onStop() ←起動時の状態に戻ったデータを保存。
onDestroy()

とデータの変更が元に戻った後に保存されるので保持されない。
onPause() で保存すれば対応できるけど保存処理に
長い時間がかかる場合は呼ばれる頻度が高い onPause() ではちょっと困る。



2012/07/08 android の match_parent
android 2.2 (API Level 8)から追加されたレイアウトの幅の定義。
機能は fill_parent と同じ。
andoroid 2.1 で match_parent を使うと落ちる。

これにより fill_parent は deprecated (非推奨)になった。

ADT r20 以降でも自動生成されるレイアウトの XML は
fill_parent ではなく match_parent になっている。



2012/07/07 android-support-v4.jar
ADT r20 以降ではプロジェクトを作成すると自動で組み込まれる。

android-support-v4.jar は Support Library と呼ばれ、android 3.0 で追加された
新しいUI機能を android 3.0 未満で使えるようにするもの。

つまり
・ターゲットが android 3.0 以降で追加機能を直接使う場合。
・ターゲットが android 3.0 未満で追加機能を使わない場合。
は不要となる。

プロジェクトディレクトリの libs に置かれている android-support-v4.jar を
削除すると apk のサイズが約 450KB ほど小さくなる。



2012/06/28 Android の ProGuard
Java は C/C++ と違い、機械語ではなく中間コードで配布される形になるので
逆コンパイルすると綺麗なコードが生成される可能性が高い。

SDK に付属している ProGuard を使うと、クラスやメソッド、メンバの名称を
意味の無い文字列に変更し、逆コンパイルしてもわかりづらいように難読化してくれる。
オプションで最適化も可能だが Android SDK の初期設定では無効に設定されている。

SDKバージョンが古いと ProGuard の設定ファイル名が異なる。

プロジェクトを作成時に自動的に生成される project.properties の次の1行から
#proguard.config=${sdk.dir}\tools\proguard\proguard-android.txt:proguard-project.txt
先頭の # を消してコメントを解除すると ProGuard が有効になる。

ProGuard の細かい設定は SDK フォルダとプロジェクトに存在する
2つのファイルの記述が結合されて反映される。
(SDK_PATH)\tools\proguard\proguard-android.txt
(PROJECT_PATH)\proguard-project.txt

ProGuard を使用して apk を生成すると ProGuard の出力フォルダが
作成されるので、その中にある mapping.txt で難読化の内容が確認可能。

(project)\proguard\mapping.txt



2012/06/25 デバッグビルドとリリースビルド
ビルドすると自動生成される

/gen/BuildConfig.java

BuildConfig.DEBUG の値(true/false)を判定すればデバッグモード、リリースモードを
判定する事が出来る。

通常時はデバッグモード。認証付き apk 生成時はリリースモードになる。

ただし、Eclipse の [Build Automatically] が有効になっていると
正しく切り替えが行われないバグがある。



2012/06/17 レイアウトのファイル名
レイアウトの XML のファイル名を Game.xml にしたらエラーが出た。

res\layout\Game.xml: Invalid file name: must contain only [a-z0-9_.]

小文字アルファベットと数字しか使えないらしい。
"Game.xml" を "game.xml" に変更したら問題は解消された。



2012/06/16 ドット(.)の警告
Stringタグに「Loading...」と入力すると警告が出て表示が正しくない。

Replace "..." with ellipsis character (・・・,&&,#8230;)?

ドットを3つ続けて記述しているのが問題らしい。
一部の記号文字は""で括らないと正常に表示できない。

正常に表示するには「Loading"."".""."」と書き換える必要がある。
@ 等の他の記号も""で括る必要がある。



2012/06/09 weight 使用時の警告
android のレイアウトで weight を使うと警告が出ることがある。

Use a layout_width of 0dip instead of wrap_content for better performance
Use a layout_width of 0dip instead of fill_parent for better performance

これはパフォーマンス低下の警告。
無視しても構わないけど width や height を 0dip に変更すると
解消されることが多い。

入れ子になるようなレイアウトで使用した時の警告。

Nested weights are bad for performance

これの対策は不明。
全てのレイアウトに android:layout_weight 記述すれば
解決するとか…(未確認)。



2012/06/02 android インストール失敗
昔のツールで生成した著名なしの apk をインストールすると
INSTALL_PARSE_FAILED_NO_CERTIFICATES
が発生して失敗する。

対策:著名した apk を作る。

同じアプリでも異なった著名で作成したアプリだと
INSTALL_PARSE_FAILED_NO_CERTIFICATES
が発生して失敗する。

対策:アプリをアンインストールしてからインストールする。



2012/05/28 android 実機転送
コマンドプロンプトを使ってアプリを転送する方法。

複数のデバイスがあると「どれに転送するかわからない」とエラーになってしまう。
C:\android\platform-tools>adb install -r hoge.apk
error: more than one device and emulator

デバイス一覧でシリアルを確認して
C:\android\platform-tools>adb devices
List of devices attached
emulator-5554 device
192.168.1.1:5555 device

シリアル指定で実行する。
C:\android\platform-tools>adb -s 192.168.1.1:5555 install -r hoge.apk
557 KB/s (35594 bytes in 0.062s)
pkg: /data/local/tmp/hoge.apk

Wi-Fi接続、VMware接続だと無理っぽいけど、USBとエミュレータを
区別したいだけなら -d(USB)と-e(emu)で出来る。
adb -d install -r hoge.apk
adb -e install -r hoge.apk



2012/04/21 VC6 で使える最新SDK
VC6 で Windows SDK v7.0 を使おうとするとビルドで
非対応の構文 deprecated でエラーになり、失敗してしまう。

一応、VS2008EE 付属の Windows SDK v6.0A であれば警告が出るものの
サービスパックを当てた VC6 ならビルドを通す事はできる。



2012/04/14 OpenWatom C/C++ 1.9 vs Pentium ODP(P24)
Watcom の最適化オプションを変えると、どのくらい最適化されるか調べてみた。

MP3 をファイルからメモリに読み込んで再生1秒間分のデコード処理のみを
RDTSC 命令を使って測定した結果。(出力バッファはそのままで再生はしない。)

mp3dec_0 基準 -ot -s
-- 65,920,972 Clock

mp3dec_1 最適化 -ot -s -ob
-- 64,202,550 Clock
mp3dec_2 最適化 -ot -s -ol
-- 63,666,060 Clock
mp3dec_3 最適化 -ot -s -oc
-- 65,920,930 Clock
mp3dec_4 最適化 -ot -s -oi
-- 65,948,400 Clock
mp3dec_5 最適化 -ot -s -oa
-- 65,910,592 Clock
mp3dec_6 最適化 -ot -s -or
-- 56,722,842 Clock
mp3dec_7 最適化 -ot -s -oh
-- 67,827,725 Clock
mp3dec_8 最適化 -ot -s -om
-- 65,924,327 Clock
mp3dec_9 最適化 -ot -s -on
-- 65,918,147 Clock
mp3dec_a 最適化 -ot -s -op
-- 68,465,363 Clock
mp3dec_b 最適化 -ot -s -oe
-- 65,922,010 Clock

mp3dec_x 最適化 -ot -s -oblciarmne
-- 54,336,913 Clock

※ P5系では -op で遅くなっているが最近の CPU では結構速くなる。
※ P5系では -ol はちょい速だが、最近の CPU では結構速くなる。



2012/02/05 OpenWatom C/C++ 1.9 option2
最速の32ビットインテルコードを生成するための推奨オプションは、以下の通りです。

※Pentium Pro
  /onatx /oh /oi+ /ei /zp8 /fp6

※Pentium
  /onatx /oh /oi+ /ei /zp8 /5 /fp5

※486
  /onatx /oh /oi+ /ei /zp8 /4 /fp3


すべてのプロセッサに対して良好な性能を期待できるオプションは、以下の通りです。
※386、486,Pentium
  /onatx /oh /oi+ /ei /zp8 /5 /fp3



2012/01/29 OpenWatom C/C++ 1.9 option
※ /ot
コード生成過程においてコードサイズに一切構わず、より速いコード順序を
選択するためには必ず指定しなくてはなりません。

※ /ox
”obmiler”と”s”オプションの組み合わせと同等の効果をもたらします。

※ /ob _ Branch prediction
コンパイラ/コード生成器においての分岐予測を考慮したコードを生成します。

※ /ol _ Loop optimizations
ループ最適化の実行を行います。

※ /oc _ Call/return optimizations
呼び出しの最適化を行います。

※ /oi _ In-line intrinsic functions
組み込み関数のインライン展開を行います。

※ /oi+ _ ???
C++コンパイラで組み込み関数をインラインに展開します。(C++専用版です。)
さらに、inline_depthを最大値(255)に設定します。
初期値では、inline_depthの値は3となります。
inline_depthの値は、C++のinline_depthプラグマを使用して変更することもできます。

※ /oa _ Relax alias checking
コンパイラの別名チェックする基準を「ゆるく」します。

※ /or _ Instruction scheduling
パイプラインの停止を避けるための命令再発行を考慮したコードを生成します。

※ /oh _ Allow Repeated optimizations
オプションは、最適化の繰り返しを試行します。
(コンパイルに長時間かかりますが、より最適化されたコードを生成します)

※ /om _ Math optimizations
サイン、コサイン、平方根のような数学関数においてインラインの387命令を生成します。

※ /on _ Numerically unstable optimizations
コンパイラが浮動小数点の除算を乗算に変換して置き換えます。
これはより速いコードを生成しますが(乗算は除算より速いため)、
計算結果が同一になるとは限りません。
なぜならば、変換は正確に行われるとは限らないからです。

※ /op _ Consistent FP results
一貫した浮動少数演算の結果を返す?

※ /oe _ ???
小規模なユーザ定義関数の呼出を生成するかわりに、関数をインラインに展開します。
関数をインラインに展開することで、関数の呼出が生成されたことを検出する方法を
最適化するよりも効率よく、コードを実行することができます。

※ /s _ Disable stack depth checking
スタックオーバフローの確認を生成しない。

※ /ei _ Force enums to be type int
すべての列挙型について少なくとも”int”を割り当てます。

/or オプションは、PentiumおよびPentium Proプロセッサにおいて
高速なコードを生成するのに、非常に重要なものとなります。

ある環境下では、”ob”と”ol+”による最適化が32ビットインテルコードに
よりよい性能をもたらすことがあります。




2011/12/18 OpenWatcom C/C++ 1.9のバグ
作成したプログラムがVCでは正常に動作するがWCだと動作しないので
徹底的に調べた結果、オプション -ml (-ox 含む)を付けて以下のコードを
ビルドすると本来は"20"となる処理が"25"になってしまうバグを突き止めた。

void loop_c()
{
 int i;
 int counter = 0;
 int flag = 0x0004;
 int al[21];

 if( flag & 0x01 )
 {
  for( ; counter < 6; counter++ )
  {
   al[counter] = 5;
  }
 }
 else
 {
  for( ; counter < 6; counter++ )
  {
   al[counter] = 10;
  }
 }
 if( flag & 0x02 )
 {
  for( ; counter < 11; counter++ )
  {
   al[counter] = 15;
  }
 }
 else
 {
  for( ; counter < 11; counter++ )
  {
   al[counter] = 20;
  }
 }
 if( flag & 0x04 )
 {
  for( ; counter < 16; counter++ )
  {
   al[counter] = 25;
  }
 }
 else
 {
  for( ; counter < 16; counter++ )
  {
   al[counter] = 30;
  }
 }
 if( flag & 0x08 )
 {
  for( ; counter < 21; counter++ )
  {
   al[counter] = 35;
  }
 }
 else
 {
  for( ; counter < 21; counter++ )
  {
   al[counter] = 40;
  }
 }

 for( i=0;i<21;i++ )
 {
  printf( "[%d]\n",al[i] );
 }
}



2011/11/09 Win32 ミリ精度の設定
Windows で timeBeginPeriod() を使うと Sleep()、GetTickCount() や
マルチメディアタイマーの最小精度を設定する事ができる。
(timeGetTime() は timeBeginPeriod() の使用に関わらず常に高精度らしい。)

しかし、timeBeginPeriod() は OS (Windows 本体) に対して設定されるので
他のプロセスもこの精度で動作するようになる。
(複数のプロセスから使用された場合には低い値(高精度)が優先されるらしい。)

Windows Vista 以降は AvSetMmThreadCharacteristics() が追加され、
この AvSetMmThreadCharacteristics() を使用した場合にはカレントスレッドの
精度のみが変更される…らしい。

Windows Vista 以降でしか動作しなくなるが他のプロセス、スレッドに影響を
与えないと言う意味では行儀の良いソフトと言えるのかもしれない。

ただし、Windows SDK の avrt.h と avrt.lib が必要になる。



2011/09/25 Win32 レジスタ退避
Windows の 関数呼び出しでは eax,ecx,edx の値は保持されない。

ebx,edi,esi 等は値が保持される。

当然ながら全ての関数はこのルールを守る必要がある。



2011/08/07 VCのアセンブラ出力の確認
メニュー「プロジェクト」→「設定」→「C/C++」タブ→
「リスティング ファイル タイプ」を「ソースコード含む」に変更する。
(オプションに直接 /FAs を追加でもいい。)

ビルドすれば出力フォルダにアセンブラのソースが出力される。

コンパイラ最適化の確認やコンパイラのバグ探しに有効。



2011/08/06 x86 FPUアセンブラ
FPU でコードを記述する場合は逆ポーランド記法を使うと良い。

float fpu_sample(float a, float b, float c, float d)
{
 float ans;
 //ans = (a + b) * (c - d);
 // 逆ポーランド記法では上の式は 「ab+cd-*」 となる
 _asm
 {
  fld a // ;aをst(0)にプッシュ
  fadd b // ;st(0) = st(0) + b
  fld c // ;cをst(0)にプッシュ、先ほどのst(0)はst(1)となる
  fsub d // ;st(0) = st(0) - d
  fmul // ;st(1) = st(1) * st(0)
     // ;st(0)はポップされ、st(1)がst(0)として残る
  fstp ans // ;ansに値を格納する
 }
 return ans;
}



2011/02/06 64ビット変数

コンパイラ 定義 備考
Visual C++ __int64 VisualStudio 2005 以降なら long long も使える?
Borland C++ __int64 -
Watcom C++ __int64 OpenWatcom 1.9 なら long long も使える。
GCC long long -

定義 printf 系 サフィックス
__int64 %I64d、%I64i、%I64u、
%I64x、%I64X
i64、I64、ui64、UI64
long long %lld、%lli、%llu、
%llx、%llX
-



2010/12/04 continue 文
continue の動き(飛び)方。

c = 0;
do
{
 c++;
 continue; // do に行かず while に飛ぶ
 printf( "end\n" );
}
while( c < 10 );


c = 0;
do
{
 c++;
 switch( c )
 {
  case 100: //dummy
   break;
  default:
   printf( "switch(%d)\n",c );
   continue; // switch を無視して飛ぶ
 }
 printf( "end\n" );
}
while( c < 10 );



2010/11/27 1次元配列から多重配列へのキャスト
キャスト。

void func1( int v[][10] )
{
 int i,k;
 int (*p)[10] = v;
 for( i=0;i<2;i++ )
 {
  for( k=0;k<10;k++ )
  {
   printf( "%d,",p[i][k] );
  }
  printf( "\n" );
 }
}

void main()
{
 int val[20]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};

 func1( (int (*)[10])val );
}



2010/11/06 テクスチャアトラス
1つにまとめた画像をテクスチャアトラスと呼ぶらしい。

複数のテクスチャを glBindTexture で切り替えるよりも画像を1つにまとめて
テクスチャ座標で指定(切り替え)した方が処理が速くなる。

これは DirectX でも同様らしい。



2010/10/29 四角形を3Dで描画する
下の図のような頂点 ABCD の四角形を描画する。
頂点の順番で右回りと左回りで面の裏表が変わるので
座標系( OpenGL と Direct3D では異なる。)に合わせて選択する。

A B
D C

TRIANGLE_STRIP で描画する場合は
ABDC もしくは ADBC の順番で頂点を指定する。

POLYGON,QUAD で描画する場合は
ABCD もしくは ADCB の順番で頂点を指定する。



2010/10/10 mfc100.dll
「mfc100.dll が見つからなかったため、アプリケーションを開始できませんでした。」と
エラーが出た場合は VC++ 2010 再配布パッケージをインストールすると解決する。

VC製品バージョン MFC 備考
Microsoft C/C++ 7.0 MFC 1.0 -
Visual C++ 1.0 MFC 2.0 -
Visual C++ 2.0 MFC 3.0 -
Visual C++ 2.1 MFC 3.1 -
Visual C++ 2.2 MFC 3.2 -
Visual C++ 4.0 MFC 4.0 -
Visual C++ 4.1 MFC 4.1 -
Visual C++ 4.2 MFC 4.2 mfc42.dll
Visual C++ 5.0 MFC 4.21 mfc42.dll
Visual C++ 6.0 MFC 6.0 mfc42.dll
Visual C++ .NET 2002 MFC 7.0 mfc70.dll
Visual C++ .NET 2003 MFC 7.1 mfc71.dll
Visual C++ .NET 2005 MFC 8.0 mfc80.dll
VC++ 2005再配布パッケージに含まれる。
Visual C++ .NET 2008 MFC 9.0 mfc90.dll
VC++ 2008再配布パッケージに含まれる。
Visual C++ .NET 2010 MFC 10.0 mfc100.dll
VC++ 2010再配布パッケージに含まれる。




2010/09/29 float の無効値
VC のデバッガで float 型が「1.#IND000000000000」と表示される。

IND → 計算結果が無効な値?
INF → 計算結果が無効な値?
NaN → 計算結果が無限大。

オーバーフローした時になるらしい。
IND と INF の違いは?



2010/09/24 多重インクルードの回避
複数回インクルードされるのを防ぐプリプロセッサ。

#ifndef __HOGE_H__
#define __HOGE_H__
〜宣言〜
#endif // __HOGE_H__

上の記述と同等のプラグマ。(ただし、コンパイラ依存)
#pragma once
〜宣言〜

この2つを合わせて使っても意味はない。



2010/09/09 タイマー精度 (winmm.lib)
何もしない状態だと Sleep(1) としても 1ms を
大幅に超える時間が経過した後に処理が終了する。
timeBeginPeriod(1) を実行すると最小単位が 1ms となるので
Sleep(1) での動作が改善される。

この影響を受ける関数↓は他にもあるかも知れない。
timeSetEvent(),Sleep(),GetTickCount(),timeGetTime()

しかも timeBeginPeriod() は OS で共通の設定っぽい。

WindowsXP ではソフトAで timeBeginPeriod(1) を実行し、
ソフトBで Sleep(1) を実行しても 1ms となり効果はある。
ただし、ソフトAを終了し、 timeEndPeriod(1) が呼ばれた後に
ソフトBで Sleep(1) を実行した場合には 1ms で動作しなくなる。

なお、最近のPCでは timeBeginPeriod(1) としても問題ないが
timeGetDevCaps() で設定可能な最小値を取得して
設定するのが正しい実装。



2010/09/01 古い関数の警告を発生させる
Visual Studio 2005 以降で strcpy 等の標準関数を使うと
「warning C4996: 'strcpy' が古い形式として宣言されました。」と
警告が発生するけどこれは deprecated が定義されているから。

つまり deprecated を使えば同じ事が実現できるけど VC2005 と gcc では構文が違う。

#if defined(MSC_VER)
// VC++
__declspec(deprecated("*** This function should not be used.")) void old_func();
#else
// GCC
void old_func () __attribute__ ((deprecated));
#endif



2010/08/25 無効ヒープ
VC のデバッグ版で実行した時に出たエラーログ。

HEAP[test.exe]: Invalid address specified to RtlValidateHeap( 00260000, 0012F5A4 )

主に exe と dll でリンクしている CRT が違う場合にヒープが異なる為に発生する問題。

それ以外にもスタック変数を delete しても起きる。



2010/08/24 メモリアクセス違反
VC のデバッグ版で実行した時に出たエラーログ。

Heap block at 0024A0F0 modified at 0024B2F8 past requested size of 1200

0x0024A0F0 番地に確保されたヒープブロックにおいて、確保したサイズ"1200"を超えた
0x0024B2F8 番地が変更されたらしい。

●考えられる原因
・そもそも確保したメモリサイズが少ない。
・確保したメモリ以上の範囲でループを回してしまった。
・構造体のサイズを間違えている。(アライメントの影響とか。)



2010/08/21 スタックのアライメント
コンパイラに AUTO 変数のアドレスが奇数にならないように支持する。
奇数アドレスのアクセス制限は 2010/05/21 を参照。

VC6 だとこんな感じで使える。(SP6からのサポート)
#define ALIGNED __declspec(align(16))

ALIGNED float temp[4]


struct __declspec(align(16)) OPT_BUFFER
{
  char buffer[8];
  int size;
};

VC6 と gcc では構文が違うのでマクロとか。
#if defined(MSC_VAR)
 #define ATTRIBUTE_ALIGN(n) __declspec(align(n))
#else
 #define ATTRIBUTE_ALIGN(n) __attribute__((aligned(n)))
#endif



2010/06/19 コンパイラ バージョン
Microsoft (_MSC_VER)
コンパイラ 数値
MS C 6.0 600
MS C/C++ 7.0 700
Visual C++ 1.0 800
Visual C++ 2.0 900
Visual C++ 4.0 1000
Visual C++ 4.1 1010
Visual C++ 4.2 1020
Visual C++ 5.0 (VS 97) 1100
Visual C++ 6.0 (VS 6.0) 1200
Visual C++ 7.0 (VS 2002) 1300
Visual C++ 7.1 (VS 2003) 1310
Visual C++ 8.0 (VS 2005) 1400
Visual C++ 9.0 (VS 2008) 1500
Visual C++ 10.0 (VS 2010) 1600


Borland (__TURBOC__)
コンパイラ 数値
Turbo C 2.0 0x18d
Turbo C++ 1.01 0x296
Turbo C++ for Win3.1 0x400
Turbo C++ 4.0 0x452


Borland (__BORLANDC__)
コンパイラ 数値
Borland C++ 5.0 0x500
Borland C++ 5.51 0x551
Borland C++ Builder 1.0 0x520
Borland C++ Builder 3.0 0x530
Borland C++ Builder 6.0 0x560
Borland C++ Builder 2009 0x610
Borland C++ Builder 2010 0x620
Borland C++ Builder 2010
Update 2
0x621


Watcom (__WATCOMC__)
コンパイラ 数値
Watcom C++ 10.5 1050
Watcom C++ 11.0 1100
OpenWatcom 1.1 1210
OpenWatcom 1.4 1240
OpenWatcom 1.9 1290


Intel (__INTEL_COMPILER)
コンパイラ 数値
Intel Compiler 6.0 600
Intel Compiler 11.0 1100


Metrowerks (__MWERKS__)
コンパイラ 数値
CodeWarrior 7.0 (__MWERKS__ & 0xFF00) == 0x2400
CodeWarrior 8.0 (__MWERKS__ & 0xFF00) == 0x3000
CodeWarrior 9.0 (__MWERKS__ & 0xFF00) == 0x3200


gcc (__GNUC__)
コンパイラ 数値
GNU C/C++ 2.7.0 __GNUC__ 2
__GNUC_MINOR__ 7
__GNUC_PATCHLEVEL__ 0
GNU C/C++ 3.0.2 __GNUC__ 3
__GNUC_MINOR__ 0
__GNUC_PATCHLEVEL__ 2


MinGW (__MINGW32__)
コンパイラ 数値
MinGW 2.4 __MINGW32_MAJOR_VERSION 2
__MINGW32_MINOR_VERSION 4


DJGPP (__DJGPP__)
コンパイラ 数値
DJGPP 2.01 __DJGPP__ 2
__DJGPP_MINOR__ 1




2010/05/22 volatile
コンパイラには必ずメモリにアクセスするコードを生成するように指示する。
マルチスレッドや割り込みのコーディングで必要になる。

問題のコード。
int x = 0;
int flag = 1; // 別スレッドから書き換える

while( flag )
{
  x++;
}

コンパイラが最適化すると…
int x = 0;

while( 1 ) // 最適化でメンバ変数が抹消され、無限ループになる。
{
  x++;
}

対策コード。
int x = 0;
volatile int flag = 1; // 必ずメモリを参照する

while( flag )
{
  x++;
}

volatile で最適化されなくなる。



2010/05/21 UNALIGNED と __unaligned
UNALIGNED キーワードを使うとコンパイラが
奇数アドレスへのアクセスを意識したコードを生成する。
ただし、余計なコードが生成されるので速度は低下する。

x86 では不要だけど RISC 系 CPU (SH4,MIPS)では必要。

問題のコード。
char c[8];
int* p;
int q;

p = (int*)&c[1];

q = *p; // 例外が発生する

対策コード。
char c[8];
UNALIGNED int* p; // UNALIGNEDを宣言
int q;

p = (UNALIGNED int*)&c[1];

q = *p; // 例外が発生しなくなる



2010/02/27 "#ifdef xyz" と "#if defined(xyz)"
● defined(xyz) の利点

#if defined(xyz1) || defined(xyz2)
 〜
#endif

と複数の定義を or や and 条件で比較して記述できる。

また、複数の連続条件判定もできる。

#if defined(xyz1)
 〜
#elif defined(xyz2)
 〜
#endif

これらは全て #ifdef では実現できない。



2010/02/22 VC のC++規格対応度
未だに VC6 を使っている人は多いのではないかとと思ったり。

VC の C99 サポートは VC++2005 で使用可能?



2010/01/04 DllMain の制約
DllMain でやってはイケないこと。

●DllMain の中で 再度 DllMain が呼ばれる実装
ローダは DllMain を実行する前にロックをかけるので以下の API を
DllMain で呼び出すとデッドロックしてしまう。
・LoadLibrary 系
・GetModuleHandle 系
・スレッド操作系 + CriticalSection 系

●DllMain の中で Kernel32 以外の API の使用禁止
DllMainが実行された段階で user32.dll/gdi32.dll 等の DLL の
初期化が完了していないケースが存在し、例外(アクセス違反)が
発生する可能性がある。

●マネージドコードの使用禁止
C#



2009/12/29 VC ftol の実装
Visual C++ 2002 以降では float/double から__int64/int の変換に_ftol2 を使い、
2005 以降では更に float/double から int の変換に _ftol2_sse を試行した後
_ftol2 を使用する。
これらの関数の中では浮動小数点制御ワードの変更を行わず切り捨てを実現する。
_ftol2 の中では浮動小数点のビット表現を利用した計算のみで切り捨てを行う。



2009/11/09 VC6 で ftol2 のリンクエラー
最新のVC用のライブラリをリンクしたりすると発生する。
ftol2 で望んでいる結果は ftol と同じなので以下のコードで
問題を回避出来る。

extern "C" long _ftol2( double dblSource )
{
  return _ftol( dblSource );
}



2009/10/17 VC6 SP6
Visual C++ 6.0 SP6 はパッチ無し状態と比べて約 10KB ほど大きな実行ファイルを
生成する。

CRT ライブラリもしくはスタートアップのコードが大きくなったと思われる。



2009/10/11 VC6 Tiny EXE
この大容量化した時代に需要があるとは思えないが…。

Cランタイムを使わなければ数十KB、サイズが小さくなるというやつです。

これを行うと exe のサイズは小さくなりますが、
代償としてCランタイム+αの機能が使えなくなります。
(C++の主要機能も使えなくなるようです。)


●とりあえず発生する制限を回避する方法。

・浮動少数から整数へのキャスト → _ftol が無いとリンカでエラーになる。
 (コンパイラは _ftol を呼び出すコードを生成する)

対象方法は2つ。
→ ftol 相当の関数をCで実装し、キャストを全て自作関数に置き換える
→ _ftol を実装する。(要アセンブラ)

↓は IEEE754 フォーマット処理が面倒なのでインラインアセンブラで手抜きの例。
/*
ftol 関数では、浮動小数点型から整数型への変換に加えて、
浮動小数点制御ワードのビット 10 と 11 を設定して、
FPU (Floating-Point Unit) の丸めモードをゼロ (切り捨て) にします。
したがって、浮動小数点型から整数型への変換は、ANSI C 規格どおりに行われ、
小数部分を破棄することが保証されます。
*/
EXTERN_C int _fltused = 0x9875; // 合わせて必要(ランタイムライブラリで使用される)
long __cdecl _ftol(float f)
{
long x;
#if 0
// x87 丸めモードのビットは考慮しないのでどれになるか保証できない
// ・一番近い値に丸める (中間の場合は偶数)。
// ・負の無限大に丸める。
// ・正の無限大に丸める。
// ・ゼロに丸める。
float temp = 0.5f;
_asm
{
fld dword ptr [f] ; 少数ロード
fsub dword ptr [temp] ; 0.5を引いて
fistp dword ptr [x] ; 整数ストア
}
#else
short temp1; // ビット初期状態
short temp2; // ビット変更状態
_asm
{
fld dword ptr [f] ; 少数ロード
wait ; コプロ完了待ち
fnstcw word ptr [temp1] ; バックアップ
wait ; コプロ完了待ち
mov ax,word ptr [temp1] ; レジスタに移す
or ah,0Ch ; ビット立てる(ANSI 準拠)
mov word ptr [temp2],ax ; 代入
fldcw word ptr [temp2] ; モード変更
fistp dword ptr [x] ; 整数ストア
fldcw word ptr [temp1] ; 元に戻す
}
#endif
return x;
}


・大きな配列の AUTO 変数を引数で渡す → _chkstk が無いとリンカでエラーになる。

対象方法は2つ。
→ AUTO 変数を static にしてしまう。
→ _chkstk を実装する。(要アセンブラ)
chkstk.asm / .obj って Enterprise Edition にしか入ってないみたい…?

海外サイトを探すと chkstk のソースはあるんだけど、
MASM 6.14 でアセンブルしても正常に実行できない。

なので文法を NASM に書き換えてアセンブルすればビルドできる。



2007/xx/xx 静的クラスのコンストラクタ
VC6 の仕様らしいが…

クラスのインスタンスを static で生成すると VC6 では困った動作になる。
・デバッグ版でビルドするとコンストラクタは呼ばれる。
・リリース版でビルドするとコンストラクタが呼ばれない

gcc とか他のコンパイラはどうなんだろ?



2007/02/20 afxres.h
環境を変えたらリソーススクリプトで afxres.h が存在しないと
エラーが出てビルドが通らなくなった。

fatal error RC1015: cannot open include file 'afxres.h'.

調べてみるとMFCのヘッダファイルらしい。
そういえばインストールの時にMFCのチェックを外したな…

Express Edition はMFCが付属していないので同様の問題が発生する。

とりあえずこんな感じで修正すればビルドは通るが…
//#include "afxres.h"
#include "windows.h"
#define IDC_STATIC -1



2006/05/04 Opteron Rev.F の新命令
RDTSCP
 RDTSCPは、RDTSCを改良した命令です。
RDTSCは1命令で1増加するカウンタであるTSCを読み込む命令です。
AMD x86_64では実行しているCPUによって TSC の値が変わってしまうという問題が
ありました。

  RDTSCP命令はTSCだけでなく、同時にTSC_AUX領域の中身も読み込みます。
TSC_AUX領域はCPUごとに違う値を持たせることができるので、
CPU番号などを埋め込んでおけば、どのCPUで命令が実行されているのかを
確認できます。



2006/04/16 ウワサ
SetThreadAffinityMask() が機能しないことがあるらしい。

開発環境が VC Enterprise Edition でないと完璧な動作はしないとか…。
事実ならスタートアップ・モジュールが違うのかな?



2005/01/27 WinMainCRTStartup
VC のスタートアップ・モジュール。

実行時にCランタイムライブリの初期化等を実行した後に
WinMain を呼び出す関数。

コンパイラ(ソフト)が変わると名称も変わるらしい。
Borland は当然、別の名称を使っている?






Back (だるだる団)