--- /dev/null
+/third_party/externals/
+/toolchains/
+.cproject
+.externalToolBuilders/
+.project
+.pydevproject
+app/.classpath
+app/.project
+app/bin/
+app/gen/
+app/lint.xml
--- /dev/null
+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"],
+# },
+#]
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.skia"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <uses-sdk android:minSdkVersion="14" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.ACCESS_ALL_EXTERNAL_STORAGE" />
+ <!-- Needed to add to the download manager. -->
+ <uses-permission android:name="android.permission.INTERNET" />
+ <application android:label="SkiaAndroid">
+ <receiver android:name=".SkiaReceiver" android:enabled="true">
+ <intent-filter>
+ <action android:name="com.skia.intent.action.LAUNCH_SKIA" />
+ </intent-filter>
+ </receiver>
+ <service android:name=".SkiaIntentService"
+ android:process=":skia_native">
+ </service>
+ <activity android:name=".SkiaSampleActivity"
+ android:theme="@android:style/Theme.Holo.Light"
+ android:configChanges="orientation|screenSize"
+ android:label="@string/app_name">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="SkiaAndroid" default="help">
+
+ <!-- The local.properties file is created and updated by the 'android' tool.
+ It contains the path to the SDK. It should *NOT* be checked into
+ Version Control Systems. -->
+ <property file="local.properties" />
+
+ <!-- The project.properties file is created and updated by the 'android'
+ tool, as well as ADT.
+
+ This contains project specific properties such as project target, and library
+ dependencies. Lower level build properties are stored in ant.properties
+ (or in .classpath for Eclipse projects).
+
+ This file is an integral part of the build system for your
+ application and should be checked into Version Control Systems. -->
+ <loadproperties srcFile="project.properties" />
+
+ <!-- quick check on sdk.dir -->
+ <fail
+ message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through an env var"
+ unless="sdk.dir"
+ />
+
+ <!--
+ Import per project custom build rules if present at the root of the project.
+ This is the place to put custom intermediary targets such as:
+ -pre-build
+ -pre-compile
+ -post-compile (This is typically used for code obfuscation.
+ Compiled code location: ${out.classes.absolute.dir}
+ If this is not done in place, override ${out.dex.input.absolute.dir})
+ -post-package
+ -post-build
+ -pre-clean
+ -->
+ <import file="custom_rules.xml" optional="true" />
+
+ <!-- Import the actual build file.
+
+ To customize existing targets, there are two options:
+ - Customize only one target:
+ - copy/paste the target into this file, *before* the
+ <import> task.
+ - customize it to your needs.
+ - Customize the whole content of build.xml
+ - copy/paste the content of the rules files (minus the top node)
+ into this file, replacing the <import> task.
+ - customize to your needs.
+
+ ***********************
+ ****** IMPORTANT ******
+ ***********************
+ In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
+ in order to avoid having your file be overridden by tools such as "android update project"
+ -->
+ <!-- version-tag: 1 -->
+ <import file="${sdk.dir}/tools/ant/build.xml" />
+
+</project>
--- /dev/null
+#include "com_skia_SkiaIntentService.h"
+
+#include <stdint.h>
+#include <stdio.h>
+
+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;
+}
--- /dev/null
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* 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
--- /dev/null
+
+/*
+ * 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 <jni.h>
+#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<char**>(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();
+}
--- /dev/null
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* 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
--- /dev/null
+# 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
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2011 Google Inc.
+
+ Use of this source code is governed by a BSD-style license that can be
+ found in the LICENSE file.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/holder"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <TextView android:id="@+id/title_view"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ />
+</LinearLayout>
+
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2011 Google Inc.
+
+ Use of this source code is governed by a BSD-style license that can be
+ found in the LICENSE file.
+-->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:id="@+id/fps"
+ android:title="@string/fps"
+ android:showAsAction="ifRoom"
+ />
+ <item
+ android:id="@+id/toggle_rendering"
+ android:title="@string/toggle_rendering"
+ android:showAsAction="ifRoom"
+ />
+ <item
+ android:id="@+id/prev"
+ android:showAsAction="always"
+ android:icon="@drawable/ic_btn_find_prev"
+ />
+ <item
+ android:id="@+id/next"
+ android:showAsAction="always"
+ android:icon="@drawable/ic_btn_find_next"
+ />
+ <item
+ android:id="@+id/overview"
+ android:title="@string/overview"
+ />
+ <item
+ android:id="@+id/slideshow"
+ android:title="@string/slideshow"
+ />
+ <item
+ android:id="@+id/tiling"
+ android:title="@string/tiling"
+ />
+ <item
+ android:id="@+id/bbox"
+ android:title="@string/bbox"
+ />
+ <item
+ android:id="@+id/save_to_pdf"
+ android:title="@string/save_to_pdf"
+ />
+</menu>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="app_name">Skia Samples</string>
+ <string name="overview">Overview</string>
+ <string name="toggle_rendering">Toggle Rendering</string>
+ <string name="slideshow">Slideshow</string>
+ <string name="fps">FPS</string>
+ <string name="tiling">Toggle Tiling</string>
+ <string name="bbox">Toggle SKP BBox</string>
+ <string name="save_to_pdf">Save to PDF</string>
+ <string name="save_failed">Save Failed</string>
+ <string name="file_saved">%s saved!</string>
+</resources>
\ No newline at end of file
--- /dev/null
+// 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);
+}
--- /dev/null
+// 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
--- /dev/null
+/*
+ * 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<String> 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<String>(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();
+ }
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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();
+ }
+ });
+ }
+}
--- /dev/null
+#!/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 "<Unknown>" 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 = '<Unknown>'
+ 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
--- /dev/null
+#!/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
+
--- /dev/null
+#!/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
--- /dev/null
+#!/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
--- /dev/null
+#!/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
--- /dev/null
+#!/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
--- /dev/null
+#!/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;
--- /dev/null
+#!/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
--- /dev/null
+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 $*
+#}
--- /dev/null
+#!/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"
--- /dev/null
+#!/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
--- /dev/null
+# 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",
+ },
+]
--- /dev/null
+# 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',
+ ],
+ },
+
+ },
+ ]
+}
--- /dev/null
+{
+ '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': '<!(echo $ANDROID_SDK_ROOT)'
+ },
+ 'actions': [
+ {
+ 'action_name': 'SkiaAndroid_apk',
+ 'inputs': [
+ '<(android_base)/app/AndroidManifest.xml',
+ '<(android_base)/app/build.xml',
+ '<(android_base)/app/project.properties',
+ '<(android_base)/app/jni/com_skia_SkiaIntentService.h',
+ '<(android_base)/app/jni/com_skia_SkiaIntentService.cpp',
+ '<(android_base)/app/jni/com_skia_SkiaSampleRenderer.h',
+ '<(android_base)/app/jni/com_skia_SkiaSampleRenderer.cpp',
+ '<(android_base)/app/src/com/skia/SkiaReceiver.java',
+ '<(android_base)/app/src/com/skia/SkiaIntentService.java',
+ '<(android_base)/app/src/com/skia/SkiaSampleActivity.java',
+ '<(android_base)/app/src/com/skia/SkiaSampleRenderer.java',
+ '<(android_base)/app/src/com/skia/SkiaSampleView.java',
+ ],
+ 'outputs': [
+ '<(PRODUCT_DIR)/../android/bin/SkiaAndroid.apk',
+ ],
+ 'action': [
+ 'ant',
+ '-f',
+ '<(android_base)/app/build.xml',
+ '-Dout.dir=<(PRODUCT_DIR)/android/bin',
+ '-Dgen.absolute.dir=<(PRODUCT_DIR)/android/gen',
+ '-Dnative.libs.absolute.dir=<(PRODUCT_DIR)/android/libs',
+ '-Dout.final.file=<(PRODUCT_DIR)/android/bin/SkiaAndroid.apk',
+ '-Dsdk.dir=<(ANDROID_SDK_ROOT)',
+ 'debug',
+ ],
+ },
+ ],
+ },
+ ],
+}
--- /dev/null
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <dlfcn.h>
+#include <stdio.h>
+
+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);
+}
--- /dev/null
+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
--- /dev/null
+/*
+ * 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 <sys/system_properties.h>
+#ifdef __arm__
+#include <machine/cpu-features.h>
+#endif
+#include <pthread.h>
+#include "cpu-features.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+
+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 <asm/hwcap.h> 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=<name> 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)
+ *
+ */
--- /dev/null
+/*
+ * 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 <sys/cdefs.h>
+#include <stdint.h>
+
+__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 <arm_neon.h>).
+ * 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 */