From: djsollen@google.com Date: Mon, 29 Apr 2013 12:09:31 +0000 (+0000) Subject: Copy the top level Android directory into trunk. X-Git-Tag: accepted/tizen/5.0/unified/20181102.025319~12578 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=dcdd57faf02fb4fd23bb8265392b9c22e068907e;p=platform%2Fupstream%2FlibSkiaSharp.git Copy the top level Android directory into trunk. This CL is the first step in a series needed to move the android directory into trunk. After the copy we will update GYP and DEPS to point to the new location and only then remove the original directory. git-svn-id: http://skia.googlecode.com/svn/trunk@8891 2bbb7eff-a529-9590-31e7-b0007b416f81 --- diff --git a/platform_tools/android/.gitignore b/platform_tools/android/.gitignore new file mode 100644 index 0000000..e8a6d18 --- /dev/null +++ b/platform_tools/android/.gitignore @@ -0,0 +1,11 @@ +/third_party/externals/ +/toolchains/ +.cproject +.externalToolBuilders/ +.project +.pydevproject +app/.classpath +app/.project +app/bin/ +app/gen/ +app/lint.xml diff --git a/platform_tools/android/DEPS b/platform_tools/android/DEPS new file mode 100644 index 0000000..82ca559 --- /dev/null +++ b/platform_tools/android/DEPS @@ -0,0 +1,17 @@ +use_relative_paths = True + +# Dependencies on external packages. +deps = { + "third_party/externals/expat" : "https://android.googlesource.com/platform/external/expat.git", + "third_party/externals/gif" : "https://android.googlesource.com/platform/external/giflib.git", + "third_party/externals/png" : "https://android.googlesource.com/platform/external/libpng.git", + "third_party/externals/jpeg" : "https://android.googlesource.com/platform/external/jpeg.git", +} + +#hooks = [ +# { +# # A change to a .gyp, .gypi, or to GYP itself should run the generator. +# "pattern": ".", +# "action": ["python", "trunk/gyp_skia"], +# }, +#] diff --git a/platform_tools/android/app/AndroidManifest.xml b/platform_tools/android/app/AndroidManifest.xml new file mode 100644 index 0000000..7b7f7bc --- /dev/null +++ b/platform_tools/android/app/AndroidManifest.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/platform_tools/android/app/build.xml b/platform_tools/android/app/build.xml new file mode 100644 index 0000000..fbba716 --- /dev/null +++ b/platform_tools/android/app/build.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/platform_tools/android/app/jni/com_skia_SkiaIntentService.cpp b/platform_tools/android/app/jni/com_skia_SkiaIntentService.cpp new file mode 100644 index 0000000..cd1d6a1 --- /dev/null +++ b/platform_tools/android/app/jni/com_skia_SkiaIntentService.cpp @@ -0,0 +1,38 @@ +#include "com_skia_SkiaIntentService.h" + +#include +#include + +extern int main(int argc, char * const argv[]); + +void cleanUp(JNIEnv* env, jobjectArray jstrs, const char** strs, int32_t count) { + for (int32_t i = 0; i < count; ++i) + env->ReleaseStringUTFChars( + (jstring) env->GetObjectArrayElement(jstrs, i), strs[i]); +} + +JNIEXPORT jint JNICALL Java_com_skia_SkiaIntentService_run( + JNIEnv* env, + jobject, + jobjectArray args) { + + // Convert command line arguments to C format. + int argc = env->GetArrayLength(args); + const char** argv = new const char*[argc]; + for (int32_t i = 0; i < argc; ++i) { + jstring str = (jstring) env->GetObjectArrayElement(args, i); + argv[i] = env->GetStringUTFChars(str, NULL); + if (NULL == argv[i]) { + cleanUp(env, args, argv, i - 1); + return 1; + } + } + + // Execute program main() + int retval = main(argc, (char* const*) argv); + + // Clean up temporaries and return the exit code. + cleanUp(env, args, argv, argc); + delete[] argv; + return retval; +} diff --git a/platform_tools/android/app/jni/com_skia_SkiaIntentService.h b/platform_tools/android/app/jni/com_skia_SkiaIntentService.h new file mode 100644 index 0000000..89fbfd2 --- /dev/null +++ b/platform_tools/android/app/jni/com_skia_SkiaIntentService.h @@ -0,0 +1,21 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class com_skia_SkiaIntentService */ + +#ifndef _Included_com_skia_SkiaIntentService +#define _Included_com_skia_SkiaIntentService +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: com_skia_SkiaIntentService + * Method: run + * Signature: ([Ljava/lang/String;)I + */ +JNIEXPORT jint JNICALL Java_com_skia_SkiaIntentService_run + (JNIEnv *, jobject, jobjectArray); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/platform_tools/android/app/jni/com_skia_SkiaSampleRenderer.cpp b/platform_tools/android/app/jni/com_skia_SkiaSampleRenderer.cpp new file mode 100644 index 0000000..9817074 --- /dev/null +++ b/platform_tools/android/app/jni/com_skia_SkiaSampleRenderer.cpp @@ -0,0 +1,324 @@ + +/* + * Copyright 2011 Skia + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +#include "com_skia_SkiaSampleRenderer.h" + +#include "GrContext.h" +#include "gl/GrGLInterface.h" +#include "SampleApp.h" +#include "SkApplication.h" +#include "SkCanvas.h" +#include "SkDevice.h" +#include "SkEvent.h" +#include "SkWindow.h" + +#include +#include "android/AndroidKeyToSkKey.h" + + +/////////////////////////////////////////// +///////////////// Globals ///////////////// +/////////////////////////////////////////// + +struct ActivityGlue { + JNIEnv* m_env; + jweak m_obj; + jmethodID m_setTitle; + jmethodID m_setSlideList; + jmethodID m_addToDownloads; + ActivityGlue() { + m_env = NULL; + m_obj = NULL; + m_setTitle = NULL; + m_setSlideList = NULL; + m_addToDownloads = NULL; + } +} gActivityGlue; + +struct WindowGlue { + jweak m_obj; + jmethodID m_inval; + jmethodID m_queueSkEvent; + jmethodID m_startTimer; + WindowGlue() { + m_obj = NULL; + m_inval = NULL; + m_queueSkEvent = NULL; + m_startTimer = NULL; + } +} gWindowGlue; + +SampleWindow* gWindow; + +/////////////////////////////////////////// +///////////// SkOSWindow impl ///////////// +/////////////////////////////////////////// + +void SkOSWindow::onSetTitle(const char title[]) +{ + JNIEnv* env = gActivityGlue.m_env; + if (!env) { + return; + } + if (env->IsSameObject(gActivityGlue.m_obj, NULL)) { + SkDebugf("ERROR: The JNI WeakRef to the Activity is invalid"); + return; + } + + jstring string = env->NewStringUTF(title); + env->CallVoidMethod(gActivityGlue.m_obj, gActivityGlue.m_setTitle, string); + env->DeleteLocalRef(string); +} + +void SkOSWindow::onHandleInval(const SkIRect& rect) +{ + JNIEnv* env = gActivityGlue.m_env; + if (!env || !gWindowGlue.m_inval || !gWindowGlue.m_obj) { + return; + } + if (env->IsSameObject(gWindowGlue.m_obj, NULL)) { + SkDebugf("ERROR: The JNI WeakRef to the Window is invalid"); + return; + } + env->CallVoidMethod(gWindowGlue.m_obj, gWindowGlue.m_inval); +} + +void SkOSWindow::onPDFSaved(const char title[], const char desc[], + const char path[]) +{ + JNIEnv* env = gActivityGlue.m_env; + if (!env || !gActivityGlue.m_addToDownloads || !gActivityGlue.m_obj) { + return; + } + if (env->IsSameObject(gActivityGlue.m_obj, NULL)) { + SkDebugf("ERROR: The JNI WeakRef to the Activity is invalid"); + return; + } + + jstring jtitle = env->NewStringUTF(title); + jstring jdesc = env->NewStringUTF(desc); + jstring jpath = env->NewStringUTF(path); + + env->CallVoidMethod(gActivityGlue.m_obj, gActivityGlue.m_addToDownloads, + jtitle, jdesc, jpath); + + env->DeleteLocalRef(jtitle); + env->DeleteLocalRef(jdesc); + env->DeleteLocalRef(jpath); +} + +/////////////////////////////////////////// +/////////////// SkEvent impl ////////////// +/////////////////////////////////////////// + +void SkEvent::SignalQueueTimer(SkMSec ms) +{ + JNIEnv* env = gActivityGlue.m_env; + if (!env || !gWindowGlue.m_startTimer || !gWindowGlue.m_obj || !ms) { + return; + } + if (env->IsSameObject(gWindowGlue.m_obj, NULL)) { + SkDebugf("ERROR: The JNI WeakRef to the Window is invalid"); + return; + } + env->CallVoidMethod(gWindowGlue.m_obj, + gWindowGlue.m_startTimer, ms); +} + +void SkEvent::SignalNonEmptyQueue() +{ + JNIEnv* env = gActivityGlue.m_env; + if (!env || !gWindowGlue.m_queueSkEvent || !gWindowGlue.m_obj) { + return; + } + if (env->IsSameObject(gWindowGlue.m_obj, NULL)) { + SkDebugf("ERROR: The JNI WeakRef to the Window is invalid"); + return; + } + env->CallVoidMethod(gWindowGlue.m_obj, gWindowGlue.m_queueSkEvent); +} + +/////////////////////////////////////////// +////////////////// JNI //////////////////// +/////////////////////////////////////////// + +static jmethodID GetJMethod(JNIEnv* env, jclass clazz, const char name[], + const char signature[]) +{ + jmethodID m = env->GetMethodID(clazz, name, signature); + if (!m) SkDebugf("Could not find Java method %s\n", name); + return m; +} + +JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_init(JNIEnv* env, + jobject thiz, jobject jsampleActivity) +{ + // setup jni hooks to the java activity + gActivityGlue.m_env = env; + jclass clazz = env->FindClass("com/skia/SkiaSampleActivity"); + gActivityGlue.m_obj = env->NewWeakGlobalRef(jsampleActivity); + gActivityGlue.m_setTitle = GetJMethod(env, clazz, "setTitle", "(Ljava/lang/CharSequence;)V"); + gActivityGlue.m_setSlideList = GetJMethod(env, clazz, "setSlideList", "([Ljava/lang/String;)V"); + gActivityGlue.m_addToDownloads = GetJMethod(env, clazz, "addToDownloads", + "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); + env->DeleteLocalRef(clazz); + + // setup jni hooks to the java renderer + clazz = env->FindClass("com/skia/SkiaSampleRenderer"); + gWindowGlue.m_obj = env->NewWeakGlobalRef(thiz); + gWindowGlue.m_inval = GetJMethod(env, clazz, "requestRender", "()V"); + gWindowGlue.m_queueSkEvent = GetJMethod(env, clazz, "queueSkEvent", "()V"); + gWindowGlue.m_startTimer = GetJMethod(env, clazz, "startTimer", "(I)V"); + env->DeleteLocalRef(clazz); + + application_init(); + // TODO: push ability to select skp dir into the UI + const char* argv[] = { "SampleApp", "--pictureDir", "/sdcard/skiabot/skia_skp" }; + gWindow = new SampleWindow(NULL, sizeof(argv)/sizeof(char*), const_cast(argv), NULL); + + // send the list of slides up to the activity + const int slideCount = gWindow->sampleCount(); + jobjectArray slideList = env->NewObjectArray(slideCount, env->FindClass("java/lang/String"), env->NewStringUTF("")); + for (int i = 0; i < slideCount; i++) { + jstring slideTitle = env->NewStringUTF(gWindow->getSampleTitle(i).c_str()); + env->SetObjectArrayElement(slideList, i, slideTitle); + env->DeleteLocalRef(slideTitle); + } + env->CallVoidMethod(gActivityGlue.m_obj, gActivityGlue.m_setSlideList, slideList); + env->DeleteLocalRef(slideList); +} + +JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_term(JNIEnv* env, + jobject thiz) +{ + delete gWindow; + gWindow = NULL; + application_term(); + if (gWindowGlue.m_obj) { + env->DeleteWeakGlobalRef(gWindowGlue.m_obj); + gWindowGlue.m_obj = NULL; + } + if (gActivityGlue.m_obj) { + env->DeleteWeakGlobalRef(gActivityGlue.m_obj); + gActivityGlue.m_obj = NULL; + } +} + +JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_draw( + JNIEnv* env, jobject thiz) +{ + if (!gWindow) return; + gWindow->update(NULL); +} + +JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_updateSize(JNIEnv* env, + jobject thiz, jint w, jint h) +{ + gWindow->resize(w, h); +} + +JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_handleClick(JNIEnv* env, + jobject thiz, jint owner, jfloat x, jfloat y, jint jstate) +{ + SkView::Click::State state; + switch(jstate) { + case 0: // MotionEvent.ACTION_DOWN + state = SkView::Click::kDown_State; + break; + case 1: // MotionEvent.ACTION_UP + case 3: // MotionEvent.ACTION_CANCEL + state = SkView::Click::kUp_State; + break; + case 2: // MotionEvent.ACTION_MOVE + state = SkView::Click::kMoved_State; + break; + default: + SkDebugf("motion event ignored\n"); + return; + } + gWindow->handleClick(x, y, state, (void*) owner); +} + +JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_nextSample( + JNIEnv* env, jobject thiz) +{ + gWindow->nextSample(); +} + +JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_previousSample( + JNIEnv* env, jobject thiz) +{ + gWindow->previousSample(); +} + +JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_goToSample( + JNIEnv* env, jobject thiz, jint position) +{ + gWindow->goToSample(position); +} + +JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_toggleRenderingMode( + JNIEnv* env, jobject thiz) +{ + gWindow->toggleRendering(); +} + +JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_showOverview( + JNIEnv* env, jobject thiz) +{ + gWindow->showOverview(); +} + +JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_toggleSlideshow( + JNIEnv* env, jobject thiz) +{ + gWindow->toggleSlideshow(); +} + +JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_toggleFPS( + JNIEnv* env, jobject thiz) +{ + gWindow->toggleFPS(); +} + +JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_toggleTiling( + JNIEnv* env, jobject thiz) +{ + gWindow->handleChar('t'); +} + +JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_toggleBBox( + JNIEnv* env, jobject thiz) +{ + gWindow->handleChar('b'); +} + +JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_processSkEvent( + JNIEnv* env, jobject thiz) +{ + if (SkEvent::ProcessEvent()) { + SkEvent::SignalNonEmptyQueue(); + } +} + +JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_serviceQueueTimer( + JNIEnv* env, jobject thiz) +{ + SkEvent::ServiceQueueTimer(); +} + +JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_saveToPDF( + JNIEnv* env, jobject thiz) +{ + gWindow->saveToPdf(); +} + +JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_postInval( + JNIEnv* env, jobject thiz) +{ + gWindow->postInvalDelay(); +} diff --git a/platform_tools/android/app/jni/com_skia_SkiaSampleRenderer.h b/platform_tools/android/app/jni/com_skia_SkiaSampleRenderer.h new file mode 100644 index 0000000..5d37123 --- /dev/null +++ b/platform_tools/android/app/jni/com_skia_SkiaSampleRenderer.h @@ -0,0 +1,157 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class com_skia_SkiaSampleRenderer */ + +#ifndef _Included_com_skia_SkiaSampleRenderer +#define _Included_com_skia_SkiaSampleRenderer +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: com_skia_SkiaSampleRenderer + * Method: init + * Signature: (Lcom/skia/SkiaSampleActivity;)V + */ +JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_init + (JNIEnv *, jobject, jobject); + +/* + * Class: com_skia_SkiaSampleRenderer + * Method: term + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_term + (JNIEnv *, jobject); + +/* + * Class: com_skia_SkiaSampleRenderer + * Method: draw + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_draw + (JNIEnv *, jobject); + +/* + * Class: com_skia_SkiaSampleRenderer + * Method: updateSize + * Signature: (II)V + */ +JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_updateSize + (JNIEnv *, jobject, jint, jint); + +/* + * Class: com_skia_SkiaSampleRenderer + * Method: handleClick + * Signature: (IFFI)V + */ +JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_handleClick + (JNIEnv *, jobject, jint, jfloat, jfloat, jint); + +/* + * Class: com_skia_SkiaSampleRenderer + * Method: showOverview + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_showOverview + (JNIEnv *, jobject); + +/* + * Class: com_skia_SkiaSampleRenderer + * Method: nextSample + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_nextSample + (JNIEnv *, jobject); + +/* + * Class: com_skia_SkiaSampleRenderer + * Method: previousSample + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_previousSample + (JNIEnv *, jobject); + +/* + * Class: com_skia_SkiaSampleRenderer + * Method: goToSample + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_goToSample + (JNIEnv *, jobject, jint); + +/* + * Class: com_skia_SkiaSampleRenderer + * Method: toggleRenderingMode + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_toggleRenderingMode + (JNIEnv *, jobject); + +/* + * Class: com_skia_SkiaSampleRenderer + * Method: toggleSlideshow + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_toggleSlideshow + (JNIEnv *, jobject); + +/* + * Class: com_skia_SkiaSampleRenderer + * Method: toggleFPS + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_toggleFPS + (JNIEnv *, jobject); + +/* + * Class: com_skia_SkiaSampleRenderer + * Method: toggleTiling + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_toggleTiling + (JNIEnv *, jobject); + +/* + * Class: com_skia_SkiaSampleRenderer + * Method: toggleBBox + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_toggleBBox + (JNIEnv *, jobject); + +/* + * Class: com_skia_SkiaSampleRenderer + * Method: processSkEvent + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_processSkEvent + (JNIEnv *, jobject); + +/* + * Class: com_skia_SkiaSampleRenderer + * Method: serviceQueueTimer + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_serviceQueueTimer + (JNIEnv *, jobject); + +/* + * Class: com_skia_SkiaSampleRenderer + * Method: saveToPdf + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_saveToPDF + (JNIEnv *, jobject); + +/* + * Class: com_skia_SkiaSampleRenderer + * Method: postInval + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_skia_SkiaSampleRenderer_postInval + (JNIEnv *, jobject); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/platform_tools/android/app/project.properties b/platform_tools/android/app/project.properties new file mode 100644 index 0000000..0840b4a --- /dev/null +++ b/platform_tools/android/app/project.properties @@ -0,0 +1,14 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system edit +# "ant.properties", and override values to adapt the script to your +# project structure. +# +# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): +#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt + +# Project target. +target=android-15 diff --git a/platform_tools/android/app/res/drawable-hdpi/ic_btn_find_next.png b/platform_tools/android/app/res/drawable-hdpi/ic_btn_find_next.png new file mode 100644 index 0000000..b696a6b Binary files /dev/null and b/platform_tools/android/app/res/drawable-hdpi/ic_btn_find_next.png differ diff --git a/platform_tools/android/app/res/drawable-hdpi/ic_btn_find_prev.png b/platform_tools/android/app/res/drawable-hdpi/ic_btn_find_prev.png new file mode 100644 index 0000000..5550c5a Binary files /dev/null and b/platform_tools/android/app/res/drawable-hdpi/ic_btn_find_prev.png differ diff --git a/platform_tools/android/app/res/layout/layout.xml b/platform_tools/android/app/res/layout/layout.xml new file mode 100644 index 0000000..cdb90e9 --- /dev/null +++ b/platform_tools/android/app/res/layout/layout.xml @@ -0,0 +1,17 @@ + + + + + + diff --git a/platform_tools/android/app/res/menu/action_bar.xml b/platform_tools/android/app/res/menu/action_bar.xml new file mode 100644 index 0000000..2e8cf70 --- /dev/null +++ b/platform_tools/android/app/res/menu/action_bar.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + diff --git a/platform_tools/android/app/res/values/strings.xml b/platform_tools/android/app/res/values/strings.xml new file mode 100644 index 0000000..610ef38 --- /dev/null +++ b/platform_tools/android/app/res/values/strings.xml @@ -0,0 +1,13 @@ + + + Skia Samples + Overview + Toggle Rendering + Slideshow + FPS + Toggle Tiling + Toggle SKP BBox + Save to PDF + Save Failed + %s saved! + \ No newline at end of file diff --git a/platform_tools/android/app/src/com/skia/SkiaIntentService.java b/platform_tools/android/app/src/com/skia/SkiaIntentService.java new file mode 100644 index 0000000..e2707f7 --- /dev/null +++ b/platform_tools/android/app/src/com/skia/SkiaIntentService.java @@ -0,0 +1,93 @@ +// Copyright 2012 Google Inc. All Rights Reserved. + +package com.skia; + +import android.app.IntentService; +import android.content.Intent; +import android.os.Bundle; +import android.os.IBinder; +import android.util.Log; + +/** + * @author borenet@google.com (Eric Boren) + * + */ +public class SkiaIntentService extends IntentService { + public SkiaIntentService() { + super("SkiaIntentService"); + } + + @Override + public IBinder onBind(Intent arg0) { + return null; + } + @Override + public void onCreate() { + super.onCreate(); + } + + @Override + public void onDestroy() { + super.onDestroy(); + } + + @Override + public void onHandleIntent(Intent intent) { + + // Extract command-line arguments + Bundle bundle = intent.getExtras(); + + // Number of times to repeat the SkiaReturnCode in the log. + int returnRepeats = bundle.getInt("returnRepeats", 1); + + // We require at least the program name to be specified. + if (!bundle.containsKey("args")) { + Log.e("skia", + "No command line arguments supplied. Unable to continue."); + SkiaReturn(-1, returnRepeats); + return; + } + + String cmd = bundle.getString("args").trim(); + String[] args = cmd.split("\\s+"); + Log.d("skia", "Executing Command: " + cmd); + + // Load the requested library + String lib = args[0]; + try { + System.loadLibrary(lib); + } catch (UnsatisfiedLinkError e) { + Log.e("skia", "Library " + lib + + " could not be linked! Unable to continue."); + SkiaReturn(-1, returnRepeats); + throw e; + } + + // JNI call to run the program + int retval = run(args); + SkiaReturn(retval, returnRepeats); + } + + /** + * Print out the exit code of the native program. Skia's buildbots watch the + * logcat output for this line. The buildbots occasionally have to restart + * a dead adb process, which causes them to miss some log output (Bug: + * https://code.google.com/p/skia/issues/detail?id=809). If this + * "SKIA_RETURN_CODE" line is missed while adb is being restarted, then the + * test may never finish. Therefore, we print the line as many times as the + * caller specifies, waiting one second in between. + */ + private void SkiaReturn(int code, int repeats) { + Log.d("skia", "SKIA_RETURN_CODE " + code); + for (int i = 1; i < repeats; ++i) { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + return; + } + Log.d("skia", "SKIA_RETURN_CODE " + code); + } + } + + native int run(String[] args); +} diff --git a/platform_tools/android/app/src/com/skia/SkiaReceiver.java b/platform_tools/android/app/src/com/skia/SkiaReceiver.java new file mode 100644 index 0000000..b62a979 --- /dev/null +++ b/platform_tools/android/app/src/com/skia/SkiaReceiver.java @@ -0,0 +1,26 @@ +// Copyright 2012 Google Inc. All Rights Reserved. + +package com.skia; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import com.skia.SkiaIntentService; + +/** + * @author borenet@google.com (Eric Boren) + * + */ +public class SkiaReceiver extends BroadcastReceiver +{ + @Override + public void onReceive(Context context, Intent intent) { + Intent skIntent = new Intent(context, SkiaIntentService.class); + + // Forward any command-line arguments to the background service + skIntent.putExtras(intent.getExtras()); + + // Launch executable + context.startService(skIntent); + } +} \ No newline at end of file diff --git a/platform_tools/android/app/src/com/skia/SkiaSampleActivity.java b/platform_tools/android/app/src/com/skia/SkiaSampleActivity.java new file mode 100644 index 0000000..4b5e7d6 --- /dev/null +++ b/platform_tools/android/app/src/com/skia/SkiaSampleActivity.java @@ -0,0 +1,200 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +package com.skia; + +import android.app.ActionBar; +import android.app.Activity; +import android.app.DownloadManager; +import android.content.Context; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.view.KeyEvent; +import android.view.Menu; +import android.view.MenuItem; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.Toast; + +import java.io.File; + +public class SkiaSampleActivity extends Activity +{ + private TextView mTitle; + private SkiaSampleView mSampleView; + + private ArrayAdapter mSlideList; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.layout); + mTitle = (TextView) findViewById(R.id.title_view); + mSampleView = new SkiaSampleView(this); + mSlideList = new ArrayAdapter(this, android.R.layout.simple_expandable_list_item_1); + + try { + System.loadLibrary("SampleApp"); + + LinearLayout holder = (LinearLayout) findViewById(R.id.holder); + holder.addView(mSampleView, new LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT)); + + setupActionBar(); + + } catch (UnsatisfiedLinkError e) { + mTitle.setText("ERROR: native library could not be loaded"); + } + } + + private void setupActionBar() { + ActionBar.OnNavigationListener navigationCallback = new ActionBar.OnNavigationListener() { + @Override + public boolean onNavigationItemSelected(int position, long itemId) { + mSampleView.goToSample(position); + return true; + } + }; + + ActionBar actionBar = getActionBar(); + actionBar.setDisplayShowHomeEnabled(false); + actionBar.setDisplayShowTitleEnabled(false); + actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST); + actionBar.setListNavigationCallbacks(mSlideList, navigationCallback); + } + + @Override + protected void onResume () { + super.onResume(); + if (mSampleView.getWidth() > 0 && mSampleView.getHeight() > 0) { + //TODO try mSampleView.requestRender() instead + mSampleView.inval(); + } + } + + @Override + public void onDestroy() { + mSampleView.terminate(); + super.onDestroy(); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.action_bar, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.overview: + mSampleView.showOverview(); + return true; + case R.id.prev: + mSampleView.previousSample(); + return true; + case R.id.next: + mSampleView.nextSample(); + return true; + case R.id.toggle_rendering: + mSampleView.toggleRenderingMode(); + return true; + case R.id.slideshow: + mSampleView.toggleSlideshow(); + return true; + case R.id.fps: + mSampleView.toggleFPS(); + return true; + case R.id.tiling: + mSampleView.toggleTiling(); + return true; + case R.id.bbox: + mSampleView.toggleBBox(); + return true; + case R.id.save_to_pdf: + mSampleView.saveToPDF(); + return true; + default: + return false; + } + } + + @Override + public boolean dispatchKeyEvent(KeyEvent event) { + final int keycode = event.getKeyCode(); + if (keycode == KeyEvent.KEYCODE_BACK) { + if (event.getAction() == KeyEvent.ACTION_UP) { + finish(); + } + return true; + } + return false; + } + + private static final int SET_TITLE = 1; + private static final int SET_SLIDES = 2; + private static final int TOAST_DOWNLOAD = 3; + + private Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case SET_TITLE: + mTitle.setText((String) msg.obj); + SkiaSampleActivity.this.getActionBar().setSubtitle((String) msg.obj); + break; + case SET_SLIDES: + mSlideList.addAll((String[]) msg.obj); + break; + case TOAST_DOWNLOAD: + Toast.makeText(SkiaSampleActivity.this, (String) msg.obj, + Toast.LENGTH_SHORT).show(); + break; + default: + break; + } + } + }; + + // Called by JNI + @Override + public void setTitle(CharSequence title) { + mHandler.obtainMessage(SET_TITLE, title).sendToTarget(); + } + + // Called by JNI + public void setSlideList(String[] slideList) { + mHandler.obtainMessage(SET_SLIDES, slideList).sendToTarget(); + } + + // Called by JNI + public void addToDownloads(final String title, final String desc, final String path) { + File file = new File(path); + final long length = file.exists() ? file.length() : 0; + if (length == 0) { + String failed = getString(R.string.save_failed); + mHandler.obtainMessage(TOAST_DOWNLOAD, failed).sendToTarget(); + return; + } + String toast = getString(R.string.file_saved).replace("%s", title); + mHandler.obtainMessage(TOAST_DOWNLOAD, toast).sendToTarget(); + final DownloadManager manager = + (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE); + new Thread("Add PDF to downloads") { + @Override + public void run() { + final String mimeType = "application/pdf"; + manager.addCompletedDownload(title, desc, true, mimeType, path, length, true); + } + }.start(); + } +} diff --git a/platform_tools/android/app/src/com/skia/SkiaSampleRenderer.java b/platform_tools/android/app/src/com/skia/SkiaSampleRenderer.java new file mode 100644 index 0000000..1479c92 --- /dev/null +++ b/platform_tools/android/app/src/com/skia/SkiaSampleRenderer.java @@ -0,0 +1,92 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +package com.skia; + +import android.opengl.GLSurfaceView; +import android.os.Handler; + +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.opengles.GL10; + +public class SkiaSampleRenderer implements GLSurfaceView.Renderer { + + private final SkiaSampleView mSampleView; + private Handler mHandler = new Handler(); + + SkiaSampleRenderer(SkiaSampleView view) { + mSampleView = view; + } + + @Override + public void onDrawFrame(GL10 gl) { + draw(); + } + + @Override + public void onSurfaceChanged(GL10 gl, int width, int height) { + updateSize(width, height); + } + + @Override + public void onSurfaceCreated(GL10 gl, EGLConfig config) { + gl.glClearStencil(0); + gl.glClear(GL10.GL_STENCIL_BUFFER_BIT); + init((SkiaSampleActivity)mSampleView.getContext()); + } + + // Called by JNI + private void startTimer(int ms) { + // After the delay, queue an event to the Renderer's thread + // to handle the event on the timer queue + mHandler.postDelayed(new Runnable() { + @Override + public void run() { + mSampleView.queueEvent(new Runnable() { + @Override + public void run() { + serviceQueueTimer(); + } + }); + } + }, ms); + } + + // Called by JNI + private void queueSkEvent() { + mSampleView.queueEvent(new Runnable() { + @Override + public void run() { + processSkEvent(); + } + }); + } + + // Called by JNI + private void requestRender() { + mSampleView.requestRender(); + } + + native void init(SkiaSampleActivity activity); + native void term(); + native void draw(); + native void updateSize(int w, int h); + native void handleClick(int owner, float x, float y, int state); + native void showOverview(); + native void nextSample(); + native void previousSample(); + native void goToSample(int position); + native void toggleRenderingMode(); + native void toggleSlideshow(); + native void toggleFPS(); + native void toggleTiling(); + native void toggleBBox(); + native void processSkEvent(); + native void serviceQueueTimer(); + native void saveToPDF(); + native void postInval(); +} \ No newline at end of file diff --git a/platform_tools/android/app/src/com/skia/SkiaSampleView.java b/platform_tools/android/app/src/com/skia/SkiaSampleView.java new file mode 100644 index 0000000..0d493c9 --- /dev/null +++ b/platform_tools/android/app/src/com/skia/SkiaSampleView.java @@ -0,0 +1,165 @@ +/* + * Copyright 2012 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +package com.skia; + +import android.content.Context; +import android.opengl.GLSurfaceView; +import android.view.MotionEvent; + +public class SkiaSampleView extends GLSurfaceView { + + private final SkiaSampleRenderer mSampleRenderer; + + public SkiaSampleView(Context ctx) { + super(ctx); + + mSampleRenderer = new SkiaSampleRenderer(this); + + setEGLContextClientVersion(2); + setEGLConfigChooser(8,8,8,8,0,8); + setRenderer(mSampleRenderer); + setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + int count = event.getPointerCount(); + for (int i = 0; i < count; i++) { + final float x = event.getX(i); + final float y = event.getY(i); + final int owner = event.getPointerId(i); + int action = event.getAction() & MotionEvent.ACTION_MASK; + switch (action) { + case MotionEvent.ACTION_POINTER_UP: + action = MotionEvent.ACTION_UP; + break; + case MotionEvent.ACTION_POINTER_DOWN: + action = MotionEvent.ACTION_DOWN; + break; + default: + break; + } + final int finalAction = action; + queueEvent(new Runnable() { + @Override + public void run() { + mSampleRenderer.handleClick(owner, x, y, finalAction); + } + }); + } + return true; + } + + public void inval() { + queueEvent(new Runnable() { + @Override + public void run() { + mSampleRenderer.postInval(); + } + }); + } + + public void terminate() { + queueEvent(new Runnable() { + @Override + public void run() { + mSampleRenderer.term(); + } + }); + } + + public void showOverview() { + queueEvent(new Runnable() { + @Override + public void run() { + mSampleRenderer.showOverview(); + } + }); + } + + public void nextSample() { + queueEvent(new Runnable() { + @Override + public void run() { + mSampleRenderer.nextSample(); + } + }); + } + + public void previousSample() { + queueEvent(new Runnable() { + @Override + public void run() { + mSampleRenderer.previousSample(); + } + }); + } + + public void goToSample(final int position) { + queueEvent(new Runnable() { + @Override + public void run() { + mSampleRenderer.goToSample(position); + } + }); + } + + public void toggleRenderingMode() { + queueEvent(new Runnable() { + @Override + public void run() { + mSampleRenderer.toggleRenderingMode(); + } + }); + } + + public void toggleSlideshow() { + queueEvent(new Runnable() { + @Override + public void run() { + mSampleRenderer.toggleSlideshow(); + } + }); + } + + public void toggleFPS() { + queueEvent(new Runnable() { + @Override + public void run() { + mSampleRenderer.toggleFPS(); + } + }); + } + + public void toggleTiling() { + queueEvent(new Runnable() { + @Override + public void run() { + mSampleRenderer.toggleTiling(); + } + }); + } + + public void toggleBBox() { + queueEvent(new Runnable() { + @Override + public void run() { + mSampleRenderer.toggleBBox(); + } + }); + } + + public void saveToPDF() { + queueEvent(new Runnable() { + @Override + public void run() { + mSampleRenderer.saveToPDF(); + } + }); + } +} diff --git a/platform_tools/android/bin/adb_list_devices.py b/platform_tools/android/bin/adb_list_devices.py new file mode 100755 index 0000000..f140484 --- /dev/null +++ b/platform_tools/android/bin/adb_list_devices.py @@ -0,0 +1,153 @@ +#!/usr/bin/python +# +# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +""" adb_list_devices: list information about attached Android devices. """ + + +import os +import re +import shlex +import subprocess +import sys + +# This file, which resides on every Android device, contains a great deal of +# information about the device. +INFO_FILE = '/system/build.prop' + +# Default set of properties to query about a device. +DEFAULT_PROPS_TO_GET = ['ro.product.device', 'ro.build.version.release', + 'ro.build.type'] + + +def GetDeviceInfo(adb, serial, props_to_get): + """ Return a list of values (or "" if no value can be found) for the + given set of properties for the device with the given serial number. + + adb: path to the ADB program. + serial: serial number of the target device. + props_to_get: list of strings indicating which properties to determine. + """ + device_proc = subprocess.Popen([adb, '-s', serial, 'shell', 'cat', + INFO_FILE], stdout=subprocess.PIPE) + code = device_proc.wait() + if code != 0: + raise Exception('Could not query device with serial number %s.' % serial) + output = device_proc.stdout.read() + device_info = [] + for prop in props_to_get: + # Find the property in the outputs + search_str = r'%s=(\S+)' % prop + match = re.search(search_str, output) + if not match: + value = '' + else: + value = match.group(1) + device_info.append(value) + return device_info + + +def PrintPrettyTable(data, file=None): + """ Print out the given data in a nicely-spaced format. This function scans + the list multiple times and uses extra memory, so don't use it for big data + sets. + + data: list of lists of strings, where each list represents a row of data. + This table is assumed to be rectangular; if the length of any list differs + some of the output may not get printed. + file: file-like object into which the table should be written. If none is + provided, the table is written to stdout. + """ + if not file: + file = sys.stdout + column_widths = [0 for length in data[0]] + for line in data: + column_widths = [max(longest_len, len(prop)) for \ + longest_len, prop in zip(column_widths, line)] + for line in data: + for prop, width in zip(line, column_widths): + file.write(prop.ljust(width + 1)) + file.write('\n') + + +def FindADB(hint=None): + """ Attempt to find the ADB program using the following sequence of steps. + Returns the path to ADB if it can be found, or None otherwise. + 1. If a hint was provided, is it a valid path to ADB? + 2. Is ADB in PATH? + 3. Is there an environment variable for ADB? + 4. If the ANDROID_SDK_ROOT variable is set, try to find ADB in the SDK + directory. + + hint: string indicating a possible path to ADB. + """ + # 1. If a hint was provided, does it point to ADB? + if hint: + if os.path.basename(hint) == 'adb': + adb = hint + else: + adb = os.path.join(hint, 'adb') + if subprocess.Popen([adb, 'version'], stdout=subprocess.PIPE).wait() == 0: + return adb + + # 2. Is 'adb' in our PATH? + adb = 'adb' + if subprocess.Popen([adb, 'version'], stdout=subprocess.PIPE).wait() == 0: + return adb + + # 3. Is there an environment variable for ADB? + try: + adb = os.environ.get('ADB') + if subprocess.Popen([adb, 'version'], stdout=subprocess.PIPE).wait() == 0: + return adb + except: + pass + + # 4. If ANDROID_SDK_ROOT is set, try to find ADB in the SDK directory. + try: + sdk_dir = os.environ.get('ANDROID_SDK_ROOT') + adb = os.path.join(sdk_dir, 'platform-tools', 'adb') + if subprocess.Popen([adb, 'version'], stdout=subprocess.PIPE).wait() == 0: + return adb + except: + pass + return None + + +def main(argv): + """ Print out information about connected Android devices. By default, print + the serial number, status, device name, OS version, and build type of each + device. If any arguments are supplied on the command line, print the serial + number and status for each device along with values for those arguments + interpreted as properties. + """ + if len(argv) > 1: + props_to_get = argv[1:] + else: + props_to_get = DEFAULT_PROPS_TO_GET + adb = FindADB() + if not adb: + raise Exception('Could not find ADB!') + proc = subprocess.Popen([adb, 'devices'], stdout=subprocess.PIPE) + code = proc.wait() + if code != 0: + raise Exception('Failure in ADB: could not find attached devices.') + header = ['Serial', 'Status'] + header.extend(props_to_get) + output_lines = [header] + for line in proc.stdout: + line = line.rstrip() + if line != 'List of devices attached' and line != '': + line_list = shlex.split(line) + serial = line_list[0] + status = line_list[1] + device_info = [serial, status] + device_info.extend(GetDeviceInfo(adb, serial, props_to_get)) + output_lines.append(device_info) + PrintPrettyTable(output_lines) + + +if __name__ == '__main__': + sys.exit(main(sys.argv)) \ No newline at end of file diff --git a/platform_tools/android/bin/android_gdb b/platform_tools/android/bin/android_gdb new file mode 100755 index 0000000..58e0b17 --- /dev/null +++ b/platform_tools/android/bin/android_gdb @@ -0,0 +1,63 @@ +#!/bin/bash +# +# android_gdb: Pushes parameter binary and gdbserver. Connects +# and enters debugging environment. + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +APP_NAME=$(basename $1) +PORT=5039 + +# Collect extra arguments to be passed to the Skia binary +shift +while (( "$#" )); do + APP_ARGS="$APP_ARGS $1" + shift +done + +source $SCRIPT_DIR/android_setup.sh +source $SCRIPT_DIR/utils/setup_adb.sh + +echo "Installing Skia Android app" +$SCRIPT_DIR/android_install_skia -f + +# Forward local to remote socket connection. +$ADB forward "tcp:$PORT" "tcp:$PORT" + +# We kill all previous instances of gdbserver to rid all port overriding errors. +$ADB shell ps | grep gdbserver | awk '{print $2}' | xargs -r $ADB shell kill + +# We need the debug symbols from these files +GDB_TMP_DIR=$(pwd)/android_gdb_tmp +mkdir $GDB_TMP_DIR +echo "Copying symbol files" +$ADB pull /system/bin/app_process $GDB_TMP_DIR +$ADB pull /system/lib/libc.so $GDB_TMP_DIR +$ADB pull /data/data/com.skia/lib/lib$APP_NAME.so $GDB_TMP_DIR + +# Launch the app +SK_COMMAND="$APP_NAME$APP_ARGS" +echo "Running command $SK_COMMAND" +$ADB shell am broadcast -a com.skia.intent.action.LAUNCH_SKIA -n com.skia/.SkiaReceiver -e args "$SK_COMMAND" + +# Attach gdbserver to the app process +PID=$($ADB shell ps | grep skia_native | awk '{print $2}') +echo "Attaching to pid: $PID" +$ADB shell /data/data/com.skia/lib/gdbserver :$PORT --attach $PID & + +# Wait for gdbserver +sleep 2 + +# Set up gdb commands +GDBSETUP=$GDB_TMP_DIR/gdb.setup +echo "file $GDB_TMP_DIR/app_process" >> $GDBSETUP +echo "target remote :$PORT" >> $GDBSETUP +echo "set solib-absolute-prefix $GDB_TMP_DIR" >> $GDBSETUP +echo "set solib-search-path $GDB_TMP_DIR" >> $GDBSETUP + +# Launch gdb client +echo "Entering gdb client shell" +$ANDROID_TOOLCHAIN/arm-linux-androideabi-gdb -x $GDBSETUP + +# Clean up +rm -rf $GDB_TMP_DIR + diff --git a/platform_tools/android/bin/android_gdb_exe b/platform_tools/android/bin/android_gdb_exe new file mode 100755 index 0000000..21c739d --- /dev/null +++ b/platform_tools/android/bin/android_gdb_exe @@ -0,0 +1,80 @@ +#!/bin/bash +# +# android_gdb: Pushes gdbserver. Connects and enters debugging environment. + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +APP_NAME=$(basename $1) +PORT=5039 + +# Collect extra arguments to be passed to the Skia binary +shift +while (( "$#" )); do + APP_ARGS="$APP_ARGS $1" + shift +done + +source $SCRIPT_DIR/android_setup.sh +source $SCRIPT_DIR/utils/setup_adb.sh + +# We need the debug symbols from these files +GDB_TMP_DIR=$(pwd)/android_gdb_tmp +mkdir $GDB_TMP_DIR +echo "Copying symbol files" +$ADB pull /system/bin/skia_launcher $GDB_TMP_DIR +$ADB pull /system/lib/libc.so $GDB_TMP_DIR +$ADB pull /data/data/com.skia/lib/lib$APP_NAME.so $GDB_TMP_DIR + +echo "Checking for skia_launcher app..." +if [ ! -f $GDB_TMP_DIR/skia_launcher ] +then + echo "Unable for find the skia_launcher on the device" + rm -rf $GDB_TMP_DIR + exit 1; +fi + +echo "Checking for $APP_NAME library..." +if [ ! -f $GDB_TMP_DIR/lib$APP_NAME.so ] +then + echo "Unable for find the app's shared library on the device" + rm -rf $GDB_TMP_DIR + exit 1; +fi + +echo "Pushing gdbserver..." +$ADB remount +$ADB push $ANDROID_TOOLCHAIN/../gdbserver /system/bin/gdbserver + +echo "Setting up port forward" +$ADB forward "tcp:5039" "tcp:5039" + +# Kill all previous instances of gdbserver and skia_launcher to rid all port overriding errors. +echo "Killing any running Skia processes." +$ADB shell ps | grep gdbserver | awk '{print $2}' | xargs $ADB shell kill +$ADB shell ps | grep skia_launcher | awk '{print $2}' | xargs $ADB shell kill + +# Starting up gdbserver in android shell +echo "Starting gdbserver with command: skia_launcher $APP_NAME$APP_ARGS" +$ADB shell gdbserver :5039 /system/bin/skia_launcher $APP_NAME$APP_ARGS & + +# Wait for gdbserver +sleep 2 + +# Set up gdb commands +GDBSETUP=$GDB_TMP_DIR/gdb.setup +echo "file $GDB_TMP_DIR/skia_launcher" >> $GDBSETUP +echo "target remote :$PORT" >> $GDBSETUP +echo "set solib-absolute-prefix $GDB_TMP_DIR" >> $GDBSETUP +echo "set solib-search-path $GDB_TMP_DIR" >> $GDBSETUP + +# The apps shared library symbols are not loaded by default so we load them here +echo "break skia_launcher.cpp:launch_app" >> $GDBSETUP +echo "continue" >> $GDBSETUP +echo "sharedLibrary $APP_NAME" >> $GDBSETUP + + +# Launch gdb client +echo "Entering gdb client shell" +$ANDROID_TOOLCHAIN/arm-linux-androideabi-gdb -x $GDBSETUP + +# Clean up +rm -rf $GDB_TMP_DIR \ No newline at end of file diff --git a/platform_tools/android/bin/android_install_skia b/platform_tools/android/bin/android_install_skia new file mode 100755 index 0000000..da16b1a --- /dev/null +++ b/platform_tools/android/bin/android_install_skia @@ -0,0 +1,78 @@ +#!/bin/bash +# +# android_install_skia: installs the skia apk on the device. + +function print_usage { + echo "USAGE: android_install_skia [options]" + echo " Options: -f Forces the package to be installed by removing any" + echo " previously installed packages" + echo " -h Prints this help message" + echo " --install-launcher Remounts the system partition and installs the" + echo " skia_launcher binary on the device" + echo " --release Install the release build of Skia" + echo " -s [device_s/n] Serial number of the device to be used" +} + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +source $SCRIPT_DIR/utils/setup_adb.sh +source $SCRIPT_DIR/utils/setup_skia_out.sh + +forceRemoval="false" +installLauncher="false" +installOptions="-r" +configuration="Debug" +serialNumber="" + +while (( "$#" )); do + + if [[ "$1" == "-f" ]]; + then + forceRemoval="true" + elif [[ "$1" == "-h" ]]; + then + print_usage + exit + elif [[ "$1" == "--install-launcher" ]]; + then + installLauncher="true" + elif [[ "$1" == "-r" ]]; + then + echo "DEPRECATED: -r is now a no-op" + elif [[ "$1" == "--release" ]]; + then + configuration="Release" + elif [[ "$1" == "-s" ]]; + then + if [[ $# -lt 2 ]]; + then + echo "ERROR: missing serial number" + exit 1; + fi + serialNumber="-s $2" + shift + else + echo "ERROR: unrecognized option $1" + print_usage + exit 1; + fi + +shift +done + +if [[ "$forceRemoval" == "true" ]]; +then + echo "Forcing removal of previously installed packages" + $ADB ${serialNumber} uninstall com.skia > /dev/null +fi + +if [[ "$installLauncher" == "true" ]]; +then + echo "Installing skia_launcher binary" + $ADB ${serialNumber} root + $ADB ${serialNumber} remount + $ADB ${serialNumber} push ${SKIA_OUT}/${configuration}/skia_launcher /system/bin +fi + +echo "Installing Skia App from ${SKIA_OUT}/${configuration}" +$ADB ${serialNumber} install ${installOptions} ${SKIA_OUT}/${configuration}/android/bin/SkiaAndroid.apk diff --git a/platform_tools/android/bin/android_kill_skia b/platform_tools/android/bin/android_kill_skia new file mode 100755 index 0000000..5560efc --- /dev/null +++ b/platform_tools/android/bin/android_kill_skia @@ -0,0 +1,16 @@ +#!/bin/bash +# +# android_kill_skia: kills any skia processes on the device. + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +source $SCRIPT_DIR/utils/setup_adb.sh + +if [ $(uname) == "Linux" ]; then + $ADB shell ps | grep skia | awk '{print $2}' | xargs -r $ADB shell kill +elif [ $(uname) == "Darwin" ]; then + $ADB shell ps | grep skia | awk '{print $2}' | xargs $ADB shell kill +else + echo "Could not automatically determine OS!" + exit 1; +fi diff --git a/platform_tools/android/bin/android_make b/platform_tools/android/bin/android_make new file mode 100755 index 0000000..497859d --- /dev/null +++ b/platform_tools/android/bin/android_make @@ -0,0 +1,57 @@ +#!/bin/bash + +makeVars="" +deviceID="" + +while (( "$#" )); do + + if [[ $(echo "$1" | grep "^-d$") != "" ]]; + then + deviceID="$2" + shift + elif [[ "$1" == "--use-ccache" ]]; + then + if [[ -z "$ANDROID_MAKE_CCACHE" ]]; + then + ANDROID_MAKE_CCACHE=$(which ccache) + fi + else + makeVars="$makeVars $1" + fi + +shift +done + +if [[ -n "$ANDROID_MAKE_CCACHE" ]]; then + $ANDROID_MAKE_CCACHE --version &> /dev/null + if [[ "$?" != "0" ]]; then + echo "Unable to find ccache!" + exit 1 + fi +fi + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +# hack for x86 support in android_setup.sh +if [ "$deviceID" == "x86" ] +then + ANDROID_ARCH="x86" +fi + +source $SCRIPT_DIR/android_setup.sh + +setup_device $deviceID +returnVal=$? +if [ $returnVal != 0 ] +then + exit 1; +fi + +# write the out directory into the .android_config file +echo $SKIA_OUT > .android_config + +make $makeVars +if [ $? != 0 ] +then + exit 1; +fi diff --git a/platform_tools/android/bin/android_perf b/platform_tools/android/bin/android_perf new file mode 100644 index 0000000..5e4b7c8 --- /dev/null +++ b/platform_tools/android/bin/android_perf @@ -0,0 +1,145 @@ +#!/bin/bash +# +# android_perf: utility for running perf on an android device +# +# The basic usage sequence is to run... +# 1) perf record [gm/tests/bench] # runs profiler on specified app +# 2) perf report # prints profiler results +# 3) perf clean # cleans the temporary directory used to store results +# + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +PERF_CMD=$1 + +source $SCRIPT_DIR/utils/setup_adb.sh + +if [ $(uname) == "Linux" ]; then + PERFHOST=$SCRIPT_DIR/linux/perfhost +elif [ $(uname) == "Darwin" ]; then + PERFHOST=$SCRIPT_DIR/mac/perfhost +else + echo "Could not automatically determine OS!" + exit 1; +fi + +# We need the debug symbols from these files +PERF_TMP_DIR=$(pwd)/android_perf_tmp + +TMP_SYS_BIN=$PERF_TMP_DIR/system/bin +TMP_SYS_LIB=$PERF_TMP_DIR/system/lib +TMP_APP_LIB=$PERF_TMP_DIR/data/data/com.skia/lib + +perf_setup() { + + mkdir -p $TMP_SYS_BIN + mkdir -p $TMP_SYS_LIB + mkdir -p $TMP_APP_LIB + + # setup symlinks to account for perf potentially looking elsewhere + mkdir -p $PERF_TMP_DIR/data/app-lib + $( cd $PERF_TMP_DIR/data/app-lib && ln -s ../data/com.skia/lib com.skia-1) + $( cd $PERF_TMP_DIR/data/app-lib && ln -s ../data/com.skia/lib com.skia-2) + + echo "Copying symbol files" + $ADB pull /system/bin/skia_launcher $TMP_SYS_BIN + $ADB pull /system/lib/libc.so $TMP_SYS_LIB + $ADB pull /system/lib/libstlport.so $TMP_SYS_LIB + $ADB pull /system/lib/libcutils.so $TMP_SYS_LIB + $ADB pull /system/lib/libGLESv2.so $TMP_SYS_LIB + $ADB pull /system/lib/libandroid.so $TMP_SYS_LIB + $ADB pull /system/lib/libm.so $TMP_SYS_LIB + $ADB pull /system/lib/libz.so $TMP_SYS_LIB + + if [ $# -ge 2 ] + then + APP_NAME=$(basename $2) + $ADB pull /data/data/com.skia/lib/lib${APP_NAME}.so $TMP_APP_LIB + else + $ADB pull /data/data/com.skia/lib/ $TMP_APP_LIB + fi + + +} + +perf_record() { + + APP_NAME=$(basename $2) + # Collect extra arguments to be passed to the skia_launcher binary + shift # perf_cmd + shift # app_name + while (( "$#" )); do + APP_ARGS="$APP_ARGS $1" + shift + done + + echo "Checking for skia_launcher app..." + if [ ! -f $TMP_SYS_BIN/skia_launcher ] + then + echo "Unable to find the skia_launcher on the device" + rm -rf $PERF_TMP_DIR + exit 1; + fi + + echo "Checking for $APP_NAME library..." + if [ ! -f $TMP_APP_LIB/lib$APP_NAME.so ] + then + echo "Unable to find the app's shared library on the device" + rm -rf $PERF_TMP_DIR + exit 1; + fi + + echo "Killing any running Skia processes." + $ADB shell ps | grep skia_launcher | awk '{print $2}' | xargs $ADB shell kill + + echo "Starting application" + $ADB shell skia_launcher $APP_NAME $APP_ARGS & + + # WE REALLY REALLY WANT TO BE ABLE TO PASS THE SKIA_LAUNCHER APP DIRECTLY TO + # PERF, BUT AT THIS POINT THE DATA FILE WE GET WHEN GOING THAT ROUTE IS UNABLE + # TO BE READ BY THE REPORTING TOOL + echo "Starting profiler" + APP_PID=$($ADB shell ps | grep skia_launcher | awk '{print $2}') + $ADB shell perf record -p ${APP_PID} sleep 70 + + $ADB pull /data/perf.data $PERF_TMP_DIR/perf.data + + exit 0; +} + +perf_report() { + # Collect extra arguments to be passed to the perfhost binary + while (( "$#" )); do + APP_ARGS="$APP_ARGS $1" + shift + done + + $PERFHOST report -i $PERF_TMP_DIR/perf.data --symfs=$PERF_TMP_DIR $APP_ARGS +} + +# Clean up +perf_clean() { + rm -rf $PERF_TMP_DIR +} + +case $PERF_CMD in + setup) + perf_setup $@ + ;; + record) + perf_setup $@ + perf_record $@ + ;; + report) + perf_report + ;; + clean) + perf_clean + ;; + *) + echo -n "ERROR: unknown perf command ($PERF_CMD), valid values: " + echo "setup, record, report, clean" + exit 1; + ;; +esac + +exit 0; diff --git a/platform_tools/android/bin/android_run_skia b/platform_tools/android/bin/android_run_skia new file mode 100755 index 0000000..f958b76 --- /dev/null +++ b/platform_tools/android/bin/android_run_skia @@ -0,0 +1,48 @@ +#!/bin/bash +# +# android_run_skia: starts the correct skia program on the device, prints the +# output, and kills the app if interrupted. + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +source $SCRIPT_DIR/utils/setup_adb.sh + +APP_ARGS="" +USE_INTENT="false" +SERIAL="" + +while (( "$#" )); do + + if [[ "$1" == "--intent" ]]; + then + USE_INTENT="true" + elif [[ "$1" == "-s" ]]; + then + if [[ $# -lt 2 ]]; + then + echo "ERROR: missing serial number" + exit 1; + fi + SERIAL="-s $2" + shift + else + APP_ARGS="$APP_ARGS $1" + fi + +shift +done + + +if [[ "$USE_INTENT" == "true" ]]; +then + $ADB logcat -c + $ADB $SERIAL shell am broadcast -a com.skia.intent.action.LAUNCH_SKIA -n com.skia/.SkiaReceiver -e args "$APP_ARGS" + trap "echo \"Interrupt.\"" INT + eval "($ADB logcat)" + trap - INT + echo "Interrupt. Killing Skia process..." + $SCRIPT_DIR/android_kill_skia + echo "Done." +else + $ADB $SERIAL shell skia_launcher $APP_ARGS +fi diff --git a/platform_tools/android/bin/android_setup.sh b/platform_tools/android/bin/android_setup.sh new file mode 100755 index 0000000..058d943 --- /dev/null +++ b/platform_tools/android/bin/android_setup.sh @@ -0,0 +1,189 @@ +function exportVar { + NAME=$1 + VALUE=$2 + echo export $NAME=\"$VALUE\" + export $NAME="$VALUE" +} + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +# A valid Android SDK installation is required to build the sample app. +if [ -z "$ANDROID_SDK_ROOT" ]; then + ANDROID_TOOL=$(which android 2>/dev/null) + if [ -z "$ANDROID_TOOL" ]; then + echo "ERROR: Please define ANDROID_SDK_ROOT in your environment to point" + echo " to a valid Android SDK installation." + return 1 + fi + ANDROID_SDK_ROOT=$(cd $(dirname "$ANDROID_TOOL")/.. && pwd) + exportVar ANDROID_SDK_ROOT "$ANDROID_SDK_ROOT" +fi + +# ant is required to be installed on your system and in your PATH +ant -version &> /dev/null +if [[ "$?" != "0" ]]; then + echo "ERROR: Unable to find ant. Please install it before proceeding." + exit 1 +fi + +# determine the toolchain that we will be using +API_LEVEL=14 + +if [[ -z "$NDK_REV" ]]; +then + NDK_REV="8d" +fi + +if [[ -z "$ANDROID_ARCH" ]]; +then + ANDROID_ARCH="arm" +fi + +TOOLCHAIN_DIR=${SCRIPT_DIR}/../toolchains +if [ $(uname) == "Linux" ]; then + echo "Using Linux toolchain." + TOOLCHAIN_TYPE=ndk-r$NDK_REV-$ANDROID_ARCH-linux_v$API_LEVEL +elif [ $(uname) == "Darwin" ]; then + echo "Using Mac toolchain." + TOOLCHAIN_TYPE=ndk-r$NDK_REV-$ANDROID_ARCH-mac_v$API_LEVEL +else + echo "Could not automatically determine toolchain! Defaulting to Linux." + TOOLCHAIN_TYPE=ndk-r$NDK_REV-$ANDROID_ARCH-linux_v$API_LEVEL +fi +exportVar ANDROID_TOOLCHAIN ${TOOLCHAIN_DIR}/${TOOLCHAIN_TYPE}/bin + +# if the toolchain doesn't exist on your machine then we need to fetch it +if [ ! -d "$ANDROID_TOOLCHAIN" ]; then + # gsutil must be installed on your system and in your PATH + gsutil version &> /dev/null + if [[ "$?" != "0" ]]; then + echo "ERROR: Unable to find gsutil. Please install it before proceeding." + exit 1 + fi + # create the toolchain directory if needed + if [ ! -d "$TOOLCHAIN_DIR" ]; then + mkdir $TOOLCHAIN_DIR + fi + # enter the toolchain directory then download, unpack, and remove the tarball + pushd $TOOLCHAIN_DIR + TARBALL=ndk-r$NDK_REV-v$API_LEVEL.tgz + gsutil cp gs://chromium-skia-gm/android-toolchains/$TARBALL $TARBALL + echo "Untarring $TOOLCHAIN_TYPE from $TARBALL." + tar -xzf $TARBALL $TOOLCHAIN_TYPE + echo "Removing $TARBALL" + rm $TARBALL + popd +fi + +if [ ! -d "$ANDROID_TOOLCHAIN" ]; then + echo "ERROR: unable to download/setup the required toolchain (${TOOLCHAIN_TYPE})" + return 1; +fi + +echo "The build is targeting NDK API level $API_LEVEL for use on Android 4.0 (NDK Revision $NDK_REV) and above" + +LS="/bin/ls" # Use directly to avoid any 'ls' alias that might be defined. +GCC=$($LS $ANDROID_TOOLCHAIN/*-gcc | head -n1) +if [ -z "$GCC" ]; then + echo "ERROR: Could not find Android cross-compiler in: $ANDROID_TOOLCHAIN" + return 1 +fi + +# Remove the '-gcc' at the end to get the full toolchain prefix +ANDROID_TOOLCHAIN_PREFIX=${GCC%%-gcc} + +exportVar AR "$ANDROID_TOOLCHAIN_PREFIX-ar" +if [[ -z "$ANDROID_MAKE_CCACHE" ]]; then + exportVar CC "$ANDROID_TOOLCHAIN_PREFIX-gcc" + exportVar CXX "$ANDROID_TOOLCHAIN_PREFIX-g++" + exportVar LINK "$ANDROID_TOOLCHAIN_PREFIX-gcc" +else + exportVar CC "$ANDROID_MAKE_CCACHE $ANDROID_TOOLCHAIN_PREFIX-gcc" + exportVar CXX "$ANDROID_MAKE_CCACHE $ANDROID_TOOLCHAIN_PREFIX-g++" + exportVar LINK "$ANDROID_MAKE_CCACHE $ANDROID_TOOLCHAIN_PREFIX-gcc" +fi +exportVar RANLIB "$ANDROID_TOOLCHAIN_PREFIX-ranlib" +exportVar OBJCOPY "$ANDROID_TOOLCHAIN_PREFIX-objcopy" +exportVar STRIP "$ANDROID_TOOLCHAIN_PREFIX-strip" + +# Helper function to configure the GYP defines to the appropriate values +# based on the target device. +setup_device() { + DEFINES="OS=android" + DEFINES="${DEFINES} host_os=$(uname -s | sed -e 's/Linux/linux/;s/Darwin/mac/')" + DEFINES="${DEFINES} skia_os=android" + DEFINES="${DEFINES} android_base=${SCRIPT_DIR}/.." + DEFINES="${DEFINES} android_toolchain=${TOOLCHAIN_TYPE}" + + # Setup the build variation depending on the target device + TARGET_DEVICE="$1" + + if [ -z "$TARGET_DEVICE" ]; then + echo "INFO: no target device type was specified so using the default 'arm_v7'" + TARGET_DEVICE="arm_v7" + fi + + case $TARGET_DEVICE in + nexus_s) + DEFINES="${DEFINES} skia_arch_type=arm arm_neon=1 armv7=1 arm_thumb=0" + DEFINES="${DEFINES} skia_texture_cache_mb_limit=24" + ;; + nexus_4 | nexus_7 | nexus_10) + DEFINES="${DEFINES} skia_arch_type=arm arm_neon=1 armv7=1 arm_thumb=0" + ;; + xoom) + DEFINES="${DEFINES} skia_arch_type=arm arm_neon=0 armv7=1 arm_thumb=0" + ;; + galaxy_nexus) + DEFINES="${DEFINES} skia_arch_type=arm arm_neon=1 armv7=1 arm_thumb=0" + DEFINES="${DEFINES} skia_texture_cache_mb_limit=32" + ;; + razr_i) + DEFINES="${DEFINES} skia_arch_type=x86 skia_arch_width=32" + DEFINES="${DEFINES} skia_texture_cache_mb_limit=32" + ;; + arm_v7) + DEFINES="${DEFINES} skia_arch_type=arm arm_neon_optional=1 armv7=1 arm_thumb=0" + ;; + arm_v7_thumb) + DEFINES="${DEFINES} skia_arch_type=arm arm_neon_optional=1 armv7=1 arm_thumb=1" + ;; + arm) + DEFINES="${DEFINES} skia_arch_type=arm arm_neon=0 armv7=0 arm_thumb=0" + ;; + arm_thumb) + DEFINES="${DEFINES} skia_arch_type=arm arm_neon=0 armv7=0 arm_thumb=1" + ;; + x86) + DEFINES="${DEFINES} skia_arch_type=x86 skia_arch_width=32" + DEFINES="${DEFINES} skia_texture_cache_mb_limit=32" + ;; + *) + echo -n "ERROR: unknown device specified ($TARGET_DEVICE), valid values: " + echo "nexus_[s,4,7,10] xoom galaxy_nexus arm arm_thumb arm_v7 arm_v7_thumb x86" + return 1; + ;; + esac + + echo "The build is targeting the device: $TARGET_DEVICE" + + exportVar GYP_DEFINES "$DEFINES" + exportVar SKIA_OUT "out/config/android-${TARGET_DEVICE}" +} + +# Run the setup device command initially as a convenience for the user +#setup_device +#echo "** The device has been setup for you by default. If you would like to **" +#echo "** use a different device then run the setup_device function with the **" +#echo "** appropriate input. **" + +# Use the "android" flavor of the Makefile generator for both Linux and OS X. +exportVar GYP_GENERATORS "make-android" + +# Helper function so that when we run "make" to build for clank it exports +# the toolchain variables to make. +#make_android() { +# CC="$CROSS_CC" CXX="$CROSS_CXX" LINK="$CROSS_LINK" \ +# AR="$CROSS_AR" RANLIB="$CROSS_RANLIB" \ +# command make $* +#} diff --git a/platform_tools/android/bin/linux/adb b/platform_tools/android/bin/linux/adb new file mode 100755 index 0000000..94257a0 Binary files /dev/null and b/platform_tools/android/bin/linux/adb differ diff --git a/platform_tools/android/bin/linux/perfhost b/platform_tools/android/bin/linux/perfhost new file mode 100644 index 0000000..926a639 Binary files /dev/null and b/platform_tools/android/bin/linux/perfhost differ diff --git a/platform_tools/android/bin/mac/adb b/platform_tools/android/bin/mac/adb new file mode 100755 index 0000000..137d7fd Binary files /dev/null and b/platform_tools/android/bin/mac/adb differ diff --git a/platform_tools/android/bin/mac/perfhost b/platform_tools/android/bin/mac/perfhost new file mode 100755 index 0000000..3e81fbc Binary files /dev/null and b/platform_tools/android/bin/mac/perfhost differ diff --git a/platform_tools/android/bin/utils/setup_adb.sh b/platform_tools/android/bin/utils/setup_adb.sh new file mode 100644 index 0000000..2f4e529 --- /dev/null +++ b/platform_tools/android/bin/utils/setup_adb.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# + +UTIL_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +if [ "$(which adb)" != "" ]; then + ADB="$(which adb)" +elif [ $(uname) == "Linux" ]; then + ADB=$UTIL_DIR/../linux/adb +elif [ $(uname) == "Darwin" ]; then + ADB=$UTIL_DIR/../mac/adb +else + echo "ERROR: Could not find ADB!" + exit 1; +fi + +echo "ADB is: $ADB" diff --git a/platform_tools/android/bin/utils/setup_skia_out.sh b/platform_tools/android/bin/utils/setup_skia_out.sh new file mode 100644 index 0000000..78375a5 --- /dev/null +++ b/platform_tools/android/bin/utils/setup_skia_out.sh @@ -0,0 +1,22 @@ +#!/bin/bash +# + +UTIL_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +if [ -z "$SKIA_OUT" ] +then + + if [ ! -f .android_config ] + then + echo "Unable to find the .android_config file" + exit 1; + fi + + export SKIA_OUT=$(cat .android_config) + + if [ ! -d ${SKIA_OUT} ] + then + echo "The contents of .android_config are invalid" + exit 1; + fi +fi \ No newline at end of file diff --git a/platform_tools/android/gclient.config b/platform_tools/android/gclient.config new file mode 100644 index 0000000..9e066ea --- /dev/null +++ b/platform_tools/android/gclient.config @@ -0,0 +1,13 @@ +# To develop Skia targeting Android, +# copy this file to your root development directory as ".gclient" +# and then run "gclient sync". +solutions = [ + { + "name" : "android", + "url" : "https://skia.googlecode.com/svn/android", + }, + { + "name" : "trunk", + "url" : "https://skia.googlecode.com/svn/trunk", + }, +] diff --git a/platform_tools/android/gyp/dependencies.gypi b/platform_tools/android/gyp/dependencies.gypi new file mode 100644 index 0000000..4934903 --- /dev/null +++ b/platform_tools/android/gyp/dependencies.gypi @@ -0,0 +1,260 @@ +# This GYP file stores the dependencies necessary to build Skia on the Android +# platform. The OS doesn't provide many stable libraries as part of the +# distribution so we have to build a few of them ourselves. +# +# NOTE: We tried adding the gyp file to the android/ directory at the root of +# the Skia repo, but that resulted in the generated makefiles being created +# outside of the out directory. We may be able to move the bulk of this gyp +# to the /android directory and put a simple shim here, but that has yet to be +# tested. + +{ + 'variables': { + 'skia_warnings_as_errors': 0, + }, + 'targets': [ + { + 'target_name': 'cpu_features', + 'type': 'static_library', + 'direct_dependent_settings': { + 'include_dirs': [ + '../third_party/cpufeatures', + ], + }, + 'sources': [ + '../third_party/cpufeatures/cpu-features.c', + '../third_party/cpufeatures/cpu-features.h', + ], + 'cflags!': [ + '-fno-rtti', # supresses warnings about invalid option of non-C++ code + ], + }, + { + 'target_name': 'expat', + 'type': 'static_library', + 'sources': [ + '../third_party/externals/expat/lib/xmlparse.c', + '../third_party/externals/expat/lib/xmlrole.c', + '../third_party/externals/expat/lib/xmltok.c', + ], + 'include_dirs': [ + '../third_party/externals/expat', + '../third_party/externals/expat/lib', + ], + 'cflags': [ + '-Wall', + '-Wmissing-prototypes', + '-Wstrict-prototypes', + '-fexceptions', + '-DHAVE_EXPAT_CONFIG_H', + ], + 'cflags!': [ + '-fno-rtti', # supresses warnings about invalid option of non-C++ code + ], + 'direct_dependent_settings': { + 'include_dirs': [ + '../third_party/externals/expat/lib', # For expat.h + ], + } + }, + { + 'target_name': 'gif', + 'type': 'static_library', + 'sources': [ + '../third_party/externals/gif/dgif_lib.c', + '../third_party/externals/gif/gifalloc.c', + '../third_party/externals/gif/gif_err.c', + ], + 'include_dirs': [ + '../third_party/externals/gif', + ], + 'cflags': [ + '-Wno-format', + '-DHAVE_CONFIG_H', + ], + 'cflags!': [ + '-fno-rtti', # supresses warnings about invalid option of non-C++ code + '-Wall', + ], + 'direct_dependent_settings': { + 'include_dirs': [ + '../third_party/externals/gif', + ], + } + }, + { + 'target_name': 'png', + 'type': 'static_library', + 'sources': [ + '../third_party/externals/png/png.c', + '../third_party/externals/png/pngerror.c', + '../third_party/externals/png/pnggccrd.c', + '../third_party/externals/png/pngget.c', + '../third_party/externals/png/pngmem.c', + '../third_party/externals/png/pngpread.c', + '../third_party/externals/png/pngread.c', + '../third_party/externals/png/pngrio.c', + '../third_party/externals/png/pngrtran.c', + '../third_party/externals/png/pngrutil.c', + '../third_party/externals/png/pngset.c', + '../third_party/externals/png/pngtrans.c', + '../third_party/externals/png/pngvcrd.c', + '../third_party/externals/png/pngwio.c', + '../third_party/externals/png/pngwrite.c', + '../third_party/externals/png/pngwtran.c', + '../third_party/externals/png/pngwutil.c', + ], + 'include_dirs': [ + '../third_party/externals/png', + ], + 'cflags': [ + '-fvisibility=hidden', + ], + 'cflags!': [ + '-fno-rtti', # supresses warnings about invalid option of non-C++ code + '-Wall', + ], + 'link_settings': { + 'libraries': [ + '-lz', + ], + }, + 'direct_dependent_settings': { + 'include_dirs': [ + '../third_party/externals/png', + ], + } + }, + { + 'target_name': 'jpeg', + 'type': 'static_library', + 'sources': [ + '../third_party/externals/jpeg/jcapimin.c', + '../third_party/externals/jpeg/jcapistd.c', + '../third_party/externals/jpeg/jccoefct.c', + '../third_party/externals/jpeg/jccolor.c', + '../third_party/externals/jpeg/jcdctmgr.c', + '../third_party/externals/jpeg/jchuff.c', + '../third_party/externals/jpeg/jcinit.c', + '../third_party/externals/jpeg/jcmainct.c', + '../third_party/externals/jpeg/jcmarker.c', + '../third_party/externals/jpeg/jcmaster.c', + '../third_party/externals/jpeg/jcomapi.c', + '../third_party/externals/jpeg/jcparam.c', + '../third_party/externals/jpeg/jcphuff.c', + '../third_party/externals/jpeg/jcprepct.c', + '../third_party/externals/jpeg/jcsample.c', + '../third_party/externals/jpeg/jctrans.c', + '../third_party/externals/jpeg/jdapimin.c', + '../third_party/externals/jpeg/jdapistd.c', + '../third_party/externals/jpeg/jdatadst.c', + '../third_party/externals/jpeg/jdatasrc.c', + '../third_party/externals/jpeg/jdcoefct.c', + '../third_party/externals/jpeg/jdcolor.c', + '../third_party/externals/jpeg/jddctmgr.c', + '../third_party/externals/jpeg/jdhuff.c', + '../third_party/externals/jpeg/jdinput.c', + '../third_party/externals/jpeg/jdmainct.c', + '../third_party/externals/jpeg/jdmarker.c', + '../third_party/externals/jpeg/jdmaster.c', + '../third_party/externals/jpeg/jdmerge.c', + '../third_party/externals/jpeg/jdphuff.c', + '../third_party/externals/jpeg/jdpostct.c', + '../third_party/externals/jpeg/jdsample.c', + '../third_party/externals/jpeg/jdtrans.c', + '../third_party/externals/jpeg/jerror.c', + '../third_party/externals/jpeg/jfdctflt.c', + '../third_party/externals/jpeg/jfdctfst.c', + '../third_party/externals/jpeg/jfdctint.c', + '../third_party/externals/jpeg/jidctflt.c', + '../third_party/externals/jpeg/jidctfst.c', + '../third_party/externals/jpeg/jidctint.c', + '../third_party/externals/jpeg/jidctred.c', + '../third_party/externals/jpeg/jquant1.c', + '../third_party/externals/jpeg/jquant2.c', + '../third_party/externals/jpeg/jutils.c', + '../third_party/externals/jpeg/jmemmgr.c', + '../third_party/externals/jpeg/jmem-android.c', # ashmem is also available + ], + 'include_dirs': [ + '../third_party/externals/jpeg', + ], + 'cflags': [ + '-fvisibility=hidden', + '-DAVOID_TABLES', + '-O3', + '-fstrict-aliasing', + '-fprefetch-loop-arrays', + '-DANDROID_TILE_BASED_DECODE', + ], + 'cflags!': [ + '-fno-rtti', # supresses warnings about invalid option of non-C++ code + '-Wall', + ], + 'direct_dependent_settings': { + 'include_dirs': [ + '../third_party/externals/jpeg', + ], + } + }, + { + # This target is a dependency for all console-type Skia applications which + # will run on Android. Since Android requires us to load native code in + # shared libraries, we need a common entry point to wrap around main(). + # Here we also change the type of all would-be executables to be shared + # libraries. The alternative would be to introduce a condition in every + # executable target which changes to a shared library if the target OS is + # Android. This is nicer because the switch is in one place. + 'target_name': 'Android_EntryPoint', + 'type': 'static_library', + 'direct_dependent_settings': { + 'target_conditions': [ + # '_type' is an 'automatic variable' which is defined for any + # target which defines a key-value pair with 'type' as the key (so, + # all of them). Conditionals inside 'target_conditions' are evaluated + # *after* all other definitions and conditionals are evaluated, so + # we're guaranteed that '_type' will be defined when we get here. + # For more info, see: + # - http://code.google.com/p/gyp/wiki/InputFormatReference#Variables + # - http://codereview.appspot.com/6353065/ + ['_type == "executable"', { + 'type': 'shared_library', + }], + ], + }, + 'sources': [ + '../../android/app/jni/com_skia_SkiaIntentService.cpp', + ], + }, + { + # This target is a dependency for Skia Sample application which runs on + # Android. Since Android requires us to load native code in shared + # libraries, we need a common entry point to wrap around main(). Here + # we also change the type of all would-be executables to be shared + # libraries. The alternative would be to introduce a condition in every + # executable target which changes to a shared library if the target OS is + # Android. This is nicer because the switch is in one place. + 'target_name': 'Android_SampleApp', + 'type': 'static_library', + 'direct_dependent_settings': { + 'target_conditions': [ + # '_type' is an 'automatic variable' which is defined for any + # target which defines a key-value pair with 'type' as the key (so, + # all of them). Conditionals inside 'target_conditions' are evaluated + # *after* all other definitions and conditionals are evaluated, so + # we're guaranteed that '_type' will be defined when we get here. + # For more info, see: + # - http://code.google.com/p/gyp/wiki/InputFormatReference#Variables + # - http://codereview.appspot.com/6353065/ + ['_type == "executable"', { + 'type': 'shared_library', + }], + ], + 'sources': [ + '../../android/app/jni/com_skia_SkiaSampleRenderer.cpp', + ], + }, + + }, + ] +} diff --git a/platform_tools/android/gyp/skia_android.gypi b/platform_tools/android/gyp/skia_android.gypi new file mode 100644 index 0000000..43c59c1 --- /dev/null +++ b/platform_tools/android/gyp/skia_android.gypi @@ -0,0 +1,115 @@ +{ + 'targets': [ + { + 'target_name': 'CopySkiaAppDeps', + 'type': 'none', + 'dependencies': [ + 'SampleApp.gyp:SampleApp', + 'bench.gyp:bench', + 'gm.gyp:gm', + 'tests.gyp:tests', + 'pathops_unittest.gyp:pathops_unittest', + 'tools.gyp:bench_pictures', + 'tools.gyp:render_pictures', + 'tools.gyp:render_pdfs', + 'tools.gyp:skimage', + ], + 'variables': { + 'conditions': [ + [ 'skia_arch_type == "x86"', { + 'android_arch%': "x86", + }, { + 'conditions': [ + [ 'armv7', { + 'android_arch%': "armeabi-v7a", + }, { + 'android_arch%': "armeabi", + }], + ], + }], + ], + }, + 'copies': [ + # Copy gdbserver into the lib.target directory, so that it gets packaged + # in the APK. This is necessary for debugging. + { + 'destination': '<(PRODUCT_DIR)/lib.target', + 'files': [ + '<(android_base)/toolchains/<(android_toolchain)/gdbserver', + ], + }, + # Copy all shared libraries into the Android app's libs folder. Note + # that this copy requires us to build SkiaAndroidApp after those + # libraries, so that they exist by the time it occurs. If there are no + # libraries to copy, this will cause an error in Make, but the app will + # still build. + { + 'destination': '<(PRODUCT_DIR)/android/libs/<(android_arch)', + 'files': [ + '<(PRODUCT_DIR)/lib.target/libbench.so', + '<(PRODUCT_DIR)/lib.target/libbench_pictures.so', + '<(PRODUCT_DIR)/lib.target/libgm.so', + '<(PRODUCT_DIR)/lib.target/librender_pdfs.so', + '<(PRODUCT_DIR)/lib.target/librender_pictures.so', + '<(PRODUCT_DIR)/lib.target/libSampleApp.so', + '<(PRODUCT_DIR)/lib.target/libskimage.so', + '<(PRODUCT_DIR)/lib.target/libtests.so', + '<(PRODUCT_DIR)/lib.target/libpathops_unittest.so', + '<(PRODUCT_DIR)/lib.target/gdbserver', + ], + }, + ], + }, + { + 'target_name': 'skia_launcher', + 'type': 'executable', + 'sources': [ + '../launcher/skia_launcher.cpp', + ], + }, + { + 'target_name': 'SkiaAndroidApp', + 'type': 'none', + 'dependencies': [ + 'CopySkiaAppDeps', + 'skia_launcher', + ], + 'variables': { + 'ANDROID_SDK_ROOT': ' +#include + +void usage(const char* argv0) { + printf("[USAGE] %s program_name [options]\n", argv0); + printf(" program_name: the skia program you want to launch (e.g. tests, bench)\n"); + printf(" options: options specific to the program you are launching\n"); +} + +bool file_exists(const char* fileName) { + FILE* file = fopen(fileName, "r"); + if (file) { + fclose(file); + return true; + } + return false; +} + +int launch_app(int (*app_main)(int, const char**), int argc, + const char** argv) { + return (*app_main)(argc, argv); +} + +int main(int argc, const char** argv) { + + // check that the program name was specified + if (argc < 2) { + printf("ERROR: No program_name was specified\n"); + usage(argv[0]); + return -1; + } + + // attempt to lookup the location of the skia app + const char* appLocation = "/data/data/com.skia"; + if (!file_exists(appLocation)) { + printf("ERROR: Unable to find the com.skia app on the device.\n"); + return -1; + } + + // attempt to lookup the location of the shared libraries + char libraryLocation[100]; + sprintf(libraryLocation, "%s/lib/lib%s.so", appLocation, argv[1]); + if (!file_exists(libraryLocation)) { + printf("ERROR: Unable to find the appropriate library in the Skia App.\n"); + printf("ERROR: Did you provide the correct program_name?\n"); + usage(argv[0]); + return -1; + } + + // load the appropriate library + void* appLibrary = dlopen(libraryLocation, RTLD_LOCAL | RTLD_LAZY); + if (!appLibrary) { + printf("ERROR: Unable to open the shared library.\n"); + printf("ERROR: %s", dlerror()); + return -1; + } + + // find the address of the main function + int (*app_main)(int, const char**); + *(void **) (&app_main) = dlsym(appLibrary, "main"); + + if (!app_main) { + printf("ERROR: Unable to load the main function of the selected program.\n"); + printf("ERROR: %s\n", dlerror()); + return -1; + } + + // find the address of the SkPrintToConsole function + void (*app_SkDebugToStdOut)(bool); + *(void **) (&app_SkDebugToStdOut) = dlsym(appLibrary, "AndroidSkDebugToStdOut"); + + if (app_SkDebugToStdOut) { + (*app_SkDebugToStdOut)(true); + } else { + printf("WARNING: Unable to redirect output to the console.\n"); + printf("WARNING: %s\n", dlerror()); + } + + // pass all additional arguments to the main function + return launch_app(app_main, argc - 1, ++argv); +} diff --git a/platform_tools/android/third_party/cpufeatures/README b/platform_tools/android/third_party/cpufeatures/README new file mode 100644 index 0000000..5815f0c --- /dev/null +++ b/platform_tools/android/third_party/cpufeatures/README @@ -0,0 +1,5 @@ +The contents of this directory are directly copied from the Android NDK to +avoid the need to have a dependency on the NDK directly. + +NDK_REVISION: 8d (December 2012) +NDK_FILE_LOCAtION: ($NDK)/source/android/cpufeatures diff --git a/platform_tools/android/third_party/cpufeatures/cpu-features.c b/platform_tools/android/third_party/cpufeatures/cpu-features.c new file mode 100644 index 0000000..5b0a9d9 --- /dev/null +++ b/platform_tools/android/third_party/cpufeatures/cpu-features.c @@ -0,0 +1,927 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* ChangeLog for this library: + * + * NDK r8d: Add android_setCpu(). + * + * NDK r8c: Add new ARM CPU features: VFPv2, VFP_D32, VFP_FP16, + * VFP_FMA, NEON_FMA, IDIV_ARM, IDIV_THUMB2 and iWMMXt. + * + * Rewrite the code to parse /proc/self/auxv instead of + * the "Features" field in /proc/cpuinfo. + * + * Dynamically allocate the buffer that hold the content + * of /proc/cpuinfo to deal with newer hardware. + * + * NDK r7c: Fix CPU count computation. The old method only reported the + * number of _active_ CPUs when the library was initialized, + * which could be less than the real total. + * + * NDK r5: Handle buggy kernels which report a CPU Architecture number of 7 + * for an ARMv6 CPU (see below). + * + * Handle kernels that only report 'neon', and not 'vfpv3' + * (VFPv3 is mandated by the ARM architecture is Neon is implemented) + * + * Handle kernels that only report 'vfpv3d16', and not 'vfpv3' + * + * Fix x86 compilation. Report ANDROID_CPU_FAMILY_X86 in + * android_getCpuFamily(). + * + * NDK r4: Initial release + */ +#include +#ifdef __arm__ +#include +#endif +#include +#include "cpu-features.h" +#include +#include +#include +#include + +static pthread_once_t g_once; +static int g_inited; +static AndroidCpuFamily g_cpuFamily; +static uint64_t g_cpuFeatures; +static int g_cpuCount; + +static const int android_cpufeatures_debug = 0; + +#ifdef __arm__ +# define DEFAULT_CPU_FAMILY ANDROID_CPU_FAMILY_ARM +#elif defined __i386__ +# define DEFAULT_CPU_FAMILY ANDROID_CPU_FAMILY_X86 +#else +# define DEFAULT_CPU_FAMILY ANDROID_CPU_FAMILY_UNKNOWN +#endif + +#define D(...) \ + do { \ + if (android_cpufeatures_debug) { \ + printf(__VA_ARGS__); fflush(stdout); \ + } \ + } while (0) + +#ifdef __i386__ +static __inline__ void x86_cpuid(int func, int values[4]) +{ + int a, b, c, d; + /* We need to preserve ebx since we're compiling PIC code */ + /* this means we can't use "=b" for the second output register */ + __asm__ __volatile__ ( \ + "push %%ebx\n" + "cpuid\n" \ + "mov %%ebx, %1\n" + "pop %%ebx\n" + : "=a" (a), "=r" (b), "=c" (c), "=d" (d) \ + : "a" (func) \ + ); + values[0] = a; + values[1] = b; + values[2] = c; + values[3] = d; +} +#endif + +/* Get the size of a file by reading it until the end. This is needed + * because files under /proc do not always return a valid size when + * using fseek(0, SEEK_END) + ftell(). Nor can they be mmap()-ed. + */ +static int +get_file_size(const char* pathname) +{ + int fd, ret, result = 0; + char buffer[256]; + + fd = open(pathname, O_RDONLY); + if (fd < 0) { + D("Can't open %s: %s\n", pathname, strerror(errno)); + return -1; + } + + for (;;) { + int ret = read(fd, buffer, sizeof buffer); + if (ret < 0) { + if (errno == EINTR) + continue; + D("Error while reading %s: %s\n", pathname, strerror(errno)); + break; + } + if (ret == 0) + break; + + result += ret; + } + close(fd); + return result; +} + +/* Read the content of /proc/cpuinfo into a user-provided buffer. + * Return the length of the data, or -1 on error. Does *not* + * zero-terminate the content. Will not read more + * than 'buffsize' bytes. + */ +static int +read_file(const char* pathname, char* buffer, size_t buffsize) +{ + int fd, count; + + fd = open(pathname, O_RDONLY); + if (fd < 0) { + D("Could not open %s: %s\n", pathname, strerror(errno)); + return -1; + } + count = 0; + while (count < (int)buffsize) { + int ret = read(fd, buffer + count, buffsize - count); + if (ret < 0) { + if (errno == EINTR) + continue; + D("Error while reading from %s: %s\n", pathname, strerror(errno)); + if (count == 0) + count = -1; + break; + } + if (ret == 0) + break; + count += ret; + } + close(fd); + return count; +} + +/* Extract the content of a the first occurence of a given field in + * the content of /proc/cpuinfo and return it as a heap-allocated + * string that must be freed by the caller. + * + * Return NULL if not found + */ +static char* +extract_cpuinfo_field(char* buffer, int buflen, const char* field) +{ + int fieldlen = strlen(field); + char* bufend = buffer + buflen; + char* result = NULL; + int len, ignore; + const char *p, *q; + + /* Look for first field occurence, and ensures it starts the line. */ + p = buffer; + bufend = buffer + buflen; + for (;;) { + p = memmem(p, bufend-p, field, fieldlen); + if (p == NULL) + goto EXIT; + + if (p == buffer || p[-1] == '\n') + break; + + p += fieldlen; + } + + /* Skip to the first column followed by a space */ + p += fieldlen; + p = memchr(p, ':', bufend-p); + if (p == NULL || p[1] != ' ') + goto EXIT; + + /* Find the end of the line */ + p += 2; + q = memchr(p, '\n', bufend-p); + if (q == NULL) + q = bufend; + + /* Copy the line into a heap-allocated buffer */ + len = q-p; + result = malloc(len+1); + if (result == NULL) + goto EXIT; + + memcpy(result, p, len); + result[len] = '\0'; + +EXIT: + return result; +} + +/* Like strlen(), but for constant string literals */ +#define STRLEN_CONST(x) ((sizeof(x)-1) + + +/* Checks that a space-separated list of items contains one given 'item'. + * Returns 1 if found, 0 otherwise. + */ +static int +has_list_item(const char* list, const char* item) +{ + const char* p = list; + int itemlen = strlen(item); + + if (list == NULL) + return 0; + + while (*p) { + const char* q; + + /* skip spaces */ + while (*p == ' ' || *p == '\t') + p++; + + /* find end of current list item */ + q = p; + while (*q && *q != ' ' && *q != '\t') + q++; + + if (itemlen == q-p && !memcmp(p, item, itemlen)) + return 1; + + /* skip to next item */ + p = q; + } + return 0; +} + +/* Parse an decimal integer starting from 'input', but not going further + * than 'limit'. Return the value into '*result'. + * + * NOTE: Does not skip over leading spaces, or deal with sign characters. + * NOTE: Ignores overflows. + * + * The function returns NULL in case of error (bad format), or the new + * position after the decimal number in case of success (which will always + * be <= 'limit'). + */ +static const char* +parse_decimal(const char* input, const char* limit, int* result) +{ + const char* p = input; + int val = 0; + while (p < limit) { + int d = (*p - '0'); + if ((unsigned)d >= 10U) + break; + val = val*10 + d; + p++; + } + if (p == input) + return NULL; + + *result = val; + return p; +} + +/* This small data type is used to represent a CPU list / mask, as read + * from sysfs on Linux. See http://www.kernel.org/doc/Documentation/cputopology.txt + * + * For now, we don't expect more than 32 cores on mobile devices, so keep + * everything simple. + */ +typedef struct { + uint32_t mask; +} CpuList; + +static __inline__ void +cpulist_init(CpuList* list) { + list->mask = 0; +} + +static __inline__ void +cpulist_and(CpuList* list1, CpuList* list2) { + list1->mask &= list2->mask; +} + +static __inline__ void +cpulist_set(CpuList* list, int index) { + if ((unsigned)index < 32) { + list->mask |= (uint32_t)(1U << index); + } +} + +static __inline__ int +cpulist_count(CpuList* list) { + return __builtin_popcount(list->mask); +} + +/* Parse a textual list of cpus and store the result inside a CpuList object. + * Input format is the following: + * - comma-separated list of items (no spaces) + * - each item is either a single decimal number (cpu index), or a range made + * of two numbers separated by a single dash (-). Ranges are inclusive. + * + * Examples: 0 + * 2,4-127,128-143 + * 0-1 + */ +static void +cpulist_parse(CpuList* list, const char* line, int line_len) +{ + const char* p = line; + const char* end = p + line_len; + const char* q; + + /* NOTE: the input line coming from sysfs typically contains a + * trailing newline, so take care of it in the code below + */ + while (p < end && *p != '\n') + { + int val, start_value, end_value; + + /* Find the end of current item, and put it into 'q' */ + q = memchr(p, ',', end-p); + if (q == NULL) { + q = end; + } + + /* Get first value */ + p = parse_decimal(p, q, &start_value); + if (p == NULL) + goto BAD_FORMAT; + + end_value = start_value; + + /* If we're not at the end of the item, expect a dash and + * and integer; extract end value. + */ + if (p < q && *p == '-') { + p = parse_decimal(p+1, q, &end_value); + if (p == NULL) + goto BAD_FORMAT; + } + + /* Set bits CPU list bits */ + for (val = start_value; val <= end_value; val++) { + cpulist_set(list, val); + } + + /* Jump to next item */ + p = q; + if (p < end) + p++; + } + +BAD_FORMAT: + ; +} + +/* Read a CPU list from one sysfs file */ +static void +cpulist_read_from(CpuList* list, const char* filename) +{ + char file[64]; + int filelen; + + cpulist_init(list); + + filelen = read_file(filename, file, sizeof file); + if (filelen < 0) { + D("Could not read %s: %s\n", filename, strerror(errno)); + return; + } + + cpulist_parse(list, file, filelen); +} + +// See kernel header. +#define HWCAP_VFP (1 << 6) +#define HWCAP_IWMMXT (1 << 9) +#define HWCAP_NEON (1 << 12) +#define HWCAP_VFPv3 (1 << 13) +#define HWCAP_VFPv3D16 (1 << 14) +#define HWCAP_VFPv4 (1 << 16) +#define HWCAP_IDIVA (1 << 17) +#define HWCAP_IDIVT (1 << 18) + +#define AT_HWCAP 16 + +/* Read the ELF HWCAP flags by parsing /proc/self/auxv + */ +static uint32_t +get_elf_hwcap(void) +{ + uint32_t result = 0; + const char filepath[] = "/proc/self/auxv"; + int fd = open(filepath, O_RDONLY); + if (fd < 0) { + D("Could not open %s: %s\n", filepath, strerror(errno)); + return 0; + } + + struct { uint32_t tag; uint32_t value; } entry; + + for (;;) { + int ret = read(fd, (char*)&entry, sizeof entry); + if (ret < 0) { + if (errno == EINTR) + continue; + D("Error while reading %s: %s\n", filepath, strerror(errno)); + break; + } + // Detect end of list. + if (ret == 0 || (entry.tag == 0 && entry.value == 0)) + break; + if (entry.tag == AT_HWCAP) { + result = entry.value; + break; + } + } + close(fd); + return result; +} + +/* Return the number of cpus present on a given device. + * + * To handle all weird kernel configurations, we need to compute the + * intersection of the 'present' and 'possible' CPU lists and count + * the result. + */ +static int +get_cpu_count(void) +{ + CpuList cpus_present[1]; + CpuList cpus_possible[1]; + + cpulist_read_from(cpus_present, "/sys/devices/system/cpu/present"); + cpulist_read_from(cpus_possible, "/sys/devices/system/cpu/possible"); + + /* Compute the intersection of both sets to get the actual number of + * CPU cores that can be used on this device by the kernel. + */ + cpulist_and(cpus_present, cpus_possible); + + return cpulist_count(cpus_present); +} + +static void +android_cpuInitFamily(void) +{ +#if defined(__ARM_ARCH__) + g_cpuFamily = ANDROID_CPU_FAMILY_ARM; +#elif defined(__i386__) + g_cpuFamily = ANDROID_CPU_FAMILY_X86; +#elif defined(_MIPS_ARCH) + g_cpuFamily = ANDROID_CPU_FAMILY_MIPS; +#else + g_cpuFamily = ANDROID_CPU_FAMILY_UNKNOWN; +#endif +} + +static void +android_cpuInit(void) +{ + char* cpuinfo = NULL; + int cpuinfo_len; + + android_cpuInitFamily(); + + g_cpuFeatures = 0; + g_cpuCount = 1; + g_inited = 1; + + cpuinfo_len = get_file_size("/proc/cpuinfo"); + if (cpuinfo_len < 0) { + D("cpuinfo_len cannot be computed!"); + return; + } + cpuinfo = malloc(cpuinfo_len); + if (cpuinfo == NULL) { + D("cpuinfo buffer could not be allocated"); + return; + } + cpuinfo_len = read_file("/proc/cpuinfo", cpuinfo, cpuinfo_len); + D("cpuinfo_len is (%d):\n%.*s\n", cpuinfo_len, + cpuinfo_len >= 0 ? cpuinfo_len : 0, cpuinfo); + + if (cpuinfo_len < 0) /* should not happen */ { + free(cpuinfo); + return; + } + + /* Count the CPU cores, the value may be 0 for single-core CPUs */ + g_cpuCount = get_cpu_count(); + if (g_cpuCount == 0) { + g_cpuCount = 1; + } + + D("found cpuCount = %d\n", g_cpuCount); + +#ifdef __ARM_ARCH__ + { + char* features = NULL; + char* architecture = NULL; + + /* Extract architecture from the "CPU Architecture" field. + * The list is well-known, unlike the the output of + * the 'Processor' field which can vary greatly. + * + * See the definition of the 'proc_arch' array in + * $KERNEL/arch/arm/kernel/setup.c and the 'c_show' function in + * same file. + */ + char* cpuArch = extract_cpuinfo_field(cpuinfo, cpuinfo_len, "CPU architecture"); + + if (cpuArch != NULL) { + char* end; + long archNumber; + int hasARMv7 = 0; + + D("found cpuArch = '%s'\n", cpuArch); + + /* read the initial decimal number, ignore the rest */ + archNumber = strtol(cpuArch, &end, 10); + + /* Here we assume that ARMv8 will be upwards compatible with v7 + * in the future. Unfortunately, there is no 'Features' field to + * indicate that Thumb-2 is supported. + */ + if (end > cpuArch && archNumber >= 7) { + hasARMv7 = 1; + } + + /* Unfortunately, it seems that certain ARMv6-based CPUs + * report an incorrect architecture number of 7! + * + * See http://code.google.com/p/android/issues/detail?id=10812 + * + * We try to correct this by looking at the 'elf_format' + * field reported by the 'Processor' field, which is of the + * form of "(v7l)" for an ARMv7-based CPU, and "(v6l)" for + * an ARMv6-one. + */ + if (hasARMv7) { + char* cpuProc = extract_cpuinfo_field(cpuinfo, cpuinfo_len, + "Processor"); + if (cpuProc != NULL) { + D("found cpuProc = '%s'\n", cpuProc); + if (has_list_item(cpuProc, "(v6l)")) { + D("CPU processor and architecture mismatch!!\n"); + hasARMv7 = 0; + } + free(cpuProc); + } + } + + if (hasARMv7) { + g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_ARMv7; + } + + /* The LDREX / STREX instructions are available from ARMv6 */ + if (archNumber >= 6) { + g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_LDREX_STREX; + } + + free(cpuArch); + } + + /* Extract the list of CPU features from ELF hwcaps */ + uint32_t hwcaps = get_elf_hwcap(); + + if (hwcaps != 0) { + int has_vfp = (hwcaps & HWCAP_VFP); + int has_vfpv3 = (hwcaps & HWCAP_VFPv3); + int has_vfpv3d16 = (hwcaps & HWCAP_VFPv3D16); + int has_vfpv4 = (hwcaps & HWCAP_VFPv4); + int has_neon = (hwcaps & HWCAP_NEON); + int has_idiva = (hwcaps & HWCAP_IDIVA); + int has_idivt = (hwcaps & HWCAP_IDIVT); + int has_iwmmxt = (hwcaps & HWCAP_IWMMXT); + + // The kernel does a poor job at ensuring consistency when + // describing CPU features. So lots of guessing is needed. + + // 'vfpv4' implies VFPv3|VFP_FMA|FP16 + if (has_vfpv4) + g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv3 | + ANDROID_CPU_ARM_FEATURE_VFP_FP16 | + ANDROID_CPU_ARM_FEATURE_VFP_FMA; + + // 'vfpv3' or 'vfpv3d16' imply VFPv3. Note that unlike GCC, + // a value of 'vfpv3' doesn't necessarily mean that the D32 + // feature is present, so be conservative. All CPUs in the + // field that support D32 also support NEON, so this should + // not be a problem in practice. + if (has_vfpv3 || has_vfpv3d16) + g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv3; + + // 'vfp' is super ambiguous. Depending on the kernel, it can + // either mean VFPv2 or VFPv3. Make it depend on ARMv7. + if (has_vfp) { + if (g_cpuFeatures & ANDROID_CPU_ARM_FEATURE_ARMv7) + g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv3; + else + g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv2; + } + + // Neon implies VFPv3|D32, and if vfpv4 is detected, NEON_FMA + if (has_neon) { + g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv3 | + ANDROID_CPU_ARM_FEATURE_NEON | + ANDROID_CPU_ARM_FEATURE_VFP_D32; + if (has_vfpv4) + g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_NEON_FMA; + } + + // VFPv3 implies VFPv2 and ARMv7 + if (g_cpuFeatures & ANDROID_CPU_ARM_FEATURE_VFPv3) + g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv2 | + ANDROID_CPU_ARM_FEATURE_ARMv7; + + // Note that some buggy kernels do not report these even when + // the CPU actually support the division instructions. However, + // assume that if 'vfpv4' is detected, then the CPU supports + // sdiv/udiv properly. + if (has_idiva || has_vfpv4) + g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_IDIV_ARM; + if (has_idivt || has_vfpv4) + g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_IDIV_THUMB2; + + if (has_iwmmxt) + g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_iWMMXt; + } + } +#endif /* __ARM_ARCH__ */ + +#ifdef __i386__ + int regs[4]; + +/* According to http://en.wikipedia.org/wiki/CPUID */ +#define VENDOR_INTEL_b 0x756e6547 +#define VENDOR_INTEL_c 0x6c65746e +#define VENDOR_INTEL_d 0x49656e69 + + x86_cpuid(0, regs); + int vendorIsIntel = (regs[1] == VENDOR_INTEL_b && + regs[2] == VENDOR_INTEL_c && + regs[3] == VENDOR_INTEL_d); + + x86_cpuid(1, regs); + if ((regs[2] & (1 << 9)) != 0) { + g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_SSSE3; + } + if ((regs[2] & (1 << 23)) != 0) { + g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_POPCNT; + } + if (vendorIsIntel && (regs[2] & (1 << 22)) != 0) { + g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_MOVBE; + } +#endif + + free(cpuinfo); +} + + +AndroidCpuFamily +android_getCpuFamily(void) +{ + pthread_once(&g_once, android_cpuInit); + return g_cpuFamily; +} + + +uint64_t +android_getCpuFeatures(void) +{ + pthread_once(&g_once, android_cpuInit); + return g_cpuFeatures; +} + + +int +android_getCpuCount(void) +{ + pthread_once(&g_once, android_cpuInit); + return g_cpuCount; +} + +static void +android_cpuInitDummy(void) +{ + g_inited = 1; +} + +int +android_setCpu(int cpu_count, uint64_t cpu_features) +{ + /* Fail if the library was already initialized. */ + if (g_inited) + return 0; + + android_cpuInitFamily(); + g_cpuCount = (cpu_count <= 0 ? 1 : cpu_count); + g_cpuFeatures = cpu_features; + pthread_once(&g_once, android_cpuInitDummy); + + return 1; +} + +/* + * Technical note: Making sense of ARM's FPU architecture versions. + * + * FPA was ARM's first attempt at an FPU architecture. There is no Android + * device that actually uses it since this technology was already obsolete + * when the project started. If you see references to FPA instructions + * somewhere, you can be sure that this doesn't apply to Android at all. + * + * FPA was followed by "VFP", soon renamed "VFPv1" due to the emergence of + * new versions / additions to it. ARM considers this obsolete right now, + * and no known Android device implements it either. + * + * VFPv2 added a few instructions to VFPv1, and is an *optional* extension + * supported by some ARMv5TE, ARMv6 and ARMv6T2 CPUs. Note that a device + * supporting the 'armeabi' ABI doesn't necessarily support these. + * + * VFPv3-D16 adds a few instructions on top of VFPv2 and is typically used + * on ARMv7-A CPUs which implement a FPU. Note that it is also mandated + * by the Android 'armeabi-v7a' ABI. The -D16 suffix in its name means + * that it provides 16 double-precision FPU registers (d0-d15) and 32 + * single-precision ones (s0-s31) which happen to be mapped to the same + * register banks. + * + * VFPv3-D32 is the name of an extension to VFPv3-D16 that provides 16 + * additional double precision registers (d16-d31). Note that there are + * still only 32 single precision registers. + * + * VFPv3xD is a *subset* of VFPv3-D16 that only provides single-precision + * registers. It is only used on ARMv7-M (i.e. on micro-controllers) which + * are not supported by Android. Note that it is not compatible with VFPv2. + * + * NOTE: The term 'VFPv3' usually designate either VFPv3-D16 or VFPv3-D32 + * depending on context. For example GCC uses it for VFPv3-D32, but + * the Linux kernel code uses it for VFPv3-D16 (especially in + * /proc/cpuinfo). Always try to use the full designation when + * possible. + * + * NEON, a.k.a. "ARM Advanced SIMD" is an extension that provides + * instructions to perform parallel computations on vectors of 8, 16, + * 32, 64 and 128 bit quantities. NEON requires VFPv32-D32 since all + * NEON registers are also mapped to the same register banks. + * + * VFPv4-D16, adds a few instructions on top of VFPv3-D16 in order to + * perform fused multiply-accumulate on VFP registers, as well as + * half-precision (16-bit) conversion operations. + * + * VFPv4-D32 is VFPv4-D16 with 32, instead of 16, FPU double precision + * registers. + * + * VPFv4-NEON is VFPv4-D32 with NEON instructions. It also adds fused + * multiply-accumulate instructions that work on the NEON registers. + * + * NOTE: Similarly, "VFPv4" might either reference VFPv4-D16 or VFPv4-D32 + * depending on context. + * + * The following information was determined by scanning the binutils-2.22 + * sources: + * + * Basic VFP instruction subsets: + * + * #define FPU_VFP_EXT_V1xD 0x08000000 // Base VFP instruction set. + * #define FPU_VFP_EXT_V1 0x04000000 // Double-precision insns. + * #define FPU_VFP_EXT_V2 0x02000000 // ARM10E VFPr1. + * #define FPU_VFP_EXT_V3xD 0x01000000 // VFPv3 single-precision. + * #define FPU_VFP_EXT_V3 0x00800000 // VFPv3 double-precision. + * #define FPU_NEON_EXT_V1 0x00400000 // Neon (SIMD) insns. + * #define FPU_VFP_EXT_D32 0x00200000 // Registers D16-D31. + * #define FPU_VFP_EXT_FP16 0x00100000 // Half-precision extensions. + * #define FPU_NEON_EXT_FMA 0x00080000 // Neon fused multiply-add + * #define FPU_VFP_EXT_FMA 0x00040000 // VFP fused multiply-add + * + * FPU types (excluding NEON) + * + * FPU_VFP_V1xD (EXT_V1xD) + * | + * +--------------------------+ + * | | + * FPU_VFP_V1 (+EXT_V1) FPU_VFP_V3xD (+EXT_V2+EXT_V3xD) + * | | + * | | + * FPU_VFP_V2 (+EXT_V2) FPU_VFP_V4_SP_D16 (+EXT_FP16+EXT_FMA) + * | + * FPU_VFP_V3D16 (+EXT_Vx3D+EXT_V3) + * | + * +--------------------------+ + * | | + * FPU_VFP_V3 (+EXT_D32) FPU_VFP_V4D16 (+EXT_FP16+EXT_FMA) + * | | + * | FPU_VFP_V4 (+EXT_D32) + * | + * FPU_VFP_HARD (+EXT_FMA+NEON_EXT_FMA) + * + * VFP architectures: + * + * ARCH_VFP_V1xD (EXT_V1xD) + * | + * +------------------+ + * | | + * | ARCH_VFP_V3xD (+EXT_V2+EXT_V3xD) + * | | + * | ARCH_VFP_V3xD_FP16 (+EXT_FP16) + * | | + * | ARCH_VFP_V4_SP_D16 (+EXT_FMA) + * | + * ARCH_VFP_V1 (+EXT_V1) + * | + * ARCH_VFP_V2 (+EXT_V2) + * | + * ARCH_VFP_V3D16 (+EXT_V3xD+EXT_V3) + * | + * +-------------------+ + * | | + * | ARCH_VFP_V3D16_FP16 (+EXT_FP16) + * | + * +-------------------+ + * | | + * | ARCH_VFP_V4_D16 (+EXT_FP16+EXT_FMA) + * | | + * | ARCH_VFP_V4 (+EXT_D32) + * | | + * | ARCH_NEON_VFP_V4 (+EXT_NEON+EXT_NEON_FMA) + * | + * ARCH_VFP_V3 (+EXT_D32) + * | + * +-------------------+ + * | | + * | ARCH_VFP_V3_FP16 (+EXT_FP16) + * | + * ARCH_VFP_V3_PLUS_NEON_V1 (+EXT_NEON) + * | + * ARCH_NEON_FP16 (+EXT_FP16) + * + * -fpu= values and their correspondance with FPU architectures above: + * + * {"vfp", FPU_ARCH_VFP_V2}, + * {"vfp9", FPU_ARCH_VFP_V2}, + * {"vfp3", FPU_ARCH_VFP_V3}, // For backwards compatbility. + * {"vfp10", FPU_ARCH_VFP_V2}, + * {"vfp10-r0", FPU_ARCH_VFP_V1}, + * {"vfpxd", FPU_ARCH_VFP_V1xD}, + * {"vfpv2", FPU_ARCH_VFP_V2}, + * {"vfpv3", FPU_ARCH_VFP_V3}, + * {"vfpv3-fp16", FPU_ARCH_VFP_V3_FP16}, + * {"vfpv3-d16", FPU_ARCH_VFP_V3D16}, + * {"vfpv3-d16-fp16", FPU_ARCH_VFP_V3D16_FP16}, + * {"vfpv3xd", FPU_ARCH_VFP_V3xD}, + * {"vfpv3xd-fp16", FPU_ARCH_VFP_V3xD_FP16}, + * {"neon", FPU_ARCH_VFP_V3_PLUS_NEON_V1}, + * {"neon-fp16", FPU_ARCH_NEON_FP16}, + * {"vfpv4", FPU_ARCH_VFP_V4}, + * {"vfpv4-d16", FPU_ARCH_VFP_V4D16}, + * {"fpv4-sp-d16", FPU_ARCH_VFP_V4_SP_D16}, + * {"neon-vfpv4", FPU_ARCH_NEON_VFP_V4}, + * + * + * Simplified diagram that only includes FPUs supported by Android: + * Only ARCH_VFP_V3D16 is actually mandated by the armeabi-v7a ABI, + * all others are optional and must be probed at runtime. + * + * ARCH_VFP_V3D16 (EXT_V1xD+EXT_V1+EXT_V2+EXT_V3xD+EXT_V3) + * | + * +-------------------+ + * | | + * | ARCH_VFP_V3D16_FP16 (+EXT_FP16) + * | + * +-------------------+ + * | | + * | ARCH_VFP_V4_D16 (+EXT_FP16+EXT_FMA) + * | | + * | ARCH_VFP_V4 (+EXT_D32) + * | | + * | ARCH_NEON_VFP_V4 (+EXT_NEON+EXT_NEON_FMA) + * | + * ARCH_VFP_V3 (+EXT_D32) + * | + * +-------------------+ + * | | + * | ARCH_VFP_V3_FP16 (+EXT_FP16) + * | + * ARCH_VFP_V3_PLUS_NEON_V1 (+EXT_NEON) + * | + * ARCH_NEON_FP16 (+EXT_FP16) + * + */ diff --git a/platform_tools/android/third_party/cpufeatures/cpu-features.h b/platform_tools/android/third_party/cpufeatures/cpu-features.h new file mode 100644 index 0000000..f8553e8 --- /dev/null +++ b/platform_tools/android/third_party/cpufeatures/cpu-features.h @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#ifndef CPU_FEATURES_H +#define CPU_FEATURES_H + +#include +#include + +__BEGIN_DECLS + +typedef enum { + ANDROID_CPU_FAMILY_UNKNOWN = 0, + ANDROID_CPU_FAMILY_ARM, + ANDROID_CPU_FAMILY_X86, + ANDROID_CPU_FAMILY_MIPS, + + ANDROID_CPU_FAMILY_MAX /* do not remove */ + +} AndroidCpuFamily; + +/* Return family of the device's CPU */ +extern AndroidCpuFamily android_getCpuFamily(void); + +/* The list of feature flags for ARM CPUs that can be recognized by the + * library. Value details are: + * + * VFPv2: + * CPU supports the VFPv2 instruction set. Many, but not all, ARMv6 CPUs + * support these instructions. VFPv2 is a subset of VFPv3 so this will + * be set whenever VFPv3 is set too. + * + * ARMv7: + * CPU supports the ARMv7-A basic instruction set. + * This feature is mandated by the 'armeabi-v7a' ABI. + * + * VFPv3: + * CPU supports the VFPv3-D16 instruction set, providing hardware FPU + * support for single and double precision floating point registers. + * Note that only 16 FPU registers are available by default, unless + * the D32 bit is set too. This feature is also mandated by the + * 'armeabi-v7a' ABI. + * + * VFP_D32: + * CPU VFP optional extension that provides 32 FPU registers, + * instead of 16. Note that ARM mandates this feature is the 'NEON' + * feature is implemented by the CPU. + * + * NEON: + * CPU FPU supports "ARM Advanced SIMD" instructions, also known as + * NEON. Note that this mandates the VFP_D32 feature as well, per the + * ARM Architecture specification. + * + * VFP_FP16: + * Half-width floating precision VFP extension. If set, the CPU + * supports instructions to perform floating-point operations on + * 16-bit registers. This is part of the VFPv4 specification, but + * not mandated by any Android ABI. + * + * VFP_FMA: + * Fused multiply-accumulate VFP instructions extension. Also part of + * the VFPv4 specification, but not mandated by any Android ABI. + * + * NEON_FMA: + * Fused multiply-accumulate NEON instructions extension. Optional + * extension from the VFPv4 specification, but not mandated by any + * Android ABI. + * + * IDIV_ARM: + * Integer division available in ARM mode. Only available + * on recent CPUs (e.g. Cortex-A15). + * + * IDIV_THUMB2: + * Integer division available in Thumb-2 mode. Only available + * on recent CPUs (e.g. Cortex-A15). + * + * iWMMXt: + * Optional extension that adds MMX registers and operations to an + * ARM CPU. This is only available on a few XScale-based CPU designs + * sold by Marvell. Pretty rare in practice. + * + * If you want to tell the compiler to generate code that targets one of + * the feature set above, you should probably use one of the following + * flags (for more details, see technical note at the end of this file): + * + * -mfpu=vfp + * -mfpu=vfpv2 + * These are equivalent and tell GCC to use VFPv2 instructions for + * floating-point operations. Use this if you want your code to + * run on *some* ARMv6 devices, and any ARMv7-A device supported + * by Android. + * + * Generated code requires VFPv2 feature. + * + * -mfpu=vfpv3-d16 + * Tell GCC to use VFPv3 instructions (using only 16 FPU registers). + * This should be generic code that runs on any CPU that supports the + * 'armeabi-v7a' Android ABI. Note that no ARMv6 CPU supports this. + * + * Generated code requires VFPv3 feature. + * + * -mfpu=vfpv3 + * Tell GCC to use VFPv3 instructions with 32 FPU registers. + * Generated code requires VFPv3|VFP_D32 features. + * + * -mfpu=neon + * Tell GCC to use VFPv3 instructions with 32 FPU registers, and + * also support NEON intrinsics (see ). + * Generated code requires VFPv3|VFP_D32|NEON features. + * + * -mfpu=vfpv4-d16 + * Generated code requires VFPv3|VFP_FP16|VFP_FMA features. + * + * -mfpu=vfpv4 + * Generated code requires VFPv3|VFP_FP16|VFP_FMA|VFP_D32 features. + * + * -mfpu=neon-vfpv4 + * Generated code requires VFPv3|VFP_FP16|VFP_FMA|VFP_D32|NEON|NEON_FMA + * features. + * + * -mcpu=cortex-a7 + * -mcpu=cortex-a15 + * Generated code requires VFPv3|VFP_FP16|VFP_FMA|VFP_D32| + * NEON|NEON_FMA|IDIV_ARM|IDIV_THUMB2 + * This flag implies -mfpu=neon-vfpv4. + * + * -mcpu=iwmmxt + * Allows the use of iWMMXt instrinsics with GCC. + */ +enum { + ANDROID_CPU_ARM_FEATURE_ARMv7 = (1 << 0), + ANDROID_CPU_ARM_FEATURE_VFPv3 = (1 << 1), + ANDROID_CPU_ARM_FEATURE_NEON = (1 << 2), + ANDROID_CPU_ARM_FEATURE_LDREX_STREX = (1 << 3), + ANDROID_CPU_ARM_FEATURE_VFPv2 = (1 << 4), + ANDROID_CPU_ARM_FEATURE_VFP_D32 = (1 << 5), + ANDROID_CPU_ARM_FEATURE_VFP_FP16 = (1 << 6), + ANDROID_CPU_ARM_FEATURE_VFP_FMA = (1 << 7), + ANDROID_CPU_ARM_FEATURE_NEON_FMA = (1 << 8), + ANDROID_CPU_ARM_FEATURE_IDIV_ARM = (1 << 9), + ANDROID_CPU_ARM_FEATURE_IDIV_THUMB2 = (1 << 10), + ANDROID_CPU_ARM_FEATURE_iWMMXt = (1 << 11), +}; + +enum { + ANDROID_CPU_X86_FEATURE_SSSE3 = (1 << 0), + ANDROID_CPU_X86_FEATURE_POPCNT = (1 << 1), + ANDROID_CPU_X86_FEATURE_MOVBE = (1 << 2), +}; + +extern uint64_t android_getCpuFeatures(void); + +/* Return the number of CPU cores detected on this device. */ +extern int android_getCpuCount(void); + +/* The following is used to force the CPU count and features + * mask in sandboxed processes. Under 4.1 and higher, these processes + * cannot access /proc, which is the only way to get information from + * the kernel about the current hardware (at least on ARM). + * + * It _must_ be called only once, and before any android_getCpuXXX + * function, any other case will fail. + * + * This function return 1 on success, and 0 on failure. + */ +extern int android_setCpu(int cpu_count, + uint64_t cpu_features); + +__END_DECLS + +#endif /* CPU_FEATURES_H */ diff --git a/platform_tools/android/whitespace.txt b/platform_tools/android/whitespace.txt new file mode 100644 index 0000000..fd40910 --- /dev/null +++ b/platform_tools/android/whitespace.txt @@ -0,0 +1,4 @@ + + + +