diff options
587 files changed, 35442 insertions, 8733 deletions
diff --git a/api/current.txt b/api/current.txt index 7edfa5316dbc..d034b89c9d5c 100644 --- a/api/current.txt +++ b/api/current.txt @@ -614,8 +614,10 @@ package android { field public static final int layout_height = 16842997; // 0x10100f5 field public static final int layout_margin = 16842998; // 0x10100f6 field public static final int layout_marginBottom = 16843002; // 0x10100fa + field public static final int layout_marginEnd = 16843692; // 0x10103ac field public static final int layout_marginLeft = 16842999; // 0x10100f7 field public static final int layout_marginRight = 16843001; // 0x10100f9 + field public static final int layout_marginStart = 16843691; // 0x10103ab field public static final int layout_marginTop = 16843000; // 0x10100f8 field public static final int layout_row = 16843643; // 0x101037b field public static final int layout_rowSpan = 16843644; // 0x101037c @@ -711,8 +713,10 @@ package android { field public static final int packageNames = 16843649; // 0x1010381 field public static final int padding = 16842965; // 0x10100d5 field public static final int paddingBottom = 16842969; // 0x10100d9 + field public static final int paddingEnd = 16843690; // 0x10103aa field public static final int paddingLeft = 16842966; // 0x10100d6 field public static final int paddingRight = 16842968; // 0x10100d8 + field public static final int paddingStart = 16843689; // 0x10103a9 field public static final int paddingTop = 16842967; // 0x10100d7 field public static final int panelBackground = 16842846; // 0x101005e field public static final int panelColorBackground = 16842849; // 0x1010061 @@ -992,6 +996,7 @@ package android { field public static final int textColorTertiary = 16843282; // 0x1010212 field public static final int textColorTertiaryInverse = 16843283; // 0x1010213 field public static final int textCursorDrawable = 16843618; // 0x1010362 + field public static final int textDirection = 16843688; // 0x10103a8 field public static final int textEditNoPasteWindowLayout = 16843541; // 0x1010315 field public static final int textEditPasteWindowLayout = 16843540; // 0x1010314 field public static final int textEditSideNoPasteWindowLayout = 16843615; // 0x101035f @@ -20478,6 +20483,19 @@ package android.text { method public int getTopPadding(); } + public abstract interface TextDirectionHeuristic { + } + + public class TextDirectionHeuristics { + ctor public TextDirectionHeuristics(); + field public static final android.text.TextDirectionHeuristic ANYRTL_LTR; + field public static final android.text.TextDirectionHeuristic FIRSTSTRONG_LTR; + field public static final android.text.TextDirectionHeuristic FIRSTSTRONG_RTL; + field public static final android.text.TextDirectionHeuristic LOCALE; + field public static final android.text.TextDirectionHeuristic LTR; + field public static final android.text.TextDirectionHeuristic RTL; + } + public class TextPaint extends android.graphics.Paint { ctor public TextPaint(); ctor public TextPaint(int); @@ -23165,12 +23183,15 @@ package android.view { method public android.view.View.OnFocusChangeListener getOnFocusChangeListener(); method public int getOverScrollMode(); method public int getPaddingBottom(); + method public int getPaddingEnd(); method public int getPaddingLeft(); method public int getPaddingRight(); + method public int getPaddingStart(); method public int getPaddingTop(); method public final android.view.ViewParent getParent(); method public float getPivotX(); method public float getPivotY(); + method public int getResolvedTextDirection(); method public android.content.res.Resources getResources(); method public final int getRight(); method protected float getRightFadingEdgeStrength(); @@ -23190,6 +23211,7 @@ package android.view { method public int getSystemUiVisibility(); method public java.lang.Object getTag(); method public java.lang.Object getTag(int); + method public int getTextDirection(); method public final int getTop(); method protected float getTopFadingEdgeStrength(); method protected int getTopPaddingOffset(); @@ -23240,6 +23262,7 @@ package android.view { method public boolean isLongClickable(); method public boolean isOpaque(); method protected boolean isPaddingOffsetRequired(); + method public boolean isPaddingRelative(); method public boolean isPressed(); method public boolean isSaveEnabled(); method public boolean isSaveFromParentEnabled(); @@ -23287,6 +23310,9 @@ package android.view { method protected void onMeasure(int, int); method protected void onOverScrolled(int, int, boolean, boolean); method public void onPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent); + method public void onResetResolvedTextDirection(); + method public void onResolvePadding(int); + method public void onResolveTextDirection(); method protected void onRestoreInstanceState(android.os.Parcelable); method protected android.os.Parcelable onSaveInstanceState(); method protected void onScrollChanged(int, int, int, int); @@ -23321,8 +23347,11 @@ package android.view { method public void requestLayout(); method public boolean requestRectangleOnScreen(android.graphics.Rect); method public boolean requestRectangleOnScreen(android.graphics.Rect, boolean); + method public void resetResolvedTextDirection(); + method public void resolvePadding(); method public static int resolveSize(int, int); method public static int resolveSizeAndState(int, int, int); + method public void resolveTextDirection(); method public void restoreHierarchyState(android.util.SparseArray<android.os.Parcelable>); method public void saveHierarchyState(android.util.SparseArray<android.os.Parcelable>); method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long); @@ -23381,6 +23410,7 @@ package android.view { method public void setOnTouchListener(android.view.View.OnTouchListener); method public void setOverScrollMode(int); method public void setPadding(int, int, int, int); + method public void setPaddingRelative(int, int, int, int); method public void setPivotX(float); method public void setPivotY(float); method public void setPressed(boolean); @@ -23402,6 +23432,7 @@ package android.view { method public void setSystemUiVisibility(int); method public void setTag(java.lang.Object); method public void setTag(int, java.lang.Object); + method public void setTextDirection(int); method public final void setTop(int); method public void setTouchDelegate(android.view.TouchDelegate); method public void setTranslationX(float); @@ -23424,6 +23455,7 @@ package android.view { method public boolean willNotCacheDrawing(); method public boolean willNotDraw(); field public static final android.util.Property ALPHA; + field protected static int DEFAULT_TEXT_DIRECTION; field public static final int DRAWING_CACHE_QUALITY_AUTO = 0; // 0x0 field public static final int DRAWING_CACHE_QUALITY_HIGH = 1048576; // 0x100000 field public static final int DRAWING_CACHE_QUALITY_LOW = 524288; // 0x80000 @@ -23500,6 +23532,12 @@ package android.view { field public static final int SYSTEM_UI_FLAG_HIDE_NAVIGATION = 2; // 0x2 field public static final int SYSTEM_UI_FLAG_LOW_PROFILE = 1; // 0x1 field public static final int SYSTEM_UI_FLAG_VISIBLE = 0; // 0x0 + field public static final int TEXT_DIRECTION_ANY_RTL = 2; // 0x2 + field public static final int TEXT_DIRECTION_FIRST_STRONG = 1; // 0x1 + field public static final int TEXT_DIRECTION_INHERIT = 0; // 0x0 + field public static final int TEXT_DIRECTION_LOCALE = 5; // 0x5 + field public static final int TEXT_DIRECTION_LTR = 3; // 0x3 + field public static final int TEXT_DIRECTION_RTL = 4; // 0x4 field public static final android.util.Property TRANSLATION_X; field public static final android.util.Property TRANSLATION_Y; field protected static final java.lang.String VIEW_LOG_TAG = "View"; @@ -23766,7 +23804,6 @@ package android.view { method public boolean requestSendAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent); method public void requestTransparentRegion(android.view.View); method protected void resetResolvedLayoutDirection(); - method protected void resetResolvedTextDirection(); method public void scheduleLayoutAnimation(); method public void setAddStatesFromChildren(boolean); method public void setAlwaysDrawnWithCacheEnabled(boolean); @@ -23818,10 +23855,15 @@ package android.view { ctor public ViewGroup.MarginLayoutParams(int, int); ctor public ViewGroup.MarginLayoutParams(android.view.ViewGroup.MarginLayoutParams); ctor public ViewGroup.MarginLayoutParams(android.view.ViewGroup.LayoutParams); + method public int getMarginEnd(); + method public int getMarginStart(); + method public boolean isMarginRelative(); method public void setMargins(int, int, int, int); field public int bottomMargin; + field public int endMargin; field public int leftMargin; field public int rightMargin; + field public int startMargin; field public int topMargin; } @@ -27595,7 +27637,6 @@ package android.widget { method protected void resetResolvedDrawables(); method protected void resetResolvedLayoutDirection(); method protected void resolveDrawables(); - method protected void resolveTextDirection(); method public void setAllCaps(boolean); method public final void setAutoLinkMask(int); method public void setCompoundDrawablePadding(int); diff --git a/cmds/backup/backup.cpp b/cmds/backup/backup.cpp index d4e669b5d9e8..ea1888beea2a 100644 --- a/cmds/backup/backup.cpp +++ b/cmds/backup/backup.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include <utils/BackupHelpers.h> +#include <androidfw/BackupHelpers.h> #include <utils/String8.h> #include <fcntl.h> diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp index 0d5b4caa91b4..3545ace49179 100644 --- a/cmds/bootanimation/BootAnimation.cpp +++ b/cmds/bootanimation/BootAnimation.cpp @@ -25,12 +25,12 @@ #include <cutils/properties.h> +#include <androidfw/AssetManager.h> #include <binder/IPCThreadState.h> -#include <utils/threads.h> #include <utils/Atomic.h> #include <utils/Errors.h> #include <utils/Log.h> -#include <utils/AssetManager.h> +#include <utils/threads.h> #include <ui/PixelFormat.h> #include <ui/Rect.h> diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h index 8e28bba2de3c..c85d72c1a998 100644 --- a/cmds/bootanimation/BootAnimation.h +++ b/cmds/bootanimation/BootAnimation.h @@ -20,8 +20,8 @@ #include <stdint.h> #include <sys/types.h> +#include <androidfw/AssetManager.h> #include <utils/threads.h> -#include <utils/AssetManager.h> #include <surfaceflinger/ISurfaceComposer.h> #include <surfaceflinger/SurfaceComposerClient.h> diff --git a/cmds/content/Android.mk b/cmds/content/Android.mk new file mode 100644 index 000000000000..a3d83cf8848a --- /dev/null +++ b/cmds/content/Android.mk @@ -0,0 +1,35 @@ +# Copyright 2012 The Android Open Source Project + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_MODULE := content + +LOCAL_MODULE_TAGS := optional + +include $(BUILD_JAVA_LIBRARY) + +include $(CLEAR_VARS) +ALL_PREBUILT += $(TARGET_OUT)/bin/content +$(TARGET_OUT)/bin/content : $(LOCAL_PATH)/content | $(ACP) + $(transform-prebuilt-to-target) + +NOTICE_FILE := NOTICE +files_noticed := bin/content + +# Generate rules for a single file. The argument is the file path relative to +# the installation root +define make-notice-file + +$(TARGET_OUT_NOTICE_FILES)/src/$(1).txt: $(LOCAL_PATH)/$(NOTICE_FILE) + @echo Notice file: $$< -- $$@ + @mkdir -p $$(dir $$@) + @cat $$< >> $$@ + +$(TARGET_OUT_NOTICE_FILES)/hash-timestamp: $(TARGET_OUT_NOTICE_FILES)/src/$(1).txt + +endef + +$(foreach file,$(files_noticed),$(eval $(call make-notice-file,$(file)))) diff --git a/cmds/content/MODULE_LICENSE_APACHE2 b/cmds/content/MODULE_LICENSE_APACHE2 new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/cmds/content/MODULE_LICENSE_APACHE2 diff --git a/cmds/content/NOTICE b/cmds/content/NOTICE new file mode 100644 index 000000000000..33ff96160b77 --- /dev/null +++ b/cmds/content/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2005-2012, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/cmds/content/content b/cmds/content/content new file mode 100755 index 000000000000..a8e056d04d69 --- /dev/null +++ b/cmds/content/content @@ -0,0 +1,5 @@ +# Script to start "content" on the device, which has a very rudimentary shell. +base=/system +export CLASSPATH=$base/framework/content.jar +exec app_process $base/bin com.android.commands.content.Content "$@" + diff --git a/cmds/content/src/com/android/commands/content/Content.java b/cmds/content/src/com/android/commands/content/Content.java new file mode 100644 index 000000000000..1dcba70405fc --- /dev/null +++ b/cmds/content/src/com/android/commands/content/Content.java @@ -0,0 +1,442 @@ +/* +** Copyright 2012, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +package com.android.commands.content; + +import android.app.ActivityManagerNative; +import android.app.IActivityManager; +import android.app.IActivityManager.ContentProviderHolder; +import android.content.ContentValues; +import android.content.IContentProvider; +import android.database.Cursor; +import android.net.Uri; +import android.os.Binder; +import android.os.IBinder; +import android.text.TextUtils; + +/** + * This class is a command line utility for manipulating content. A client + * can insert, update, and remove records in a content provider. For example, + * some settings may be configured before running the CTS tests, etc. + * <p> + * Examples: + * <ul> + * <li> + * # Add "new_setting" secure setting with value "new_value".</br> + * adb shell content insert --uri content://settings/secure --bind name:s:new_setting + * --bind value:s:new_value + * </li> + * <li> + * # Change "new_setting" secure setting to "newer_value" (You have to escape single quotes in + * the where clause).</br> + * adb shell content update --uri content://settings/secure --bind value:s:newer_value + * --where "name=\'new_setting\'" + * </li> + * <li> + * # Remove "new_setting" secure setting.</br> + * adb shell content delete --uri content://settings/secure --where "name=\'new_setting\'" + * </li> + * <li> + * # Query \"name\" and \"value\" columns from secure settings where \"name\" is equal to" + * \"new_setting\" and sort the result by name in ascending order.\n" + * adb shell content query --uri content://settings/secure --projection name:value + * --where "name=\'new_setting\'" --sort \"name ASC\" + * </li> + * </ul> + * </p> + */ +public class Content { + + private static final String USAGE = + "usage: adb shell content [subcommand] [options]\n" + + "\n" + + "usage: adb shell content insert --uri <URI> --bind <BINDING> [--bind <BINDING>...]\n" + + " <URI> a content provider URI.\n" + + " <BINDING> binds a typed value to a column and is formatted:\n" + + " <COLUMN_NAME>:<TYPE>:<COLUMN_VALUE> where:\n" + + " <TYPE> specifies data type such as:\n" + + " b - boolean, s - string, i - integer, l - long, f - float, d - double\n" + + " Example:\n" + + " # Add \"new_setting\" secure setting with value \"new_value\".\n" + + " adb shell content insert --uri content://settings/secure --bind name:s:new_setting" + + " --bind value:s:new_value\n" + + "\n" + + "usage: adb shell content update --uri <URI> [--where <WHERE>]\n" + + " <WHERE> is a SQL style where clause in quotes (You have to escape single quotes" + + " - see example below).\n" + + " Example:\n" + + " # Change \"new_setting\" secure setting to \"newer_value\".\n" + + " adb shell content update --uri content://settings/secure --bind" + + " value:s:newer_value --where \"name=\'new_setting\'\"\n" + + "\n" + + "usage: adb shell content delete --uri <URI> --bind <BINDING>" + + " [--bind <BINDING>...] [--where <WHERE>]\n" + + " Example:\n" + + " # Remove \"new_setting\" secure setting.\n" + + " adb shell content delete --uri content://settings/secure " + + "--where \"name=\'new_setting\'\"\n" + + "\n" + + "usage: adb shell content query --uri <URI> [--projection <PROJECTION>]" + + " [--where <WHERE>] [--sort <SORT_ORDER>]\n" + + " <PROJECTION> is a list of colon separated column names and is formatted:\n" + + " <COLUMN_NAME>[:<COLUMN_NAME>...]\n" + + " <SORT_OREDER> is the order in which rows in the result should be sorted.\n" + + " Example:\n" + + " # Select \"name\" and \"value\" columns from secure settings where \"name\" is " + + "equal to \"new_setting\" and sort the result by name in ascending order.\n" + + " adb shell content query --uri content://settings/secure --projection name:value" + + " --where \"name=\'new_setting\'\" --sort \"name ASC\"\n" + + "\n"; + + private static class Parser { + private static final String ARGUMENT_INSERT = "insert"; + private static final String ARGUMENT_DELETE = "delete"; + private static final String ARGUMENT_UPDATE = "update"; + private static final String ARGUMENT_QUERY = "query"; + private static final String ARGUMENT_WHERE = "--where"; + private static final String ARGUMENT_BIND = "--bind"; + private static final String ARGUMENT_URI = "--uri"; + private static final String ARGUMENT_PROJECTION = "--projection"; + private static final String ARGUMENT_SORT = "--sort"; + private static final String TYPE_BOOLEAN = "b"; + private static final String TYPE_STRING = "s"; + private static final String TYPE_INTEGER = "i"; + private static final String TYPE_LONG = "l"; + private static final String TYPE_FLOAT = "f"; + private static final String TYPE_DOUBLE = "d"; + private static final String COLON = ":"; + private static final String ARGUMENT_PREFIX = "--"; + + private final Tokenizer mTokenizer; + + public Parser(String[] args) { + mTokenizer = new Tokenizer(args); + } + + public Command parseCommand() { + try { + String operation = mTokenizer.nextArg(); + if (ARGUMENT_INSERT.equals(operation)) { + return parseInsertCommand(); + } else if (ARGUMENT_DELETE.equals(operation)) { + return parseDeleteCommand(); + } else if (ARGUMENT_UPDATE.equals(operation)) { + return parseUpdateCommand(); + } else if (ARGUMENT_QUERY.equals(operation)) { + return parseQueryCommand(); + } else { + throw new IllegalArgumentException("Unsupported operation: " + operation); + } + } catch (IllegalArgumentException iae) { + System.out.println(USAGE); + System.out.println("[ERROR] " + iae.getMessage()); + return null; + } + } + + private InsertCommand parseInsertCommand() { + Uri uri = null; + ContentValues values = new ContentValues(); + for (String argument; (argument = mTokenizer.nextArg()) != null;) { + if (ARGUMENT_URI.equals(argument)) { + uri = Uri.parse(argumentValueRequired(argument)); + } else if (ARGUMENT_BIND.equals(argument)) { + parseBindValue(values); + } else { + throw new IllegalArgumentException("Unsupported argument: " + argument); + } + } + if (uri == null) { + throw new IllegalArgumentException("Content provider URI not specified." + + " Did you specify --uri argument?"); + } + if (values.size() == 0) { + throw new IllegalArgumentException("Bindings not specified." + + " Did you specify --bind argument(s)?"); + } + return new InsertCommand(uri, values); + } + + private DeleteCommand parseDeleteCommand() { + Uri uri = null; + String where = null; + for (String argument; (argument = mTokenizer.nextArg())!= null;) { + if (ARGUMENT_URI.equals(argument)) { + uri = Uri.parse(argumentValueRequired(argument)); + } else if (ARGUMENT_WHERE.equals(argument)) { + where = argumentValueRequired(argument); + } else { + throw new IllegalArgumentException("Unsupported argument: " + argument); + } + } + if (uri == null) { + throw new IllegalArgumentException("Content provider URI not specified." + + " Did you specify --uri argument?"); + } + return new DeleteCommand(uri, where); + } + + private UpdateCommand parseUpdateCommand() { + Uri uri = null; + String where = null; + ContentValues values = new ContentValues(); + for (String argument; (argument = mTokenizer.nextArg())!= null;) { + if (ARGUMENT_URI.equals(argument)) { + uri = Uri.parse(argumentValueRequired(argument)); + } else if (ARGUMENT_WHERE.equals(argument)) { + where = argumentValueRequired(argument); + } else if (ARGUMENT_BIND.equals(argument)) { + parseBindValue(values); + } else { + throw new IllegalArgumentException("Unsupported argument: " + argument); + } + } + if (uri == null) { + throw new IllegalArgumentException("Content provider URI not specified." + + " Did you specify --uri argument?"); + } + if (values.size() == 0) { + throw new IllegalArgumentException("Bindings not specified." + + " Did you specify --bind argument(s)?"); + } + return new UpdateCommand(uri, values, where); + } + + public QueryCommand parseQueryCommand() { + Uri uri = null; + String[] projection = null; + String sort = null; + String where = null; + for (String argument; (argument = mTokenizer.nextArg())!= null;) { + if (ARGUMENT_URI.equals(argument)) { + uri = Uri.parse(argumentValueRequired(argument)); + } else if (ARGUMENT_WHERE.equals(argument)) { + where = argumentValueRequired(argument); + } else if (ARGUMENT_SORT.equals(argument)) { + sort = argumentValueRequired(argument); + } else if (ARGUMENT_PROJECTION.equals(argument)) { + projection = argumentValueRequired(argument).split("[\\s]*:[\\s]*"); + } else { + throw new IllegalArgumentException("Unsupported argument: " + argument); + } + } + if (uri == null) { + throw new IllegalArgumentException("Content provider URI not specified." + + " Did you specify --uri argument?"); + } + return new QueryCommand(uri, projection, where, sort); + } + + private void parseBindValue(ContentValues values) { + String argument = mTokenizer.nextArg(); + if (TextUtils.isEmpty(argument)) { + throw new IllegalArgumentException("Binding not well formed: " + argument); + } + String[] binding = argument.split(COLON); + if (binding.length != 3) { + throw new IllegalArgumentException("Binding not well formed: " + argument); + } + String column = binding[0]; + String type = binding[1]; + String value = binding[2]; + if (TYPE_STRING.equals(type)) { + values.put(column, value); + } else if (TYPE_BOOLEAN.equalsIgnoreCase(type)) { + values.put(column, Boolean.parseBoolean(value)); + } else if (TYPE_INTEGER.equalsIgnoreCase(type) || TYPE_LONG.equalsIgnoreCase(type)) { + values.put(column, Long.parseLong(value)); + } else if (TYPE_FLOAT.equalsIgnoreCase(type) || TYPE_DOUBLE.equalsIgnoreCase(type)) { + values.put(column, Double.parseDouble(value)); + } else { + throw new IllegalArgumentException("Unsupported type: " + type); + } + } + + private String argumentValueRequired(String argument) { + String value = mTokenizer.nextArg(); + if (TextUtils.isEmpty(value) || value.startsWith(ARGUMENT_PREFIX)) { + throw new IllegalArgumentException("No value for argument: " + argument); + } + return value; + } + } + + private static class Tokenizer { + private final String[] mArgs; + private int mNextArg; + + public Tokenizer(String[] args) { + mArgs = args; + } + + private String nextArg() { + if (mNextArg < mArgs.length) { + return mArgs[mNextArg++]; + } else { + return null; + } + } + } + + private static abstract class Command { + final Uri mUri; + + public Command(Uri uri) { + mUri = uri; + } + + public final void execute() { + String providerName = mUri.getAuthority(); + try { + IActivityManager activityManager = ActivityManagerNative.getDefault(); + IContentProvider provider = null; + IBinder token = new Binder(); + try { + ContentProviderHolder holder = activityManager.getContentProviderExternal( + providerName, token); + if (holder == null) { + throw new IllegalStateException("Could not find provider: " + providerName); + } + provider = holder.provider; + onExecute(provider); + } finally { + if (provider != null) { + activityManager.removeContentProviderExternal(providerName, token); + } + } + } catch (Exception e) { + System.err.println("Error while accessing provider:" + providerName); + e.printStackTrace(); + } + } + + protected abstract void onExecute(IContentProvider provider) throws Exception; + } + + private static class InsertCommand extends Command { + final ContentValues mContentValues; + + public InsertCommand(Uri uri, ContentValues contentValues) { + super(uri); + mContentValues = contentValues; + } + + @Override + public void onExecute(IContentProvider provider) throws Exception { + provider.insert(mUri, mContentValues); + } + } + + private static class DeleteCommand extends Command { + final String mWhere; + + public DeleteCommand(Uri uri, String where) { + super(uri); + mWhere = where; + } + + @Override + public void onExecute(IContentProvider provider) throws Exception { + provider.delete(mUri, mWhere, null); + } + } + + private static class QueryCommand extends DeleteCommand { + final String[] mProjection; + final String mSortOrder; + + public QueryCommand(Uri uri, String[] projection, String where, String sortOrder) { + super(uri, where); + mProjection = projection; + mSortOrder = sortOrder; + } + + @Override + public void onExecute(IContentProvider provider) throws Exception { + Cursor cursor = provider.query(mUri, mProjection, mWhere, null, mSortOrder, null); + if (cursor == null) { + System.out.println("No result found."); + return; + } + try { + if (cursor.moveToFirst()) { + int rowIndex = 0; + StringBuilder builder = new StringBuilder(); + do { + builder.setLength(0); + builder.append("Row: ").append(rowIndex).append(" "); + rowIndex++; + final int columnCount = cursor.getColumnCount(); + for (int i = 0; i < columnCount; i++) { + if (i > 0) { + builder.append(", "); + } + String columnName = cursor.getColumnName(i); + String columnValue = null; + final int columnIndex = cursor.getColumnIndex(columnName); + final int type = cursor.getType(columnIndex); + switch (type) { + case Cursor.FIELD_TYPE_FLOAT: + columnValue = String.valueOf(cursor.getFloat(columnIndex)); + break; + case Cursor.FIELD_TYPE_INTEGER: + columnValue = String.valueOf(cursor.getInt(columnIndex)); + break; + case Cursor.FIELD_TYPE_STRING: + columnValue = cursor.getString(columnIndex); + break; + case Cursor.FIELD_TYPE_BLOB: + columnValue = "BLOB"; + break; + case Cursor.FIELD_TYPE_NULL: + columnValue = "NULL"; + break; + } + builder.append(columnName).append("=").append(columnValue); + } + System.out.println(builder); + } while (cursor.moveToNext()); + } else { + System.out.println("No reuslt found."); + } + } finally { + cursor.close(); + } + } + } + + private static class UpdateCommand extends InsertCommand { + final String mWhere; + + public UpdateCommand(Uri uri, ContentValues contentValues, String where) { + super(uri, contentValues); + mWhere = where; + } + + @Override + public void onExecute(IContentProvider provider) throws Exception { + provider.update(mUri, mContentValues, mWhere, null); + } + } + + public static void main(String[] args) { + Parser parser = new Parser(args); + Command command = parser.parseCommand(); + if (command != null) { + command.execute(); + } + } +} diff --git a/cmds/keystore/keystore.cpp b/cmds/keystore/keystore.cpp deleted file mode 100644 index 2c9cb35b7b25..000000000000 --- a/cmds/keystore/keystore.cpp +++ /dev/null @@ -1,810 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <stdio.h> -#include <stdint.h> -#include <string.h> -#include <unistd.h> -#include <signal.h> -#include <errno.h> -#include <dirent.h> -#include <fcntl.h> -#include <limits.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/stat.h> -#include <sys/time.h> -#include <arpa/inet.h> - -#include <openssl/aes.h> -#include <openssl/evp.h> -#include <openssl/md5.h> - -#define LOG_TAG "keystore" -#include <cutils/log.h> -#include <cutils/sockets.h> -#include <private/android_filesystem_config.h> - -#include "keystore.h" - -/* KeyStore is a secured storage for key-value pairs. In this implementation, - * each file stores one key-value pair. Keys are encoded in file names, and - * values are encrypted with checksums. The encryption key is protected by a - * user-defined password. To keep things simple, buffers are always larger than - * the maximum space we needed, so boundary checks on buffers are omitted. */ - -#define KEY_SIZE ((NAME_MAX - 15) / 2) -#define VALUE_SIZE 32768 -#define PASSWORD_SIZE VALUE_SIZE - -struct Value { - int length; - uint8_t value[VALUE_SIZE]; -}; - -/* Here is the encoding of keys. This is necessary in order to allow arbitrary - * characters in keys. Characters in [0-~] are not encoded. Others are encoded - * into two bytes. The first byte is one of [+-.] which represents the first - * two bits of the character. The second byte encodes the rest of the bits into - * [0-o]. Therefore in the worst case the length of a key gets doubled. Note - * that Base64 cannot be used here due to the need of prefix match on keys. */ - -static int encode_key(char* out, uid_t uid, const Value* key) { - int n = snprintf(out, NAME_MAX, "%u_", uid); - out += n; - const uint8_t* in = key->value; - int length = key->length; - for (int i = length; i > 0; --i, ++in, ++out) { - if (*in >= '0' && *in <= '~') { - *out = *in; - } else { - *out = '+' + (*in >> 6); - *++out = '0' + (*in & 0x3F); - ++length; - } - } - *out = '\0'; - return n + length; -} - -static int decode_key(uint8_t* out, char* in, int length) { - for (int i = 0; i < length; ++i, ++in, ++out) { - if (*in >= '0' && *in <= '~') { - *out = *in; - } else { - *out = (*in - '+') << 6; - *out |= (*++in - '0') & 0x3F; - --length; - } - } - *out = '\0'; - return length; -} - -static size_t readFully(int fd, uint8_t* data, size_t size) { - size_t remaining = size; - while (remaining > 0) { - ssize_t n = TEMP_FAILURE_RETRY(read(fd, data, size)); - if (n == -1 || n == 0) { - return size-remaining; - } - data += n; - remaining -= n; - } - return size; -} - -static size_t writeFully(int fd, uint8_t* data, size_t size) { - size_t remaining = size; - while (remaining > 0) { - ssize_t n = TEMP_FAILURE_RETRY(write(fd, data, size)); - if (n == -1 || n == 0) { - return size-remaining; - } - data += n; - remaining -= n; - } - return size; -} - -class Entropy { -public: - Entropy() : mRandom(-1) {} - ~Entropy() { - if (mRandom != -1) { - close(mRandom); - } - } - - bool open() { - const char* randomDevice = "/dev/urandom"; - mRandom = ::open(randomDevice, O_RDONLY); - if (mRandom == -1) { - ALOGE("open: %s: %s", randomDevice, strerror(errno)); - return false; - } - return true; - } - - bool generate_random_data(uint8_t* data, size_t size) { - return (readFully(mRandom, data, size) == size); - } - -private: - int mRandom; -}; - -/* Here is the file format. There are two parts in blob.value, the secret and - * the description. The secret is stored in ciphertext, and its original size - * can be found in blob.length. The description is stored after the secret in - * plaintext, and its size is specified in blob.info. The total size of the two - * parts must be no more than VALUE_SIZE bytes. The first three bytes of the - * file are reserved for future use and are always set to zero. Fields other - * than blob.info, blob.length, and blob.value are modified by encryptBlob() - * and decryptBlob(). Thus they should not be accessed from outside. */ - -struct __attribute__((packed)) blob { - uint8_t reserved[3]; - uint8_t info; - uint8_t vector[AES_BLOCK_SIZE]; - uint8_t encrypted[0]; - uint8_t digest[MD5_DIGEST_LENGTH]; - uint8_t digested[0]; - int32_t length; // in network byte order when encrypted - uint8_t value[VALUE_SIZE + AES_BLOCK_SIZE]; -}; - -class Blob { -public: - Blob(uint8_t* value, int32_t valueLength, uint8_t* info, uint8_t infoLength) { - mBlob.length = valueLength; - memcpy(mBlob.value, value, valueLength); - - mBlob.info = infoLength; - memcpy(mBlob.value + valueLength, info, infoLength); - } - - Blob(blob b) { - mBlob = b; - } - - Blob() {} - - uint8_t* getValue() { - return mBlob.value; - } - - int32_t getLength() { - return mBlob.length; - } - - uint8_t getInfo() { - return mBlob.info; - } - - ResponseCode encryptBlob(const char* filename, AES_KEY *aes_key, Entropy* entropy) { - if (!entropy->generate_random_data(mBlob.vector, AES_BLOCK_SIZE)) { - return SYSTEM_ERROR; - } - - // data includes the value and the value's length - size_t dataLength = mBlob.length + sizeof(mBlob.length); - // pad data to the AES_BLOCK_SIZE - size_t digestedLength = ((dataLength + AES_BLOCK_SIZE - 1) - / AES_BLOCK_SIZE * AES_BLOCK_SIZE); - // encrypted data includes the digest value - size_t encryptedLength = digestedLength + MD5_DIGEST_LENGTH; - // move info after space for padding - memmove(&mBlob.encrypted[encryptedLength], &mBlob.value[mBlob.length], mBlob.info); - // zero padding area - memset(mBlob.value + mBlob.length, 0, digestedLength - dataLength); - - mBlob.length = htonl(mBlob.length); - MD5(mBlob.digested, digestedLength, mBlob.digest); - - uint8_t vector[AES_BLOCK_SIZE]; - memcpy(vector, mBlob.vector, AES_BLOCK_SIZE); - AES_cbc_encrypt(mBlob.encrypted, mBlob.encrypted, encryptedLength, - aes_key, vector, AES_ENCRYPT); - - memset(mBlob.reserved, 0, sizeof(mBlob.reserved)); - size_t headerLength = (mBlob.encrypted - (uint8_t*) &mBlob); - size_t fileLength = encryptedLength + headerLength + mBlob.info; - - const char* tmpFileName = ".tmp"; - int out = open(tmpFileName, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR); - if (out == -1) { - return SYSTEM_ERROR; - } - size_t writtenBytes = writeFully(out, (uint8_t*) &mBlob, fileLength); - if (close(out) != 0) { - return SYSTEM_ERROR; - } - if (writtenBytes != fileLength) { - unlink(tmpFileName); - return SYSTEM_ERROR; - } - return (rename(tmpFileName, filename) == 0) ? NO_ERROR : SYSTEM_ERROR; - } - - ResponseCode decryptBlob(const char* filename, AES_KEY *aes_key) { - int in = open(filename, O_RDONLY); - if (in == -1) { - return (errno == ENOENT) ? KEY_NOT_FOUND : SYSTEM_ERROR; - } - // fileLength may be less than sizeof(mBlob) since the in - // memory version has extra padding to tolerate rounding up to - // the AES_BLOCK_SIZE - size_t fileLength = readFully(in, (uint8_t*) &mBlob, sizeof(mBlob)); - if (close(in) != 0) { - return SYSTEM_ERROR; - } - size_t headerLength = (mBlob.encrypted - (uint8_t*) &mBlob); - if (fileLength < headerLength) { - return VALUE_CORRUPTED; - } - - ssize_t encryptedLength = fileLength - (headerLength + mBlob.info); - if (encryptedLength < 0 || encryptedLength % AES_BLOCK_SIZE != 0) { - return VALUE_CORRUPTED; - } - AES_cbc_encrypt(mBlob.encrypted, mBlob.encrypted, encryptedLength, aes_key, - mBlob.vector, AES_DECRYPT); - size_t digestedLength = encryptedLength - MD5_DIGEST_LENGTH; - uint8_t computedDigest[MD5_DIGEST_LENGTH]; - MD5(mBlob.digested, digestedLength, computedDigest); - if (memcmp(mBlob.digest, computedDigest, MD5_DIGEST_LENGTH) != 0) { - return VALUE_CORRUPTED; - } - - ssize_t maxValueLength = digestedLength - sizeof(mBlob.length); - mBlob.length = ntohl(mBlob.length); - if (mBlob.length < 0 || mBlob.length > maxValueLength) { - return VALUE_CORRUPTED; - } - if (mBlob.info != 0) { - // move info from after padding to after data - memmove(&mBlob.value[mBlob.length], &mBlob.value[maxValueLength], mBlob.info); - } - return NO_ERROR; - } - -private: - struct blob mBlob; -}; - -class KeyStore { -public: - KeyStore(Entropy* entropy) : mEntropy(entropy), mRetry(MAX_RETRY) { - if (access(MASTER_KEY_FILE, R_OK) == 0) { - setState(STATE_LOCKED); - } else { - setState(STATE_UNINITIALIZED); - } - } - - State getState() { - return mState; - } - - int8_t getRetry() { - return mRetry; - } - - ResponseCode initialize(Value* pw) { - if (!generateMasterKey()) { - return SYSTEM_ERROR; - } - ResponseCode response = writeMasterKey(pw); - if (response != NO_ERROR) { - return response; - } - setupMasterKeys(); - return NO_ERROR; - } - - ResponseCode writeMasterKey(Value* pw) { - uint8_t passwordKey[MASTER_KEY_SIZE_BYTES]; - generateKeyFromPassword(passwordKey, MASTER_KEY_SIZE_BYTES, pw, mSalt); - AES_KEY passwordAesKey; - AES_set_encrypt_key(passwordKey, MASTER_KEY_SIZE_BITS, &passwordAesKey); - Blob masterKeyBlob(mMasterKey, sizeof(mMasterKey), mSalt, sizeof(mSalt)); - return masterKeyBlob.encryptBlob(MASTER_KEY_FILE, &passwordAesKey, mEntropy); - } - - ResponseCode readMasterKey(Value* pw) { - int in = open(MASTER_KEY_FILE, O_RDONLY); - if (in == -1) { - return SYSTEM_ERROR; - } - - // we read the raw blob to just to get the salt to generate - // the AES key, then we create the Blob to use with decryptBlob - blob rawBlob; - size_t length = readFully(in, (uint8_t*) &rawBlob, sizeof(rawBlob)); - if (close(in) != 0) { - return SYSTEM_ERROR; - } - // find salt at EOF if present, otherwise we have an old file - uint8_t* salt; - if (length > SALT_SIZE && rawBlob.info == SALT_SIZE) { - salt = (uint8_t*) &rawBlob + length - SALT_SIZE; - } else { - salt = NULL; - } - uint8_t passwordKey[MASTER_KEY_SIZE_BYTES]; - generateKeyFromPassword(passwordKey, MASTER_KEY_SIZE_BYTES, pw, salt); - AES_KEY passwordAesKey; - AES_set_decrypt_key(passwordKey, MASTER_KEY_SIZE_BITS, &passwordAesKey); - Blob masterKeyBlob(rawBlob); - ResponseCode response = masterKeyBlob.decryptBlob(MASTER_KEY_FILE, &passwordAesKey); - if (response == SYSTEM_ERROR) { - return SYSTEM_ERROR; - } - if (response == NO_ERROR && masterKeyBlob.getLength() == MASTER_KEY_SIZE_BYTES) { - // if salt was missing, generate one and write a new master key file with the salt. - if (salt == NULL) { - if (!generateSalt()) { - return SYSTEM_ERROR; - } - response = writeMasterKey(pw); - } - if (response == NO_ERROR) { - memcpy(mMasterKey, masterKeyBlob.getValue(), MASTER_KEY_SIZE_BYTES); - setupMasterKeys(); - } - return response; - } - if (mRetry <= 0) { - reset(); - return UNINITIALIZED; - } - --mRetry; - switch (mRetry) { - case 0: return WRONG_PASSWORD_0; - case 1: return WRONG_PASSWORD_1; - case 2: return WRONG_PASSWORD_2; - case 3: return WRONG_PASSWORD_3; - default: return WRONG_PASSWORD_3; - } - } - - bool reset() { - clearMasterKeys(); - setState(STATE_UNINITIALIZED); - - DIR* dir = opendir("."); - struct dirent* file; - - if (!dir) { - return false; - } - while ((file = readdir(dir)) != NULL) { - unlink(file->d_name); - } - closedir(dir); - return true; - } - - bool isEmpty() { - DIR* dir = opendir("."); - struct dirent* file; - if (!dir) { - return true; - } - bool result = true; - while ((file = readdir(dir)) != NULL) { - if (isKeyFile(file->d_name)) { - result = false; - break; - } - } - closedir(dir); - return result; - } - - void lock() { - clearMasterKeys(); - setState(STATE_LOCKED); - } - - ResponseCode get(const char* filename, Blob* keyBlob) { - return keyBlob->decryptBlob(filename, &mMasterKeyDecryption); - } - - ResponseCode put(const char* filename, Blob* keyBlob) { - return keyBlob->encryptBlob(filename, &mMasterKeyEncryption, mEntropy); - } - -private: - static const char* MASTER_KEY_FILE; - static const int MASTER_KEY_SIZE_BYTES = 16; - static const int MASTER_KEY_SIZE_BITS = MASTER_KEY_SIZE_BYTES * 8; - - static const int MAX_RETRY = 4; - static const size_t SALT_SIZE = 16; - - Entropy* mEntropy; - - State mState; - int8_t mRetry; - - uint8_t mMasterKey[MASTER_KEY_SIZE_BYTES]; - uint8_t mSalt[SALT_SIZE]; - - AES_KEY mMasterKeyEncryption; - AES_KEY mMasterKeyDecryption; - - void setState(State state) { - mState = state; - if (mState == STATE_NO_ERROR || mState == STATE_UNINITIALIZED) { - mRetry = MAX_RETRY; - } - } - - bool generateSalt() { - return mEntropy->generate_random_data(mSalt, sizeof(mSalt)); - } - - bool generateMasterKey() { - if (!mEntropy->generate_random_data(mMasterKey, sizeof(mMasterKey))) { - return false; - } - if (!generateSalt()) { - return false; - } - return true; - } - - void setupMasterKeys() { - AES_set_encrypt_key(mMasterKey, MASTER_KEY_SIZE_BITS, &mMasterKeyEncryption); - AES_set_decrypt_key(mMasterKey, MASTER_KEY_SIZE_BITS, &mMasterKeyDecryption); - setState(STATE_NO_ERROR); - } - - void clearMasterKeys() { - memset(mMasterKey, 0, sizeof(mMasterKey)); - memset(mSalt, 0, sizeof(mSalt)); - memset(&mMasterKeyEncryption, 0, sizeof(mMasterKeyEncryption)); - memset(&mMasterKeyDecryption, 0, sizeof(mMasterKeyDecryption)); - } - - static void generateKeyFromPassword(uint8_t* key, ssize_t keySize, Value* pw, uint8_t* salt) { - size_t saltSize; - if (salt != NULL) { - saltSize = SALT_SIZE; - } else { - // pre-gingerbread used this hardwired salt, readMasterKey will rewrite these when found - salt = (uint8_t*) "keystore"; - // sizeof = 9, not strlen = 8 - saltSize = sizeof("keystore"); - } - PKCS5_PBKDF2_HMAC_SHA1((char*) pw->value, pw->length, salt, saltSize, 8192, keySize, key); - } - - static bool isKeyFile(const char* filename) { - return ((strcmp(filename, MASTER_KEY_FILE) != 0) - && (strcmp(filename, ".") != 0) - && (strcmp(filename, "..") != 0)); - } -}; - -const char* KeyStore::MASTER_KEY_FILE = ".masterkey"; - -/* Here is the protocol used in both requests and responses: - * code [length_1 message_1 ... length_n message_n] end-of-file - * where code is one byte long and lengths are unsigned 16-bit integers in - * network order. Thus the maximum length of a message is 65535 bytes. */ - -static int recv_code(int sock, int8_t* code) { - return recv(sock, code, 1, 0) == 1; -} - -static int recv_message(int sock, uint8_t* message, int length) { - uint8_t bytes[2]; - if (recv(sock, &bytes[0], 1, 0) != 1 || - recv(sock, &bytes[1], 1, 0) != 1) { - return -1; - } else { - int offset = bytes[0] << 8 | bytes[1]; - if (length < offset) { - return -1; - } - length = offset; - offset = 0; - while (offset < length) { - int n = recv(sock, &message[offset], length - offset, 0); - if (n <= 0) { - return -1; - } - offset += n; - } - } - return length; -} - -static int recv_end_of_file(int sock) { - uint8_t byte; - return recv(sock, &byte, 1, 0) == 0; -} - -static void send_code(int sock, int8_t code) { - send(sock, &code, 1, 0); -} - -static void send_message(int sock, uint8_t* message, int length) { - uint16_t bytes = htons(length); - send(sock, &bytes, 2, 0); - send(sock, message, length, 0); -} - -/* Here are the actions. Each of them is a function without arguments. All - * information is defined in global variables, which are set properly before - * performing an action. The number of parameters required by each action is - * fixed and defined in a table. If the return value of an action is positive, - * it will be treated as a response code and transmitted to the client. Note - * that the lengths of parameters are checked when they are received, so - * boundary checks on parameters are omitted. */ - -static const ResponseCode NO_ERROR_RESPONSE_CODE_SENT = (ResponseCode) 0; - -static ResponseCode test(KeyStore* keyStore, int sock, uid_t uid, Value*, Value*) { - return (ResponseCode) keyStore->getState(); -} - -static ResponseCode get(KeyStore* keyStore, int sock, uid_t uid, Value* keyName, Value*) { - char filename[NAME_MAX]; - encode_key(filename, uid, keyName); - Blob keyBlob; - ResponseCode responseCode = keyStore->get(filename, &keyBlob); - if (responseCode != NO_ERROR) { - return responseCode; - } - send_code(sock, NO_ERROR); - send_message(sock, keyBlob.getValue(), keyBlob.getLength()); - return NO_ERROR_RESPONSE_CODE_SENT; -} - -static ResponseCode insert(KeyStore* keyStore, int sock, uid_t uid, Value* keyName, Value* val) { - char filename[NAME_MAX]; - encode_key(filename, uid, keyName); - Blob keyBlob(val->value, val->length, NULL, 0); - return keyStore->put(filename, &keyBlob); -} - -static ResponseCode del(KeyStore* keyStore, int sock, uid_t uid, Value* keyName, Value*) { - char filename[NAME_MAX]; - encode_key(filename, uid, keyName); - return (unlink(filename) && errno != ENOENT) ? SYSTEM_ERROR : NO_ERROR; -} - -static ResponseCode exist(KeyStore* keyStore, int sock, uid_t uid, Value* keyName, Value*) { - char filename[NAME_MAX]; - encode_key(filename, uid, keyName); - if (access(filename, R_OK) == -1) { - return (errno != ENOENT) ? SYSTEM_ERROR : KEY_NOT_FOUND; - } - return NO_ERROR; -} - -static ResponseCode saw(KeyStore* keyStore, int sock, uid_t uid, Value* keyPrefix, Value*) { - DIR* dir = opendir("."); - if (!dir) { - return SYSTEM_ERROR; - } - char filename[NAME_MAX]; - int n = encode_key(filename, uid, keyPrefix); - send_code(sock, NO_ERROR); - - struct dirent* file; - while ((file = readdir(dir)) != NULL) { - if (!strncmp(filename, file->d_name, n)) { - char* p = &file->d_name[n]; - keyPrefix->length = decode_key(keyPrefix->value, p, strlen(p)); - send_message(sock, keyPrefix->value, keyPrefix->length); - } - } - closedir(dir); - return NO_ERROR_RESPONSE_CODE_SENT; -} - -static ResponseCode reset(KeyStore* keyStore, int sock, uid_t uid, Value*, Value*) { - return keyStore->reset() ? NO_ERROR : SYSTEM_ERROR; -} - -/* Here is the history. To improve the security, the parameters to generate the - * master key has been changed. To make a seamless transition, we update the - * file using the same password when the user unlock it for the first time. If - * any thing goes wrong during the transition, the new file will not overwrite - * the old one. This avoids permanent damages of the existing data. */ - -static ResponseCode password(KeyStore* keyStore, int sock, uid_t uid, Value* pw, Value*) { - switch (keyStore->getState()) { - case STATE_UNINITIALIZED: { - // generate master key, encrypt with password, write to file, initialize mMasterKey*. - return keyStore->initialize(pw); - } - case STATE_NO_ERROR: { - // rewrite master key with new password. - return keyStore->writeMasterKey(pw); - } - case STATE_LOCKED: { - // read master key, decrypt with password, initialize mMasterKey*. - return keyStore->readMasterKey(pw); - } - } - return SYSTEM_ERROR; -} - -static ResponseCode lock(KeyStore* keyStore, int sock, uid_t uid, Value*, Value*) { - keyStore->lock(); - return NO_ERROR; -} - -static ResponseCode unlock(KeyStore* keyStore, int sock, uid_t uid, Value* pw, Value* unused) { - return password(keyStore, sock, uid, pw, unused); -} - -static ResponseCode zero(KeyStore* keyStore, int sock, uid_t uid, Value*, Value*) { - return keyStore->isEmpty() ? KEY_NOT_FOUND : NO_ERROR; -} - -/* Here are the permissions, actions, users, and the main function. */ - -enum perm { - TEST = 1, - GET = 2, - INSERT = 4, - DELETE = 8, - EXIST = 16, - SAW = 32, - RESET = 64, - PASSWORD = 128, - LOCK = 256, - UNLOCK = 512, - ZERO = 1024, -}; - -static const int MAX_PARAM = 2; - -static const State STATE_ANY = (State) 0; - -static struct action { - ResponseCode (*run)(KeyStore* keyStore, int sock, uid_t uid, Value* param1, Value* param2); - int8_t code; - State state; - uint32_t perm; - int lengths[MAX_PARAM]; -} actions[] = { - {test, 't', STATE_ANY, TEST, {0, 0}}, - {get, 'g', STATE_NO_ERROR, GET, {KEY_SIZE, 0}}, - {insert, 'i', STATE_NO_ERROR, INSERT, {KEY_SIZE, VALUE_SIZE}}, - {del, 'd', STATE_ANY, DELETE, {KEY_SIZE, 0}}, - {exist, 'e', STATE_ANY, EXIST, {KEY_SIZE, 0}}, - {saw, 's', STATE_ANY, SAW, {KEY_SIZE, 0}}, - {reset, 'r', STATE_ANY, RESET, {0, 0}}, - {password, 'p', STATE_ANY, PASSWORD, {PASSWORD_SIZE, 0}}, - {lock, 'l', STATE_NO_ERROR, LOCK, {0, 0}}, - {unlock, 'u', STATE_LOCKED, UNLOCK, {PASSWORD_SIZE, 0}}, - {zero, 'z', STATE_ANY, ZERO, {0, 0}}, - {NULL, 0 , STATE_ANY, 0, {0, 0}}, -}; - -static struct user { - uid_t uid; - uid_t euid; - uint32_t perms; -} users[] = { - {AID_SYSTEM, ~0, ~0}, - {AID_VPN, AID_SYSTEM, GET}, - {AID_WIFI, AID_SYSTEM, GET}, - {AID_ROOT, AID_SYSTEM, GET}, - {~0, ~0, TEST | GET | INSERT | DELETE | EXIST | SAW}, -}; - -static ResponseCode process(KeyStore* keyStore, int sock, uid_t uid, int8_t code) { - struct user* user = users; - struct action* action = actions; - int i; - - while (~user->uid && user->uid != uid) { - ++user; - } - while (action->code && action->code != code) { - ++action; - } - if (!action->code) { - return UNDEFINED_ACTION; - } - if (!(action->perm & user->perms)) { - return PERMISSION_DENIED; - } - if (action->state != STATE_ANY && action->state != keyStore->getState()) { - return (ResponseCode) keyStore->getState(); - } - if (~user->euid) { - uid = user->euid; - } - Value params[MAX_PARAM]; - for (i = 0; i < MAX_PARAM && action->lengths[i] != 0; ++i) { - params[i].length = recv_message(sock, params[i].value, action->lengths[i]); - if (params[i].length < 0) { - return PROTOCOL_ERROR; - } - } - if (!recv_end_of_file(sock)) { - return PROTOCOL_ERROR; - } - return action->run(keyStore, sock, uid, ¶ms[0], ¶ms[1]); -} - -int main(int argc, char* argv[]) { - int controlSocket = android_get_control_socket("keystore"); - if (argc < 2) { - ALOGE("A directory must be specified!"); - return 1; - } - if (chdir(argv[1]) == -1) { - ALOGE("chdir: %s: %s", argv[1], strerror(errno)); - return 1; - } - - Entropy entropy; - if (!entropy.open()) { - return 1; - } - if (listen(controlSocket, 3) == -1) { - ALOGE("listen: %s", strerror(errno)); - return 1; - } - - signal(SIGPIPE, SIG_IGN); - - KeyStore keyStore(&entropy); - int sock; - while ((sock = accept(controlSocket, NULL, 0)) != -1) { - struct timeval tv; - tv.tv_sec = 3; - setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); - setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); - - struct ucred cred; - socklen_t size = sizeof(cred); - int credResult = getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &cred, &size); - if (credResult != 0) { - ALOGW("getsockopt: %s", strerror(errno)); - } else { - int8_t request; - if (recv_code(sock, &request)) { - State old_state = keyStore.getState(); - ResponseCode response = process(&keyStore, sock, cred.uid, request); - if (response == NO_ERROR_RESPONSE_CODE_SENT) { - response = NO_ERROR; - } else { - send_code(sock, response); - } - ALOGI("uid: %d action: %c -> %d state: %d -> %d retry: %d", - cred.uid, - request, response, - old_state, keyStore.getState(), - keyStore.getRetry()); - } - } - close(sock); - } - ALOGE("accept: %s", strerror(errno)); - return 1; -} diff --git a/cmds/keystore/keystore.h b/cmds/keystore/keystore.h deleted file mode 100644 index 5ae3d24acee0..000000000000 --- a/cmds/keystore/keystore.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __KEYSTORE_H__ -#define __KEYSTORE_H__ - -// note state values overlap with ResponseCode for the purposes of the state() API -enum State { - STATE_NO_ERROR = 1, - STATE_LOCKED = 2, - STATE_UNINITIALIZED = 3, -}; - -enum ResponseCode { - NO_ERROR = STATE_NO_ERROR, // 1 - LOCKED = STATE_LOCKED, // 2 - UNINITIALIZED = STATE_UNINITIALIZED, // 3 - SYSTEM_ERROR = 4, - PROTOCOL_ERROR = 5, - PERMISSION_DENIED = 6, - KEY_NOT_FOUND = 7, - VALUE_CORRUPTED = 8, - UNDEFINED_ACTION = 9, - WRONG_PASSWORD_0 = 10, - WRONG_PASSWORD_1 = 11, - WRONG_PASSWORD_2 = 12, - WRONG_PASSWORD_3 = 13, // MAX_RETRY = 4 -}; - -#endif diff --git a/cmds/keystore/keystore_cli.cpp b/cmds/keystore/keystore_cli.cpp deleted file mode 100644 index dcd3bcb8fc01..000000000000 --- a/cmds/keystore/keystore_cli.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <stdio.h> -#include <stdint.h> -#include <string.h> -#include <sys/types.h> -#include <sys/socket.h> - -#include <cutils/sockets.h> - -#include "keystore.h" - -static const char* responses[] = { - NULL, - /* [NO_ERROR] = */ "No error", - /* [LOCKED] = */ "Locked", - /* [UNINITIALIZED] = */ "Uninitialized", - /* [SYSTEM_ERROR] = */ "System error", - /* [PROTOCOL_ERROR] = */ "Protocol error", - /* [PERMISSION_DENIED] = */ "Permission denied", - /* [KEY_NOT_FOUND] = */ "Key not found", - /* [VALUE_CORRUPTED] = */ "Value corrupted", - /* [UNDEFINED_ACTION] = */ "Undefined action", - /* [WRONG_PASSWORD] = */ "Wrong password (last chance)", - /* [WRONG_PASSWORD + 1] = */ "Wrong password (2 tries left)", - /* [WRONG_PASSWORD + 2] = */ "Wrong password (3 tries left)", - /* [WRONG_PASSWORD + 3] = */ "Wrong password (4 tries left)", -}; - -int main(int argc, char* argv[]) -{ - if (argc < 2) { - printf("Usage: %s action [parameter ...]\n", argv[0]); - return 0; - } - - int sock = socket_local_client("keystore", ANDROID_SOCKET_NAMESPACE_RESERVED, - SOCK_STREAM); - if (sock == -1) { - puts("Failed to connect"); - return 1; - } - - send(sock, argv[1], 1, 0); - uint8_t bytes[65536]; - for (int i = 2; i < argc; ++i) { - uint16_t length = strlen(argv[i]); - bytes[0] = length >> 8; - bytes[1] = length; - send(sock, &bytes, 2, 0); - send(sock, argv[i], length, 0); - } - shutdown(sock, SHUT_WR); - - uint8_t code; - if (recv(sock, &code, 1, 0) != 1) { - puts("Failed to receive"); - return 1; - } - printf("%d %s\n", code , responses[code] ? responses[code] : "Unknown"); - int i; - while ((i = recv(sock, &bytes[0], 1, 0)) == 1) { - int length; - int offset; - if ((i = recv(sock, &bytes[1], 1, 0)) != 1) { - puts("Failed to receive"); - return 1; - } - length = bytes[0] << 8 | bytes[1]; - for (offset = 0; offset < length; offset += i) { - i = recv(sock, &bytes[offset], length - offset, 0); - if (i <= 0) { - puts("Failed to receive"); - return 1; - } - } - fwrite(bytes, 1, length, stdout); - puts(""); - } - return 0; -} diff --git a/cmds/keystore/keystore_get.h b/cmds/keystore/keystore_get.h deleted file mode 100644 index 4b4923e5c736..000000000000 --- a/cmds/keystore/keystore_get.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __KEYSTORE_GET_H__ -#define __KEYSTORE_GET_H__ - -#include <stdio.h> -#include <stdint.h> -#include <unistd.h> -#include <sys/types.h> -#include <sys/socket.h> - -#include <cutils/sockets.h> - -#define KEYSTORE_MESSAGE_SIZE 65535 - -#ifdef __cplusplus -extern "C" { -#endif - -/* This function is provided for native components to get values from keystore. - * Users are required to link against libcutils. Keys and values are 8-bit safe. - * The first two arguments are the key and its length. The third argument - * specifies the buffer to store the retrieved value, which must be an array of - * KEYSTORE_MESSAGE_SIZE bytes. This function returns the length of the value or - * -1 if an error happens. */ -static int keystore_get(const char *key, int length, char *value) -{ - uint8_t bytes[2] = {length >> 8, length}; - uint8_t code = 'g'; - int sock; - - if (length < 0 || length > KEYSTORE_MESSAGE_SIZE) { - return -1; - } - sock = socket_local_client("keystore", ANDROID_SOCKET_NAMESPACE_RESERVED, - SOCK_STREAM); - if (sock == -1) { - return -1; - } - if (send(sock, &code, 1, 0) == 1 && send(sock, bytes, 2, 0) == 2 && - send(sock, key, length, 0) == length && shutdown(sock, SHUT_WR) == 0 && - recv(sock, &code, 1, 0) == 1 && code == /* NO_ERROR */ 1 && - recv(sock, &bytes[0], 1, 0) == 1 && recv(sock, &bytes[1], 1, 0) == 1) { - int offset = 0; - length = bytes[0] << 8 | bytes[1]; - while (offset < length) { - int n = recv(sock, &value[offset], length - offset, 0); - if (n <= 0) { - length = -1; - break; - } - offset += n; - } - } else { - length = -1; - } - - close(sock); - return length; -} - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/cmds/keystore/test-keystore b/cmds/keystore/test-keystore deleted file mode 100755 index 3be51b3e7bfb..000000000000 --- a/cmds/keystore/test-keystore +++ /dev/null @@ -1,273 +0,0 @@ -#!/bin/bash -# -# Copyright 2011, The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set -e - -prefix=$0 -log_file=$prefix.log -baseline_file=$prefix.baseline - -function cleanup_output() { - rm -f $log_file - rm -f $baseline_file -} - -function log() { - echo "$@" - append $log_file \# "$@" - append $baseline_file \# "$@" -} - -function expect() { - append $baseline_file "$@" -} - -function append() { - declare -r file=$1 - shift - echo "$@" >> $file -} - -function run() { - # strip out carriage returns from adb - # strip out date/time from ls -l - "$@" | tr --delete '\r' | sed -E 's/[0-9]{4}-[0-9]{2}-[0-9]{2} +[0-9]{1,2}:[0-9]{2} //' >> $log_file -} - -function keystore() { - declare -r user=$1 - shift - run adb shell su $user keystore_cli "$@" -} - -function list_keystore_directory() { - run adb shell ls -al /data/misc/keystore -} - -function compare() { - log "comparing $baseline_file and $log_file" - diff $baseline_file $log_file || (log $tag FAILED && exit 1) -} - -function test_basic() { - - # - # reset - # - log "reset keystore as system user" - keystore system r - expect "1 No error" - list_keystore_directory - - # - # basic tests as system/root - # - log "root does not have permission to run test" - keystore root t - expect "6 Permission denied" - - log "but system user does" - keystore system t - expect "3 Uninitialized" - list_keystore_directory - - log "password is now bar" - keystore system p bar - expect "1 No error" - list_keystore_directory - expect "-rw------- keystore keystore 84 .masterkey" - - log "no error implies initialized and unlocked" - keystore system t - expect "1 No error" - - log "saw with no argument" - keystore system s - expect "5 Protocol error" - - log "saw nothing" - keystore system s "" - expect "1 No error" - - log "add key baz" - keystore system i baz quux - expect "1 No error" - - log "1000 is uid of system" - list_keystore_directory - expect "-rw------- keystore keystore 84 .masterkey" - expect "-rw------- keystore keystore 52 1000_baz" - - log "saw baz" - keystore system s "" - expect "1 No error" - expect "baz" - - log "get baz" - keystore system g baz - expect "1 No error" - expect "quux" - - log "root can read system user keys (as can wifi or vpn users)" - keystore root g baz - expect "1 No error" - expect "quux" - - # - # app user tests - # - - # app_0 has uid 10000, as seen below - log "other uses cannot see the system keys" - keystore app_0 g baz - expect "7 Key not found" - - log "app user cannot use reset, password, lock, unlock" - keystore app_0 r - expect "6 Permission denied" - keystore app_0 p - expect "6 Permission denied" - keystore app_0 l - expect "6 Permission denied" - keystore app_0 u - expect "6 Permission denied" - - log "install app_0 key" - keystore app_0 i 0x deadbeef - expect 1 No error - list_keystore_directory - expect "-rw------- keystore keystore 84 .masterkey" - expect "-rw------- keystore keystore 52 10000_0x" - expect "-rw------- keystore keystore 52 1000_baz" - - log "get with no argument" - keystore app_0 g - expect "5 Protocol error" - - keystore app_0 g 0x - expect "1 No error" - expect "deadbeef" - - keystore app_0 i fred barney - expect "1 No error" - - keystore app_0 s "" - expect "1 No error" - expect "0x" - expect "fred" - - log "note that saw returns the suffix of prefix matches" - keystore app_0 s fr # fred - expect "1 No error" - expect "ed" # fred - - # - # lock tests - # - log "lock the store as system" - keystore system l - expect "1 No error" - keystore system t - expect "2 Locked" - - log "saw works while locked" - keystore app_0 s "" - expect "1 No error" - expect "0x" - expect "fred" - - log "...but cannot read keys..." - keystore app_0 g 0x - expect "2 Locked" - - log "...but they can be deleted." - keystore app_0 e 0x - expect "1 No error" - keystore app_0 d 0x - expect "1 No error" - keystore app_0 e 0x - expect "7 Key not found" - - # - # password - # - log "wrong password" - keystore system u foo - expect "13 Wrong password (4 tries left)" - log "right password" - keystore system u bar - expect "1 No error" - - log "make the password foo" - keystore system p foo - expect "1 No error" - - # - # final reset - # - log "reset wipes everything for all users" - keystore system r - expect "1 No error" - list_keystore_directory - - keystore system t - expect "3 Uninitialized" - -} - -function test_4599735() { - # http://b/4599735 - log "start regression test for b/4599735" - keystore system r - expect "1 No error" - - keystore system p foo - expect "1 No error" - - keystore system i baz quux - expect "1 No error" - - keystore root g baz - expect "1 No error" - expect "quux" - - keystore system l - expect "1 No error" - - keystore system p foo - expect "1 No error" - - log "after unlock, regression led to result of '8 Value corrupted'" - keystore root g baz - expect "1 No error" - expect "quux" - - keystore system r - expect "1 No error" - log "end regression test for b/4599735" -} - -function main() { - cleanup_output - log $tag START - test_basic - test_4599735 - compare - log $tag PASSED - cleanup_output -} - -main diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c index cfc2d1611628..71c5622ec382 100644 --- a/cmds/servicemanager/service_manager.c +++ b/cmds/servicemanager/service_manager.c @@ -43,6 +43,8 @@ static struct { { AID_RADIO, "isms" }, { AID_RADIO, "iphonesubinfo" }, { AID_RADIO, "simphonebook" }, + { AID_MEDIA, "common_time.clock" }, + { AID_MEDIA, "common_time.config" }, }; void *svcmgr_handle; diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java index cc1efb9acd98..6fbeee36e03a 100755 --- a/core/java/android/animation/ValueAnimator.java +++ b/core/java/android/animation/ValueAnimator.java @@ -522,8 +522,7 @@ public class ValueAnimator extends Animator { * animations possible. * */ - private static class AnimationHandler extends Handler - implements Choreographer.OnAnimateListener { + private static class AnimationHandler extends Handler implements Runnable { // The per-thread list of all active animations private final ArrayList<ValueAnimator> mAnimations = new ArrayList<ValueAnimator>(); @@ -539,7 +538,7 @@ public class ValueAnimator extends Animator { private final ArrayList<ValueAnimator> mReadyAnims = new ArrayList<ValueAnimator>(); private final Choreographer mChoreographer; - private boolean mIsChoreographed; + private boolean mAnimationScheduled; private AnimationHandler() { mChoreographer = Choreographer.getInstance(); @@ -644,22 +643,17 @@ public class ValueAnimator extends Animator { // If there are still active or delayed animations, schedule a future call to // onAnimate to process the next frame of the animations. - if (!mAnimations.isEmpty() || !mDelayedAnims.isEmpty()) { - if (!mIsChoreographed) { - mIsChoreographed = true; - mChoreographer.addOnAnimateListener(this); - } - mChoreographer.scheduleAnimation(); - } else { - if (mIsChoreographed) { - mIsChoreographed = false; - mChoreographer.removeOnAnimateListener(this); - } + if (!mAnimationScheduled + && (!mAnimations.isEmpty() || !mDelayedAnims.isEmpty())) { + mChoreographer.postAnimationCallback(this); + mAnimationScheduled = true; } } + // Called by the Choreographer. @Override - public void onAnimate() { + public void run() { + mAnimationScheduled = false; doAnimationFrame(); } } diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 5a364665768d..24079a5d8a2f 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -581,6 +581,21 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM return true; } + case GET_CONTENT_PROVIDER_EXTERNAL_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + String name = data.readString(); + IBinder token = data.readStrongBinder(); + ContentProviderHolder cph = getContentProviderExternal(name, token); + reply.writeNoException(); + if (cph != null) { + reply.writeInt(1); + cph.writeToParcel(reply, 0); + } else { + reply.writeInt(0); + } + return true; + } + case PUBLISH_CONTENT_PROVIDERS_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); IBinder b = data.readStrongBinder(); @@ -601,7 +616,16 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM reply.writeNoException(); return true; } - + + case REMOVE_CONTENT_PROVIDER_EXTERNAL_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + String name = data.readString(); + IBinder token = data.readStrongBinder(); + removeContentProviderExternal(name, token); + reply.writeNoException(); + return true; + } + case GET_RUNNING_SERVICE_CONTROL_PANEL_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); ComponentName comp = ComponentName.CREATOR.createFromParcel(data); @@ -2178,6 +2202,25 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); return cph; } + public ContentProviderHolder getContentProviderExternal(String name, IBinder token) + throws RemoteException + { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeString(name); + data.writeStrongBinder(token); + mRemote.transact(GET_CONTENT_PROVIDER_EXTERNAL_TRANSACTION, data, reply, 0); + reply.readException(); + int res = reply.readInt(); + ContentProviderHolder cph = null; + if (res != 0) { + cph = ContentProviderHolder.CREATOR.createFromParcel(reply); + } + data.recycle(); + reply.recycle(); + return cph; + } public void publishContentProviders(IApplicationThread caller, List<ContentProviderHolder> providers) throws RemoteException { @@ -2204,7 +2247,19 @@ class ActivityManagerProxy implements IActivityManager data.recycle(); reply.recycle(); } - + + public void removeContentProviderExternal(String name, IBinder token) throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeString(name); + data.writeStrongBinder(token); + mRemote.transact(REMOVE_CONTENT_PROVIDER_EXTERNAL_TRANSACTION, data, reply, 0); + reply.readException(); + data.recycle(); + reply.recycle(); + } + public PendingIntent getRunningServiceControlPanel(ComponentName service) throws RemoteException { diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index ebf692a99080..6d5cce5efdc3 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -911,6 +911,19 @@ class ContextImpl extends Context { } } + /** @hide */ + @Override + public void sendBroadcast(Intent intent, int userId) { + String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); + try { + intent.setAllowFds(false); + ActivityManagerNative.getDefault().broadcastIntent(mMainThread.getApplicationThread(), + intent, resolvedType, null, Activity.RESULT_OK, null, null, null, false, false, + userId); + } catch (RemoteException e) { + } + } + @Override public void sendBroadcast(Intent intent, String receiverPermission) { String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 7deb615f6f9f..53a71db82b14 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -150,8 +150,11 @@ public interface IActivityManager extends IInterface { Bitmap thumbnail, CharSequence description) throws RemoteException; public ContentProviderHolder getContentProvider(IApplicationThread caller, String name) throws RemoteException; + public ContentProviderHolder getContentProviderExternal(String name, IBinder token) + throws RemoteException; public void removeContentProvider(IApplicationThread caller, String name) throws RemoteException; + public void removeContentProviderExternal(String name, IBinder token) throws RemoteException; public void publishContentProviders(IApplicationThread caller, List<ContentProviderHolder> providers) throws RemoteException; public PendingIntent getRunningServiceControlPanel(ComponentName service) @@ -415,7 +418,7 @@ public interface IActivityManager extends IInterface { source.readStrongBinder()); noReleaseNeeded = source.readInt() != 0; } - }; + } /** Information returned after waiting for an activity start. */ public static class WaitResult implements Parcelable { @@ -601,4 +604,6 @@ public interface IActivityManager extends IInterface { int SHOW_BOOT_MESSAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+137; int DISMISS_KEYGUARD_ON_NEXT_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+138; int KILL_ALL_BACKGROUND_PROCESSES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+139; + int GET_CONTENT_PROVIDER_EXTERNAL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+140; + int REMOVE_CONTENT_PROVIDER_EXTERNAL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+141; } diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 6d4cdaee1060..a1198dedef13 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -905,6 +905,16 @@ public abstract class Context { public abstract void sendBroadcast(Intent intent); /** + * Same as #sendBroadcast(Intent intent), but for a specific user. Used by the system only. + * @param intent the intent to broadcast + * @param userId user to send the intent to + * @hide + */ + public void sendBroadcast(Intent intent, int userId) { + throw new RuntimeException("Not implemented. Must override in a subclass."); + } + + /** * Broadcast the given intent to all interested BroadcastReceivers, allowing * an optional required permission to be enforced. This * call is asynchronous; it returns immediately, and you will continue diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java index cd8d87f9d057..5ba9dccd36b3 100644 --- a/core/java/android/content/ContextWrapper.java +++ b/core/java/android/content/ContextWrapper.java @@ -294,6 +294,12 @@ public class ContextWrapper extends Context { mBase.sendBroadcast(intent); } + /** @hide */ + @Override + public void sendBroadcast(Intent intent, int userId) { + mBase.sendBroadcast(intent, userId); + } + @Override public void sendBroadcast(Intent intent, String receiverPermission) { mBase.sendBroadcast(intent, receiverPermission); diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java index aeb5d92386ea..3fdf2469a96e 100644 --- a/core/java/android/hardware/SensorManager.java +++ b/core/java/android/hardware/SensorManager.java @@ -616,6 +616,7 @@ public class SensorManager Message msg = Message.obtain(); msg.what = 0; msg.obj = t; + msg.setAsynchronous(true); mHandler.sendMessage(msg); } } diff --git a/core/java/android/net/http/CertificateChainValidator.java b/core/java/android/net/http/CertificateChainValidator.java index f94d3207f23d..06c6c6ec248f 100644 --- a/core/java/android/net/http/CertificateChainValidator.java +++ b/core/java/android/net/http/CertificateChainValidator.java @@ -25,15 +25,17 @@ import javax.net.ssl.DefaultHostnameVerifier; import javax.net.ssl.SSLHandshakeException; import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSocket; +import javax.net.ssl.X509TrustManager; import org.apache.harmony.security.provider.cert.X509CertImpl; import org.apache.harmony.xnet.provider.jsse.SSLParametersImpl; +import org.apache.harmony.xnet.provider.jsse.TrustManagerImpl; /** * Class responsible for all server certificate validation functionality * * {@hide} */ -class CertificateChainValidator { +public class CertificateChainValidator { /** * The singleton instance of the certificate chain validator @@ -122,6 +124,18 @@ class CertificateChainValidator { } /** + * Handles updates to credential storage. + */ + public static void handleTrustStorageUpdate() { + + X509TrustManager x509TrustManager = SSLParametersImpl.getDefaultTrustManager(); + if( x509TrustManager instanceof TrustManagerImpl ) { + TrustManagerImpl trustManager = (TrustManagerImpl) x509TrustManager; + trustManager.handleTrustStorageUpdate(); + } + } + + /** * Common code of doHandshakeAndValidateServerCertificates and verifyServerCertificates. * Calls DomainNamevalidator to verify the domain, and TrustManager to verify the certs. * @param chain the cert chain in X509 cert format. diff --git a/core/java/android/net/http/HttpResponseCache.java b/core/java/android/net/http/HttpResponseCache.java index 21736aa3d9a2..73f3d7cc339a 100644 --- a/core/java/android/net/http/HttpResponseCache.java +++ b/core/java/android/net/http/HttpResponseCache.java @@ -22,8 +22,10 @@ import java.io.File; import java.io.IOException; import java.net.CacheRequest; import java.net.CacheResponse; +import java.net.ExtendedResponseCache; import java.net.HttpURLConnection; import java.net.ResponseCache; +import java.net.ResponseSource; import java.net.URI; import java.net.URLConnection; import java.util.List; @@ -149,7 +151,8 @@ import org.apache.http.impl.client.DefaultHttpClient; * } catch (Exception httpResponseCacheNotAvailable) { * }}</pre> */ -public final class HttpResponseCache extends ResponseCache implements Closeable { +public final class HttpResponseCache extends ResponseCache + implements Closeable, ExtendedResponseCache { private final libcore.net.http.HttpResponseCache delegate; @@ -260,6 +263,21 @@ public final class HttpResponseCache extends ResponseCache implements Closeable return delegate.getRequestCount(); } + /** @hide */ + @Override public void trackResponse(ResponseSource source) { + delegate.trackResponse(source); + } + + /** @hide */ + @Override public void trackConditionalCacheHit() { + delegate.trackConditionalCacheHit(); + } + + /** @hide */ + @Override public void update(CacheResponse conditionalCacheHit, HttpURLConnection connection) { + delegate.update(conditionalCacheHit, connection); + } + /** * Uninstalls the cache and releases any active resources. Stored contents * will remain on the filesystem. diff --git a/core/java/android/os/CommonClock.java b/core/java/android/os/CommonClock.java new file mode 100644 index 000000000000..3a1da9761b6b --- /dev/null +++ b/core/java/android/os/CommonClock.java @@ -0,0 +1,414 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.os; + +import java.net.InetAddress; +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetSocketAddress; +import java.util.NoSuchElementException; +import static libcore.io.OsConstants.*; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.Binder; +import android.os.CommonTimeUtils; +import android.os.IBinder; +import android.os.Parcel; +import android.os.RemoteException; +import android.os.ServiceManager; + +/** + * Used for accessing the android common time service's common clock and receiving notifications + * about common time synchronization status changes. + * @hide + */ +public class CommonClock { + /** + * Sentinel value returned by {@link #getTime()} and {@link #getEstimatedError()} when the + * common time service is not able to determine the current common time due to a lack of + * synchronization. + */ + public static final long TIME_NOT_SYNCED = -1; + + /** + * Sentinel value returned by {@link #getTimelineId()} when the common time service is not + * currently synced to any timeline. + */ + public static final long INVALID_TIMELINE_ID = 0; + + /** + * Sentinel value returned by {@link #getEstimatedError()} when the common time service is not + * currently synced to any timeline. + */ + public static final int ERROR_ESTIMATE_UNKNOWN = 0x7FFFFFFF; + + /** + * Value used by {@link #getState()} to indicate that there was an internal error while + * attempting to determine the state of the common time service. + */ + public static final int STATE_INVALID = -1; + + /** + * Value used by {@link #getState()} to indicate that the common time service is in its initial + * state and attempting to find the current timeline master, if any. The service will + * transition to either {@link #STATE_CLIENT} if it finds an active master, or to + * {@link #STATE_MASTER} if no active master is found and this client becomes the master of a + * new timeline. + */ + public static final int STATE_INITIAL = 0; + + /** + * Value used by {@link #getState()} to indicate that the common time service is in its client + * state and is synchronizing its time to a different timeline master on the network. + */ + public static final int STATE_CLIENT = 1; + + /** + * Value used by {@link #getState()} to indicate that the common time service is in its master + * state and is serving as the timeline master for other common time service clients on the + * network. + */ + public static final int STATE_MASTER = 2; + + /** + * Value used by {@link #getState()} to indicate that the common time service is in its Ronin + * state. Common time service instances in the client state enter the Ronin state after their + * timeline master becomes unreachable on the network. Common time services who enter the Ronin + * state will begin a new master election for the timeline they were recently clients of. As + * clients detect they are not the winner and drop out of the election, they will transition to + * the {@link #STATE_WAIT_FOR_ELECTION} state. When there is only one client remaining in the + * election, it will assume ownership of the timeline and transition to the + * {@link #STATE_MASTER} state. During the election, all clients will allow their timeline to + * drift without applying correction. + */ + public static final int STATE_RONIN = 3; + + /** + * Value used by {@link #getState()} to indicate that the common time service is waiting for a + * master election to conclude and for the new master to announce itself before transitioning to + * the {@link #STATE_CLIENT} state. If no new master announces itself within the timeout + * threshold, the time service will transition back to the {@link #STATE_RONIN} state in order + * to restart the election. + */ + public static final int STATE_WAIT_FOR_ELECTION = 4; + + /** + * Name of the underlying native binder service + */ + public static final String SERVICE_NAME = "common_time.clock"; + + /** + * Class constructor. + * @throws android.os.RemoteException + */ + public CommonClock() + throws RemoteException { + mRemote = ServiceManager.getService(SERVICE_NAME); + if (null == mRemote) + throw new RemoteException(); + + mInterfaceDesc = mRemote.getInterfaceDescriptor(); + mUtils = new CommonTimeUtils(mRemote, mInterfaceDesc); + mRemote.linkToDeath(mDeathHandler, 0); + registerTimelineChangeListener(); + } + + /** + * Handy class factory method. + */ + static public CommonClock create() { + CommonClock retVal; + + try { + retVal = new CommonClock(); + } + catch (RemoteException e) { + retVal = null; + } + + return retVal; + } + + /** + * Release all native resources held by this {@link android.os.CommonClock} instance. Once + * resources have been released, the {@link android.os.CommonClock} instance is disconnected from + * the native service and will throw a {@link android.os.RemoteException} if any of its + * methods are called. Clients should always call release on their client instances before + * releasing their last Java reference to the instance. Failure to do this will cause + * non-deterministic native resource reclamation and may cause the common time service to remain + * active on the network for longer than it should. + */ + public void release() { + unregisterTimelineChangeListener(); + if (null != mRemote) { + try { + mRemote.unlinkToDeath(mDeathHandler, 0); + } + catch (NoSuchElementException e) { } + mRemote = null; + } + mUtils = null; + } + + /** + * Gets the common clock's current time. + * + * @return a signed 64-bit value representing the current common time in microseconds, or the + * special value {@link #TIME_NOT_SYNCED} if the common time service is currently not + * synchronized. + * @throws android.os.RemoteException + */ + public long getTime() + throws RemoteException { + throwOnDeadServer(); + return mUtils.transactGetLong(METHOD_GET_COMMON_TIME, TIME_NOT_SYNCED); + } + + /** + * Gets the current estimation of common clock's synchronization accuracy from the common time + * service. + * + * @return a signed 32-bit value representing the common time service's estimation of + * synchronization accuracy in microseconds, or the special value + * {@link #ERROR_ESTIMATE_UNKNOWN} if the common time service is currently not synchronized. + * Negative values indicate that the local server estimates that the nominal common time is + * behind the local server's time (in other words, the local clock is running fast) Positive + * values indicate that the local server estimates that the nominal common time is ahead of the + * local server's time (in other words, the local clock is running slow) + * @throws android.os.RemoteException + */ + public int getEstimatedError() + throws RemoteException { + throwOnDeadServer(); + return mUtils.transactGetInt(METHOD_GET_ESTIMATED_ERROR, ERROR_ESTIMATE_UNKNOWN); + } + + /** + * Gets the ID of the timeline the common time service is currently synchronizing its clock to. + * + * @return a long representing the unique ID of the timeline the common time service is + * currently synchronizing with, or {@link #INVALID_TIMELINE_ID} if the common time service is + * currently not synchronized. + * @throws android.os.RemoteException + */ + public long getTimelineId() + throws RemoteException { + throwOnDeadServer(); + return mUtils.transactGetLong(METHOD_GET_TIMELINE_ID, INVALID_TIMELINE_ID); + } + + /** + * Gets the current state of this clock's common time service in the the master election + * algorithm. + * + * @return a integer indicating the current state of the this clock's common time service in the + * master election algorithm or {@link #STATE_INVALID} if there is an internal error. + * @throws android.os.RemoteException + */ + public int getState() + throws RemoteException { + throwOnDeadServer(); + return mUtils.transactGetInt(METHOD_GET_STATE, STATE_INVALID); + } + + /** + * Gets the IP address and UDP port of the current timeline master. + * + * @return an InetSocketAddress containing the IP address and UDP port of the current timeline + * master, or null if there is no current master. + * @throws android.os.RemoteException + */ + public InetSocketAddress getMasterAddr() + throws RemoteException { + throwOnDeadServer(); + return mUtils.transactGetSockaddr(METHOD_GET_MASTER_ADDRESS); + } + + /** + * The OnTimelineChangedListener interface defines a method called by the + * {@link android.os.CommonClock} instance to indicate that the time synchronization service has + * either synchronized with a new timeline, or is no longer a member of any timeline. The + * client application can implement this interface and register the listener with the + * {@link #setTimelineChangedListener(OnTimelineChangedListener)} method. + */ + public interface OnTimelineChangedListener { + /** + * Method called when the time service's timeline has changed. + * + * @param newTimelineId a long which uniquely identifies the timeline the time + * synchronization service is now a member of, or {@link #INVALID_TIMELINE_ID} if the the + * service is not synchronized to any timeline. + */ + void onTimelineChanged(long newTimelineId); + } + + /** + * Registers an OnTimelineChangedListener interface. + * <p>Call this method with a null listener to stop receiving server death notifications. + */ + public void setTimelineChangedListener(OnTimelineChangedListener listener) { + synchronized (mListenerLock) { + mTimelineChangedListener = listener; + } + } + + /** + * The OnServerDiedListener interface defines a method called by the + * {@link android.os.CommonClock} instance to indicate that the connection to the native media + * server has been broken and that the {@link android.os.CommonClock} instance will need to be + * released and re-created. The client application can implement this interface and register + * the listener with the {@link #setServerDiedListener(OnServerDiedListener)} method. + */ + public interface OnServerDiedListener { + /** + * Method called when the native media server has died. <p>If the native common time + * service encounters a fatal error and needs to restart, the binder connection from the + * {@link android.os.CommonClock} instance to the common time service will be broken. To + * restore functionality, clients should {@link #release()} their old visualizer and create + * a new instance. + */ + void onServerDied(); + } + + /** + * Registers an OnServerDiedListener interface. + * <p>Call this method with a null listener to stop receiving server death notifications. + */ + public void setServerDiedListener(OnServerDiedListener listener) { + synchronized (mListenerLock) { + mServerDiedListener = listener; + } + } + + protected void finalize() throws Throwable { release(); } + + private void throwOnDeadServer() throws RemoteException { + if ((null == mRemote) || (null == mUtils)) + throw new RemoteException(); + } + + private final Object mListenerLock = new Object(); + private OnTimelineChangedListener mTimelineChangedListener = null; + private OnServerDiedListener mServerDiedListener = null; + + private IBinder mRemote = null; + private String mInterfaceDesc = ""; + private CommonTimeUtils mUtils; + + private IBinder.DeathRecipient mDeathHandler = new IBinder.DeathRecipient() { + public void binderDied() { + synchronized (mListenerLock) { + if (null != mServerDiedListener) + mServerDiedListener.onServerDied(); + } + } + }; + + private class TimelineChangedListener extends Binder { + @Override + protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) + throws RemoteException { + switch (code) { + case METHOD_CBK_ON_TIMELINE_CHANGED: + data.enforceInterface(DESCRIPTOR); + long timelineId = data.readLong(); + synchronized (mListenerLock) { + if (null != mTimelineChangedListener) + mTimelineChangedListener.onTimelineChanged(timelineId); + } + return true; + } + + return super.onTransact(code, data, reply, flags); + } + + private static final String DESCRIPTOR = "android.os.ICommonClockListener"; + }; + + private TimelineChangedListener mCallbackTgt = null; + + private void registerTimelineChangeListener() throws RemoteException { + if (null != mCallbackTgt) + return; + + boolean success = false; + android.os.Parcel data = android.os.Parcel.obtain(); + android.os.Parcel reply = android.os.Parcel.obtain(); + mCallbackTgt = new TimelineChangedListener(); + + try { + data.writeInterfaceToken(mInterfaceDesc); + data.writeStrongBinder(mCallbackTgt); + mRemote.transact(METHOD_REGISTER_LISTENER, data, reply, 0); + success = (0 == reply.readInt()); + } + catch (RemoteException e) { + success = false; + } + finally { + reply.recycle(); + data.recycle(); + } + + // Did we catch a remote exception or fail to register our callback target? If so, our + // object must already be dead (or be as good as dead). Clear out all of our state so that + // our other methods will properly indicate a dead object. + if (!success) { + mCallbackTgt = null; + mRemote = null; + mUtils = null; + } + } + + private void unregisterTimelineChangeListener() { + if (null == mCallbackTgt) + return; + + android.os.Parcel data = android.os.Parcel.obtain(); + android.os.Parcel reply = android.os.Parcel.obtain(); + + try { + data.writeInterfaceToken(mInterfaceDesc); + data.writeStrongBinder(mCallbackTgt); + mRemote.transact(METHOD_UNREGISTER_LISTENER, data, reply, 0); + } + catch (RemoteException e) { } + finally { + reply.recycle(); + data.recycle(); + mCallbackTgt = null; + } + } + + private static final int METHOD_IS_COMMON_TIME_VALID = IBinder.FIRST_CALL_TRANSACTION; + private static final int METHOD_COMMON_TIME_TO_LOCAL_TIME = METHOD_IS_COMMON_TIME_VALID + 1; + private static final int METHOD_LOCAL_TIME_TO_COMMON_TIME = METHOD_COMMON_TIME_TO_LOCAL_TIME + 1; + private static final int METHOD_GET_COMMON_TIME = METHOD_LOCAL_TIME_TO_COMMON_TIME + 1; + private static final int METHOD_GET_COMMON_FREQ = METHOD_GET_COMMON_TIME + 1; + private static final int METHOD_GET_LOCAL_TIME = METHOD_GET_COMMON_FREQ + 1; + private static final int METHOD_GET_LOCAL_FREQ = METHOD_GET_LOCAL_TIME + 1; + private static final int METHOD_GET_ESTIMATED_ERROR = METHOD_GET_LOCAL_FREQ + 1; + private static final int METHOD_GET_TIMELINE_ID = METHOD_GET_ESTIMATED_ERROR + 1; + private static final int METHOD_GET_STATE = METHOD_GET_TIMELINE_ID + 1; + private static final int METHOD_GET_MASTER_ADDRESS = METHOD_GET_STATE + 1; + private static final int METHOD_REGISTER_LISTENER = METHOD_GET_MASTER_ADDRESS + 1; + private static final int METHOD_UNREGISTER_LISTENER = METHOD_REGISTER_LISTENER + 1; + + private static final int METHOD_CBK_ON_TIMELINE_CHANGED = IBinder.FIRST_CALL_TRANSACTION; +} diff --git a/core/java/android/os/CommonTimeConfig.java b/core/java/android/os/CommonTimeConfig.java new file mode 100644 index 000000000000..3355ee33d486 --- /dev/null +++ b/core/java/android/os/CommonTimeConfig.java @@ -0,0 +1,448 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.os; + +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.util.NoSuchElementException; + +import android.os.CommonTimeUtils; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.ServiceManager; + +/** + * Used for configuring and controlling the status of the android common time service. + * @hide + */ +public class CommonTimeConfig { + /** + * Successful operation. + */ + public static final int SUCCESS = 0; + /** + * Unspecified error. + */ + public static final int ERROR = -1; + /** + * Operation failed due to bad parameter value. + */ + public static final int ERROR_BAD_VALUE = -4; + /** + * Operation failed due to dead remote object. + */ + public static final int ERROR_DEAD_OBJECT = -7; + + /** + * Sentinel value returned by {@link #getMasterElectionGroupId()} when an error occurs trying to + * fetch the master election group. + */ + public static final long INVALID_GROUP_ID = -1; + + /** + * Name of the underlying native binder service + */ + public static final String SERVICE_NAME = "common_time.config"; + + /** + * Class constructor. + * @throws android.os.RemoteException + */ + public CommonTimeConfig() + throws RemoteException { + mRemote = ServiceManager.getService(SERVICE_NAME); + if (null == mRemote) + throw new RemoteException(); + + mInterfaceDesc = mRemote.getInterfaceDescriptor(); + mUtils = new CommonTimeUtils(mRemote, mInterfaceDesc); + mRemote.linkToDeath(mDeathHandler, 0); + } + + /** + * Handy class factory method. + */ + static public CommonTimeConfig create() { + CommonTimeConfig retVal; + + try { + retVal = new CommonTimeConfig(); + } + catch (RemoteException e) { + retVal = null; + } + + return retVal; + } + + /** + * Release all native resources held by this {@link android.os.CommonTimeConfig} instance. Once + * resources have been released, the {@link android.os.CommonTimeConfig} instance is + * disconnected from the native service and will throw a {@link android.os.RemoteException} if + * any of its methods are called. Clients should always call release on their client instances + * before releasing their last Java reference to the instance. Failure to do this will cause + * non-deterministic native resource reclamation and may cause the common time service to remain + * active on the network for longer than it should. + */ + public void release() { + if (null != mRemote) { + try { + mRemote.unlinkToDeath(mDeathHandler, 0); + } + catch (NoSuchElementException e) { } + mRemote = null; + } + mUtils = null; + } + + /** + * Gets the current priority of the common time service used in the master election protocol. + * + * @return an 8 bit value indicating the priority of this common time service relative to other + * common time services operating in the same domain. + * @throws android.os.RemoteException + */ + public byte getMasterElectionPriority() + throws RemoteException { + throwOnDeadServer(); + return (byte)mUtils.transactGetInt(METHOD_GET_MASTER_ELECTION_PRIORITY, -1); + } + + /** + * Sets the current priority of the common time service used in the master election protocol. + * + * @param priority priority of the common time service used in the master election protocol. + * Lower numbers are lower priority. + * @return {@link #SUCCESS} in case of success, + * {@link #ERROR} or {@link #ERROR_DEAD_OBJECT} in case of failure. + */ + public int setMasterElectionPriority(byte priority) { + if (checkDeadServer()) + return ERROR_DEAD_OBJECT; + return mUtils.transactSetInt(METHOD_SET_MASTER_ELECTION_PRIORITY, priority); + } + + /** + * Gets the IP endpoint used by the time service to participate in the master election protocol. + * + * @return an InetSocketAddress containing the IP address and UDP port being used by the + * system's common time service to participate in the master election protocol. + * @throws android.os.RemoteException + */ + public InetSocketAddress getMasterElectionEndpoint() + throws RemoteException { + throwOnDeadServer(); + return mUtils.transactGetSockaddr(METHOD_GET_MASTER_ELECTION_ENDPOINT); + } + + /** + * Sets the IP endpoint used by the common time service to participate in the master election + * protocol. + * + * @param ep The IP address and UDP port to be used by the common time service to participate in + * the master election protocol. The supplied IP address must be either the broadcast or + * multicast address, unicast addresses are considered to be illegal values. + * @return {@link #SUCCESS} in case of success, + * {@link #ERROR}, {@link #ERROR_BAD_VALUE} or {@link #ERROR_DEAD_OBJECT} in case of failure. + */ + public int setMasterElectionEndpoint(InetSocketAddress ep) { + if (checkDeadServer()) + return ERROR_DEAD_OBJECT; + return mUtils.transactSetSockaddr(METHOD_SET_MASTER_ELECTION_ENDPOINT, ep); + } + + /** + * Gets the current group ID used by the common time service in the master election protocol. + * + * @return The 64-bit group ID of the common time service. + * @throws android.os.RemoteException + */ + public long getMasterElectionGroupId() + throws RemoteException { + throwOnDeadServer(); + return mUtils.transactGetLong(METHOD_GET_MASTER_ELECTION_GROUP_ID, INVALID_GROUP_ID); + } + + /** + * Sets the current group ID used by the common time service in the master election protocol. + * + * @param id The 64-bit group ID of the common time service. + * @return {@link #SUCCESS} in case of success, + * {@link #ERROR}, {@link #ERROR_BAD_VALUE} or {@link #ERROR_DEAD_OBJECT} in case of failure. + */ + public int setMasterElectionGroupId(long id) { + if (checkDeadServer()) + return ERROR_DEAD_OBJECT; + return mUtils.transactSetLong(METHOD_SET_MASTER_ELECTION_GROUP_ID, id); + } + + /** + * Gets the name of the network interface which the common time service attempts to bind to. + * + * @return a string with the network interface name which the common time service is bound to, + * or null if the service is currently unbound. Examples of interface names are things like + * "eth0", or "wlan0". + * @throws android.os.RemoteException + */ + public String getInterfaceBinding() + throws RemoteException { + throwOnDeadServer(); + + String ifaceName = mUtils.transactGetString(METHOD_GET_INTERFACE_BINDING, null); + + if ((null != ifaceName) && (0 == ifaceName.length())) + return null; + + return ifaceName; + } + + /** + * Sets the name of the network interface which the common time service should attempt to bind + * to. + * + * @param ifaceName The name of the network interface ("eth0", "wlan0", etc...) wich the common + * time service should attempt to bind to, or null to force the common time service to unbind + * from the network and run in networkless mode. + * @return {@link #SUCCESS} in case of success, + * {@link #ERROR}, {@link #ERROR_BAD_VALUE} or {@link #ERROR_DEAD_OBJECT} in case of failure. + */ + public int setNetworkBinding(String ifaceName) { + if (checkDeadServer()) + return ERROR_DEAD_OBJECT; + + return mUtils.transactSetString(METHOD_SET_INTERFACE_BINDING, + (null == ifaceName) ? "" : ifaceName); + } + + /** + * Gets the amount of time the common time service will wait between master announcements when + * it is the timeline master. + * + * @return The time (in milliseconds) between master announcements. + * @throws android.os.RemoteException + */ + public int getMasterAnnounceInterval() + throws RemoteException { + throwOnDeadServer(); + return mUtils.transactGetInt(METHOD_GET_MASTER_ANNOUNCE_INTERVAL, -1); + } + + /** + * Sets the amount of time the common time service will wait between master announcements when + * it is the timeline master. + * + * @param interval The time (in milliseconds) between master announcements. + * @return {@link #SUCCESS} in case of success, + * {@link #ERROR}, {@link #ERROR_BAD_VALUE} or {@link #ERROR_DEAD_OBJECT} in case of failure. + */ + public int setMasterAnnounceInterval(int interval) { + if (checkDeadServer()) + return ERROR_DEAD_OBJECT; + return mUtils.transactSetInt(METHOD_SET_MASTER_ANNOUNCE_INTERVAL, interval); + } + + /** + * Gets the amount of time the common time service will wait between time synchronization + * requests when it is the client of another common time service on the network. + * + * @return The time (in milliseconds) between time sync requests. + * @throws android.os.RemoteException + */ + public int getClientSyncInterval() + throws RemoteException { + throwOnDeadServer(); + return mUtils.transactGetInt(METHOD_GET_CLIENT_SYNC_INTERVAL, -1); + } + + /** + * Sets the amount of time the common time service will wait between time synchronization + * requests when it is the client of another common time service on the network. + * + * @param interval The time (in milliseconds) between time sync requests. + * @return {@link #SUCCESS} in case of success, + * {@link #ERROR}, {@link #ERROR_BAD_VALUE} or {@link #ERROR_DEAD_OBJECT} in case of failure. + */ + public int setClientSyncInterval(int interval) { + if (checkDeadServer()) + return ERROR_DEAD_OBJECT; + return mUtils.transactSetInt(METHOD_SET_CLIENT_SYNC_INTERVAL, interval); + } + + /** + * Gets the panic threshold for the estimated error level of the common time service. When the + * common time service's estimated error rises above this level, the service will panic and + * reset, causing a discontinuity in the currently synchronized timeline. + * + * @return The threshold (in microseconds) past which the common time service will panic. + * @throws android.os.RemoteException + */ + public int getPanicThreshold() + throws RemoteException { + throwOnDeadServer(); + return mUtils.transactGetInt(METHOD_GET_PANIC_THRESHOLD, -1); + } + + /** + * Sets the panic threshold for the estimated error level of the common time service. When the + * common time service's estimated error rises above this level, the service will panic and + * reset, causing a discontinuity in the currently synchronized timeline. + * + * @param threshold The threshold (in microseconds) past which the common time service will + * panic. + * @return {@link #SUCCESS} in case of success, + * {@link #ERROR}, {@link #ERROR_BAD_VALUE} or {@link #ERROR_DEAD_OBJECT} in case of failure. + */ + public int setPanicThreshold(int threshold) { + if (checkDeadServer()) + return ERROR_DEAD_OBJECT; + return mUtils.transactSetInt(METHOD_SET_PANIC_THRESHOLD, threshold); + } + + /** + * Gets the current state of the common time service's auto disable flag. + * + * @return The current state of the common time service's auto disable flag. + * @throws android.os.RemoteException + */ + public boolean getAutoDisable() + throws RemoteException { + throwOnDeadServer(); + return (1 == mUtils.transactGetInt(METHOD_GET_AUTO_DISABLE, 1)); + } + + /** + * Sets the current state of the common time service's auto disable flag. When the time + * service's auto disable flag is set, it will automatically cease all network activity when + * it has no active local clients, resuming activity the next time the service has interested + * local clients. When the auto disabled flag is cleared, the common time service will continue + * to participate the time synchronization group even when it has no active local clients. + * + * @param autoDisable The desired state of the common time service's auto disable flag. + * @return {@link #SUCCESS} in case of success, + * {@link #ERROR} or {@link #ERROR_DEAD_OBJECT} in case of failure. + */ + public int setAutoDisable(boolean autoDisable) { + if (checkDeadServer()) + return ERROR_DEAD_OBJECT; + + return mUtils.transactSetInt(METHOD_SET_AUTO_DISABLE, autoDisable ? 1 : 0); + } + + /** + * At startup, the time service enters the initial state and remains there until it is given a + * network interface to bind to. Common time will be unavailable to clients of the common time + * service until the service joins a network (even an empty network). Devices may use the + * {@link #forceNetworklessMasterMode()} method to force a time service in the INITIAL state + * with no network configuration to assume MASTER status for a brand new timeline in order to + * allow clients of the common time service to operate, even though the device is isolated and + * not on any network. When a networkless master does join a network, it will defer to any + * masters already on the network, or continue to maintain the timeline it made up during its + * networkless state if no other masters are detected. Attempting to force a client into master + * mode while it is actively bound to a network will fail with the status code {@link #ERROR} + * + * @return {@link #SUCCESS} in case of success, + * {@link #ERROR} or {@link #ERROR_DEAD_OBJECT} in case of failure. + */ + public int forceNetworklessMasterMode() { + android.os.Parcel data = android.os.Parcel.obtain(); + android.os.Parcel reply = android.os.Parcel.obtain(); + + try { + data.writeInterfaceToken(mInterfaceDesc); + mRemote.transact(METHOD_FORCE_NETWORKLESS_MASTER_MODE, data, reply, 0); + + return reply.readInt(); + } + catch (RemoteException e) { + return ERROR_DEAD_OBJECT; + } + finally { + reply.recycle(); + data.recycle(); + } + } + + /** + * The OnServerDiedListener interface defines a method called by the + * {@link android.os.CommonTimeConfig} instance to indicate that the connection to the native + * media server has been broken and that the {@link android.os.CommonTimeConfig} instance will + * need to be released and re-created. The client application can implement this interface and + * register the listener with the {@link #setServerDiedListener(OnServerDiedListener)} method. + */ + public interface OnServerDiedListener { + /** + * Method called when the native common time service has died. <p>If the native common time + * service encounters a fatal error and needs to restart, the binder connection from the + * {@link android.os.CommonTimeConfig} instance to the common time service will be broken. + */ + void onServerDied(); + } + + /** + * Registers an OnServerDiedListener interface. + * <p>Call this method with a null listener to stop receiving server death notifications. + */ + public void setServerDiedListener(OnServerDiedListener listener) { + synchronized (mListenerLock) { + mServerDiedListener = listener; + } + } + + protected void finalize() throws Throwable { release(); } + + private boolean checkDeadServer() { + return ((null == mRemote) || (null == mUtils)); + } + + private void throwOnDeadServer() throws RemoteException { + if (checkDeadServer()) + throw new RemoteException(); + } + + private final Object mListenerLock = new Object(); + private OnServerDiedListener mServerDiedListener = null; + + private IBinder mRemote = null; + private String mInterfaceDesc = ""; + private CommonTimeUtils mUtils; + + private IBinder.DeathRecipient mDeathHandler = new IBinder.DeathRecipient() { + public void binderDied() { + synchronized (mListenerLock) { + if (null != mServerDiedListener) + mServerDiedListener.onServerDied(); + } + } + }; + + private static final int METHOD_GET_MASTER_ELECTION_PRIORITY = IBinder.FIRST_CALL_TRANSACTION; + private static final int METHOD_SET_MASTER_ELECTION_PRIORITY = METHOD_GET_MASTER_ELECTION_PRIORITY + 1; + private static final int METHOD_GET_MASTER_ELECTION_ENDPOINT = METHOD_SET_MASTER_ELECTION_PRIORITY + 1; + private static final int METHOD_SET_MASTER_ELECTION_ENDPOINT = METHOD_GET_MASTER_ELECTION_ENDPOINT + 1; + private static final int METHOD_GET_MASTER_ELECTION_GROUP_ID = METHOD_SET_MASTER_ELECTION_ENDPOINT + 1; + private static final int METHOD_SET_MASTER_ELECTION_GROUP_ID = METHOD_GET_MASTER_ELECTION_GROUP_ID + 1; + private static final int METHOD_GET_INTERFACE_BINDING = METHOD_SET_MASTER_ELECTION_GROUP_ID + 1; + private static final int METHOD_SET_INTERFACE_BINDING = METHOD_GET_INTERFACE_BINDING + 1; + private static final int METHOD_GET_MASTER_ANNOUNCE_INTERVAL = METHOD_SET_INTERFACE_BINDING + 1; + private static final int METHOD_SET_MASTER_ANNOUNCE_INTERVAL = METHOD_GET_MASTER_ANNOUNCE_INTERVAL + 1; + private static final int METHOD_GET_CLIENT_SYNC_INTERVAL = METHOD_SET_MASTER_ANNOUNCE_INTERVAL + 1; + private static final int METHOD_SET_CLIENT_SYNC_INTERVAL = METHOD_GET_CLIENT_SYNC_INTERVAL + 1; + private static final int METHOD_GET_PANIC_THRESHOLD = METHOD_SET_CLIENT_SYNC_INTERVAL + 1; + private static final int METHOD_SET_PANIC_THRESHOLD = METHOD_GET_PANIC_THRESHOLD + 1; + private static final int METHOD_GET_AUTO_DISABLE = METHOD_SET_PANIC_THRESHOLD + 1; + private static final int METHOD_SET_AUTO_DISABLE = METHOD_GET_AUTO_DISABLE + 1; + private static final int METHOD_FORCE_NETWORKLESS_MASTER_MODE = METHOD_SET_AUTO_DISABLE + 1; +} diff --git a/core/java/android/os/CommonTimeUtils.java b/core/java/android/os/CommonTimeUtils.java new file mode 100644 index 000000000000..9081ee411d61 --- /dev/null +++ b/core/java/android/os/CommonTimeUtils.java @@ -0,0 +1,291 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.os; + +import java.net.InetAddress; +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetSocketAddress; +import static libcore.io.OsConstants.*; + +class CommonTimeUtils { + /** + * Successful operation. + */ + public static final int SUCCESS = 0; + /** + * Unspecified error. + */ + public static final int ERROR = -1; + /** + * Operation failed due to bad parameter value. + */ + public static final int ERROR_BAD_VALUE = -4; + /** + * Operation failed due to dead remote object. + */ + public static final int ERROR_DEAD_OBJECT = -7; + + public CommonTimeUtils(IBinder remote, String interfaceDesc) { + mRemote = remote; + mInterfaceDesc = interfaceDesc; + } + + public int transactGetInt(int method_code, int error_ret_val) + throws RemoteException { + android.os.Parcel data = android.os.Parcel.obtain(); + android.os.Parcel reply = android.os.Parcel.obtain(); + int ret_val; + + try { + int res; + data.writeInterfaceToken(mInterfaceDesc); + mRemote.transact(method_code, data, reply, 0); + + res = reply.readInt(); + ret_val = (0 == res) ? reply.readInt() : error_ret_val; + } + finally { + reply.recycle(); + data.recycle(); + } + + return ret_val; + } + + public int transactSetInt(int method_code, int val) { + android.os.Parcel data = android.os.Parcel.obtain(); + android.os.Parcel reply = android.os.Parcel.obtain(); + + try { + data.writeInterfaceToken(mInterfaceDesc); + data.writeInt(val); + mRemote.transact(method_code, data, reply, 0); + + return reply.readInt(); + } + catch (RemoteException e) { + return ERROR_DEAD_OBJECT; + } + finally { + reply.recycle(); + data.recycle(); + } + } + + public long transactGetLong(int method_code, long error_ret_val) + throws RemoteException { + android.os.Parcel data = android.os.Parcel.obtain(); + android.os.Parcel reply = android.os.Parcel.obtain(); + long ret_val; + + try { + int res; + data.writeInterfaceToken(mInterfaceDesc); + mRemote.transact(method_code, data, reply, 0); + + res = reply.readInt(); + ret_val = (0 == res) ? reply.readLong() : error_ret_val; + } + finally { + reply.recycle(); + data.recycle(); + } + + return ret_val; + } + + public int transactSetLong(int method_code, long val) { + android.os.Parcel data = android.os.Parcel.obtain(); + android.os.Parcel reply = android.os.Parcel.obtain(); + + try { + data.writeInterfaceToken(mInterfaceDesc); + data.writeLong(val); + mRemote.transact(method_code, data, reply, 0); + + return reply.readInt(); + } + catch (RemoteException e) { + return ERROR_DEAD_OBJECT; + } + finally { + reply.recycle(); + data.recycle(); + } + } + + public String transactGetString(int method_code, String error_ret_val) + throws RemoteException { + android.os.Parcel data = android.os.Parcel.obtain(); + android.os.Parcel reply = android.os.Parcel.obtain(); + String ret_val; + + try { + int res; + data.writeInterfaceToken(mInterfaceDesc); + mRemote.transact(method_code, data, reply, 0); + + res = reply.readInt(); + ret_val = (0 == res) ? reply.readString() : error_ret_val; + } + finally { + reply.recycle(); + data.recycle(); + } + + return ret_val; + } + + public int transactSetString(int method_code, String val) { + android.os.Parcel data = android.os.Parcel.obtain(); + android.os.Parcel reply = android.os.Parcel.obtain(); + + try { + data.writeInterfaceToken(mInterfaceDesc); + data.writeString(val); + mRemote.transact(method_code, data, reply, 0); + + return reply.readInt(); + } + catch (RemoteException e) { + return ERROR_DEAD_OBJECT; + } + finally { + reply.recycle(); + data.recycle(); + } + } + + public InetSocketAddress transactGetSockaddr(int method_code) + throws RemoteException { + android.os.Parcel data = android.os.Parcel.obtain(); + android.os.Parcel reply = android.os.Parcel.obtain(); + InetSocketAddress ret_val = null; + + try { + int res; + data.writeInterfaceToken(mInterfaceDesc); + mRemote.transact(method_code, data, reply, 0); + + res = reply.readInt(); + if (0 == res) { + int type; + int port = 0; + String addrStr = null; + + type = reply.readInt(); + + if (AF_INET == type) { + int addr = reply.readInt(); + port = reply.readInt(); + addrStr = String.format("%d.%d.%d.%d", (addr >> 24) & 0xFF, + (addr >> 16) & 0xFF, + (addr >> 8) & 0xFF, + addr & 0xFF); + } else if (AF_INET6 == type) { + int addr1 = reply.readInt(); + int addr2 = reply.readInt(); + int addr3 = reply.readInt(); + int addr4 = reply.readInt(); + + port = reply.readInt(); + + int flowinfo = reply.readInt(); + int scope_id = reply.readInt(); + + addrStr = String.format("[%04X:%04X:%04X:%04X:%04X:%04X:%04X:%04X]", + (addr1 >> 16) & 0xFFFF, addr1 & 0xFFFF, + (addr2 >> 16) & 0xFFFF, addr2 & 0xFFFF, + (addr3 >> 16) & 0xFFFF, addr3 & 0xFFFF, + (addr4 >> 16) & 0xFFFF, addr4 & 0xFFFF); + } + + if (null != addrStr) { + ret_val = new InetSocketAddress(addrStr, port); + } + } + } + finally { + reply.recycle(); + data.recycle(); + } + + return ret_val; + } + + public int transactSetSockaddr(int method_code, InetSocketAddress addr) { + android.os.Parcel data = android.os.Parcel.obtain(); + android.os.Parcel reply = android.os.Parcel.obtain(); + int ret_val = ERROR; + + try { + data.writeInterfaceToken(mInterfaceDesc); + + if (null == addr) { + data.writeInt(0); + } else { + data.writeInt(1); + final InetAddress a = addr.getAddress(); + final byte[] b = a.getAddress(); + final int p = addr.getPort(); + + if (a instanceof Inet4Address) { + int v4addr = (((int)b[0] & 0xFF) << 24) | + (((int)b[1] & 0xFF) << 16) | + (((int)b[2] & 0xFF) << 8) | + ((int)b[3] & 0xFF); + + data.writeInt(AF_INET); + data.writeInt(v4addr); + data.writeInt(p); + } else + if (a instanceof Inet6Address) { + int i; + Inet6Address v6 = (Inet6Address)a; + data.writeInt(AF_INET6); + for (i = 0; i < 4; ++i) { + int aword = (((int)b[(i*4) + 0] & 0xFF) << 24) | + (((int)b[(i*4) + 1] & 0xFF) << 16) | + (((int)b[(i*4) + 2] & 0xFF) << 8) | + ((int)b[(i*4) + 3] & 0xFF); + data.writeInt(aword); + } + data.writeInt(p); + data.writeInt(0); // flow info + data.writeInt(v6.getScopeId()); + } else { + return ERROR_BAD_VALUE; + } + } + + mRemote.transact(method_code, data, reply, 0); + ret_val = reply.readInt(); + } + catch (RemoteException e) { + ret_val = ERROR_DEAD_OBJECT; + } + finally { + reply.recycle(); + data.recycle(); + } + + return ret_val; + } + + private IBinder mRemote; + private String mInterfaceDesc; +}; diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java index af2fa9bf1ffa..610b3550402a 100644 --- a/core/java/android/os/Handler.java +++ b/core/java/android/os/Handler.java @@ -513,7 +513,7 @@ public class Handler { * message queue. */ public final void removeMessages(int what) { - mQueue.removeMessages(this, what, null, true); + mQueue.removeMessages(this, what, null); } /** @@ -522,7 +522,7 @@ public class Handler { * all messages will be removed. */ public final void removeMessages(int what, Object object) { - mQueue.removeMessages(this, what, object, true); + mQueue.removeMessages(this, what, object); } /** @@ -539,7 +539,7 @@ public class Handler { * the message queue. */ public final boolean hasMessages(int what) { - return mQueue.removeMessages(this, what, null, false); + return mQueue.hasMessages(this, what, null); } /** @@ -547,7 +547,7 @@ public class Handler { * whose obj is 'object' in the message queue. */ public final boolean hasMessages(int what, Object object) { - return mQueue.removeMessages(this, what, object, false); + return mQueue.hasMessages(this, what, object); } // if we can get rid of this method, the handler need not remember its loop diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java index 5607f7fc7917..a06aadb6d131 100644 --- a/core/java/android/os/Looper.java +++ b/core/java/android/os/Looper.java @@ -55,13 +55,13 @@ public class Looper { // sThreadLocal.get() will return null unless you've called prepare(). static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); + private static Looper sMainLooper; // guarded by Looper.class final MessageQueue mQueue; final Thread mThread; volatile boolean mRun; - private Printer mLogging = null; - private static Looper mMainLooper = null; // guarded by Looper.class + private Printer mLogging; /** Initialize the current thread as a looper. * This gives you a chance to create handlers that then reference @@ -70,10 +70,14 @@ public class Looper { * {@link #quit()}. */ public static void prepare() { + prepare(true); + } + + private static void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } - sThreadLocal.set(new Looper()); + sThreadLocal.set(new Looper(quitAllowed)); } /** @@ -83,19 +87,21 @@ public class Looper { * to call this function yourself. See also: {@link #prepare()} */ public static void prepareMainLooper() { - prepare(); - setMainLooper(myLooper()); - myLooper().mQueue.mQuitAllowed = false; - } - - private synchronized static void setMainLooper(Looper looper) { - mMainLooper = looper; + prepare(false); + synchronized (Looper.class) { + if (sMainLooper != null) { + throw new IllegalStateException("The main Looper has already been prepared."); + } + sMainLooper = myLooper(); + } } /** Returns the application's main looper, which lives in the main thread of the application. */ - public synchronized static Looper getMainLooper() { - return mMainLooper; + public static Looper getMainLooper() { + synchronized (Looper.class) { + return sMainLooper; + } } /** @@ -103,63 +109,61 @@ public class Looper { * {@link #quit()} to end the loop. */ public static void loop() { - Looper me = myLooper(); + final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } - MessageQueue queue = me.mQueue; - + final MessageQueue queue = me.mQueue; + // Make sure the identity of this thread is that of the local process, // and keep track of what that identity token actually is. Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity(); - - while (true) { + + for (;;) { Message msg = queue.next(); // might block - if (msg != null) { - if (msg.target == null) { - // No target is a magic identifier for the quit message. - return; - } + if (msg == null) { + // No message indicates that the message queue is quitting. + return; + } - long wallStart = 0; - long threadStart = 0; + long wallStart = 0; + long threadStart = 0; - // This must be in a local variable, in case a UI event sets the logger - Printer logging = me.mLogging; - if (logging != null) { - logging.println(">>>>> Dispatching to " + msg.target + " " + - msg.callback + ": " + msg.what); - wallStart = SystemClock.currentTimeMicro(); - threadStart = SystemClock.currentThreadTimeMicro(); - } + // This must be in a local variable, in case a UI event sets the logger + Printer logging = me.mLogging; + if (logging != null) { + logging.println(">>>>> Dispatching to " + msg.target + " " + + msg.callback + ": " + msg.what); + wallStart = SystemClock.currentTimeMicro(); + threadStart = SystemClock.currentThreadTimeMicro(); + } - msg.target.dispatchMessage(msg); + msg.target.dispatchMessage(msg); - if (logging != null) { - long wallTime = SystemClock.currentTimeMicro() - wallStart; - long threadTime = SystemClock.currentThreadTimeMicro() - threadStart; + if (logging != null) { + long wallTime = SystemClock.currentTimeMicro() - wallStart; + long threadTime = SystemClock.currentThreadTimeMicro() - threadStart; - logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); - if (logging instanceof Profiler) { - ((Profiler) logging).profile(msg, wallStart, wallTime, - threadStart, threadTime); - } + logging.println("<<<<< Finished to " + msg.target + " " + msg.callback); + if (logging instanceof Profiler) { + ((Profiler) logging).profile(msg, wallStart, wallTime, + threadStart, threadTime); } + } - // Make sure that during the course of dispatching the - // identity of the thread wasn't corrupted. - final long newIdent = Binder.clearCallingIdentity(); - if (ident != newIdent) { - Log.wtf(TAG, "Thread identity changed from 0x" - + Long.toHexString(ident) + " to 0x" - + Long.toHexString(newIdent) + " while dispatching to " - + msg.target.getClass().getName() + " " - + msg.callback + " what=" + msg.what); - } - - msg.recycle(); + // Make sure that during the course of dispatching the + // identity of the thread wasn't corrupted. + final long newIdent = Binder.clearCallingIdentity(); + if (ident != newIdent) { + Log.wtf(TAG, "Thread identity changed from 0x" + + Long.toHexString(ident) + " to 0x" + + Long.toHexString(newIdent) + " while dispatching to " + + msg.target.getClass().getName() + " " + + msg.callback + " what=" + msg.what); } + + msg.recycle(); } } @@ -193,18 +197,61 @@ public class Looper { return myLooper().mQueue; } - private Looper() { - mQueue = new MessageQueue(); + private Looper(boolean quitAllowed) { + mQueue = new MessageQueue(quitAllowed); mRun = true; mThread = Thread.currentThread(); } + /** + * Quits the looper. + * + * Causes the {@link #loop} method to terminate as soon as possible. + */ public void quit() { - Message msg = Message.obtain(); - // NOTE: By enqueueing directly into the message queue, the - // message is left with a null target. This is how we know it is - // a quit message. - mQueue.enqueueMessage(msg, 0); + mQueue.quit(); + } + + /** + * Posts a synchronization barrier to the Looper's message queue. + * + * Message processing occurs as usual until the message queue encounters the + * synchronization barrier that has been posted. When the barrier is encountered, + * later synchronous messages in the queue are stalled (prevented from being executed) + * until the barrier is released by calling {@link #removeSyncBarrier} and specifying + * the token that identifies the synchronization barrier. + * + * This method is used to immediately postpone execution of all subsequently posted + * synchronous messages until a condition is met that releases the barrier. + * Asynchronous messages (see {@link Message#isAsynchronous} are exempt from the barrier + * and continue to be processed as usual. + * + * This call must be always matched by a call to {@link #removeSyncBarrier} with + * the same token to ensure that the message queue resumes normal operation. + * Otherwise the application will probably hang! + * + * @return A token that uniquely identifies the barrier. This token must be + * passed to {@link #removeSyncBarrier} to release the barrier. + * + * @hide + */ + public final int postSyncBarrier() { + return mQueue.enqueueSyncBarrier(SystemClock.uptimeMillis()); + } + + + /** + * Removes a synchronization barrier. + * + * @param token The synchronization barrier token that was returned by + * {@link #postSyncBarrier}. + * + * @throws IllegalStateException if the barrier was not found. + * + * @hide + */ + public final void removeSyncBarrier(int token) { + mQueue.removeSyncBarrier(token); } /** diff --git a/core/java/android/os/Message.java b/core/java/android/os/Message.java index 844ed6ac5d8b..b816b110ac44 100644 --- a/core/java/android/os/Message.java +++ b/core/java/android/os/Message.java @@ -75,13 +75,13 @@ public final class Message implements Parcelable { public Messenger replyTo; /** If set message is in use */ - /*package*/ static final int FLAG_IN_USE = 1; + /*package*/ static final int FLAG_IN_USE = 1 << 0; - /** Flags reserved for future use (All are reserved for now) */ - /*package*/ static final int FLAGS_RESERVED = ~FLAG_IN_USE; + /** If set message is asynchronous */ + /*package*/ static final int FLAG_ASYNCHRONOUS = 1 << 1; /** Flags to clear in the copyFrom method */ - /*package*/ static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAGS_RESERVED | FLAG_IN_USE; + /*package*/ static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE; /*package*/ int flags; @@ -363,6 +363,48 @@ public final class Message implements Parcelable { target.sendMessage(this); } + /** + * Returns true if the message is asynchronous. + * + * Asynchronous messages represent interrupts or events that do not require global ordering + * with represent to synchronous messages. Asynchronous messages are not subject to + * the synchronization barriers introduced by {@link MessageQueue#acquireSyncBarrier()}. + * + * @return True if the message is asynchronous. + * + * @see #setAsynchronous(boolean) + * @see MessageQueue#acquireSyncBarrier() + * @see MessageQueue#releaseSyncBarrier() + * + * @hide + */ + public boolean isAsynchronous() { + return (flags & FLAG_ASYNCHRONOUS) != 0; + } + + /** + * Sets whether the message is asynchronous. + * + * Asynchronous messages represent interrupts or events that do not require global ordering + * with represent to synchronous messages. Asynchronous messages are not subject to + * the synchronization barriers introduced by {@link MessageQueue#acquireSyncBarrier()}. + * + * @param async True if the message is asynchronous. + * + * @see #isAsynchronous() + * @see MessageQueue#acquireSyncBarrier() + * @see MessageQueue#releaseSyncBarrier() + * + * @hide + */ + public void setAsynchronous(boolean async) { + if (async) { + flags |= FLAG_ASYNCHRONOUS; + } else { + flags &= ~FLAG_ASYNCHRONOUS; + } + } + /*package*/ void clearForRecycle() { flags = 0; what = 0; diff --git a/core/java/android/os/MessageQueue.java b/core/java/android/os/MessageQueue.java index a658fc45dae4..64027ef7fc81 100644 --- a/core/java/android/os/MessageQueue.java +++ b/core/java/android/os/MessageQueue.java @@ -30,18 +30,24 @@ import java.util.ArrayList; * {@link Looper#myQueue() Looper.myQueue()}. */ public class MessageQueue { + // True if the message queue can be quit. + private final boolean mQuitAllowed; + + @SuppressWarnings("unused") + private int mPtr; // used by native code + Message mMessages; private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>(); private IdleHandler[] mPendingIdleHandlers; private boolean mQuiting; - boolean mQuitAllowed = true; // Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout. private boolean mBlocked; - @SuppressWarnings("unused") - private int mPtr; // used by native code - + // The next barrier token. + // Barriers are indicated by messages with a null target whose arg1 field carries the token. + private int mNextBarrierToken; + private native void nativeInit(); private native void nativeDestroy(); private native void nativePollOnce(int ptr, int timeoutMillis); @@ -93,11 +99,12 @@ public class MessageQueue { mIdleHandlers.remove(handler); } } - - MessageQueue() { + + MessageQueue(boolean quitAllowed) { + mQuitAllowed = quitAllowed; nativeInit(); } - + @Override protected void finalize() throws Throwable { try { @@ -118,30 +125,51 @@ public class MessageQueue { nativePollOnce(mPtr, nextPollTimeoutMillis); synchronized (this) { + if (mQuiting) { + return null; + } + // Try to retrieve the next message. Return if found. final long now = SystemClock.uptimeMillis(); - final Message msg = mMessages; + Message prevMsg = null; + Message msg = mMessages; + if (msg != null && msg.target == null) { + // Stalled by a barrier. Find the next asynchronous message in the queue. + do { + prevMsg = msg; + msg = msg.next; + } while (msg != null && !msg.isAsynchronous()); + } if (msg != null) { - final long when = msg.when; - if (now >= when) { + if (now < msg.when) { + // Next message is not ready. Set a timeout to wake up when it is ready. + nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE); + } else { + // Got a message. mBlocked = false; - mMessages = msg.next; + if (prevMsg != null) { + prevMsg.next = msg.next; + } else { + mMessages = msg.next; + } msg.next = null; if (false) Log.v("MessageQueue", "Returning message: " + msg); msg.markInUse(); return msg; - } else { - nextPollTimeoutMillis = (int) Math.min(when - now, Integer.MAX_VALUE); } } else { + // No more messages. nextPollTimeoutMillis = -1; } - // If first time, then get the number of idlers to run. - if (pendingIdleHandlerCount < 0) { + // If first time idle, then get the number of idlers to run. + // Idle handles only run if the queue is empty or if the first message + // in the queue (possibly a barrier) is due to be handled in the future. + if (pendingIdleHandlerCount < 0 + && (mMessages == null || now < mMessages.when)) { pendingIdleHandlerCount = mIdleHandlers.size(); } - if (pendingIdleHandlerCount == 0) { + if (pendingIdleHandlerCount <= 0) { // No idle handlers to run. Loop and wait some more. mBlocked = true; continue; @@ -182,41 +210,118 @@ public class MessageQueue { } } + final void quit() { + if (!mQuitAllowed) { + throw new RuntimeException("Main thread not allowed to quit."); + } + + synchronized (this) { + if (mQuiting) { + return; + } + mQuiting = true; + } + nativeWake(mPtr); + } + + final int enqueueSyncBarrier(long when) { + // Enqueue a new sync barrier token. + // We don't need to wake the queue because the purpose of a barrier is to stall it. + synchronized (this) { + final int token = mNextBarrierToken++; + final Message msg = Message.obtain(); + msg.arg1 = token; + + Message prev = null; + Message p = mMessages; + if (when != 0) { + while (p != null && p.when <= when) { + prev = p; + p = p.next; + } + } + if (prev != null) { // invariant: p == prev.next + msg.next = p; + prev.next = msg; + } else { + msg.next = p; + mMessages = msg; + } + return token; + } + } + + final void removeSyncBarrier(int token) { + // Remove a sync barrier token from the queue. + // If the queue is no longer stalled by a barrier then wake it. + final boolean needWake; + synchronized (this) { + Message prev = null; + Message p = mMessages; + while (p != null && (p.target != null || p.arg1 != token)) { + prev = p; + p = p.next; + } + if (p == null) { + throw new IllegalStateException("The specified message queue synchronization " + + " barrier token has not been posted or has already been removed."); + } + if (prev != null) { + prev.next = p.next; + needWake = false; + } else { + mMessages = p.next; + needWake = mMessages == null || mMessages.target != null; + } + p.recycle(); + } + if (needWake) { + nativeWake(mPtr); + } + } + final boolean enqueueMessage(Message msg, long when) { if (msg.isInUse()) { - throw new AndroidRuntimeException(msg - + " This message is already in use."); + throw new AndroidRuntimeException(msg + " This message is already in use."); } - if (msg.target == null && !mQuitAllowed) { - throw new RuntimeException("Main thread not allowed to quit"); + if (msg.target == null) { + throw new AndroidRuntimeException("Message must have a target."); } - final boolean needWake; + + boolean needWake; synchronized (this) { if (mQuiting) { RuntimeException e = new RuntimeException( - msg.target + " sending message to a Handler on a dead thread"); + msg.target + " sending message to a Handler on a dead thread"); Log.w("MessageQueue", e.getMessage(), e); return false; - } else if (msg.target == null) { - mQuiting = true; } msg.when = when; - //Log.d("MessageQueue", "Enqueing: " + msg); Message p = mMessages; if (p == null || when == 0 || when < p.when) { + // New head, wake up the event queue if blocked. msg.next = p; mMessages = msg; - needWake = mBlocked; // new head, might need to wake up + needWake = mBlocked; } else { - Message prev = null; - while (p != null && p.when <= when) { + // Inserted within the middle of the queue. Usually we don't have to wake + // up the event queue unless there is a barrier at the head of the queue + // and the message is the earliest asynchronous message in the queue. + needWake = mBlocked && p.target == null && msg.isAsynchronous(); + Message prev; + for (;;) { prev = p; p = p.next; + if (p == null || when < p.when) { + break; + } + if (needWake && p.isAsynchronous()) { + needWake = false; + } } - msg.next = prev.next; + msg.next = p; // invariant: p == prev.next prev.next = msg; - needWake = false; // still waiting on head, no need to wake up } } if (needWake) { @@ -225,17 +330,34 @@ public class MessageQueue { return true; } - final boolean removeMessages(Handler h, int what, Object object, - boolean doRemove) { + final boolean hasMessages(Handler h, int what, Object object) { + if (h == null) { + return false; + } + + synchronized (this) { + Message p = mMessages; + while (p != null) { + if (p.target == h && p.what == what && (object == null || p.obj == object)) { + return true; + } + p = p.next; + } + return false; + } + } + + final void removeMessages(Handler h, int what, Object object) { + if (h == null) { + return; + } + synchronized (this) { Message p = mMessages; - boolean found = false; // Remove all messages at front. while (p != null && p.target == h && p.what == what && (object == null || p.obj == object)) { - if (!doRemove) return true; - found = true; Message n = p.next; mMessages = n; p.recycle(); @@ -248,8 +370,6 @@ public class MessageQueue { if (n != null) { if (n.target == h && n.what == what && (object == null || n.obj == object)) { - if (!doRemove) return true; - found = true; Message nn = n.next; n.recycle(); p.next = nn; @@ -258,13 +378,11 @@ public class MessageQueue { } p = n; } - - return found; } } final void removeMessages(Handler h, Runnable r, Object object) { - if (r == null) { + if (h == null || r == null) { return; } @@ -298,6 +416,10 @@ public class MessageQueue { } final void removeCallbacksAndMessages(Handler h, Object object) { + if (h == null) { + return; + } + synchronized (this) { Message p = mMessages; @@ -325,16 +447,4 @@ public class MessageQueue { } } } - - /* - private void dumpQueue_l() - { - Message p = mMessages; - System.out.println(this + " queue is:"); - while (p != null) { - System.out.println(" " + p); - p = p.next; - } - } - */ } diff --git a/core/java/android/os/Power.java b/core/java/android/os/Power.java index 5a7921590156..58df940ca6b6 100644 --- a/core/java/android/os/Power.java +++ b/core/java/android/os/Power.java @@ -104,4 +104,6 @@ public class Power } private static native void rebootNative(String reason) throws IOException ; + + public static native int powerInitNative(); } diff --git a/core/java/android/text/TextDirectionHeuristics.java b/core/java/android/text/TextDirectionHeuristics.java index e5c1e5bd6bfd..ae41eab93494 100644 --- a/core/java/android/text/TextDirectionHeuristics.java +++ b/core/java/android/text/TextDirectionHeuristics.java @@ -17,13 +17,10 @@ package android.text; -import java.util.Locale; - import android.util.LocaleUtil; /** * Some objects that implement TextDirectionHeuristic. - * @hide */ public class TextDirectionHeuristics { @@ -74,9 +71,8 @@ public class TextDirectionHeuristics { * Computes the text direction based on an algorithm. Subclasses implement * {@link #defaultIsRtl} to handle cases where the algorithm cannot determine the * direction from the text alone. - * @hide */ - public static abstract class TextDirectionHeuristicImpl implements TextDirectionHeuristic { + private static abstract class TextDirectionHeuristicImpl implements TextDirectionHeuristic { private final TextDirectionAlgorithm mAlgorithm; public TextDirectionHeuristicImpl(TextDirectionAlgorithm algorithm) { @@ -157,13 +153,11 @@ public class TextDirectionHeuristics { /** * Interface for an algorithm to guess the direction of a paragraph of text. * - * @hide */ - public static interface TextDirectionAlgorithm { + private static interface TextDirectionAlgorithm { /** * Returns whether the range of text is RTL according to the algorithm. * - * @hide */ TriState checkRtl(char[] text, int start, int count); } @@ -173,9 +167,8 @@ public class TextDirectionHeuristics { * the paragraph direction. This is the standard Unicode Bidirectional * algorithm. * - * @hide */ - public static class FirstStrong implements TextDirectionAlgorithm { + private static class FirstStrong implements TextDirectionAlgorithm { @Override public TriState checkRtl(char[] text, int start, int count) { TriState result = TriState.UNKNOWN; @@ -196,9 +189,8 @@ public class TextDirectionHeuristics { * character (e.g. excludes LRE, LRO, RLE, RLO) to determine the * direction of text. * - * @hide */ - public static class AnyStrong implements TextDirectionAlgorithm { + private static class AnyStrong implements TextDirectionAlgorithm { private final boolean mLookForRtl; @Override @@ -239,7 +231,7 @@ public class TextDirectionHeuristics { /** * Algorithm that uses the Locale direction to force the direction of a paragraph. */ - public static class TextDirectionHeuristicLocale extends TextDirectionHeuristicImpl { + private static class TextDirectionHeuristicLocale extends TextDirectionHeuristicImpl { public TextDirectionHeuristicLocale() { super(null); diff --git a/core/java/android/text/method/KeyListener.java b/core/java/android/text/method/KeyListener.java index 85948523a009..318149ae6c7f 100644 --- a/core/java/android/text/method/KeyListener.java +++ b/core/java/android/text/method/KeyListener.java @@ -22,7 +22,7 @@ import android.view.View; /** * Interface for converting text key events into edit operations on an - * Editable class. Note that for must cases this interface has been + * Editable class. Note that for most cases this interface has been * superceded by general soft input methods as defined by * {@link android.view.inputmethod.InputMethod}; it should only be used * for cases where an application has its own on-screen keypad and also wants diff --git a/core/java/android/text/method/TransformationMethod.java b/core/java/android/text/method/TransformationMethod.java index 9f51c2a1e256..b542109d0beb 100644 --- a/core/java/android/text/method/TransformationMethod.java +++ b/core/java/android/text/method/TransformationMethod.java @@ -18,7 +18,6 @@ package android.text.method; import android.graphics.Rect; import android.view.View; -import android.widget.TextView; /** * TextView uses TransformationMethods to do things like replacing the diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java index 3e2d7fc60241..42c391309396 100644 --- a/core/java/android/view/Choreographer.java +++ b/core/java/android/view/Choreographer.java @@ -16,8 +16,6 @@ package android.view; -import com.android.internal.util.ArrayUtils; - import android.os.Handler; import android.os.Looper; import android.os.Message; @@ -28,8 +26,8 @@ import android.util.Log; /** * Coordinates animations and drawing for UI on a particular thread. * - * This object is thread-safe. Other threads can add and remove listeners - * or schedule work to occur at a later time on the UI thread. + * This object is thread-safe. Other threads can post callbacks to run at a later time + * on the UI thread. * * Ensuring thread-safety is a little tricky because the {@link DisplayEventReceiver} * can only be accessed from the UI thread so operations that touch the event receiver @@ -37,14 +35,10 @@ import android.util.Log; * * @hide */ -public final class Choreographer extends Handler { +public final class Choreographer { private static final String TAG = "Choreographer"; private static final boolean DEBUG = false; - // Amount of time in ms to wait before actually disposing of the display event - // receiver after all listeners have been removed. - private static final long DISPOSE_RECEIVER_DELAY = 200; - // The default amount of time in ms between animation frames. // When vsync is not enabled, we want to have some idea of how long we should // wait before posting the next animation message. It is important that the @@ -87,25 +81,27 @@ public final class Choreographer extends Handler { private static final int MSG_DO_ANIMATION = 0; private static final int MSG_DO_DRAW = 1; private static final int MSG_DO_SCHEDULE_VSYNC = 2; - private static final int MSG_DO_DISPOSE_RECEIVER = 3; private final Object mLock = new Object(); private final Looper mLooper; + private final FrameHandler mHandler; + private final FrameDisplayEventReceiver mDisplayEventReceiver; - private OnAnimateListener[] mOnAnimateListeners; - private OnDrawListener[] mOnDrawListeners; + private Callback mCallbackPool; + + private Callback mAnimationCallbacks; + private Callback mDrawCallbacks; private boolean mAnimationScheduled; private boolean mDrawScheduled; - private boolean mFrameDisplayEventReceiverNeeded; - private FrameDisplayEventReceiver mFrameDisplayEventReceiver; private long mLastAnimationTime; private long mLastDrawTime; private Choreographer(Looper looper) { - super(looper); mLooper = looper; + mHandler = new FrameHandler(looper); + mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper) : null; mLastAnimationTime = Long.MIN_VALUE; mLastDrawTime = Long.MIN_VALUE; } @@ -154,14 +150,77 @@ public final class Choreographer extends Handler { } /** - * Schedules animation (and drawing) to occur on the next frame synchronization boundary. + * Posts a callback to run on the next animation cycle and schedules an animation cycle. + * The callback only runs once and then is automatically removed. + * + * @param runnable The callback to run during the next animation cycle. + * + * @see #removeAnimationCallback */ - public void scheduleAnimation() { + public void postAnimationCallback(Runnable runnable) { + if (runnable == null) { + throw new IllegalArgumentException("runnable must not be null"); + } synchronized (mLock) { + mAnimationCallbacks = addCallbackLocked(mAnimationCallbacks, runnable); scheduleAnimationLocked(); } } + /** + * Removes an animation callback. + * Does nothing if the specified animation callback has not been posted or has already + * been removed. + * + * @param runnable The animation callback to remove. + * + * @see #postAnimationCallback + */ + public void removeAnimationCallback(Runnable runnable) { + if (runnable == null) { + throw new IllegalArgumentException("runnable must not be null"); + } + synchronized (mLock) { + mAnimationCallbacks = removeCallbackLocked(mAnimationCallbacks, runnable); + } + } + + /** + * Posts a callback to run on the next draw cycle and schedules a draw cycle. + * The callback only runs once and then is automatically removed. + * + * @param runnable The callback to run during the next draw cycle. + * + * @see #removeDrawCallback + */ + public void postDrawCallback(Runnable runnable) { + if (runnable == null) { + throw new IllegalArgumentException("runnable must not be null"); + } + synchronized (mLock) { + mDrawCallbacks = addCallbackLocked(mDrawCallbacks, runnable); + scheduleDrawLocked(); + } + } + + /** + * Removes a draw callback. + * Does nothing if the specified draw callback has not been posted or has already + * been removed. + * + * @param runnable The draw callback to remove. + * + * @see #postDrawCallback + */ + public void removeDrawCallback(Runnable runnable) { + if (runnable == null) { + throw new IllegalArgumentException("runnable must not be null"); + } + synchronized (mLock) { + mDrawCallbacks = removeCallbackLocked(mDrawCallbacks, runnable); + } + } + private void scheduleAnimationLocked() { if (!mAnimationScheduled) { mAnimationScheduled = true; @@ -173,16 +232,12 @@ public final class Choreographer extends Handler { // If running on the Looper thread, then schedule the vsync immediately, // otherwise post a message to schedule the vsync from the UI thread // as soon as possible. - if (!mFrameDisplayEventReceiverNeeded) { - mFrameDisplayEventReceiverNeeded = true; - if (mFrameDisplayEventReceiver != null) { - removeMessages(MSG_DO_DISPOSE_RECEIVER); - } - } if (isRunningOnLooperThreadLocked()) { doScheduleVsyncLocked(); } else { - sendMessageAtFrontOfQueue(obtainMessage(MSG_DO_SCHEDULE_VSYNC)); + Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC); + msg.setAsynchronous(true); + mHandler.sendMessageAtFrontOfQueue(msg); } } else { final long now = SystemClock.uptimeMillis(); @@ -190,72 +245,30 @@ public final class Choreographer extends Handler { if (DEBUG) { Log.d(TAG, "Scheduling animation in " + (nextAnimationTime - now) + " ms."); } - sendEmptyMessageAtTime(MSG_DO_ANIMATION, nextAnimationTime); + Message msg = mHandler.obtainMessage(MSG_DO_ANIMATION); + msg.setAsynchronous(true); + mHandler.sendMessageAtTime(msg, nextAnimationTime); } } } - /** - * Returns true if {@link #scheduleAnimation()} has been called but - * {@link OnAnimateListener#onAnimate() OnAnimateListener.onAnimate()} has - * not yet been called. - */ - public boolean isAnimationScheduled() { - synchronized (mLock) { - return mAnimationScheduled; - } - } - - /** - * Schedules drawing to occur on the next frame synchronization boundary. - * Must be called on the UI thread. - */ - public void scheduleDraw() { - synchronized (mLock) { - if (!mDrawScheduled) { - mDrawScheduled = true; - if (USE_ANIMATION_TIMER_FOR_DRAW) { - scheduleAnimationLocked(); - } else { - if (DEBUG) { - Log.d(TAG, "Scheduling draw immediately."); - } - sendEmptyMessage(MSG_DO_DRAW); + private void scheduleDrawLocked() { + if (!mDrawScheduled) { + mDrawScheduled = true; + if (USE_ANIMATION_TIMER_FOR_DRAW) { + scheduleAnimationLocked(); + } else { + if (DEBUG) { + Log.d(TAG, "Scheduling draw immediately."); } + Message msg = mHandler.obtainMessage(MSG_DO_DRAW); + msg.setAsynchronous(true); + mHandler.sendMessage(msg); } } } - /** - * Returns true if {@link #scheduleDraw()} has been called but - * {@link OnDrawListener#onDraw() OnDrawListener.onDraw()} has - * not yet been called. - */ - public boolean isDrawScheduled() { - synchronized (mLock) { - return mDrawScheduled; - } - } - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_DO_ANIMATION: - doAnimation(); - break; - case MSG_DO_DRAW: - doDraw(); - break; - case MSG_DO_SCHEDULE_VSYNC: - doScheduleVsync(); - break; - case MSG_DO_DISPOSE_RECEIVER: - doDisposeReceiver(); - break; - } - } - - private void doAnimation() { + void doAnimation() { doAnimationInner(); if (USE_ANIMATION_TIMER_FOR_DRAW) { @@ -263,9 +276,9 @@ public final class Choreographer extends Handler { } } - private void doAnimationInner() { + void doAnimationInner() { final long start; - final OnAnimateListener[] listeners; + final Callback callbacks; synchronized (mLock) { if (!mAnimationScheduled) { return; // no work to do @@ -279,12 +292,14 @@ public final class Choreographer extends Handler { } mLastAnimationTime = start; - listeners = mOnAnimateListeners; + callbacks = mAnimationCallbacks; + mAnimationCallbacks = null; } - if (listeners != null) { - for (int i = 0; i < listeners.length; i++) { - listeners[i].onAnimate(); + if (callbacks != null) { + runCallbacks(callbacks); + synchronized (mLock) { + recycleCallbacksLocked(callbacks); } } @@ -293,9 +308,9 @@ public final class Choreographer extends Handler { } } - private void doDraw() { + void doDraw() { final long start; - final OnDrawListener[] listeners; + final Callback callbacks; synchronized (mLock) { if (!mDrawScheduled) { return; // no work to do @@ -309,12 +324,14 @@ public final class Choreographer extends Handler { } mLastDrawTime = start; - listeners = mOnDrawListeners; + callbacks = mDrawCallbacks; + mDrawCallbacks = null; } - if (listeners != null) { - for (int i = 0; i < listeners.length; i++) { - listeners[i].onDraw(); + if (callbacks != null) { + runCallbacks(callbacks); + synchronized (mLock) { + recycleCallbacksLocked(callbacks); } } @@ -323,171 +340,106 @@ public final class Choreographer extends Handler { } } - private void doScheduleVsync() { + void doScheduleVsync() { synchronized (mLock) { doScheduleVsyncLocked(); } } private void doScheduleVsyncLocked() { - if (mFrameDisplayEventReceiverNeeded && mAnimationScheduled) { - if (mFrameDisplayEventReceiver == null) { - mFrameDisplayEventReceiver = new FrameDisplayEventReceiver(mLooper); - } - mFrameDisplayEventReceiver.scheduleVsync(); + if (mAnimationScheduled) { + mDisplayEventReceiver.scheduleVsync(); } } - private void doDisposeReceiver() { - synchronized (mLock) { - if (!mFrameDisplayEventReceiverNeeded && mFrameDisplayEventReceiver != null) { - mFrameDisplayEventReceiver.dispose(); - mFrameDisplayEventReceiver = null; - } - } + private boolean isRunningOnLooperThreadLocked() { + return Looper.myLooper() == mLooper; } - /** - * Adds an animation listener. - * - * @param listener The listener to add. - */ - public void addOnAnimateListener(OnAnimateListener listener) { - if (listener == null) { - throw new IllegalArgumentException("listener must not be null"); - } - - if (DEBUG) { - Log.d(TAG, "Adding onAnimate listener: " + listener); + private Callback addCallbackLocked(Callback head, Runnable runnable) { + Callback callback = obtainCallbackLocked(runnable); + if (head == null) { + return callback; } - - synchronized (mLock) { - mOnAnimateListeners = ArrayUtils.appendElement(OnAnimateListener.class, - mOnAnimateListeners, listener); + Callback tail = head; + while (tail.next != null) { + tail = tail.next; } + tail.next = callback; + return head; } - /** - * Removes an animation listener. - * - * @param listener The listener to remove. - */ - public void removeOnAnimateListener(OnAnimateListener listener) { - if (listener == null) { - throw new IllegalArgumentException("listener must not be null"); - } - - if (DEBUG) { - Log.d(TAG, "Removing onAnimate listener: " + listener); - } - - synchronized (mLock) { - mOnAnimateListeners = ArrayUtils.removeElement(OnAnimateListener.class, - mOnAnimateListeners, listener); - stopTimingLoopIfNoListenersLocked(); + private Callback removeCallbackLocked(Callback head, Runnable runnable) { + Callback predecessor = null; + for (Callback callback = head; callback != null;) { + final Callback next = callback.next; + if (callback.runnable == runnable) { + if (predecessor != null) { + predecessor.next = next; + } else { + head = next; + } + recycleCallbackLocked(callback); + } else { + predecessor = callback; + } + callback = next; } + return head; } - /** - * Adds a draw listener. - * - * @param listener The listener to add. - */ - public void addOnDrawListener(OnDrawListener listener) { - if (listener == null) { - throw new IllegalArgumentException("listener must not be null"); - } - - if (DEBUG) { - Log.d(TAG, "Adding onDraw listener: " + listener); - } - - synchronized (mLock) { - mOnDrawListeners = ArrayUtils.appendElement(OnDrawListener.class, - mOnDrawListeners, listener); + private void runCallbacks(Callback head) { + while (head != null) { + head.runnable.run(); + head = head.next; } } - /** - * Removes a draw listener. - * Must be called on the UI thread. - * - * @param listener The listener to remove. - */ - public void removeOnDrawListener(OnDrawListener listener) { - if (listener == null) { - throw new IllegalArgumentException("listener must not be null"); - } - - if (DEBUG) { - Log.d(TAG, "Removing onDraw listener: " + listener); - } - - synchronized (mLock) { - mOnDrawListeners = ArrayUtils.removeElement(OnDrawListener.class, - mOnDrawListeners, listener); - stopTimingLoopIfNoListenersLocked(); + private void recycleCallbacksLocked(Callback head) { + while (head != null) { + final Callback next = head.next; + recycleCallbackLocked(head); + head = next; } } - private void stopTimingLoopIfNoListenersLocked() { - if (mOnDrawListeners == null && mOnAnimateListeners == null) { - if (DEBUG) { - Log.d(TAG, "Stopping timing loop."); - } - - if (mAnimationScheduled) { - mAnimationScheduled = false; - if (USE_VSYNC) { - removeMessages(MSG_DO_SCHEDULE_VSYNC); - } else { - removeMessages(MSG_DO_ANIMATION); - } - } - - if (mDrawScheduled) { - mDrawScheduled = false; - if (!USE_ANIMATION_TIMER_FOR_DRAW) { - removeMessages(MSG_DO_DRAW); - } - } - - // Post a message to dispose the display event receiver if we haven't needed - // it again after a certain amount of time has elapsed. Another reason to - // defer disposal is that it is possible for use to attempt to dispose the - // receiver while handling a vsync event that it dispatched, which might - // cause a few problems... - if (mFrameDisplayEventReceiverNeeded) { - mFrameDisplayEventReceiverNeeded = false; - if (mFrameDisplayEventReceiver != null) { - sendEmptyMessageDelayed(MSG_DO_DISPOSE_RECEIVER, DISPOSE_RECEIVER_DELAY); - } - } + private Callback obtainCallbackLocked(Runnable runnable) { + Callback callback = mCallbackPool; + if (callback == null) { + callback = new Callback(); + } else { + mCallbackPool = callback.next; + callback.next = null; } + callback.runnable = runnable; + return callback; } - private boolean isRunningOnLooperThreadLocked() { - return Looper.myLooper() == mLooper; + private void recycleCallbackLocked(Callback callback) { + callback.runnable = null; + callback.next = mCallbackPool; + mCallbackPool = callback; } - /** - * Listens for animation frame timing events. - */ - public static interface OnAnimateListener { - /** - * Called to animate properties before drawing the frame. - */ - public void onAnimate(); - } + private final class FrameHandler extends Handler { + public FrameHandler(Looper looper) { + super(looper); + } - /** - * Listens for draw frame timing events. - */ - public static interface OnDrawListener { - /** - * Called to draw the frame. - */ - public void onDraw(); + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_DO_ANIMATION: + doAnimation(); + break; + case MSG_DO_DRAW: + doDraw(); + break; + case MSG_DO_SCHEDULE_VSYNC: + doScheduleVsync(); + break; + } + } } private final class FrameDisplayEventReceiver extends DisplayEventReceiver { @@ -500,4 +452,9 @@ public final class Choreographer extends Handler { doAnimation(); } } + + private static final class Callback { + public Callback next; + public Runnable runnable; + } } diff --git a/core/java/android/view/DisplayList.java b/core/java/android/view/DisplayList.java index fec0d4b94e8f..f60c8f0f5f54 100644 --- a/core/java/android/view/DisplayList.java +++ b/core/java/android/view/DisplayList.java @@ -27,6 +27,15 @@ package android.view; */ public abstract class DisplayList { /** + * Flag used when calling + * {@link HardwareCanvas#drawDisplayList(DisplayList, int, int, android.graphics.Rect, int)}. + * When this flag is set, draw operations lying outside of the bounds of the + * display list will be culled early. It is recommeneded to always set this + * flag. + */ + public static final int FLAG_CLIP_CHILDREN = 0x1; + + /** * Starts recording the display list. All operations performed on the * returned canvas are recorded and stored in this display list. * diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java index 1e92b43a3203..f5fc708c0c9c 100644 --- a/core/java/android/view/GLES20Canvas.java +++ b/core/java/android/view/GLES20Canvas.java @@ -385,13 +385,14 @@ class GLES20Canvas extends HardwareCanvas { private static native void nSetDisplayListName(int displayList, String name); @Override - public boolean drawDisplayList(DisplayList displayList, int width, int height, Rect dirty) { - return nDrawDisplayList(mRenderer, - ((GLES20DisplayList) displayList).getNativeDisplayList(), width, height, dirty); + public boolean drawDisplayList(DisplayList displayList, int width, int height, + Rect dirty, int flags) { + return nDrawDisplayList(mRenderer, ((GLES20DisplayList) displayList).getNativeDisplayList(), + width, height, dirty, flags); } private static native boolean nDrawDisplayList(int renderer, int displayList, - int width, int height, Rect dirty); + int width, int height, Rect dirty, int flags); @Override void outputDisplayList(DisplayList displayList) { @@ -407,9 +408,12 @@ class GLES20Canvas extends HardwareCanvas { void drawHardwareLayer(HardwareLayer layer, float x, float y, Paint paint) { final GLES20Layer glLayer = (GLES20Layer) layer; int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE; - final int nativePaint = paint == null ? 0 : paint.mNativePaint; - nDrawLayer(mRenderer, glLayer.getLayer(), x, y, nativePaint); - if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier); + try { + final int nativePaint = paint == null ? 0 : paint.mNativePaint; + nDrawLayer(mRenderer, glLayer.getLayer(), x, y, nativePaint); + } finally { + if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier); + } } private static native void nDrawLayer(int renderer, int layer, float x, float y, int paint); @@ -607,10 +611,14 @@ class GLES20Canvas extends HardwareCanvas { return saveLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, paint, saveFlags); } + int count; int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE; - final int nativePaint = paint == null ? 0 : paint.mNativePaint; - int count = nSaveLayer(mRenderer, nativePaint, saveFlags); - if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier); + try { + final int nativePaint = paint == null ? 0 : paint.mNativePaint; + count = nSaveLayer(mRenderer, nativePaint, saveFlags); + } finally { + if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier); + } return count; } @@ -620,10 +628,14 @@ class GLES20Canvas extends HardwareCanvas { public int saveLayer(float left, float top, float right, float bottom, Paint paint, int saveFlags) { if (left < right && top < bottom) { + int count; int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE; - final int nativePaint = paint == null ? 0 : paint.mNativePaint; - int count = nSaveLayer(mRenderer, left, top, right, bottom, nativePaint, saveFlags); - if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier); + try { + final int nativePaint = paint == null ? 0 : paint.mNativePaint; + count = nSaveLayer(mRenderer, left, top, right, bottom, nativePaint, saveFlags); + } finally { + if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier); + } return count; } return save(saveFlags); @@ -707,9 +719,12 @@ class GLES20Canvas extends HardwareCanvas { public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint) { int modifiers = setupModifiers(paint); - nDrawArc(mRenderer, oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle, - useCenter, paint.mNativePaint); - if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); + try { + nDrawArc(mRenderer, oval.left, oval.top, oval.right, oval.bottom, + startAngle, sweepAngle, useCenter, paint.mNativePaint); + } finally { + if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); + } } private static native void nDrawArc(int renderer, float left, float top, @@ -726,10 +741,13 @@ class GLES20Canvas extends HardwareCanvas { if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps"); // Shaders are ignored when drawing patches int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE; - final int nativePaint = paint == null ? 0 : paint.mNativePaint; - nDrawPatch(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, chunks, - dst.left, dst.top, dst.right, dst.bottom, nativePaint); - if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier); + try { + final int nativePaint = paint == null ? 0 : paint.mNativePaint; + nDrawPatch(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, chunks, + dst.left, dst.top, dst.right, dst.bottom, nativePaint); + } finally { + if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier); + } } private static native void nDrawPatch(int renderer, int bitmap, byte[] buffer, byte[] chunks, @@ -740,9 +758,12 @@ class GLES20Canvas extends HardwareCanvas { if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps"); // Shaders are ignored when drawing bitmaps int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE; - final int nativePaint = paint == null ? 0 : paint.mNativePaint; - nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, nativePaint); - if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); + try { + final int nativePaint = paint == null ? 0 : paint.mNativePaint; + nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, nativePaint); + } finally { + if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); + } } private static native void nDrawBitmap( @@ -753,10 +774,13 @@ class GLES20Canvas extends HardwareCanvas { if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps"); // Shaders are ignored when drawing bitmaps int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE; - final int nativePaint = paint == null ? 0 : paint.mNativePaint; - nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, - matrix.native_instance, nativePaint); - if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); + try { + final int nativePaint = paint == null ? 0 : paint.mNativePaint; + nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, + matrix.native_instance, nativePaint); + } finally { + if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); + } } private static native void nDrawBitmap(int renderer, int bitmap, byte[] buff, @@ -767,23 +791,26 @@ class GLES20Canvas extends HardwareCanvas { if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps"); // Shaders are ignored when drawing bitmaps int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE; - final int nativePaint = paint == null ? 0 : paint.mNativePaint; + try { + final int nativePaint = paint == null ? 0 : paint.mNativePaint; - int left, top, right, bottom; - if (src == null) { - left = top = 0; - right = bitmap.getWidth(); - bottom = bitmap.getHeight(); - } else { - left = src.left; - right = src.right; - top = src.top; - bottom = src.bottom; - } + int left, top, right, bottom; + if (src == null) { + left = top = 0; + right = bitmap.getWidth(); + bottom = bitmap.getHeight(); + } else { + left = src.left; + right = src.right; + top = src.top; + bottom = src.bottom; + } - nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom, - dst.left, dst.top, dst.right, dst.bottom, nativePaint); - if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); + nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom, + dst.left, dst.top, dst.right, dst.bottom, nativePaint); + } finally { + if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); + } } @Override @@ -791,23 +818,26 @@ class GLES20Canvas extends HardwareCanvas { if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps"); // Shaders are ignored when drawing bitmaps int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE; - final int nativePaint = paint == null ? 0 : paint.mNativePaint; - - float left, top, right, bottom; - if (src == null) { - left = top = 0; - right = bitmap.getWidth(); - bottom = bitmap.getHeight(); - } else { - left = src.left; - right = src.right; - top = src.top; - bottom = src.bottom; + try { + final int nativePaint = paint == null ? 0 : paint.mNativePaint; + + float left, top, right, bottom; + if (src == null) { + left = top = 0; + right = bitmap.getWidth(); + bottom = bitmap.getHeight(); + } else { + left = src.left; + right = src.right; + top = src.top; + bottom = src.bottom; + } + + nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom, + dst.left, dst.top, dst.right, dst.bottom, nativePaint); + } finally { + if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); } - - nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom, - dst.left, dst.top, dst.right, dst.bottom, nativePaint); - if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); } private static native void nDrawBitmap(int renderer, int bitmap, byte[] buffer, @@ -819,12 +849,15 @@ class GLES20Canvas extends HardwareCanvas { int width, int height, boolean hasAlpha, Paint paint) { // Shaders are ignored when drawing bitmaps int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE; - final Bitmap.Config config = hasAlpha ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; - final Bitmap b = Bitmap.createBitmap(colors, offset, stride, width, height, config); - final int nativePaint = paint == null ? 0 : paint.mNativePaint; - nDrawBitmap(mRenderer, b.mNativeBitmap, b.mBuffer, x, y, nativePaint); - b.recycle(); - if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier); + try { + final Bitmap.Config config = hasAlpha ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; + final Bitmap b = Bitmap.createBitmap(colors, offset, stride, width, height, config); + final int nativePaint = paint == null ? 0 : paint.mNativePaint; + nDrawBitmap(mRenderer, b.mNativeBitmap, b.mBuffer, x, y, nativePaint); + b.recycle(); + } finally { + if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier); + } } @Override @@ -854,10 +887,13 @@ class GLES20Canvas extends HardwareCanvas { colorOffset = 0; int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE; - final int nativePaint = paint == null ? 0 : paint.mNativePaint; - nDrawBitmapMesh(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, meshWidth, meshHeight, - verts, vertOffset, colors, colorOffset, nativePaint); - if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); + try { + final int nativePaint = paint == null ? 0 : paint.mNativePaint; + nDrawBitmapMesh(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, meshWidth, meshHeight, + verts, vertOffset, colors, colorOffset, nativePaint); + } finally { + if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); + } } private static native void nDrawBitmapMesh(int renderer, int bitmap, byte[] buffer, @@ -867,8 +903,11 @@ class GLES20Canvas extends HardwareCanvas { @Override public void drawCircle(float cx, float cy, float radius, Paint paint) { int modifiers = setupModifiers(paint); - nDrawCircle(mRenderer, cx, cy, radius, paint.mNativePaint); - if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); + try { + nDrawCircle(mRenderer, cx, cy, radius, paint.mNativePaint); + } finally { + if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); + } } private static native void nDrawCircle(int renderer, float cx, float cy, @@ -901,8 +940,11 @@ class GLES20Canvas extends HardwareCanvas { throw new IllegalArgumentException("The lines array must contain 4 elements per line."); } int modifiers = setupModifiers(paint); - nDrawLines(mRenderer, pts, offset, count, paint.mNativePaint); - if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); + try { + nDrawLines(mRenderer, pts, offset, count, paint.mNativePaint); + } finally { + if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); + } } private static native void nDrawLines(int renderer, float[] points, @@ -916,8 +958,11 @@ class GLES20Canvas extends HardwareCanvas { @Override public void drawOval(RectF oval, Paint paint) { int modifiers = setupModifiers(paint); - nDrawOval(mRenderer, oval.left, oval.top, oval.right, oval.bottom, paint.mNativePaint); - if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); + try { + nDrawOval(mRenderer, oval.left, oval.top, oval.right, oval.bottom, paint.mNativePaint); + } finally { + if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); + } } private static native void nDrawOval(int renderer, float left, float top, @@ -933,14 +978,17 @@ class GLES20Canvas extends HardwareCanvas { @Override public void drawPath(Path path, Paint paint) { int modifiers = setupModifiers(paint); - if (path.isSimplePath) { - if (path.rects != null) { - nDrawRects(mRenderer, path.rects.mNativeRegion, paint.mNativePaint); + try { + if (path.isSimplePath) { + if (path.rects != null) { + nDrawRects(mRenderer, path.rects.mNativeRegion, paint.mNativePaint); + } + } else { + nDrawPath(mRenderer, path.mNativePath, paint.mNativePaint); } - } else { - nDrawPath(mRenderer, path.mNativePath, paint.mNativePaint); + } finally { + if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); } - if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); } private static native void nDrawPath(int renderer, int path, int paint); @@ -1001,8 +1049,11 @@ class GLES20Canvas extends HardwareCanvas { @Override public void drawPoints(float[] pts, int offset, int count, Paint paint) { int modifiers = setupModifiers(paint); - nDrawPoints(mRenderer, pts, offset, count, paint.mNativePaint); - if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); + try { + nDrawPoints(mRenderer, pts, offset, count, paint.mNativePaint); + } finally { + if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); + } } private static native void nDrawPoints(int renderer, float[] points, @@ -1047,8 +1098,11 @@ class GLES20Canvas extends HardwareCanvas { @Override public void drawRect(float left, float top, float right, float bottom, Paint paint) { int modifiers = setupModifiers(paint); - nDrawRect(mRenderer, left, top, right, bottom, paint.mNativePaint); - if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); + try { + nDrawRect(mRenderer, left, top, right, bottom, paint.mNativePaint); + } finally { + if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); + } } private static native void nDrawRect(int renderer, float left, float top, @@ -1072,9 +1126,12 @@ class GLES20Canvas extends HardwareCanvas { @Override public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) { int modifiers = setupModifiers(paint); - nDrawRoundRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom, - rx, ry, paint.mNativePaint); - if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); + try { + nDrawRoundRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom, + rx, ry, paint.mNativePaint); + } finally { + if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); + } } private static native void nDrawRoundRect(int renderer, float left, float top, @@ -1223,17 +1280,17 @@ class GLES20Canvas extends HardwareCanvas { } private int setupModifiers(Bitmap b, Paint paint) { - if (b.getConfig() == Bitmap.Config.ALPHA_8) { - return setupModifiers(paint); - } + if (b.getConfig() != Bitmap.Config.ALPHA_8) { + final ColorFilter filter = paint.getColorFilter(); + if (filter != null) { + nSetupColorFilter(mRenderer, filter.nativeColorFilter); + return MODIFIER_COLOR_FILTER; + } - final ColorFilter filter = paint.getColorFilter(); - if (filter != null) { - nSetupColorFilter(mRenderer, filter.nativeColorFilter); - return MODIFIER_COLOR_FILTER; + return MODIFIER_NONE; + } else { + return setupModifiers(paint); } - - return MODIFIER_NONE; } private int setupModifiers(Paint paint) { diff --git a/core/java/android/view/GLES20RecordingCanvas.java b/core/java/android/view/GLES20RecordingCanvas.java index c987f487d30b..c9ba65f3ab40 100644 --- a/core/java/android/view/GLES20RecordingCanvas.java +++ b/core/java/android/view/GLES20RecordingCanvas.java @@ -143,8 +143,8 @@ class GLES20RecordingCanvas extends GLES20Canvas implements Poolable<GLES20Recor @Override public void drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight, float[] verts, int vertOffset, int[] colors, int colorOffset, Paint paint) { - super.drawBitmapMesh(bitmap, meshWidth, meshHeight, verts, vertOffset, colors, colorOffset, - paint); + super.drawBitmapMesh(bitmap, meshWidth, meshHeight, verts, vertOffset, + colors, colorOffset, paint); mDisplayList.mBitmaps.add(bitmap); // Shaders in the Paint are ignored when drawing a Bitmap } diff --git a/core/java/android/view/HardwareCanvas.java b/core/java/android/view/HardwareCanvas.java index cbdbbde45b70..838c03c96dd7 100644 --- a/core/java/android/view/HardwareCanvas.java +++ b/core/java/android/view/HardwareCanvas.java @@ -57,11 +57,14 @@ public abstract class HardwareCanvas extends Canvas { * @param height The height of the display list. * @param dirty The dirty region to redraw in the next pass, matters only * if this method returns true, can be null. + * @param flags Optional flags about drawing, see {@link DisplayList} for + * the possible flags. * * @return True if the content of the display list requires another * drawing pass (invalidate()), false otherwise */ - public abstract boolean drawDisplayList(DisplayList displayList, int width, int height, Rect dirty); + public abstract boolean drawDisplayList(DisplayList displayList, int width, int height, + Rect dirty, int flags); /** * Outputs the specified display list to the log. This method exists for use by diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java index 1932c7f39608..ec9586308568 100644 --- a/core/java/android/view/HardwareRenderer.java +++ b/core/java/android/view/HardwareRenderer.java @@ -109,8 +109,12 @@ public abstract class HardwareRenderer { /** * Turn on to draw dirty regions every other frame. + * + * Possible values: + * "true", to enable dirty regions debugging + * "false", to disable dirty regions debugging */ - private static final boolean DEBUG_DIRTY_REGION = false; + static final String DEBUG_DIRTY_REGIONS_PROPERTY = "hwui.debug_dirty_regions"; /** * A process can set this flag to false to prevent the use of hardware @@ -491,6 +495,8 @@ public abstract class HardwareRenderer { final boolean mProfileEnabled; final float[] mProfileData; int mProfileCurrentFrame = -PROFILE_FRAME_DATA_COUNT; + + final boolean mDebugDirtyRegions; final int mGlVersion; final boolean mTranslucent; @@ -502,17 +508,19 @@ public abstract class HardwareRenderer { GlRenderer(int glVersion, boolean translucent) { mGlVersion = glVersion; mTranslucent = translucent; + + String property; - final String vsyncProperty = SystemProperties.get(DISABLE_VSYNC_PROPERTY, "false"); - mVsyncDisabled = "true".equalsIgnoreCase(vsyncProperty); + property = SystemProperties.get(DISABLE_VSYNC_PROPERTY, "false"); + mVsyncDisabled = "true".equalsIgnoreCase(property); if (mVsyncDisabled) { Log.d(LOG_TAG, "Disabling v-sync"); } //noinspection PointlessBooleanExpression,ConstantConditions if (!ViewDebug.DEBUG_LATENCY) { - final String profileProperty = SystemProperties.get(PROFILE_PROPERTY, "false"); - mProfileEnabled = "true".equalsIgnoreCase(profileProperty); + property = SystemProperties.get(PROFILE_PROPERTY, "false"); + mProfileEnabled = "true".equalsIgnoreCase(property); if (mProfileEnabled) { Log.d(LOG_TAG, "Profiling hardware renderer"); } @@ -525,6 +533,12 @@ public abstract class HardwareRenderer { } else { mProfileData = null; } + + property = SystemProperties.get(DEBUG_DIRTY_REGIONS_PROPERTY, "false"); + mDebugDirtyRegions = "true".equalsIgnoreCase(property); + if (mDebugDirtyRegions) { + Log.d(LOG_TAG, "Debugging dirty regions"); + } } @Override @@ -955,7 +969,8 @@ public abstract class HardwareRenderer { } boolean invalidateNeeded = canvas.drawDisplayList(displayList, - view.getWidth(), view.getHeight(), mRedrawClip); + view.getWidth(), view.getHeight(), mRedrawClip, + DisplayList.FLAG_CLIP_CHILDREN); if (mProfileEnabled) { long now = System.nanoTime(); @@ -981,8 +996,12 @@ public abstract class HardwareRenderer { // Shouldn't reach here view.draw(canvas); } + } finally { + callbacks.onHardwarePostDraw(canvas); + canvas.restoreToCount(saveCount); + view.mRecreateDisplayList = false; - if (DEBUG_DIRTY_REGION) { + if (mDebugDirtyRegions) { if (mDebugPaint == null) { mDebugPaint = new Paint(); mDebugPaint.setColor(0x7fff0000); @@ -991,10 +1010,6 @@ public abstract class HardwareRenderer { canvas.drawRect(dirty, mDebugPaint); } } - } finally { - callbacks.onHardwarePostDraw(canvas); - canvas.restoreToCount(saveCount); - view.mRecreateDisplayList = false; } onPostDraw(); diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index 6726c56eb581..c658a80323d7 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -384,7 +384,7 @@ public class SurfaceView extends View { if (!mHaveFrame) { return; } - ViewRootImpl viewRoot = (ViewRootImpl) getRootView().getParent(); + ViewRootImpl viewRoot = getViewRootImpl(); if (viewRoot != null) { mTranslator = viewRoot.mTranslator; } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index b972abd52b8b..c16eb31b56ba 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -65,6 +65,7 @@ import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityNodeProvider; import android.view.animation.Animation; import android.view.animation.AnimationUtils; +import android.view.animation.Transformation; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputMethodManager; @@ -600,6 +601,8 @@ import java.util.concurrent.CopyOnWriteArrayList; * @attr ref android.R.styleable#View_paddingLeft * @attr ref android.R.styleable#View_paddingRight * @attr ref android.R.styleable#View_paddingTop + * @attr ref android.R.styleable#View_paddingStart + * @attr ref android.R.styleable#View_paddingEnd * @attr ref android.R.styleable#View_saveEnabled * @attr ref android.R.styleable#View_rotation * @attr ref android.R.styleable#View_rotationX @@ -1756,6 +1759,16 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal static final int LAYOUT_DIRECTION_RESOLVED = 0x00000008; + /** + * Indicates that the view is tracking some sort of transient state + * that the app should not need to be aware of, but that the framework + * should take special care to preserve. + * + * @hide + */ + static final int HAS_TRANSIENT_STATE = 0x00000010; + + /* End of masks for mPrivateFlags2 */ static final int DRAG_MASK = DRAG_CAN_ACCEPT | DRAG_HOVERED; @@ -2617,7 +2630,6 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal /** * Text direction is inherited thru {@link ViewGroup} - * @hide */ public static final int TEXT_DIRECTION_INHERIT = 0; @@ -2626,7 +2638,6 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal * determines the paragraph direction. If there is no strong directional character, the * paragraph direction is the view's resolved layout direction. * - * @hide */ public static final int TEXT_DIRECTION_FIRST_STRONG = 1; @@ -2635,42 +2646,36 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal * any strong RTL character, otherwise it is LTR if it contains any strong LTR characters. * If there are neither, the paragraph direction is the view's resolved layout direction. * - * @hide */ public static final int TEXT_DIRECTION_ANY_RTL = 2; /** * Text direction is forced to LTR. * - * @hide */ public static final int TEXT_DIRECTION_LTR = 3; /** * Text direction is forced to RTL. * - * @hide */ public static final int TEXT_DIRECTION_RTL = 4; /** * Text direction is coming from the system Locale. * - * @hide */ public static final int TEXT_DIRECTION_LOCALE = 5; /** * Default text direction is inherited * - * @hide */ protected static int DEFAULT_TEXT_DIRECTION = TEXT_DIRECTION_INHERIT; /** * The text direction that has been defined by {@link #setTextDirection(int)}. * - * {@hide} */ @ViewDebug.ExportedProperty(category = "text", mapping = { @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), @@ -2688,7 +2693,6 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal * not TEXT_DIRECTION_INHERIT, otherwise resolution proceeds up the parent * chain of the view. * - * {@hide} */ @ViewDebug.ExportedProperty(category = "text", mapping = { @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), @@ -3774,14 +3778,6 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal } if ((mPrivateFlags & FOCUSED) != 0) { - // If this is the first focusable do not clear focus since the we - // try to give it focus every time a view clears its focus. Hence, - // the view that would gain focus already has it. - View firstFocusable = getFirstFocusable(); - if (firstFocusable == this) { - return; - } - mPrivateFlags &= ~FOCUSED; if (mParent != null) { @@ -3790,24 +3786,9 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal onFocusChanged(false, 0, null); refreshDrawableState(); - - // The view cleared focus and invoked the callbacks, so now is the - // time to give focus to the the first focusable to ensure that the - // gain focus is announced after clear focus. - if (firstFocusable != null) { - firstFocusable.requestFocus(FOCUS_FORWARD); - } } } - private View getFirstFocusable() { - ViewRootImpl viewRoot = getViewRootImpl(); - if (viewRoot != null) { - return viewRoot.focusSearch(null, FOCUS_FORWARD); - } - return null; - } - /** * Called to clear the focus of a view that is about to be removed. * Doesn't call clearChildFocus, which prevents this view from taking @@ -3819,6 +3800,11 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal onFocusChanged(false, 0, null); refreshDrawableState(); + + // The view cleared focus and invoked the callbacks, so now is the + // time to give focus to the the first focusable from the top to + // ensure that the gain focus is announced after clear focus. + getRootView().requestFocus(FOCUS_FORWARD); } } @@ -4913,6 +4899,43 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal } /** + * Indicates whether the view is currently tracking transient state that the + * app should not need to concern itself with saving and restoring, but that + * the framework should take special note to preserve when possible. + * + * @return true if the view has transient state + * + * @hide + */ + @ViewDebug.ExportedProperty(category = "layout") + public boolean hasTransientState() { + return (mPrivateFlags2 & HAS_TRANSIENT_STATE) == HAS_TRANSIENT_STATE; + } + + /** + * Set whether this view is currently tracking transient state that the + * framework should attempt to preserve when possible. + * + * @param hasTransientState true if this view has transient state + * + * @hide + */ + public void setHasTransientState(boolean hasTransientState) { + if (hasTransientState() == hasTransientState) return; + + mPrivateFlags2 = (mPrivateFlags2 & ~HAS_TRANSIENT_STATE) | + (hasTransientState ? HAS_TRANSIENT_STATE : 0); + if (mParent != null) { + try { + mParent.childHasTransientStateChanged(this, hasTransientState); + } catch (AbstractMethodError e) { + Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + + " does not fully implement ViewParent", e); + } + } + } + + /** * If this view doesn't do any drawing on its own, set this flag to * allow further optimizations. By default, this flag is not set on * View, but could be set on some View subclasses such as ViewGroup. @@ -5466,12 +5489,6 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal return true; } - /** Gets the ViewAncestor, or null if not attached. */ - /*package*/ ViewRootImpl getViewRootImpl() { - View root = getRootView(); - return root != null ? (ViewRootImpl)root.getParent() : null; - } - /** * Call this to try to give focus to a specific view or to one of its descendants. This is a * special variant of {@link #requestFocus() } that will allow views that are not focuable in @@ -6849,8 +6866,8 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal if ((changed & VISIBILITY_MASK) != 0) { if (mParent instanceof ViewGroup) { - ((ViewGroup) mParent).onChildVisibilityChanged(this, (changed & VISIBILITY_MASK), - (flags & VISIBILITY_MASK)); + ((ViewGroup) mParent).onChildVisibilityChanged(this, + (changed & VISIBILITY_MASK), (flags & VISIBILITY_MASK)); ((View) mParent).invalidate(true); } else if (mParent != null) { mParent.invalidateChild(this, null); @@ -8709,6 +8726,18 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal } /** + * Gets the view root associated with the View. + * @return The view root, or null if none. + * @hide + */ + public ViewRootImpl getViewRootImpl() { + if (mAttachInfo != null) { + return mAttachInfo.mViewRootImpl; + } + return null; + } + + /** * <p>Causes the Runnable to be added to the message queue. * The runnable will be run on the user interface thread.</p> * @@ -8722,17 +8751,13 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal * looper processing the message queue is exiting. */ public boolean post(Runnable action) { - Handler handler; - AttachInfo attachInfo = mAttachInfo; + final AttachInfo attachInfo = mAttachInfo; if (attachInfo != null) { - handler = attachInfo.mHandler; - } else { - // Assume that post will succeed later - ViewRootImpl.getRunQueue().post(action); - return true; + return attachInfo.mHandler.post(action); } - - return handler.post(action); + // Assume that post will succeed later + ViewRootImpl.getRunQueue().post(action); + return true; } /** @@ -8755,17 +8780,13 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal * occurs then the message will be dropped. */ public boolean postDelayed(Runnable action, long delayMillis) { - Handler handler; - AttachInfo attachInfo = mAttachInfo; + final AttachInfo attachInfo = mAttachInfo; if (attachInfo != null) { - handler = attachInfo.mHandler; - } else { - // Assume that post will succeed later - ViewRootImpl.getRunQueue().postDelayed(action, delayMillis); - return true; + return attachInfo.mHandler.postDelayed(action, delayMillis); } - - return handler.postDelayed(action, delayMillis); + // Assume that post will succeed later + ViewRootImpl.getRunQueue().postDelayed(action, delayMillis); + return true; } /** @@ -8782,17 +8803,13 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal * (for instance, if the Runnable was not in the queue already.) */ public boolean removeCallbacks(Runnable action) { - Handler handler; - AttachInfo attachInfo = mAttachInfo; + final AttachInfo attachInfo = mAttachInfo; if (attachInfo != null) { - handler = attachInfo.mHandler; + attachInfo.mHandler.removeCallbacks(action); } else { // Assume that post will succeed later ViewRootImpl.getRunQueue().removeCallbacks(action); - return true; } - - handler.removeCallbacks(action); return true; } @@ -8841,12 +8858,9 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal public void postInvalidateDelayed(long delayMilliseconds) { // We try only with the AttachInfo because there's no point in invalidating // if we are not attached to our window - AttachInfo attachInfo = mAttachInfo; + final AttachInfo attachInfo = mAttachInfo; if (attachInfo != null) { - Message msg = Message.obtain(); - msg.what = AttachInfo.INVALIDATE_MSG; - msg.obj = this; - attachInfo.mHandler.sendMessageDelayed(msg, delayMilliseconds); + attachInfo.mViewRootImpl.dispatchInvalidateDelayed(this, delayMilliseconds); } } @@ -8869,7 +8883,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal // We try only with the AttachInfo because there's no point in invalidating // if we are not attached to our window - AttachInfo attachInfo = mAttachInfo; + final AttachInfo attachInfo = mAttachInfo; if (attachInfo != null) { final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.acquire(); info.target = this; @@ -8878,10 +8892,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal info.right = right; info.bottom = bottom; - final Message msg = Message.obtain(); - msg.what = AttachInfo.INVALIDATE_RECT_MSG; - msg.obj = info; - attachInfo.mHandler.sendMessageDelayed(msg, delayMilliseconds); + attachInfo.mViewRootImpl.dispatchInvalidateRectDelayed(info, delayMilliseconds); } } @@ -9566,10 +9577,6 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal // Clear any previous layout direction resolution mPrivateFlags2 &= ~LAYOUT_DIRECTION_RESOLVED_RTL; - // Reset also TextDirection as a change into LayoutDirection may impact the selected - // TextDirectionHeuristic - resetResolvedTextDirection(); - // Set resolved depending on layout direction switch (getLayoutDirection()) { case LAYOUT_DIRECTION_INHERIT: @@ -9606,14 +9613,15 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal } /** - * @hide + * Force padding depending on layout direction. */ - protected void resolvePadding() { + public void resolvePadding() { // If the user specified the absolute padding (either with android:padding or // android:paddingLeft/Top/Right/Bottom), use this padding, otherwise // use the default padding or the padding from the background drawable // (stored at this point in mPadding*) - switch (getResolvedLayoutDirection()) { + int resolvedLayoutDirection = getResolvedLayoutDirection(); + switch (resolvedLayoutDirection) { case LAYOUT_DIRECTION_RTL: // Start user padding override Right user padding. Otherwise, if Right user // padding is not defined, use the default Right padding. If Right user padding @@ -9649,6 +9657,18 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal mUserPaddingBottom = (mUserPaddingBottom >= 0) ? mUserPaddingBottom : mPaddingBottom; recomputePadding(); + onResolvePadding(resolvedLayoutDirection); + } + + /** + * Resolve padding depending on the layout direction. Subclasses that care about + * padding resolution should override this method. The default implementation does + * nothing. + * + * @param layoutDirection the direction of the layout + * + */ + public void onResolvePadding(int layoutDirection) { } /** @@ -9675,8 +9695,10 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal * @hide */ protected void resetResolvedLayoutDirection() { - // Reset the current View resolution + // Reset the layout direction resolution mPrivateFlags2 &= ~LAYOUT_DIRECTION_RESOLVED; + // Reset also the text direction + resetResolvedTextDirection(); } /** @@ -9715,13 +9737,12 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal } if (mAttachInfo != null) { - mAttachInfo.mHandler.removeMessages(AttachInfo.INVALIDATE_MSG, this); + mAttachInfo.mViewRootImpl.cancelInvalidate(this); } mCurrentAnimation = null; resetResolvedLayoutDirection(); - resetResolvedTextDirection(); } /** @@ -10950,6 +10971,346 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal } /** + * Utility function, called by draw(canvas, parent, drawingTime) to handle the less common + * case of an active Animation being run on the view. + */ + private boolean drawAnimation(ViewGroup parent, long drawingTime, + Animation a, boolean scalingRequired) { + Transformation invalidationTransform; + final int flags = parent.mGroupFlags; + final boolean initialized = a.isInitialized(); + if (!initialized) { + a.initialize(mRight - mLeft, mBottom - mTop, getWidth(), getHeight()); + a.initializeInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop); + onAnimationStart(); + } + + boolean more = a.getTransformation(drawingTime, parent.mChildTransformation, 1f); + if (scalingRequired && mAttachInfo.mApplicationScale != 1f) { + if (parent.mInvalidationTransformation == null) { + parent.mInvalidationTransformation = new Transformation(); + } + invalidationTransform = parent.mInvalidationTransformation; + a.getTransformation(drawingTime, invalidationTransform, 1f); + } else { + invalidationTransform = parent.mChildTransformation; + } + if (more) { + if (!a.willChangeBounds()) { + if ((flags & (parent.FLAG_OPTIMIZE_INVALIDATE | parent.FLAG_ANIMATION_DONE)) == + parent.FLAG_OPTIMIZE_INVALIDATE) { + parent.mGroupFlags |= parent.FLAG_INVALIDATE_REQUIRED; + } else if ((flags & parent.FLAG_INVALIDATE_REQUIRED) == 0) { + // The child need to draw an animation, potentially offscreen, so + // make sure we do not cancel invalidate requests + parent.mPrivateFlags |= DRAW_ANIMATION; + parent.invalidate(mLeft, mTop, mRight, mBottom); + } + } else { + if (parent.mInvalidateRegion == null) { + parent.mInvalidateRegion = new RectF(); + } + final RectF region = parent.mInvalidateRegion; + a.getInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop, region, + invalidationTransform); + + // The child need to draw an animation, potentially offscreen, so + // make sure we do not cancel invalidate requests + parent.mPrivateFlags |= DRAW_ANIMATION; + + final int left = mLeft + (int) region.left; + final int top = mTop + (int) region.top; + parent.invalidate(left, top, left + (int) (region.width() + .5f), + top + (int) (region.height() + .5f)); + } + } + return more; + } + + /** + * This method is called by ViewGroup.drawChild() to have each child view draw itself. + * This draw() method is an implementation detail and is not intended to be overridden or + * to be called from anywhere else other than ViewGroup.drawChild(). + */ + boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) { + boolean more = false; + final boolean childHasIdentityMatrix = hasIdentityMatrix(); + final int flags = parent.mGroupFlags; + + if ((flags & parent.FLAG_CLEAR_TRANSFORMATION) == parent.FLAG_CLEAR_TRANSFORMATION) { + parent.mChildTransformation.clear(); + parent.mGroupFlags &= ~parent.FLAG_CLEAR_TRANSFORMATION; + } + + Transformation transformToApply = null; + boolean concatMatrix = false; + + boolean scalingRequired = false; + boolean caching; + int layerType = parent.mDrawLayers ? getLayerType() : LAYER_TYPE_NONE; + + final boolean hardwareAccelerated = canvas.isHardwareAccelerated(); + if ((flags & parent.FLAG_CHILDREN_DRAWN_WITH_CACHE) == parent.FLAG_CHILDREN_DRAWN_WITH_CACHE || + (flags & parent.FLAG_ALWAYS_DRAWN_WITH_CACHE) == parent.FLAG_ALWAYS_DRAWN_WITH_CACHE) { + caching = true; + if (mAttachInfo != null) scalingRequired = mAttachInfo.mScalingRequired; + } else { + caching = (layerType != LAYER_TYPE_NONE) || hardwareAccelerated; + } + + final Animation a = getAnimation(); + if (a != null) { + more = drawAnimation(parent, drawingTime, a, scalingRequired); + concatMatrix = a.willChangeTransformationMatrix(); + transformToApply = parent.mChildTransformation; + } else if ((flags & parent.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) == + parent.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) { + final boolean hasTransform = + parent.getChildStaticTransformation(this, parent.mChildTransformation); + if (hasTransform) { + final int transformType = parent.mChildTransformation.getTransformationType(); + transformToApply = transformType != Transformation.TYPE_IDENTITY ? + parent.mChildTransformation : null; + concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0; + } + } + + concatMatrix |= !childHasIdentityMatrix; + + // Sets the flag as early as possible to allow draw() implementations + // to call invalidate() successfully when doing animations + mPrivateFlags |= DRAWN; + + if (!concatMatrix && canvas.quickReject(mLeft, mTop, mRight, mBottom, Canvas.EdgeType.BW) && + (mPrivateFlags & DRAW_ANIMATION) == 0) { + return more; + } + + if (hardwareAccelerated) { + // Clear INVALIDATED flag to allow invalidation to occur during rendering, but + // retain the flag's value temporarily in the mRecreateDisplayList flag + mRecreateDisplayList = (mPrivateFlags & INVALIDATED) == INVALIDATED; + mPrivateFlags &= ~INVALIDATED; + } + + computeScroll(); + + final int sx = mScrollX; + final int sy = mScrollY; + + DisplayList displayList = null; + Bitmap cache = null; + boolean hasDisplayList = false; + if (caching) { + if (!hardwareAccelerated) { + if (layerType != LAYER_TYPE_NONE) { + layerType = LAYER_TYPE_SOFTWARE; + buildDrawingCache(true); + } + cache = getDrawingCache(true); + } else { + switch (layerType) { + case LAYER_TYPE_SOFTWARE: + buildDrawingCache(true); + cache = getDrawingCache(true); + break; + case LAYER_TYPE_NONE: + // Delay getting the display list until animation-driven alpha values are + // set up and possibly passed on to the view + hasDisplayList = canHaveDisplayList(); + break; + } + } + } + + final boolean hasNoCache = cache == null || hasDisplayList; + final boolean offsetForScroll = cache == null && !hasDisplayList && + layerType != LAYER_TYPE_HARDWARE; + + final int restoreTo = canvas.save(); + if (offsetForScroll) { + canvas.translate(mLeft - sx, mTop - sy); + } else { + canvas.translate(mLeft, mTop); + if (scalingRequired) { + // mAttachInfo cannot be null, otherwise scalingRequired == false + final float scale = 1.0f / mAttachInfo.mApplicationScale; + canvas.scale(scale, scale); + } + } + + float alpha = getAlpha(); + if (transformToApply != null || alpha < 1.0f || !hasIdentityMatrix()) { + if (transformToApply != null || !childHasIdentityMatrix) { + int transX = 0; + int transY = 0; + + if (offsetForScroll) { + transX = -sx; + transY = -sy; + } + + if (transformToApply != null) { + if (concatMatrix) { + // Undo the scroll translation, apply the transformation matrix, + // then redo the scroll translate to get the correct result. + canvas.translate(-transX, -transY); + canvas.concat(transformToApply.getMatrix()); + canvas.translate(transX, transY); + parent.mGroupFlags |= parent.FLAG_CLEAR_TRANSFORMATION; + } + + float transformAlpha = transformToApply.getAlpha(); + if (transformAlpha < 1.0f) { + alpha *= transformToApply.getAlpha(); + parent.mGroupFlags |= parent.FLAG_CLEAR_TRANSFORMATION; + } + } + + if (!childHasIdentityMatrix) { + canvas.translate(-transX, -transY); + canvas.concat(getMatrix()); + canvas.translate(transX, transY); + } + } + + if (alpha < 1.0f) { + parent.mGroupFlags |= parent.FLAG_CLEAR_TRANSFORMATION; + if (hasNoCache) { + final int multipliedAlpha = (int) (255 * alpha); + if (!onSetAlpha(multipliedAlpha)) { + int layerFlags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG; + if ((flags & parent.FLAG_CLIP_CHILDREN) == parent.FLAG_CLIP_CHILDREN || + layerType != LAYER_TYPE_NONE) { + layerFlags |= Canvas.CLIP_TO_LAYER_SAVE_FLAG; + } + if (layerType == LAYER_TYPE_NONE) { + final int scrollX = hasDisplayList ? 0 : sx; + final int scrollY = hasDisplayList ? 0 : sy; + canvas.saveLayerAlpha(scrollX, scrollY, scrollX + mRight - mLeft, + scrollY + mBottom - mTop, multipliedAlpha, layerFlags); + } + } else { + // Alpha is handled by the child directly, clobber the layer's alpha + mPrivateFlags |= ALPHA_SET; + } + } + } + } else if ((mPrivateFlags & ALPHA_SET) == ALPHA_SET) { + onSetAlpha(255); + mPrivateFlags &= ~ALPHA_SET; + } + + if ((flags & parent.FLAG_CLIP_CHILDREN) == parent.FLAG_CLIP_CHILDREN) { + if (offsetForScroll) { + canvas.clipRect(sx, sy, sx + (mRight - mLeft), sy + (mBottom - mTop)); + } else { + if (!scalingRequired || cache == null) { + canvas.clipRect(0, 0, mRight - mLeft, mBottom - mTop); + } else { + canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight()); + } + } + } + + if (hasDisplayList) { + displayList = getDisplayList(); + if (!displayList.isValid()) { + // Uncommon, but possible. If a view is removed from the hierarchy during the call + // to getDisplayList(), the display list will be marked invalid and we should not + // try to use it again. + displayList = null; + hasDisplayList = false; + } + } + + if (hasNoCache) { + boolean layerRendered = false; + if (layerType == LAYER_TYPE_HARDWARE) { + final HardwareLayer layer = getHardwareLayer(); + if (layer != null && layer.isValid()) { + mLayerPaint.setAlpha((int) (alpha * 255)); + ((HardwareCanvas) canvas).drawHardwareLayer(layer, 0, 0, mLayerPaint); + layerRendered = true; + } else { + final int scrollX = hasDisplayList ? 0 : sx; + final int scrollY = hasDisplayList ? 0 : sy; + canvas.saveLayer(scrollX, scrollY, + scrollX + mRight - mLeft, scrollY + mBottom - mTop, mLayerPaint, + Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG); + } + } + + if (!layerRendered) { + if (!hasDisplayList) { + // Fast path for layouts with no backgrounds + if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) { + if (ViewDebug.TRACE_HIERARCHY) { + ViewDebug.trace(parent, ViewDebug.HierarchyTraceType.DRAW); + } + mPrivateFlags &= ~DIRTY_MASK; + dispatchDraw(canvas); + } else { + draw(canvas); + } + } else { + mPrivateFlags &= ~DIRTY_MASK; + ((HardwareCanvas) canvas).drawDisplayList(displayList, + mRight - mLeft, mBottom - mTop, null, flags); + } + } + } else if (cache != null) { + mPrivateFlags &= ~DIRTY_MASK; + Paint cachePaint; + + if (layerType == LAYER_TYPE_NONE) { + cachePaint = parent.mCachePaint; + if (cachePaint == null) { + cachePaint = new Paint(); + cachePaint.setDither(false); + parent.mCachePaint = cachePaint; + } + if (alpha < 1.0f) { + cachePaint.setAlpha((int) (alpha * 255)); + parent.mGroupFlags |= parent.FLAG_ALPHA_LOWER_THAN_ONE; + } else if ((flags & parent.FLAG_ALPHA_LOWER_THAN_ONE) == + parent.FLAG_ALPHA_LOWER_THAN_ONE) { + cachePaint.setAlpha(255); + parent.mGroupFlags &= ~parent.FLAG_ALPHA_LOWER_THAN_ONE; + } + } else { + cachePaint = mLayerPaint; + cachePaint.setAlpha((int) (alpha * 255)); + } + canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint); + } + + canvas.restoreToCount(restoreTo); + + if (a != null && !more) { + if (!hardwareAccelerated && !a.getFillAfter()) { + onSetAlpha(255); + } + parent.finishAnimatingView(this, a); + } + + if (more && hardwareAccelerated) { + // invalidation is the trigger to recreate display lists, so if we're using + // display lists to render, force an invalidate to allow the animation to + // continue drawing another frame + parent.invalidate(true); + if (a.hasAlpha() && (mPrivateFlags & ALPHA_SET) == ALPHA_SET) { + // alpha animations should cause the child to recreate its display list + invalidate(true); + } + } + + mRecreateDisplayList = false; + + return more; + } + + /** * Manually render this view (and all of its children) to the given Canvas. * The view must have already done a full layout before this function is * called. When implementing a view, implement @@ -11935,8 +12296,6 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal * @param top the top padding in pixels * @param end the end padding in pixels * @param bottom the bottom padding in pixels - * - * @hide */ public void setPaddingRelative(int start, int top, int end, int bottom) { mUserPaddingRelative = true; @@ -11991,8 +12350,6 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal * scrollbars as well. * * @return the start padding in pixels - * - * @hide */ public int getPaddingStart() { return (getResolvedLayoutDirection() == LAYOUT_DIRECTION_RTL) ? @@ -12016,8 +12373,6 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal * scrollbars as well. * * @return the end padding in pixels - * - * @hide */ public int getPaddingEnd() { return (getResolvedLayoutDirection() == LAYOUT_DIRECTION_RTL) ? @@ -12031,8 +12386,6 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal * @attr ref android.R.styleable#View_paddingEnd * * @return true if the padding is relative or false if it is not. - * - * @hide */ public boolean isPaddingRelative() { return mUserPaddingRelative; @@ -13764,8 +14117,6 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal * {@link #TEXT_DIRECTION_LTR}, * {@link #TEXT_DIRECTION_RTL}, * {@link #TEXT_DIRECTION_LOCALE}, - * - * @hide */ public int getTextDirection() { return mTextDirection; @@ -13782,8 +14133,6 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal * {@link #TEXT_DIRECTION_LTR}, * {@link #TEXT_DIRECTION_RTL}, * {@link #TEXT_DIRECTION_LOCALE}, - * - * @hide */ public void setTextDirection(int textDirection) { if (textDirection != mTextDirection) { @@ -13803,8 +14152,6 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal * {@link #TEXT_DIRECTION_LTR}, * {@link #TEXT_DIRECTION_RTL}, * {@link #TEXT_DIRECTION_LOCALE}, - * - * @hide */ public int getResolvedTextDirection() { if (mResolvedTextDirection == TEXT_DIRECTION_INHERIT) { @@ -13814,29 +14161,47 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal } /** - * Resolve the text direction. - * - * @hide + * Resolve the text direction. Will call {@link View#onResolveTextDirection()} when resolution + * is done. */ - protected void resolveTextDirection() { - if (mTextDirection != TEXT_DIRECTION_INHERIT) { - mResolvedTextDirection = mTextDirection; + public void resolveTextDirection() { + if (mResolvedTextDirection != TEXT_DIRECTION_INHERIT) { + // Resolution has already been done. return; } - if (mParent != null && mParent instanceof ViewGroup) { + if (mTextDirection != TEXT_DIRECTION_INHERIT) { + mResolvedTextDirection = mTextDirection; + } else if (mParent != null && mParent instanceof ViewGroup) { mResolvedTextDirection = ((ViewGroup) mParent).getResolvedTextDirection(); - return; + } else { + mResolvedTextDirection = TEXT_DIRECTION_FIRST_STRONG; } - mResolvedTextDirection = TEXT_DIRECTION_FIRST_STRONG; + onResolveTextDirection(); } /** - * Reset resolved text direction. Will be resolved during a call to getResolvedTextDirection(). - * - * @hide + * Called when text direction has been resolved. Subclasses that care about text direction + * resolution should override this method. The default implementation does nothing. */ - protected void resetResolvedTextDirection() { + public void onResolveTextDirection() { + } + + /** + * Reset resolved text direction. Text direction can be resolved with a call to + * getResolvedTextDirection(). Will call {@link View#onResetResolvedTextDirection()} when + * reset is done. + */ + public void resetResolvedTextDirection() { mResolvedTextDirection = TEXT_DIRECTION_INHERIT; + onResetResolvedTextDirection(); + } + + /** + * Called when text direction is reset. Subclasses that care about text direction reset should + * override this method and do a reset of the text direction of their children. The default + * implementation does nothing. + */ + public void onResetResolvedTextDirection() { } // @@ -14661,22 +15026,15 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal Canvas mCanvas; /** - * A Handler supplied by a view's {@link android.view.ViewRootImpl}. This - * handler can be used to pump events in the UI events queue. - */ - final Handler mHandler; - - /** - * Identifier for messages requesting the view to be invalidated. - * Such messages should be sent to {@link #mHandler}. + * The view root impl. */ - static final int INVALIDATE_MSG = 0x1; + final ViewRootImpl mViewRootImpl; /** - * Identifier for messages requesting the view to invalidate a region. - * Such messages should be sent to {@link #mHandler}. + * A Handler supplied by a view's {@link android.view.ViewRootImpl}. This + * handler can be used to pump events in the UI events queue. */ - static final int INVALIDATE_RECT_MSG = 0x2; + final Handler mHandler; /** * Temporary for use in computing invalidate rectangles while @@ -14706,10 +15064,11 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal * @param handler the events handler the view must use */ AttachInfo(IWindowSession session, IWindow window, - Handler handler, Callbacks effectPlayer) { + ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer) { mSession = session; mWindow = window; mWindowToken = window.asBinder(); + mViewRootImpl = viewRootImpl; mHandler = handler; mRootCallbacks = effectPlayer; } diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java index c1db5720e2f1..2a178451df9e 100644 --- a/core/java/android/view/ViewDebug.java +++ b/core/java/android/view/ViewDebug.java @@ -375,7 +375,7 @@ public class ViewDebug { } private static BufferedWriter sHierarchyTraces; - private static ViewRootImpl sHierarhcyRoot; + private static ViewRootImpl sHierarchyRoot; private static String sHierarchyTracePrefix; /** @@ -855,7 +855,7 @@ public class ViewDebug { return; } - if (sHierarhcyRoot != null) { + if (sHierarchyRoot != null) { throw new IllegalStateException("You must call stopHierarchyTracing() before running" + " a new trace!"); } @@ -874,7 +874,7 @@ public class ViewDebug { return; } - sHierarhcyRoot = (ViewRootImpl) view.getRootView().getParent(); + sHierarchyRoot = view.getViewRootImpl(); } /** @@ -896,7 +896,7 @@ public class ViewDebug { return; } - if (sHierarhcyRoot == null || sHierarchyTraces == null) { + if (sHierarchyRoot == null || sHierarchyTraces == null) { throw new IllegalStateException("You must call startHierarchyTracing() before" + " stopHierarchyTracing()!"); } @@ -921,7 +921,7 @@ public class ViewDebug { return; } - View view = sHierarhcyRoot.getView(); + View view = sHierarchyRoot.getView(); if (view instanceof ViewGroup) { ViewGroup group = (ViewGroup) view; dumpViewHierarchy(group, out, 0); @@ -932,7 +932,7 @@ public class ViewDebug { } } - sHierarhcyRoot = null; + sHierarchyRoot = null; } static void dispatchCommand(View view, String command, String parameters, diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index f9f546907c16..c68d77d6d3ac 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -77,6 +77,7 @@ import java.util.HashSet; * @attr ref android.R.styleable#ViewGroup_animateLayoutChanges */ public abstract class ViewGroup extends View implements ViewParent, ViewManager { + private static final String TAG = "ViewGroup"; private static final boolean DBG = false; @@ -103,18 +104,18 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager * A Transformation used when drawing children, to * apply on the child being drawn. */ - private final Transformation mChildTransformation = new Transformation(); + final Transformation mChildTransformation = new Transformation(); /** * Used to track the current invalidation region. */ - private RectF mInvalidateRegion; + RectF mInvalidateRegion; /** * A Transformation used to calculate a correct * invalidation area when the application is autoscaled. */ - private Transformation mInvalidationTransformation; + Transformation mInvalidationTransformation; // View currently under an ongoing drag private View mCurrentDragView; @@ -168,9 +169,14 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager */ protected int mGroupFlags; + /** + * NOTE: If you change the flags below make sure to reflect the changes + * the DisplayList class + */ + // When set, ViewGroup invalidates only the child's rectangle // Set by default - private static final int FLAG_CLIP_CHILDREN = 0x1; + static final int FLAG_CLIP_CHILDREN = 0x1; // When set, ViewGroup excludes the padding area from the invalidate rectangle // Set by default @@ -178,7 +184,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager // When set, dispatchDraw() will invoke invalidate(); this is set by drawChild() when // a child needs to be invalidated and FLAG_OPTIMIZE_INVALIDATE is set - private static final int FLAG_INVALIDATE_REQUIRED = 0x4; + static final int FLAG_INVALIDATE_REQUIRED = 0x4; // When set, dispatchDraw() will run the layout animation and unset the flag private static final int FLAG_RUN_ANIMATION = 0x8; @@ -186,7 +192,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager // When set, there is either no layout animation on the ViewGroup or the layout // animation is over // Set by default - private static final int FLAG_ANIMATION_DONE = 0x10; + static final int FLAG_ANIMATION_DONE = 0x10; // If set, this ViewGroup has padding; if unset there is no padding and we don't need // to clip it, even if FLAG_CLIP_TO_PADDING is set @@ -200,10 +206,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager // layout animation; this avoid clobbering the hierarchy // Automatically set when the layout animation starts, depending on the animation's // characteristics - private static final int FLAG_OPTIMIZE_INVALIDATE = 0x80; + static final int FLAG_OPTIMIZE_INVALIDATE = 0x80; // When set, the next call to drawChild() will clear mChildTransformation's matrix - private static final int FLAG_CLEAR_TRANSFORMATION = 0x100; + static final int FLAG_CLEAR_TRANSFORMATION = 0x100; // When set, this ViewGroup invokes mAnimationListener.onAnimationEnd() and removes // the children's Bitmap caches if necessary @@ -233,7 +239,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager // When the previous drawChild() invocation used an alpha value that was lower than // 1.0 and set it in mCachePaint - private static final int FLAG_ALPHA_LOWER_THAN_ONE = 0x1000; + static final int FLAG_ALPHA_LOWER_THAN_ONE = 0x1000; /** * When set, this ViewGroup's drawable states also include those @@ -244,13 +250,13 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager /** * When set, this ViewGroup tries to always draw its children using their drawing cache. */ - private static final int FLAG_ALWAYS_DRAWN_WITH_CACHE = 0x4000; + static final int FLAG_ALWAYS_DRAWN_WITH_CACHE = 0x4000; /** * When set, and if FLAG_ALWAYS_DRAWN_WITH_CACHE is not set, this ViewGroup will try to * draw its children with their drawing cache. */ - private static final int FLAG_CHILDREN_DRAWN_WITH_CACHE = 0x8000; + static final int FLAG_CHILDREN_DRAWN_WITH_CACHE = 0x8000; /** * When set, this group will go through its list of children to notify them of @@ -352,7 +358,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager private static final int ARRAY_CAPACITY_INCREMENT = 12; // Used to draw cached views - private Paint mCachePaint; + Paint mCachePaint; // Used to animate add/remove changes in layout private LayoutTransition mTransition; @@ -368,7 +374,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager // Indicates whether this container will use its children layers to draw @ViewDebug.ExportedProperty(category = "drawing") - private boolean mDrawLayers = true; + boolean mDrawLayers = true; + + // Indicates how many of this container's child subtrees contain transient state + @ViewDebug.ExportedProperty(category = "layout") + private int mChildCountWithTransientState = 0; public ViewGroup(Context context) { super(context); @@ -648,6 +658,38 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } /** + * Called when a child view has changed whether or not it is tracking transient state. + * + * @hide + */ + public void childHasTransientStateChanged(View child, boolean childHasTransientState) { + final boolean oldHasTransientState = hasTransientState(); + if (childHasTransientState) { + mChildCountWithTransientState++; + } else { + mChildCountWithTransientState--; + } + + final boolean newHasTransientState = hasTransientState(); + if (mParent != null && oldHasTransientState != newHasTransientState) { + try { + mParent.childHasTransientStateChanged(this, newHasTransientState); + } catch (AbstractMethodError e) { + Log.e(TAG, mParent.getClass().getSimpleName() + + " does not fully implement ViewParent", e); + } + } + } + + /** + * @hide + */ + @Override + public boolean hasTransientState() { + return mChildCountWithTransientState > 0 || super.hasTransientState(); + } + + /** * {@inheritDoc} */ @Override @@ -2620,336 +2662,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager * * @param canvas The canvas on which to draw the child * @param child Who to draw - * @param drawingTime The time at which draw is occuring + * @param drawingTime The time at which draw is occurring * @return True if an invalidate() was issued */ protected boolean drawChild(Canvas canvas, View child, long drawingTime) { - boolean more = false; - - final int cl = child.mLeft; - final int ct = child.mTop; - final int cr = child.mRight; - final int cb = child.mBottom; - - final boolean childHasIdentityMatrix = child.hasIdentityMatrix(); - - final int flags = mGroupFlags; - - if ((flags & FLAG_CLEAR_TRANSFORMATION) == FLAG_CLEAR_TRANSFORMATION) { - mChildTransformation.clear(); - mGroupFlags &= ~FLAG_CLEAR_TRANSFORMATION; - } - - Transformation transformToApply = null; - Transformation invalidationTransform; - final Animation a = child.getAnimation(); - boolean concatMatrix = false; - - boolean scalingRequired = false; - boolean caching; - int layerType = mDrawLayers ? child.getLayerType() : LAYER_TYPE_NONE; - - final boolean hardwareAccelerated = canvas.isHardwareAccelerated(); - if ((flags & FLAG_CHILDREN_DRAWN_WITH_CACHE) == FLAG_CHILDREN_DRAWN_WITH_CACHE || - (flags & FLAG_ALWAYS_DRAWN_WITH_CACHE) == FLAG_ALWAYS_DRAWN_WITH_CACHE) { - caching = true; - if (mAttachInfo != null) scalingRequired = mAttachInfo.mScalingRequired; - } else { - caching = (layerType != LAYER_TYPE_NONE) || hardwareAccelerated; - } - - if (a != null) { - final boolean initialized = a.isInitialized(); - if (!initialized) { - a.initialize(cr - cl, cb - ct, getWidth(), getHeight()); - a.initializeInvalidateRegion(0, 0, cr - cl, cb - ct); - child.onAnimationStart(); - } - - more = a.getTransformation(drawingTime, mChildTransformation, 1f); - if (scalingRequired && mAttachInfo.mApplicationScale != 1f) { - if (mInvalidationTransformation == null) { - mInvalidationTransformation = new Transformation(); - } - invalidationTransform = mInvalidationTransformation; - a.getTransformation(drawingTime, invalidationTransform, 1f); - } else { - invalidationTransform = mChildTransformation; - } - transformToApply = mChildTransformation; - - concatMatrix = a.willChangeTransformationMatrix(); - - if (more) { - if (!a.willChangeBounds()) { - if ((flags & (FLAG_OPTIMIZE_INVALIDATE | FLAG_ANIMATION_DONE)) == - FLAG_OPTIMIZE_INVALIDATE) { - mGroupFlags |= FLAG_INVALIDATE_REQUIRED; - } else if ((flags & FLAG_INVALIDATE_REQUIRED) == 0) { - // The child need to draw an animation, potentially offscreen, so - // make sure we do not cancel invalidate requests - mPrivateFlags |= DRAW_ANIMATION; - invalidate(cl, ct, cr, cb); - } - } else { - if (mInvalidateRegion == null) { - mInvalidateRegion = new RectF(); - } - final RectF region = mInvalidateRegion; - a.getInvalidateRegion(0, 0, cr - cl, cb - ct, region, invalidationTransform); - - // The child need to draw an animation, potentially offscreen, so - // make sure we do not cancel invalidate requests - mPrivateFlags |= DRAW_ANIMATION; - - final int left = cl + (int) region.left; - final int top = ct + (int) region.top; - invalidate(left, top, left + (int) (region.width() + .5f), - top + (int) (region.height() + .5f)); - } - } - } else if ((flags & FLAG_SUPPORT_STATIC_TRANSFORMATIONS) == - FLAG_SUPPORT_STATIC_TRANSFORMATIONS) { - final boolean hasTransform = getChildStaticTransformation(child, mChildTransformation); - if (hasTransform) { - final int transformType = mChildTransformation.getTransformationType(); - transformToApply = transformType != Transformation.TYPE_IDENTITY ? - mChildTransformation : null; - concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0; - } - } - - concatMatrix |= !childHasIdentityMatrix; - - // Sets the flag as early as possible to allow draw() implementations - // to call invalidate() successfully when doing animations - child.mPrivateFlags |= DRAWN; - - if (!concatMatrix && canvas.quickReject(cl, ct, cr, cb, Canvas.EdgeType.BW) && - (child.mPrivateFlags & DRAW_ANIMATION) == 0) { - return more; - } - - if (hardwareAccelerated) { - // Clear INVALIDATED flag to allow invalidation to occur during rendering, but - // retain the flag's value temporarily in the mRecreateDisplayList flag - child.mRecreateDisplayList = (child.mPrivateFlags & INVALIDATED) == INVALIDATED; - child.mPrivateFlags &= ~INVALIDATED; - } - - child.computeScroll(); - - final int sx = child.mScrollX; - final int sy = child.mScrollY; - - DisplayList displayList = null; - Bitmap cache = null; - boolean hasDisplayList = false; - if (caching) { - if (!hardwareAccelerated) { - if (layerType != LAYER_TYPE_NONE) { - layerType = LAYER_TYPE_SOFTWARE; - child.buildDrawingCache(true); - } - cache = child.getDrawingCache(true); - } else { - switch (layerType) { - case LAYER_TYPE_SOFTWARE: - child.buildDrawingCache(true); - cache = child.getDrawingCache(true); - break; - case LAYER_TYPE_NONE: - // Delay getting the display list until animation-driven alpha values are - // set up and possibly passed on to the view - hasDisplayList = child.canHaveDisplayList(); - break; - } - } - } - - final boolean hasNoCache = cache == null || hasDisplayList; - final boolean offsetForScroll = cache == null && !hasDisplayList && - layerType != LAYER_TYPE_HARDWARE; - - final int restoreTo = canvas.save(); - if (offsetForScroll) { - canvas.translate(cl - sx, ct - sy); - } else { - canvas.translate(cl, ct); - if (scalingRequired) { - // mAttachInfo cannot be null, otherwise scalingRequired == false - final float scale = 1.0f / mAttachInfo.mApplicationScale; - canvas.scale(scale, scale); - } - } - - float alpha = child.getAlpha(); - if (transformToApply != null || alpha < 1.0f || !child.hasIdentityMatrix()) { - if (transformToApply != null || !childHasIdentityMatrix) { - int transX = 0; - int transY = 0; - - if (offsetForScroll) { - transX = -sx; - transY = -sy; - } - - if (transformToApply != null) { - if (concatMatrix) { - // Undo the scroll translation, apply the transformation matrix, - // then redo the scroll translate to get the correct result. - canvas.translate(-transX, -transY); - canvas.concat(transformToApply.getMatrix()); - canvas.translate(transX, transY); - mGroupFlags |= FLAG_CLEAR_TRANSFORMATION; - } - - float transformAlpha = transformToApply.getAlpha(); - if (transformAlpha < 1.0f) { - alpha *= transformToApply.getAlpha(); - mGroupFlags |= FLAG_CLEAR_TRANSFORMATION; - } - } - - if (!childHasIdentityMatrix) { - canvas.translate(-transX, -transY); - canvas.concat(child.getMatrix()); - canvas.translate(transX, transY); - } - } - - if (alpha < 1.0f) { - mGroupFlags |= FLAG_CLEAR_TRANSFORMATION; - if (hasNoCache) { - final int multipliedAlpha = (int) (255 * alpha); - if (!child.onSetAlpha(multipliedAlpha)) { - int layerFlags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG; - if ((flags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN || - layerType != LAYER_TYPE_NONE) { - layerFlags |= Canvas.CLIP_TO_LAYER_SAVE_FLAG; - } - if (layerType == LAYER_TYPE_NONE) { - final int scrollX = hasDisplayList ? 0 : sx; - final int scrollY = hasDisplayList ? 0 : sy; - canvas.saveLayerAlpha(scrollX, scrollY, scrollX + cr - cl, - scrollY + cb - ct, multipliedAlpha, layerFlags); - } - } else { - // Alpha is handled by the child directly, clobber the layer's alpha - child.mPrivateFlags |= ALPHA_SET; - } - } - } - } else if ((child.mPrivateFlags & ALPHA_SET) == ALPHA_SET) { - child.onSetAlpha(255); - child.mPrivateFlags &= ~ALPHA_SET; - } - - if ((flags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) { - if (offsetForScroll) { - canvas.clipRect(sx, sy, sx + (cr - cl), sy + (cb - ct)); - } else { - if (!scalingRequired || cache == null) { - canvas.clipRect(0, 0, cr - cl, cb - ct); - } else { - canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight()); - } - } - } - - if (hasDisplayList) { - displayList = child.getDisplayList(); - if (!displayList.isValid()) { - // Uncommon, but possible. If a view is removed from the hierarchy during the call - // to getDisplayList(), the display list will be marked invalid and we should not - // try to use it again. - displayList = null; - hasDisplayList = false; - } - } - - if (hasNoCache) { - boolean layerRendered = false; - if (layerType == LAYER_TYPE_HARDWARE) { - final HardwareLayer layer = child.getHardwareLayer(); - if (layer != null && layer.isValid()) { - child.mLayerPaint.setAlpha((int) (alpha * 255)); - ((HardwareCanvas) canvas).drawHardwareLayer(layer, 0, 0, child.mLayerPaint); - layerRendered = true; - } else { - final int scrollX = hasDisplayList ? 0 : sx; - final int scrollY = hasDisplayList ? 0 : sy; - canvas.saveLayer(scrollX, scrollY, - scrollX + cr - cl, scrollY + cb - ct, child.mLayerPaint, - Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG); - } - } - - if (!layerRendered) { - if (!hasDisplayList) { - // Fast path for layouts with no backgrounds - if ((child.mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) { - if (ViewDebug.TRACE_HIERARCHY) { - ViewDebug.trace(this, ViewDebug.HierarchyTraceType.DRAW); - } - child.mPrivateFlags &= ~DIRTY_MASK; - child.dispatchDraw(canvas); - } else { - child.draw(canvas); - } - } else { - child.mPrivateFlags &= ~DIRTY_MASK; - ((HardwareCanvas) canvas).drawDisplayList(displayList, cr - cl, cb - ct, null); - } - } - } else if (cache != null) { - child.mPrivateFlags &= ~DIRTY_MASK; - Paint cachePaint; - - if (layerType == LAYER_TYPE_NONE) { - cachePaint = mCachePaint; - if (cachePaint == null) { - cachePaint = new Paint(); - cachePaint.setDither(false); - mCachePaint = cachePaint; - } - if (alpha < 1.0f) { - cachePaint.setAlpha((int) (alpha * 255)); - mGroupFlags |= FLAG_ALPHA_LOWER_THAN_ONE; - } else if ((flags & FLAG_ALPHA_LOWER_THAN_ONE) == FLAG_ALPHA_LOWER_THAN_ONE) { - cachePaint.setAlpha(255); - mGroupFlags &= ~FLAG_ALPHA_LOWER_THAN_ONE; - } - } else { - cachePaint = child.mLayerPaint; - cachePaint.setAlpha((int) (alpha * 255)); - } - canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint); - } - - canvas.restoreToCount(restoreTo); - - if (a != null && !more) { - if (!hardwareAccelerated && !a.getFillAfter()) { - child.onSetAlpha(255); - } - finishAnimatingView(child, a); - } - - if (more && hardwareAccelerated) { - // invalidation is the trigger to recreate display lists, so if we're using - // display lists to render, force an invalidate to allow the animation to - // continue drawing another frame - invalidate(true); - if (a.hasAlpha() && (child.mPrivateFlags & ALPHA_SET) == ALPHA_SET) { - // alpha animations should cause the child to recreate its display list - child.invalidate(true); - } - } - - child.mRecreateDisplayList = false; - - return more; + return child.draw(canvas, this, drawingTime); } /** @@ -3419,6 +3136,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager if ((child.mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE) { mGroupFlags |= FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE; } + + if (child.hasTransientState()) { + childHasTransientStateChanged(child, true); + } } private void addInArray(View child, int index) { @@ -3615,6 +3336,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager view.dispatchDetachedFromWindow(); } + if (view.hasTransientState()) { + childHasTransientStateChanged(view, false); + } + onViewRemoved(view); needGlobalAttributesUpdate(false); @@ -3686,6 +3411,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager view.dispatchDetachedFromWindow(); } + if (view.hasTransientState()) { + childHasTransientStateChanged(view, false); + } + needGlobalAttributesUpdate(false); onViewRemoved(view); @@ -3751,6 +3480,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager view.dispatchDetachedFromWindow(); } + if (view.hasTransientState()) { + childHasTransientStateChanged(view, false); + } + onViewRemoved(view); view.mParent = null; @@ -3791,6 +3524,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager child.dispatchDetachedFromWindow(); } + if (child.hasTransientState()) { + childHasTransientStateChanged(child, false); + } + onViewRemoved(child); } @@ -3929,130 +3666,136 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager // through final boolean drawAnimation = (child.mPrivateFlags & DRAW_ANIMATION) == DRAW_ANIMATION; - if (dirty == null) { - if (child.mLayerType != LAYER_TYPE_NONE) { - mPrivateFlags |= INVALIDATED; - mPrivateFlags &= ~DRAWING_CACHE_VALID; - child.mLocalDirtyRect.setEmpty(); - } - do { - View view = null; - if (parent instanceof View) { - view = (View) parent; - if (view.mLayerType != LAYER_TYPE_NONE) { - view.mLocalDirtyRect.setEmpty(); - if (view.getParent() instanceof View) { - final View grandParent = (View) view.getParent(); - grandParent.mPrivateFlags |= INVALIDATED; - grandParent.mPrivateFlags &= ~DRAWING_CACHE_VALID; + //noinspection PointlessBooleanExpression + if (!HardwareRenderer.RENDER_DIRTY_REGIONS) { + if (dirty == null) { + if (child.mLayerType != LAYER_TYPE_NONE) { + mPrivateFlags |= INVALIDATED; + mPrivateFlags &= ~DRAWING_CACHE_VALID; + child.mLocalDirtyRect.setEmpty(); + } + do { + View view = null; + if (parent instanceof View) { + view = (View) parent; + if (view.mLayerType != LAYER_TYPE_NONE) { + view.mLocalDirtyRect.setEmpty(); + if (view.getParent() instanceof View) { + final View grandParent = (View) view.getParent(); + grandParent.mPrivateFlags |= INVALIDATED; + grandParent.mPrivateFlags &= ~DRAWING_CACHE_VALID; + } + } + if ((view.mPrivateFlags & DIRTY_MASK) != 0) { + // already marked dirty - we're done + break; } } - if ((view.mPrivateFlags & DIRTY_MASK) != 0) { - // already marked dirty - we're done - break; - } - } - - if (drawAnimation) { - if (view != null) { - view.mPrivateFlags |= DRAW_ANIMATION; - } else if (parent instanceof ViewRootImpl) { - ((ViewRootImpl) parent).mIsAnimating = true; + + if (drawAnimation) { + if (view != null) { + view.mPrivateFlags |= DRAW_ANIMATION; + } else if (parent instanceof ViewRootImpl) { + ((ViewRootImpl) parent).mIsAnimating = true; + } } - } - - if (parent instanceof ViewRootImpl) { - ((ViewRootImpl) parent).invalidate(); - parent = null; - } else if (view != null) { - if ((view.mPrivateFlags & DRAWN) == DRAWN || - (view.mPrivateFlags & DRAWING_CACHE_VALID) == DRAWING_CACHE_VALID) { - view.mPrivateFlags &= ~DRAWING_CACHE_VALID; - view.mPrivateFlags |= DIRTY; - parent = view.mParent; - } else { + + if (parent instanceof ViewRootImpl) { + ((ViewRootImpl) parent).invalidate(); parent = null; + } else if (view != null) { + if ((view.mPrivateFlags & DRAWN) == DRAWN || + (view.mPrivateFlags & DRAWING_CACHE_VALID) == DRAWING_CACHE_VALID) { + view.mPrivateFlags &= ~DRAWING_CACHE_VALID; + view.mPrivateFlags |= DIRTY; + parent = view.mParent; + } else { + parent = null; + } } - } - } while (parent != null); - } else { - // Check whether the child that requests the invalidate is fully opaque - // Views being animated or transformed are not considered opaque because we may - // be invalidating their old position and need the parent to paint behind them. - Matrix childMatrix = child.getMatrix(); - final boolean isOpaque = child.isOpaque() && !drawAnimation && - child.getAnimation() == null && childMatrix.isIdentity(); - // Mark the child as dirty, using the appropriate flag - // Make sure we do not set both flags at the same time - int opaqueFlag = isOpaque ? DIRTY_OPAQUE : DIRTY; - - if (child.mLayerType != LAYER_TYPE_NONE) { - mPrivateFlags |= INVALIDATED; - mPrivateFlags &= ~DRAWING_CACHE_VALID; - child.mLocalDirtyRect.union(dirty); + } while (parent != null); } - final int[] location = attachInfo.mInvalidateChildLocation; - location[CHILD_LEFT_INDEX] = child.mLeft; - location[CHILD_TOP_INDEX] = child.mTop; - if (!childMatrix.isIdentity()) { - RectF boundingRect = attachInfo.mTmpTransformRect; - boundingRect.set(dirty); - //boundingRect.inset(-0.5f, -0.5f); - childMatrix.mapRect(boundingRect); - dirty.set((int) (boundingRect.left - 0.5f), - (int) (boundingRect.top - 0.5f), - (int) (boundingRect.right + 0.5f), - (int) (boundingRect.bottom + 0.5f)); - } + return; + } - do { - View view = null; - if (parent instanceof View) { - view = (View) parent; - if (view.mLayerType != LAYER_TYPE_NONE && - view.getParent() instanceof View) { - final View grandParent = (View) view.getParent(); - grandParent.mPrivateFlags |= INVALIDATED; - grandParent.mPrivateFlags &= ~DRAWING_CACHE_VALID; - } - } + // Check whether the child that requests the invalidate is fully opaque + // Views being animated or transformed are not considered opaque because we may + // be invalidating their old position and need the parent to paint behind them. + Matrix childMatrix = child.getMatrix(); + final boolean isOpaque = child.isOpaque() && !drawAnimation && + child.getAnimation() == null && childMatrix.isIdentity(); + // Mark the child as dirty, using the appropriate flag + // Make sure we do not set both flags at the same time + int opaqueFlag = isOpaque ? DIRTY_OPAQUE : DIRTY; - if (drawAnimation) { - if (view != null) { - view.mPrivateFlags |= DRAW_ANIMATION; - } else if (parent instanceof ViewRootImpl) { - ((ViewRootImpl) parent).mIsAnimating = true; - } + if (child.mLayerType != LAYER_TYPE_NONE) { + mPrivateFlags |= INVALIDATED; + mPrivateFlags &= ~DRAWING_CACHE_VALID; + child.mLocalDirtyRect.union(dirty); + } + + final int[] location = attachInfo.mInvalidateChildLocation; + location[CHILD_LEFT_INDEX] = child.mLeft; + location[CHILD_TOP_INDEX] = child.mTop; + if (!childMatrix.isIdentity()) { + RectF boundingRect = attachInfo.mTmpTransformRect; + boundingRect.set(dirty); + //boundingRect.inset(-0.5f, -0.5f); + childMatrix.mapRect(boundingRect); + dirty.set((int) (boundingRect.left - 0.5f), + (int) (boundingRect.top - 0.5f), + (int) (boundingRect.right + 0.5f), + (int) (boundingRect.bottom + 0.5f)); + } + + do { + View view = null; + if (parent instanceof View) { + view = (View) parent; + if (view.mLayerType != LAYER_TYPE_NONE && + view.getParent() instanceof View) { + final View grandParent = (View) view.getParent(); + grandParent.mPrivateFlags |= INVALIDATED; + grandParent.mPrivateFlags &= ~DRAWING_CACHE_VALID; } + } - // If the parent is dirty opaque or not dirty, mark it dirty with the opaque - // flag coming from the child that initiated the invalidate + if (drawAnimation) { if (view != null) { - if ((view.mViewFlags & FADING_EDGE_MASK) != 0 && - view.getSolidColor() == 0) { - opaqueFlag = DIRTY; - } - if ((view.mPrivateFlags & DIRTY_MASK) != DIRTY) { - view.mPrivateFlags = (view.mPrivateFlags & ~DIRTY_MASK) | opaqueFlag; - } + view.mPrivateFlags |= DRAW_ANIMATION; + } else if (parent instanceof ViewRootImpl) { + ((ViewRootImpl) parent).mIsAnimating = true; + } + } + + // If the parent is dirty opaque or not dirty, mark it dirty with the opaque + // flag coming from the child that initiated the invalidate + if (view != null) { + if ((view.mViewFlags & FADING_EDGE_MASK) != 0 && + view.getSolidColor() == 0) { + opaqueFlag = DIRTY; + } + if ((view.mPrivateFlags & DIRTY_MASK) != DIRTY) { + view.mPrivateFlags = (view.mPrivateFlags & ~DIRTY_MASK) | opaqueFlag; } + } - parent = parent.invalidateChildInParent(location, dirty); - if (view != null) { - // Account for transform on current parent - Matrix m = view.getMatrix(); - if (!m.isIdentity()) { - RectF boundingRect = attachInfo.mTmpTransformRect; - boundingRect.set(dirty); - m.mapRect(boundingRect); - dirty.set((int) boundingRect.left, (int) boundingRect.top, - (int) (boundingRect.right + 0.5f), - (int) (boundingRect.bottom + 0.5f)); - } + parent = parent.invalidateChildInParent(location, dirty); + if (view != null) { + // Account for transform on current parent + Matrix m = view.getMatrix(); + if (!m.isIdentity()) { + RectF boundingRect = attachInfo.mTmpTransformRect; + boundingRect.set(dirty); + m.mapRect(boundingRect); + dirty.set((int) (boundingRect.left - 0.5f), + (int) (boundingRect.top - 0.5f), + (int) (boundingRect.right + 0.5f), + (int) (boundingRect.bottom + 0.5f)); } - } while (parent != null); - } + } + } while (parent != null); } } @@ -4854,7 +4597,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager * @param view The view whose animation has finished * @param animation The animation, cannot be null */ - private void finishAnimatingView(final View view, Animation animation) { + void finishAnimatingView(final View view, Animation animation) { final ArrayList<View> disappearingChildren = mDisappearingChildren; if (disappearingChildren != null) { if (disappearingChildren.contains(view)) { @@ -5177,9 +4920,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } @Override - protected void resetResolvedTextDirection() { - super.resetResolvedTextDirection(); - + public void onResetResolvedTextDirection() { // Take care of resetting the children resolution too final int count = getChildCount(); for (int i = 0; i < count; i++) { @@ -5448,20 +5189,19 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager /** * The start margin in pixels of the child. - * - * @hide - * + * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value + * to this field. */ @ViewDebug.ExportedProperty(category = "layout") - protected int startMargin = DEFAULT_RELATIVE; + public int startMargin = DEFAULT_RELATIVE; /** * The end margin in pixels of the child. - * - * @hide + * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value + * to this field. */ @ViewDebug.ExportedProperty(category = "layout") - protected int endMargin = DEFAULT_RELATIVE; + public int endMargin = DEFAULT_RELATIVE; /** * The default start and end margin. @@ -5593,8 +5333,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart * * @return the start margin in pixels. - * - * @hide */ public int getMarginStart() { return startMargin; @@ -5606,8 +5344,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd * * @return the end margin in pixels. - * - * @hide */ public int getMarginEnd() { return endMargin; @@ -5620,8 +5356,6 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd * * @return true if either marginStart or marginEnd has been set - * - * @hide */ public boolean isMarginRelative() { return (startMargin != DEFAULT_RELATIVE) || (endMargin != DEFAULT_RELATIVE); diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java index 873d4bbd63fd..8395f1ba4b8a 100644 --- a/core/java/android/view/ViewParent.java +++ b/core/java/android/view/ViewParent.java @@ -261,4 +261,14 @@ public interface ViewParent { * @return True if the event was sent. */ public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event); + + /** + * Called when a child view now has or no longer is tracking transient state. + * + * @param child Child view whose state has changed + * @param hasTransientState true if this child has transient state + * + * @hide + */ + public void childHasTransientStateChanged(View child, boolean hasTransientState); } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 1930a5edd968..84ce2a404faf 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -61,6 +61,7 @@ import android.util.PoolableManager; import android.util.Pools; import android.util.Slog; import android.util.TypedValue; +import android.view.View.AttachInfo; import android.view.View.MeasureSpec; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityInteractionClient; @@ -96,9 +97,8 @@ import java.util.List; * {@hide} */ @SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"}) -public final class ViewRootImpl extends Handler implements ViewParent, - View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks, - Choreographer.OnDrawListener { +public final class ViewRootImpl implements ViewParent, + View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks { private static final String TAG = "ViewRootImpl"; private static final boolean DBG = false; private static final boolean LOCAL_LOGV = false; @@ -213,6 +213,7 @@ public final class ViewRootImpl extends Handler implements ViewParent, final Rect mVisRect; // used to retrieve visible rect of focused view. boolean mTraversalScheduled; + int mTraversalBarrier; long mLastTraversalFinishedTimeNanos; long mLastDrawFinishedTimeNanos; boolean mWillDrawSoon; @@ -380,7 +381,7 @@ public final class ViewRootImpl extends Handler implements ViewParent, new AccessibilityInteractionConnectionManager(); mAccessibilityManager.addAccessibilityStateChangeListener( mAccessibilityInteractionConnectionManager); - mAttachInfo = new View.AttachInfo(sWindowSession, mWindow, this, this); + mAttachInfo = new View.AttachInfo(sWindowSession, mWindow, this, mHandler, this); mViewConfiguration = ViewConfiguration.get(context); mDensity = context.getResources().getDisplayMetrics().densityDpi; mFallbackEventHandler = PolicyManager.makeNewFallbackEventHandler(context); @@ -463,8 +464,6 @@ public final class ViewRootImpl extends Handler implements ViewParent, public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) { synchronized (this) { if (mView == null) { - mChoreographer.addOnDrawListener(this); - mView = view; mFallbackEventHandler.setView(view); mWindowAttributes.copyFrom(attrs); @@ -841,16 +840,35 @@ public final class ViewRootImpl extends Handler implements ViewParent, public void scheduleTraversals() { if (!mTraversalScheduled) { mTraversalScheduled = true; - mChoreographer.scheduleDraw(); + mTraversalBarrier = mHandler.getLooper().postSyncBarrier(); + scheduleFrame(); } } public void unscheduleTraversals() { - mTraversalScheduled = false; + if (mTraversalScheduled) { + mTraversalScheduled = false; + mHandler.getLooper().removeSyncBarrier(mTraversalBarrier); + } } - @Override - public void onDraw() { + void scheduleFrame() { + if (!mFrameScheduled) { + mFrameScheduled = true; + mChoreographer.postDrawCallback(mFrameRunnable); + } + } + + void unscheduleFrame() { + unscheduleTraversals(); + + if (mFrameScheduled) { + mFrameScheduled = false; + mChoreographer.removeDrawCallback(mFrameRunnable); + } + } + + void doFrame() { if (mInputEventReceiver != null) { mInputEventReceiver.consumeBatchedInputEvents(); } @@ -858,6 +876,7 @@ public final class ViewRootImpl extends Handler implements ViewParent, if (mTraversalScheduled) { mTraversalScheduled = false; + mHandler.getLooper().removeSyncBarrier(mTraversalBarrier); doTraversal(); } } @@ -1919,7 +1938,7 @@ public final class ViewRootImpl extends Handler implements ViewParent, sFirstDrawComplete = true; final int count = sFirstDrawHandlers.size(); for (int i = 0; i< count; i++) { - post(sFirstDrawHandlers.get(i)); + mHandler.post(sFirstDrawHandlers.get(i)); } } } @@ -2376,7 +2395,7 @@ public final class ViewRootImpl extends Handler implements ViewParent, mInputChannel = null; } - mChoreographer.removeOnDrawListener(this); + unscheduleFrame(); } void updateConfiguration(Configuration config, boolean force) { @@ -2431,283 +2450,289 @@ public final class ViewRootImpl extends Handler implements ViewParent, } } - public final static int DIE = 1001; - public final static int RESIZED = 1002; - public final static int RESIZED_REPORT = 1003; - public final static int WINDOW_FOCUS_CHANGED = 1004; - public final static int DISPATCH_KEY = 1005; - public final static int DISPATCH_APP_VISIBILITY = 1008; - public final static int DISPATCH_GET_NEW_SURFACE = 1009; - public final static int IME_FINISHED_EVENT = 1010; - public final static int DISPATCH_KEY_FROM_IME = 1011; - public final static int FINISH_INPUT_CONNECTION = 1012; - public final static int CHECK_FOCUS = 1013; - public final static int CLOSE_SYSTEM_DIALOGS = 1014; - public final static int DISPATCH_DRAG_EVENT = 1015; - public final static int DISPATCH_DRAG_LOCATION_EVENT = 1016; - public final static int DISPATCH_SYSTEM_UI_VISIBILITY = 1017; - public final static int DISPATCH_GENERIC_MOTION = 1018; - public final static int UPDATE_CONFIGURATION = 1019; - public final static int DO_PERFORM_ACCESSIBILITY_ACTION = 1020; - public final static int DO_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID = 1021; - public final static int DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID = 1022; - public final static int DO_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT = 1023; - public final static int DO_PROCESS_INPUT_EVENTS = 1024; - - @Override - public String getMessageName(Message message) { - switch (message.what) { - case DIE: - return "DIE"; - case RESIZED: - return "RESIZED"; - case RESIZED_REPORT: - return "RESIZED_REPORT"; - case WINDOW_FOCUS_CHANGED: - return "WINDOW_FOCUS_CHANGED"; - case DISPATCH_KEY: - return "DISPATCH_KEY"; - case DISPATCH_APP_VISIBILITY: - return "DISPATCH_APP_VISIBILITY"; - case DISPATCH_GET_NEW_SURFACE: - return "DISPATCH_GET_NEW_SURFACE"; - case IME_FINISHED_EVENT: - return "IME_FINISHED_EVENT"; - case DISPATCH_KEY_FROM_IME: - return "DISPATCH_KEY_FROM_IME"; - case FINISH_INPUT_CONNECTION: - return "FINISH_INPUT_CONNECTION"; - case CHECK_FOCUS: - return "CHECK_FOCUS"; - case CLOSE_SYSTEM_DIALOGS: - return "CLOSE_SYSTEM_DIALOGS"; - case DISPATCH_DRAG_EVENT: - return "DISPATCH_DRAG_EVENT"; - case DISPATCH_DRAG_LOCATION_EVENT: - return "DISPATCH_DRAG_LOCATION_EVENT"; - case DISPATCH_SYSTEM_UI_VISIBILITY: - return "DISPATCH_SYSTEM_UI_VISIBILITY"; - case DISPATCH_GENERIC_MOTION: - return "DISPATCH_GENERIC_MOTION"; - case UPDATE_CONFIGURATION: - return "UPDATE_CONFIGURATION"; - case DO_PERFORM_ACCESSIBILITY_ACTION: - return "DO_PERFORM_ACCESSIBILITY_ACTION"; - case DO_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID: - return "DO_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID"; - case DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID: - return "DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID"; - case DO_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT: - return "DO_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT"; - case DO_PROCESS_INPUT_EVENTS: - return "DO_PROCESS_INPUT_EVENTS"; - } - return super.getMessageName(message); - } - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case View.AttachInfo.INVALIDATE_MSG: - ((View) msg.obj).invalidate(); - break; - case View.AttachInfo.INVALIDATE_RECT_MSG: - final View.AttachInfo.InvalidateInfo info = (View.AttachInfo.InvalidateInfo) msg.obj; - info.target.invalidate(info.left, info.top, info.right, info.bottom); - info.release(); - break; - case IME_FINISHED_EVENT: - handleImeFinishedEvent(msg.arg1, msg.arg2 != 0); - break; - case DO_PROCESS_INPUT_EVENTS: - mProcessInputEventsScheduled = false; - doProcessInputEvents(); - break; - case DISPATCH_APP_VISIBILITY: - handleAppVisibility(msg.arg1 != 0); - break; - case DISPATCH_GET_NEW_SURFACE: - handleGetNewSurface(); - break; - case RESIZED: - ResizedInfo ri = (ResizedInfo)msg.obj; + private final static int MSG_INVALIDATE = 1; + private final static int MSG_INVALIDATE_RECT = 2; + private final static int MSG_DIE = 3; + private final static int MSG_RESIZED = 4; + private final static int MSG_RESIZED_REPORT = 5; + private final static int MSG_WINDOW_FOCUS_CHANGED = 6; + private final static int MSG_DISPATCH_KEY = 7; + private final static int MSG_DISPATCH_APP_VISIBILITY = 8; + private final static int MSG_DISPATCH_GET_NEW_SURFACE = 9; + private final static int MSG_IME_FINISHED_EVENT = 10; + private final static int MSG_DISPATCH_KEY_FROM_IME = 11; + private final static int MSG_FINISH_INPUT_CONNECTION = 12; + private final static int MSG_CHECK_FOCUS = 13; + private final static int MSG_CLOSE_SYSTEM_DIALOGS = 14; + private final static int MSG_DISPATCH_DRAG_EVENT = 15; + private final static int MSG_DISPATCH_DRAG_LOCATION_EVENT = 16; + private final static int MSG_DISPATCH_SYSTEM_UI_VISIBILITY = 17; + private final static int MSG_UPDATE_CONFIGURATION = 18; + private final static int MSG_PERFORM_ACCESSIBILITY_ACTION = 19; + private final static int MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID = 20; + private final static int MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID = 21; + private final static int MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT = 22; + private final static int MSG_PROCESS_INPUT_EVENTS = 23; + + final class ViewRootHandler extends Handler { + @Override + public String getMessageName(Message message) { + switch (message.what) { + case MSG_INVALIDATE: + return "MSG_INVALIDATE"; + case MSG_INVALIDATE_RECT: + return "MSG_INVALIDATE_RECT"; + case MSG_DIE: + return "MSG_DIE"; + case MSG_RESIZED: + return "MSG_RESIZED"; + case MSG_RESIZED_REPORT: + return "MSG_RESIZED_REPORT"; + case MSG_WINDOW_FOCUS_CHANGED: + return "MSG_WINDOW_FOCUS_CHANGED"; + case MSG_DISPATCH_KEY: + return "MSG_DISPATCH_KEY"; + case MSG_DISPATCH_APP_VISIBILITY: + return "MSG_DISPATCH_APP_VISIBILITY"; + case MSG_DISPATCH_GET_NEW_SURFACE: + return "MSG_DISPATCH_GET_NEW_SURFACE"; + case MSG_IME_FINISHED_EVENT: + return "MSG_IME_FINISHED_EVENT"; + case MSG_DISPATCH_KEY_FROM_IME: + return "MSG_DISPATCH_KEY_FROM_IME"; + case MSG_FINISH_INPUT_CONNECTION: + return "MSG_FINISH_INPUT_CONNECTION"; + case MSG_CHECK_FOCUS: + return "MSG_CHECK_FOCUS"; + case MSG_CLOSE_SYSTEM_DIALOGS: + return "MSG_CLOSE_SYSTEM_DIALOGS"; + case MSG_DISPATCH_DRAG_EVENT: + return "MSG_DISPATCH_DRAG_EVENT"; + case MSG_DISPATCH_DRAG_LOCATION_EVENT: + return "MSG_DISPATCH_DRAG_LOCATION_EVENT"; + case MSG_DISPATCH_SYSTEM_UI_VISIBILITY: + return "MSG_DISPATCH_SYSTEM_UI_VISIBILITY"; + case MSG_UPDATE_CONFIGURATION: + return "MSG_UPDATE_CONFIGURATION"; + case MSG_PERFORM_ACCESSIBILITY_ACTION: + return "MSG_PERFORM_ACCESSIBILITY_ACTION"; + case MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID: + return "MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID"; + case MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID: + return "MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID"; + case MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT: + return "MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT"; + case MSG_PROCESS_INPUT_EVENTS: + return "MSG_PROCESS_INPUT_EVENTS"; + } + return super.getMessageName(message); + } - if (mWinFrame.width() == msg.arg1 && mWinFrame.height() == msg.arg2 - && mPendingContentInsets.equals(ri.coveredInsets) - && mPendingVisibleInsets.equals(ri.visibleInsets) - && ((ResizedInfo)msg.obj).newConfig == null) { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_INVALIDATE: + ((View) msg.obj).invalidate(); break; - } - // fall through... - case RESIZED_REPORT: - if (mAdded) { - Configuration config = ((ResizedInfo)msg.obj).newConfig; - if (config != null) { - updateConfiguration(config, false); - } - mWinFrame.left = 0; - mWinFrame.right = msg.arg1; - mWinFrame.top = 0; - mWinFrame.bottom = msg.arg2; - mPendingContentInsets.set(((ResizedInfo)msg.obj).coveredInsets); - mPendingVisibleInsets.set(((ResizedInfo)msg.obj).visibleInsets); - if (msg.what == RESIZED_REPORT) { - mReportNextDraw = true; + case MSG_INVALIDATE_RECT: + final View.AttachInfo.InvalidateInfo info = (View.AttachInfo.InvalidateInfo) msg.obj; + info.target.invalidate(info.left, info.top, info.right, info.bottom); + info.release(); + break; + case MSG_IME_FINISHED_EVENT: + handleImeFinishedEvent(msg.arg1, msg.arg2 != 0); + break; + case MSG_PROCESS_INPUT_EVENTS: + mProcessInputEventsScheduled = false; + doProcessInputEvents(); + break; + case MSG_DISPATCH_APP_VISIBILITY: + handleAppVisibility(msg.arg1 != 0); + break; + case MSG_DISPATCH_GET_NEW_SURFACE: + handleGetNewSurface(); + break; + case MSG_RESIZED: + ResizedInfo ri = (ResizedInfo)msg.obj; + + if (mWinFrame.width() == msg.arg1 && mWinFrame.height() == msg.arg2 + && mPendingContentInsets.equals(ri.coveredInsets) + && mPendingVisibleInsets.equals(ri.visibleInsets) + && ((ResizedInfo)msg.obj).newConfig == null) { + break; } + // fall through... + case MSG_RESIZED_REPORT: + if (mAdded) { + Configuration config = ((ResizedInfo)msg.obj).newConfig; + if (config != null) { + updateConfiguration(config, false); + } + mWinFrame.left = 0; + mWinFrame.right = msg.arg1; + mWinFrame.top = 0; + mWinFrame.bottom = msg.arg2; + mPendingContentInsets.set(((ResizedInfo)msg.obj).coveredInsets); + mPendingVisibleInsets.set(((ResizedInfo)msg.obj).visibleInsets); + if (msg.what == MSG_RESIZED_REPORT) { + mReportNextDraw = true; + } - if (mView != null) { - forceLayout(mView); + if (mView != null) { + forceLayout(mView); + } + requestLayout(); } - requestLayout(); - } - break; - case WINDOW_FOCUS_CHANGED: { - if (mAdded) { - boolean hasWindowFocus = msg.arg1 != 0; - mAttachInfo.mHasWindowFocus = hasWindowFocus; - - profileRendering(hasWindowFocus); + break; + case MSG_WINDOW_FOCUS_CHANGED: { + if (mAdded) { + boolean hasWindowFocus = msg.arg1 != 0; + mAttachInfo.mHasWindowFocus = hasWindowFocus; - if (hasWindowFocus) { - boolean inTouchMode = msg.arg2 != 0; - ensureTouchModeLocally(inTouchMode); + profileRendering(hasWindowFocus); - if (mAttachInfo.mHardwareRenderer != null && - mSurface != null && mSurface.isValid()) { - mFullRedrawNeeded = true; - try { - mAttachInfo.mHardwareRenderer.initializeIfNeeded(mWidth, mHeight, - mHolder); - } catch (Surface.OutOfResourcesException e) { - Log.e(TAG, "OutOfResourcesException locking surface", e); + if (hasWindowFocus) { + boolean inTouchMode = msg.arg2 != 0; + ensureTouchModeLocally(inTouchMode); + + if (mAttachInfo.mHardwareRenderer != null && + mSurface != null && mSurface.isValid()) { + mFullRedrawNeeded = true; try { - if (!sWindowSession.outOfMemory(mWindow)) { - Slog.w(TAG, "No processes killed for memory; killing self"); - Process.killProcess(Process.myPid()); + mAttachInfo.mHardwareRenderer.initializeIfNeeded(mWidth, mHeight, + mHolder); + } catch (Surface.OutOfResourcesException e) { + Log.e(TAG, "OutOfResourcesException locking surface", e); + try { + if (!sWindowSession.outOfMemory(mWindow)) { + Slog.w(TAG, "No processes killed for memory; killing self"); + Process.killProcess(Process.myPid()); + } + } catch (RemoteException ex) { } - } catch (RemoteException ex) { + // Retry in a bit. + sendMessageDelayed(obtainMessage(msg.what, msg.arg1, msg.arg2), 500); + return; } - // Retry in a bit. - sendMessageDelayed(obtainMessage(msg.what, msg.arg1, msg.arg2), 500); - return; } } - } - mLastWasImTarget = WindowManager.LayoutParams - .mayUseInputMethod(mWindowAttributes.flags); + mLastWasImTarget = WindowManager.LayoutParams + .mayUseInputMethod(mWindowAttributes.flags); - InputMethodManager imm = InputMethodManager.peekInstance(); - if (mView != null) { - if (hasWindowFocus && imm != null && mLastWasImTarget) { - imm.startGettingWindowFocus(mView); + InputMethodManager imm = InputMethodManager.peekInstance(); + if (mView != null) { + if (hasWindowFocus && imm != null && mLastWasImTarget) { + imm.startGettingWindowFocus(mView); + } + mAttachInfo.mKeyDispatchState.reset(); + mView.dispatchWindowFocusChanged(hasWindowFocus); } - mAttachInfo.mKeyDispatchState.reset(); - mView.dispatchWindowFocusChanged(hasWindowFocus); - } - // Note: must be done after the focus change callbacks, - // so all of the view state is set up correctly. - if (hasWindowFocus) { - if (imm != null && mLastWasImTarget) { - imm.onWindowFocus(mView, mView.findFocus(), - mWindowAttributes.softInputMode, - !mHasHadWindowFocus, mWindowAttributes.flags); - } - // Clear the forward bit. We can just do this directly, since - // the window manager doesn't care about it. - mWindowAttributes.softInputMode &= - ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION; - ((WindowManager.LayoutParams)mView.getLayoutParams()) - .softInputMode &= + // Note: must be done after the focus change callbacks, + // so all of the view state is set up correctly. + if (hasWindowFocus) { + if (imm != null && mLastWasImTarget) { + imm.onWindowFocus(mView, mView.findFocus(), + mWindowAttributes.softInputMode, + !mHasHadWindowFocus, mWindowAttributes.flags); + } + // Clear the forward bit. We can just do this directly, since + // the window manager doesn't care about it. + mWindowAttributes.softInputMode &= ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION; - mHasHadWindowFocus = true; - } + ((WindowManager.LayoutParams)mView.getLayoutParams()) + .softInputMode &= + ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION; + mHasHadWindowFocus = true; + } - if (hasWindowFocus && mView != null) { - sendAccessibilityEvents(); + if (hasWindowFocus && mView != null) { + sendAccessibilityEvents(); + } } + } break; + case MSG_DIE: + doDie(); + break; + case MSG_DISPATCH_KEY: { + KeyEvent event = (KeyEvent)msg.obj; + enqueueInputEvent(event, null, 0, true); + } break; + case MSG_DISPATCH_KEY_FROM_IME: { + if (LOCAL_LOGV) Log.v( + TAG, "Dispatching key " + + msg.obj + " from IME to " + mView); + KeyEvent event = (KeyEvent)msg.obj; + if ((event.getFlags()&KeyEvent.FLAG_FROM_SYSTEM) != 0) { + // The IME is trying to say this event is from the + // system! Bad bad bad! + //noinspection UnusedAssignment + event = KeyEvent.changeFlags(event, event.getFlags() & ~KeyEvent.FLAG_FROM_SYSTEM); + } + enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME, true); + } break; + case MSG_FINISH_INPUT_CONNECTION: { + InputMethodManager imm = InputMethodManager.peekInstance(); + if (imm != null) { + imm.reportFinishInputConnection((InputConnection)msg.obj); + } + } break; + case MSG_CHECK_FOCUS: { + InputMethodManager imm = InputMethodManager.peekInstance(); + if (imm != null) { + imm.checkFocus(); + } + } break; + case MSG_CLOSE_SYSTEM_DIALOGS: { + if (mView != null) { + mView.onCloseSystemDialogs((String)msg.obj); + } + } break; + case MSG_DISPATCH_DRAG_EVENT: + case MSG_DISPATCH_DRAG_LOCATION_EVENT: { + DragEvent event = (DragEvent)msg.obj; + event.mLocalState = mLocalDragState; // only present when this app called startDrag() + handleDragEvent(event); + } break; + case MSG_DISPATCH_SYSTEM_UI_VISIBILITY: { + handleDispatchSystemUiVisibilityChanged((SystemUiVisibilityInfo)msg.obj); + } break; + case MSG_UPDATE_CONFIGURATION: { + Configuration config = (Configuration)msg.obj; + if (config.isOtherSeqNewer(mLastConfiguration)) { + config = mLastConfiguration; + } + updateConfiguration(config, false); + } break; + case MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID: { + if (mView != null) { + getAccessibilityInteractionController() + .findAccessibilityNodeInfoByAccessibilityIdUiThread(msg); + } + } break; + case MSG_PERFORM_ACCESSIBILITY_ACTION: { + if (mView != null) { + getAccessibilityInteractionController() + .perfromAccessibilityActionUiThread(msg); + } + } break; + case MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID: { + if (mView != null) { + getAccessibilityInteractionController() + .findAccessibilityNodeInfoByViewIdUiThread(msg); + } + } break; + case MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT: { + if (mView != null) { + getAccessibilityInteractionController() + .findAccessibilityNodeInfosByTextUiThread(msg); + } + } break; } - } break; - case DIE: - doDie(); - break; - case DISPATCH_KEY: { - KeyEvent event = (KeyEvent)msg.obj; - enqueueInputEvent(event, null, 0, true); - } break; - case DISPATCH_KEY_FROM_IME: { - if (LOCAL_LOGV) Log.v( - TAG, "Dispatching key " - + msg.obj + " from IME to " + mView); - KeyEvent event = (KeyEvent)msg.obj; - if ((event.getFlags()&KeyEvent.FLAG_FROM_SYSTEM) != 0) { - // The IME is trying to say this event is from the - // system! Bad bad bad! - //noinspection UnusedAssignment - event = KeyEvent.changeFlags(event, event.getFlags() & ~KeyEvent.FLAG_FROM_SYSTEM); - } - enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME, true); - } break; - case FINISH_INPUT_CONNECTION: { - InputMethodManager imm = InputMethodManager.peekInstance(); - if (imm != null) { - imm.reportFinishInputConnection((InputConnection)msg.obj); - } - } break; - case CHECK_FOCUS: { - InputMethodManager imm = InputMethodManager.peekInstance(); - if (imm != null) { - imm.checkFocus(); - } - } break; - case CLOSE_SYSTEM_DIALOGS: { - if (mView != null) { - mView.onCloseSystemDialogs((String)msg.obj); - } - } break; - case DISPATCH_DRAG_EVENT: - case DISPATCH_DRAG_LOCATION_EVENT: { - DragEvent event = (DragEvent)msg.obj; - event.mLocalState = mLocalDragState; // only present when this app called startDrag() - handleDragEvent(event); - } break; - case DISPATCH_SYSTEM_UI_VISIBILITY: { - handleDispatchSystemUiVisibilityChanged((SystemUiVisibilityInfo)msg.obj); - } break; - case UPDATE_CONFIGURATION: { - Configuration config = (Configuration)msg.obj; - if (config.isOtherSeqNewer(mLastConfiguration)) { - config = mLastConfiguration; - } - updateConfiguration(config, false); - } break; - case DO_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID: { - if (mView != null) { - getAccessibilityInteractionController() - .findAccessibilityNodeInfoByAccessibilityIdUiThread(msg); - } - } break; - case DO_PERFORM_ACCESSIBILITY_ACTION: { - if (mView != null) { - getAccessibilityInteractionController() - .perfromAccessibilityActionUiThread(msg); - } - } break; - case DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID: { - if (mView != null) { - getAccessibilityInteractionController() - .findAccessibilityNodeInfoByViewIdUiThread(msg); - } - } break; - case DO_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT: { - if (mView != null) { - getAccessibilityInteractionController() - .findAccessibilityNodeInfosByTextUiThread(msg); - } - } break; } } + final ViewRootHandler mHandler = new ViewRootHandler(); /** * Something in the current window tells us we need to change the touch mode. For @@ -3674,7 +3699,7 @@ public final class ViewRootImpl extends Handler implements ViewParent, if (immediate) { doDie(); } else { - sendEmptyMessage(DIE); + mHandler.sendEmptyMessage(MSG_DIE); } } @@ -3711,8 +3736,8 @@ public final class ViewRootImpl extends Handler implements ViewParent, } public void requestUpdateConfiguration(Configuration config) { - Message msg = obtainMessage(UPDATE_CONFIGURATION, config); - sendMessage(msg); + Message msg = mHandler.obtainMessage(MSG_UPDATE_CONFIGURATION, config); + mHandler.sendMessage(msg); } private void destroyHardwareRenderer() { @@ -3724,10 +3749,15 @@ public final class ViewRootImpl extends Handler implements ViewParent, } void dispatchImeFinishedEvent(int seq, boolean handled) { - Message msg = obtainMessage(IME_FINISHED_EVENT); + Message msg = mHandler.obtainMessage(MSG_IME_FINISHED_EVENT); msg.arg1 = seq; msg.arg2 = handled ? 1 : 0; - sendMessage(msg); + mHandler.sendMessage(msg); + } + + public void dispatchFinishInputConnection(InputConnection connection) { + Message msg = mHandler.obtainMessage(MSG_FINISH_INPUT_CONNECTION, connection); + mHandler.sendMessage(msg); } public void dispatchResized(int w, int h, Rect coveredInsets, @@ -3736,7 +3766,7 @@ public final class ViewRootImpl extends Handler implements ViewParent, + " h=" + h + " coveredInsets=" + coveredInsets.toShortString() + " visibleInsets=" + visibleInsets.toShortString() + " reportDraw=" + reportDraw); - Message msg = obtainMessage(reportDraw ? RESIZED_REPORT :RESIZED); + Message msg = mHandler.obtainMessage(reportDraw ? MSG_RESIZED_REPORT :MSG_RESIZED); if (mTranslator != null) { mTranslator.translateRectInScreenToAppWindow(coveredInsets); mTranslator.translateRectInScreenToAppWindow(visibleInsets); @@ -3750,7 +3780,7 @@ public final class ViewRootImpl extends Handler implements ViewParent, ri.visibleInsets = new Rect(visibleInsets); ri.newConfig = newConfig; msg.obj = ri; - sendMessage(msg); + mHandler.sendMessage(msg); } /** @@ -3847,7 +3877,7 @@ public final class ViewRootImpl extends Handler implements ViewParent, private void scheduleProcessInputEvents() { if (!mProcessInputEventsScheduled) { mProcessInputEventsScheduled = true; - sendEmptyMessage(DO_PROCESS_INPUT_EVENTS); + mHandler.sendEmptyMessage(MSG_PROCESS_INPUT_EVENTS); } } @@ -3864,7 +3894,7 @@ public final class ViewRootImpl extends Handler implements ViewParent, // so we can clear the pending flag immediately. if (mProcessInputEventsScheduled) { mProcessInputEventsScheduled = false; - removeMessages(DO_PROCESS_INPUT_EVENTS); + mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS); } } @@ -3923,6 +3953,16 @@ public final class ViewRootImpl extends Handler implements ViewParent, } } + final class FrameRunnable implements Runnable { + @Override + public void run() { + mFrameScheduled = false; + doFrame(); + } + } + final FrameRunnable mFrameRunnable = new FrameRunnable(); + boolean mFrameScheduled; + final class WindowInputEventReceiver extends InputEventReceiver { public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) { super(inputChannel, looper); @@ -3935,52 +3975,74 @@ public final class ViewRootImpl extends Handler implements ViewParent, @Override public void onBatchedInputEventPending() { - mChoreographer.scheduleDraw(); + scheduleFrame(); } } WindowInputEventReceiver mInputEventReceiver; + public void dispatchInvalidateDelayed(View view, long delayMilliseconds) { + Message msg = mHandler.obtainMessage(MSG_INVALIDATE, view); + mHandler.sendMessageDelayed(msg, delayMilliseconds); + } + + public void cancelInvalidate(View view) { + mHandler.removeMessages(MSG_INVALIDATE, view); + } + + public void dispatchInvalidateRectDelayed(AttachInfo.InvalidateInfo info, + long delayMilliseconds) { + final Message msg = mHandler.obtainMessage(MSG_INVALIDATE_RECT, info); + mHandler.sendMessageDelayed(msg, delayMilliseconds); + } + public void dispatchKey(KeyEvent event) { - Message msg = obtainMessage(DISPATCH_KEY, event); - sendMessage(msg); + Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY, event); + msg.setAsynchronous(true); + mHandler.sendMessage(msg); + } + + public void dispatchKeyFromIme(KeyEvent event) { + Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY_FROM_IME, event); + msg.setAsynchronous(true); + mHandler.sendMessage(msg); } public void dispatchAppVisibility(boolean visible) { - Message msg = obtainMessage(DISPATCH_APP_VISIBILITY); + Message msg = mHandler.obtainMessage(MSG_DISPATCH_APP_VISIBILITY); msg.arg1 = visible ? 1 : 0; - sendMessage(msg); + mHandler.sendMessage(msg); } public void dispatchGetNewSurface() { - Message msg = obtainMessage(DISPATCH_GET_NEW_SURFACE); - sendMessage(msg); + Message msg = mHandler.obtainMessage(MSG_DISPATCH_GET_NEW_SURFACE); + mHandler.sendMessage(msg); } public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) { Message msg = Message.obtain(); - msg.what = WINDOW_FOCUS_CHANGED; + msg.what = MSG_WINDOW_FOCUS_CHANGED; msg.arg1 = hasFocus ? 1 : 0; msg.arg2 = inTouchMode ? 1 : 0; - sendMessage(msg); + mHandler.sendMessage(msg); } public void dispatchCloseSystemDialogs(String reason) { Message msg = Message.obtain(); - msg.what = CLOSE_SYSTEM_DIALOGS; + msg.what = MSG_CLOSE_SYSTEM_DIALOGS; msg.obj = reason; - sendMessage(msg); + mHandler.sendMessage(msg); } public void dispatchDragEvent(DragEvent event) { final int what; if (event.getAction() == DragEvent.ACTION_DRAG_LOCATION) { - what = DISPATCH_DRAG_LOCATION_EVENT; - removeMessages(what); + what = MSG_DISPATCH_DRAG_LOCATION_EVENT; + mHandler.removeMessages(what); } else { - what = DISPATCH_DRAG_EVENT; + what = MSG_DISPATCH_DRAG_EVENT; } - Message msg = obtainMessage(what, event); - sendMessage(msg); + Message msg = mHandler.obtainMessage(what, event); + mHandler.sendMessage(msg); } public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility, @@ -3990,7 +4052,14 @@ public final class ViewRootImpl extends Handler implements ViewParent, args.globalVisibility = globalVisibility; args.localValue = localValue; args.localChanges = localChanges; - sendMessage(obtainMessage(DISPATCH_SYSTEM_UI_VISIBILITY, args)); + mHandler.sendMessage(mHandler.obtainMessage(MSG_DISPATCH_SYSTEM_UI_VISIBILITY, args)); + } + + public void dispatchCheckFocus() { + if (!mHandler.hasMessages(MSG_CHECK_FOCUS)) { + // This will result in a call to checkFocus() below. + mHandler.sendEmptyMessage(MSG_CHECK_FOCUS); + } } /** @@ -4021,7 +4090,7 @@ public final class ViewRootImpl extends Handler implements ViewParent, } if (!mSendWindowContentChangedAccessibilityEvent.mIsPending) { mSendWindowContentChangedAccessibilityEvent.mIsPending = true; - postDelayed(mSendWindowContentChangedAccessibilityEvent, + mHandler.postDelayed(mSendWindowContentChangedAccessibilityEvent, ViewConfiguration.getSendRecurringAccessibilityEventsInterval()); } } @@ -4032,7 +4101,7 @@ public final class ViewRootImpl extends Handler implements ViewParent, */ private void removeSendWindowContentChangedCallback() { if (mSendWindowContentChangedAccessibilityEvent != null) { - removeCallbacks(mSendWindowContentChangedAccessibilityEvent); + mHandler.removeCallbacks(mSendWindowContentChangedAccessibilityEvent); } } @@ -4075,6 +4144,10 @@ public final class ViewRootImpl extends Handler implements ViewParent, return scrollToRectOrFocus(rectangle, immediate); } + public void childHasTransientStateChanged(View child, boolean hasTransientState) { + // Do nothing. + } + class TakenSurfaceHolder extends BaseSurfaceHolder { @Override public boolean onAllowLockCanvas() { @@ -4492,6 +4565,9 @@ public final class ViewRootImpl extends Handler implements ViewParent, } /** + * The run queue is used to enqueue pending work from Views when no Handler is + * attached. The work is executed during the next call to performTraversals on + * the thread. * @hide */ static final class RunQueue { @@ -4750,8 +4826,8 @@ public final class ViewRootImpl extends Handler implements ViewParent, long accessibilityNodeId, int interactionId, IAccessibilityInteractionConnectionCallback callback, int interrogatingPid, long interrogatingTid) { - Message message = Message.obtain(); - message.what = DO_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID; + Message message = mHandler.obtainMessage(); + message.what = MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID; message.arg1 = interrogatingPid; SomeArgs args = mPool.acquire(); args.argi1 = AccessibilityNodeInfo.getAccessibilityViewId(accessibilityNodeId); @@ -4765,11 +4841,10 @@ public final class ViewRootImpl extends Handler implements ViewParent, // client can handle the message to generate the result. if (interrogatingPid == Process.myPid() && interrogatingTid == Looper.getMainLooper().getThread().getId()) { - message.setTarget(ViewRootImpl.this); AccessibilityInteractionClient.getInstanceForThread( interrogatingTid).setSameThreadMessage(message); } else { - sendMessage(message); + mHandler.sendMessage(message); } } @@ -4808,8 +4883,8 @@ public final class ViewRootImpl extends Handler implements ViewParent, public void findAccessibilityNodeInfoByViewIdClientThread(long accessibilityNodeId, int viewId, int interactionId, IAccessibilityInteractionConnectionCallback callback, int interrogatingPid, long interrogatingTid) { - Message message = Message.obtain(); - message.what = DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID; + Message message = mHandler.obtainMessage(); + message.what = MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID; message.arg1 = AccessibilityNodeInfo.getAccessibilityViewId(accessibilityNodeId); SomeArgs args = mPool.acquire(); args.argi1 = viewId; @@ -4822,11 +4897,10 @@ public final class ViewRootImpl extends Handler implements ViewParent, // client can handle the message to generate the result. if (interrogatingPid == Process.myPid() && interrogatingTid == Looper.getMainLooper().getThread().getId()) { - message.setTarget(ViewRootImpl.this); AccessibilityInteractionClient.getInstanceForThread( interrogatingTid).setSameThreadMessage(message); } else { - sendMessage(message); + mHandler.sendMessage(message); } } @@ -4865,8 +4939,8 @@ public final class ViewRootImpl extends Handler implements ViewParent, String text, int interactionId, IAccessibilityInteractionConnectionCallback callback, int interrogatingPid, long interrogatingTid) { - Message message = Message.obtain(); - message.what = DO_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT; + Message message = mHandler.obtainMessage(); + message.what = MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT; SomeArgs args = mPool.acquire(); args.arg1 = text; args.argi1 = AccessibilityNodeInfo.getAccessibilityViewId(accessibilityNodeId); @@ -4880,11 +4954,10 @@ public final class ViewRootImpl extends Handler implements ViewParent, // client can handle the message to generate the result. if (interrogatingPid == Process.myPid() && interrogatingTid == Looper.getMainLooper().getThread().getId()) { - message.setTarget(ViewRootImpl.this); AccessibilityInteractionClient.getInstanceForThread( interrogatingTid).setSameThreadMessage(message); } else { - sendMessage(message); + mHandler.sendMessage(message); } } @@ -4951,8 +5024,8 @@ public final class ViewRootImpl extends Handler implements ViewParent, public void performAccessibilityActionClientThread(long accessibilityNodeId, int action, int interactionId, IAccessibilityInteractionConnectionCallback callback, int interogatingPid, long interrogatingTid) { - Message message = Message.obtain(); - message.what = DO_PERFORM_ACCESSIBILITY_ACTION; + Message message = mHandler.obtainMessage(); + message.what = MSG_PERFORM_ACCESSIBILITY_ACTION; message.arg1 = AccessibilityNodeInfo.getAccessibilityViewId(accessibilityNodeId); message.arg2 = AccessibilityNodeInfo.getVirtualDescendantId(accessibilityNodeId); SomeArgs args = mPool.acquire(); @@ -4966,11 +5039,10 @@ public final class ViewRootImpl extends Handler implements ViewParent, // client can handle the message to generate the result. if (interogatingPid == Process.myPid() && interrogatingTid == Looper.getMainLooper().getThread().getId()) { - message.setTarget(ViewRootImpl.this); AccessibilityInteractionClient.getInstanceForThread( interrogatingTid).setSameThreadMessage(message); } else { - sendMessage(message); + mHandler.sendMessage(message); } } diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java index bd02d62b64f2..89aba3ca1e83 100644 --- a/core/java/android/view/inputmethod/BaseInputConnection.java +++ b/core/java/android/view/inputmethod/BaseInputConnection.java @@ -19,7 +19,6 @@ package android.view.inputmethod; import android.content.Context; import android.content.res.TypedArray; import android.os.Bundle; -import android.os.Handler; import android.os.SystemClock; import android.text.Editable; import android.text.NoCopySpan; @@ -497,15 +496,14 @@ public class BaseInputConnection implements InputConnection { */ public boolean sendKeyEvent(KeyEvent event) { synchronized (mIMM.mH) { - Handler h = mTargetView != null ? mTargetView.getHandler() : null; - if (h == null) { + ViewRootImpl viewRootImpl = mTargetView != null ? mTargetView.getViewRootImpl() : null; + if (viewRootImpl == null) { if (mIMM.mServedView != null) { - h = mIMM.mServedView.getHandler(); + viewRootImpl = mIMM.mServedView.getViewRootImpl(); } } - if (h != null) { - h.sendMessage(h.obtainMessage(ViewRootImpl.DISPATCH_KEY_FROM_IME, - event)); + if (viewRootImpl != null) { + viewRootImpl.dispatchKeyFromIme(event); } } return false; diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index 7171b58482d4..c51d2440f893 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -336,6 +336,7 @@ public final class InputMethodManager { } case MSG_UNBIND: { final int sequence = msg.arg1; + boolean startInput = false; synchronized (mH) { if (mBindSequence == sequence) { if (false) { @@ -355,7 +356,12 @@ public final class InputMethodManager { if (mServedView != null && mServedView.isFocused()) { mServedConnecting = true; } + if (mActive) { + startInput = true; + } } + } + if (startInput) { startInputInner(); } return; @@ -669,11 +675,10 @@ public final class InputMethodManager { // longer the input target, so it can reset its state. Schedule // this call on its window's Handler so it will be on the correct // thread and outside of our lock. - Handler vh = mServedView.getHandler(); - if (vh != null) { + ViewRootImpl viewRootImpl = mServedView.getViewRootImpl(); + if (viewRootImpl != null) { // This will result in a call to reportFinishInputConnection() below. - vh.sendMessage(vh.obtainMessage(ViewRootImpl.FINISH_INPUT_CONNECTION, - mServedInputConnection)); + viewRootImpl.dispatchFinishInputConnection(mServedInputConnection); } } } @@ -1124,31 +1129,36 @@ public final class InputMethodManager { } static void scheduleCheckFocusLocked(View view) { - Handler vh = view.getHandler(); - if (vh != null && !vh.hasMessages(ViewRootImpl.CHECK_FOCUS)) { - // This will result in a call to checkFocus() below. - vh.sendMessage(vh.obtainMessage(ViewRootImpl.CHECK_FOCUS)); + ViewRootImpl viewRootImpl = view.getViewRootImpl(); + if (viewRootImpl != null) { + viewRootImpl.dispatchCheckFocus(); } } - + /** * @hide */ public void checkFocus() { + if (checkFocusNoStartInput()) { + startInputInner(); + } + } + + private boolean checkFocusNoStartInput() { // This is called a lot, so short-circuit before locking. if (mServedView == mNextServedView && !mNextServedNeedsStart) { - return; + return false; } InputConnection ic = null; synchronized (mH) { if (mServedView == mNextServedView && !mNextServedNeedsStart) { - return; + return false; } if (DEBUG) Log.v(TAG, "checkFocus: view=" + mServedView + " next=" + mNextServedView + " restart=" + mNextServedNeedsStart); - + mNextServedNeedsStart = false; if (mNextServedView == null) { finishInputLocked(); @@ -1156,22 +1166,22 @@ public final class InputMethodManager { // but no longer do. We should make sure the input method is // no longer shown, since it serves no purpose. closeCurrentInput(); - return; + return false; } - + ic = mServedInputConnection; - + mServedView = mNextServedView; mCurrentTextBoxAttribute = null; mCompletions = null; mServedConnecting = true; } - + if (ic != null) { ic.finishComposingText(); } - - startInputInner(); + + return true; } void closeCurrentInput() { @@ -1200,7 +1210,7 @@ public final class InputMethodManager { focusInLocked(focusedView != null ? focusedView : rootView); } - checkFocus(); + boolean startInput = checkFocusNoStartInput(); synchronized (mH) { try { @@ -1212,6 +1222,10 @@ public final class InputMethodManager { } catch (RemoteException e) { } } + + if (startInput) { + startInputInner(); + } } /** @hide */ diff --git a/core/java/android/webkit/CacheManager.java b/core/java/android/webkit/CacheManager.java index e21a02e8d8b7..e2342e9cadfc 100644 --- a/core/java/android/webkit/CacheManager.java +++ b/core/java/android/webkit/CacheManager.java @@ -37,18 +37,18 @@ import com.android.org.bouncycastle.crypto.Digest; import com.android.org.bouncycastle.crypto.digests.SHA1Digest; /** - * The class CacheManager provides the persistent cache of content that is - * received over the network. The component handles parsing of HTTP headers and - * utilizes the relevant cache headers to determine if the content should be - * stored and if so, how long it is valid for. Network requests are provided to - * this component and if they can not be resolved by the cache, the HTTP headers - * are attached, as appropriate, to the request for revalidation of content. The - * class also manages the cache size. - * - * CacheManager may only be used if your activity contains a WebView. - * + * Manages the HTTP cache used by an application's {@link WebView} instances. * @deprecated Access to the HTTP cache will be removed in a future release. */ +// The class CacheManager provides the persistent cache of content that is +// received over the network. The component handles parsing of HTTP headers and +// utilizes the relevant cache headers to determine if the content should be +// stored and if so, how long it is valid for. Network requests are provided to +// this component and if they can not be resolved by the cache, the HTTP headers +// are attached, as appropriate, to the request for revalidation of content. The +// class also manages the cache size. +// +// CacheManager may only be used if your activity contains a WebView. @Deprecated public final class CacheManager { @@ -87,10 +87,9 @@ public final class CacheManager { private static boolean mClearCacheOnInit = false; /** - * This class represents a resource retrieved from the HTTP cache. - * Instances of this class can be obtained by invoking the - * CacheManager.getCacheFile() method. - * + * Represents a resource stored in the HTTP cache. Instances of this class + * can be obtained by calling + * {@link CacheManager#getCacheFile CacheManager.getCacheFile(String, Map<String, String>))}. * @deprecated Access to the HTTP cache will be removed in a future release. */ @Deprecated @@ -114,64 +113,136 @@ public final class CacheManager { OutputStream outStream; File outFile; + /** + * Gets the status code of this cache entry. + * @return The status code of this cache entry + */ public int getHttpStatusCode() { return httpStatusCode; } + /** + * Gets the content length of this cache entry. + * @return The content length of this cache entry + */ public long getContentLength() { return contentLength; } + /** + * Gets the path of the file used to store the content of this cache + * entry, relative to the base directory of the cache. See + * {@link CacheManager#getCacheFileBaseDir CacheManager.getCacheFileBaseDir()}. + * @return The path of the file used to store this cache entry + */ public String getLocalPath() { return localPath; } + /** + * Gets the expiry date of this cache entry, expressed in milliseconds + * since midnight, January 1, 1970 UTC. + * @return The expiry date of this cache entry + */ public long getExpires() { return expires; } + /** + * Gets the expiry date of this cache entry, expressed as a string. + * @return The expiry date of this cache entry + * + */ public String getExpiresString() { return expiresString; } + /** + * Gets the date at which this cache entry was last modified, expressed + * as a string. + * @return The date at which this cache entry was last modified + */ public String getLastModified() { return lastModified; } + /** + * Gets the entity tag of this cache entry. + * @return The entity tag of this cache entry + */ public String getETag() { return etag; } + /** + * Gets the MIME type of this cache entry. + * @return The MIME type of this cache entry + */ public String getMimeType() { return mimeType; } + /** + * Gets the value of the HTTP 'Location' header with which this cache + * entry was received. + * @return The HTTP 'Location' header for this cache entry + */ public String getLocation() { return location; } + /** + * Gets the encoding of this cache entry. + * @return The encoding of this cache entry + */ public String getEncoding() { return encoding; } + /** + * Gets the value of the HTTP 'Content-Disposition' header with which + * this cache entry was received. + * @return The HTTP 'Content-Disposition' header for this cache entry + * + */ public String getContentDisposition() { return contentdisposition; } - // For out-of-package access to the underlying streams. + /** + * Gets the input stream to the content of this cache entry, to allow + * content to be read. See + * {@link CacheManager#getCacheFile CacheManager.getCacheFile(String, Map<String, String>)}. + * @return An input stream to the content of this cache entry + */ public InputStream getInputStream() { return inStream; } + /** + * Gets an output stream to the content of this cache entry, to allow + * content to be written. See + * {@link CacheManager#saveCacheFile CacheManager.saveCacheFile(String, CacheResult)}. + * @return An output stream to the content of this cache entry + */ + // Note that this is always null for objects returned by getCacheFile()! public OutputStream getOutputStream() { return outStream; } - // These fields can be set manually. + + /** + * Sets an input stream to the content of this cache entry. + * @param stream An input stream to the content of this cache entry + */ public void setInputStream(InputStream stream) { this.inStream = stream; } + /** + * Sets the encoding of this cache entry. + * @param encoding The encoding of this cache entry + */ public void setEncoding(String encoding) { this.encoding = encoding; } @@ -185,11 +256,10 @@ public final class CacheManager { } /** - * Initialize the CacheManager. - * - * Note that this is called automatically when a {@link android.webkit.WebView} is created. - * - * @param context The application context. + * Initializes the HTTP cache. This method must be called before any + * CacheManager methods are used. Note that this is called automatically + * when a {@link WebView} is created. + * @param context The application context */ static void init(Context context) { if (JniUtil.useChromiumHttpStack()) { @@ -240,15 +310,10 @@ public final class CacheManager { } /** - * Get the base directory of the cache. Together with the local path of the CacheResult, - * obtained from {@link android.webkit.CacheManager.CacheResult#getLocalPath}, this - * identifies the cache file. - * - * Cache files are not guaranteed to be in this directory before - * CacheManager#getCacheFile(String, Map<String, String>) is called. - * - * @return File The base directory of the cache. - * + * Gets the base directory in which the files used to store the contents of + * cache entries are placed. See + * {@link CacheManager.CacheResult#getLocalPath CacheManager.CacheResult.getLocalPath()}. + * @return The base directory of the cache * @deprecated Access to the HTTP cache will be removed in a future release. */ @Deprecated @@ -257,8 +322,7 @@ public final class CacheManager { } /** - * Sets whether the cache is disabled. - * + * Sets whether the HTTP cache should be disabled. * @param disabled Whether the cache should be disabled */ static void setCacheDisabled(boolean disabled) { @@ -274,10 +338,8 @@ public final class CacheManager { } /** - * Whether the cache is disabled. - * - * @return return Whether the cache is disabled - * + * Gets whether the HTTP cache is disabled. + * @return True if the HTTP cache is disabled * @deprecated Access to the HTTP cache will be removed in a future release. */ @Deprecated @@ -330,20 +392,23 @@ public final class CacheManager { return ret; } - // only called from WebCore Thread - // make sure to call startCacheTransaction/endCacheTransaction in pair /** - * @deprecated Always returns false. + * Starts a cache transaction. Returns true if this is the only running + * transaction. Otherwise, this transaction is nested inside currently + * running transactions and false is returned. + * @return True if this is the only running transaction + * @deprecated This method no longer has any effect and always returns false */ @Deprecated public static boolean startCacheTransaction() { return false; } - // only called from WebCore Thread - // make sure to call startCacheTransaction/endCacheTransaction in pair /** - * @deprecated Always returns false. + * Ends the innermost cache transaction and returns whether this was the + * only running transaction. + * @return True if this was the only running transaction + * @deprecated This method no longer has any effect and always returns false */ @Deprecated public static boolean endCacheTransaction() { @@ -351,15 +416,15 @@ public final class CacheManager { } /** - * Given a URL, returns the corresponding CacheResult if it exists, or null otherwise. - * - * The input stream of the CacheEntry object is initialized and opened and should be closed by - * the caller when access to the underlying file is no longer required. - * If a non-zero value is provided for the headers map, and the cache entry needs validation, - * HEADER_KEY_IFNONEMATCH or HEADER_KEY_IFMODIFIEDSINCE will be set in headers. - * - * @return The CacheResult for the given URL - * + * Gets the cache entry for the specified URL, or null if none is found. + * If a non-null value is provided for the HTTP headers map, and the cache + * entry needs validation, appropriate headers will be added to the map. + * The input stream of the CacheEntry object should be closed by the caller + * when access to the underlying file is no longer required. + * @param url The URL for which a cache entry is requested + * @param headers A map from HTTP header name to value, to be populated + * for the returned cache entry + * @return The cache entry for the specified URL * @deprecated Access to the HTTP cache will be removed in a future release. */ @Deprecated @@ -368,32 +433,32 @@ public final class CacheManager { return getCacheFile(url, 0, headers); } - static CacheResult getCacheFile(String url, long postIdentifier, - Map<String, String> headers) { - if (mDisabled) { + private static CacheResult getCacheFileChromiumHttpStack(String url) { + assert JniUtil.useChromiumHttpStack(); + + CacheResult result = nativeGetCacheResult(url); + if (result == null) { return null; } - - if (JniUtil.useChromiumHttpStack()) { - CacheResult result = nativeGetCacheResult(url); - if (result == null) { - return null; - } - // A temporary local file will have been created native side and localPath set - // appropriately. - File src = new File(mBaseDir, result.localPath); - try { - // Open the file here so that even if it is deleted, the content - // is still readable by the caller until close() is called. - result.inStream = new FileInputStream(src); - } catch (FileNotFoundException e) { - Log.v(LOGTAG, "getCacheFile(): Failed to open file: " + e); - // TODO: The files in the cache directory can be removed by the - // system. If it is gone, what should we do? - return null; - } - return result; + // A temporary local file will have been created native side and localPath set + // appropriately. + File src = new File(mBaseDir, result.localPath); + try { + // Open the file here so that even if it is deleted, the content + // is still readable by the caller until close() is called. + result.inStream = new FileInputStream(src); + } catch (FileNotFoundException e) { + Log.v(LOGTAG, "getCacheFile(): Failed to open file: " + e); + // TODO: The files in the cache directory can be removed by the + // system. If it is gone, what should we do? + return null; } + return result; + } + + private static CacheResult getCacheFileAndroidHttpStack(String url, + long postIdentifier) { + assert !JniUtil.useChromiumHttpStack(); String databaseKey = getDatabaseKey(url, postIdentifier); CacheResult result = mDataBase.getCache(databaseKey); @@ -419,6 +484,22 @@ public final class CacheManager { return null; } } + return result; + } + + static CacheResult getCacheFile(String url, long postIdentifier, + Map<String, String> headers) { + if (mDisabled) { + return null; + } + + CacheResult result = JniUtil.useChromiumHttpStack() ? + getCacheFileChromiumHttpStack(url) : + getCacheFileAndroidHttpStack(url, postIdentifier); + + if (result == null) { + return null; + } // A null value for headers is used by CACHE_MODE_CACHE_ONLY to imply // that we should provide the cache result even if it is expired. @@ -454,13 +535,8 @@ public final class CacheManager { * CacheResult, and is used to supply surrogate responses for URL * interception. * @return CacheResult for a given url - * @hide - hide createCacheFile since it has a parameter of type headers, which is - * in a hidden package. - * - * @deprecated Access to the HTTP cache will be removed in a future release. */ - @Deprecated - public static CacheResult createCacheFile(String url, int statusCode, + static CacheResult createCacheFile(String url, int statusCode, Headers headers, String mimeType, boolean forceCache) { if (JniUtil.useChromiumHttpStack()) { // This method is public but hidden. We break functionality. @@ -529,14 +605,15 @@ public final class CacheManager { } /** - * Save the info of a cache file for a given url to the CacheMap so that it - * can be reused later - * + * Adds a cache entry to the HTTP cache for the specicifed URL. Also closes + * the cache entry's output stream. + * @param url The URL for which the cache entry should be added + * @param cacheResult The cache entry to add * @deprecated Access to the HTTP cache will be removed in a future release. */ @Deprecated - public static void saveCacheFile(String url, CacheResult cacheRet) { - saveCacheFile(url, 0, cacheRet); + public static void saveCacheFile(String url, CacheResult cacheResult) { + saveCacheFile(url, 0, cacheResult); } static void saveCacheFile(String url, long postIdentifier, @@ -548,16 +625,26 @@ public final class CacheManager { } if (JniUtil.useChromiumHttpStack()) { - // This method is exposed in the public API but the API provides no way to obtain a - // new CacheResult object with a non-null output stream ... - // - CacheResult objects returned by getCacheFile() have a null output stream. - // - new CacheResult objects have a null output stream and no setter is provided. - // Since for the Android HTTP stack this method throws a null pointer exception in this - // case, this method is effectively useless from the point of view of the public API. - - // We should already have thrown an exception above, to maintain 'backward - // compatibility' with the Android HTTP stack. + // This method is exposed in the public API but the API provides no + // way to obtain a new CacheResult object with a non-null output + // stream ... + // - CacheResult objects returned by getCacheFile() have a null + // output stream. + // - new CacheResult objects have a null output stream and no + // setter is provided. + // Since this method throws a null pointer exception in this case, + // it is effectively useless from the point of view of the public + // API. + // + // With the Chromium HTTP stack we continue to throw the same + // exception for 'backwards compatibility' with the Android HTTP + // stack. + // + // This method is not used from within this package with the + // Chromium HTTP stack, and for public API use, we should already + // have thrown an exception above. assert false; + return; } if (!cacheRet.outFile.exists()) { diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java index 75ee33841203..95d927593799 100644 --- a/core/java/android/webkit/CallbackProxy.java +++ b/core/java/android/webkit/CallbackProxy.java @@ -920,7 +920,10 @@ class CallbackProxy extends Handler { if (PERF_PROBE) { mWebCoreThreadTime = SystemClock.currentThreadTimeMillis(); mWebCoreIdleTime = 0; - Network.getInstance(mContext).startTiming(); + if (!JniUtil.useChromiumHttpStack()) { + // Network is only used with the Android HTTP stack. + Network.getInstance(mContext).startTiming(); + } // un-comment this if PERF_PROBE is true // Looper.myQueue().setWaitCallback(mIdleCallback); } @@ -938,7 +941,10 @@ class CallbackProxy extends Handler { Log.d("WebCore", "WebCore thread used " + (SystemClock.currentThreadTimeMillis() - mWebCoreThreadTime) + " ms and idled " + mWebCoreIdleTime + " ms"); - Network.getInstance(mContext).stopTiming(); + if (!JniUtil.useChromiumHttpStack()) { + // Network is only used with the Android HTTP stack. + Network.getInstance(mContext).stopTiming(); + } } Message msg = obtainMessage(PAGE_FINISHED, url); sendMessage(msg); diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java index 9fa5593e7ad9..c500a7621fb3 100644 --- a/core/java/android/webkit/CookieManager.java +++ b/core/java/android/webkit/CookieManager.java @@ -34,7 +34,8 @@ import java.util.SortedSet; import java.util.TreeSet; /** - * CookieManager manages cookies according to RFC2109 spec. + * Manages the cookies used by an application's {@link WebView} instances. + * Cookies are manipulated according to RFC2109. */ public final class CookieManager { @@ -99,7 +100,7 @@ public final class CookieManager { private boolean mAcceptCookie = true; - private int pendingCookieOperations = 0; + private int mPendingCookieOperations = 0; /** * This contains a list of 2nd-level domains that aren't allowed to have @@ -246,12 +247,12 @@ public final class CookieManager { } /** - * Get a singleton CookieManager. If this is called before any - * {@link WebView} is created or outside of {@link WebView} context, the - * caller needs to call {@link CookieSyncManager#createInstance(Context)} + * Gets the singleton CookieManager instance. If this method is used + * before the application instantiates a {@link WebView} instance, + * {@link CookieSyncManager#createInstance(Context)} must be called * first. * - * @return CookieManager + * @return The singleton CookieManager instance */ public static synchronized CookieManager getInstance() { if (sRef == null) { @@ -261,8 +262,10 @@ public final class CookieManager { } /** - * Control whether cookie is enabled or disabled - * @param accept TRUE if accept cookie + * Sets whether the application's {@link WebView} instances should send and + * accept cookies. + * @param accept Whether {@link WebView} instances should send and accept + * cookies */ public synchronized void setAcceptCookie(boolean accept) { if (JniUtil.useChromiumHttpStack()) { @@ -274,8 +277,9 @@ public final class CookieManager { } /** - * Return whether cookie is enabled - * @return TRUE if accept cookie + * Gets whether the application's {@link WebView} instances send and accept + * cookies. + * @return True if {@link WebView} instances send and accept cookies */ public synchronized boolean acceptCookie() { if (JniUtil.useChromiumHttpStack()) { @@ -286,11 +290,13 @@ public final class CookieManager { } /** - * Set cookie for a given url. The old cookie with same host/path/name will - * be removed. The new cookie will be added if it is not expired or it does - * not have expiration which implies it is session cookie. - * @param url The url which cookie is set for - * @param value The value for set-cookie: in http response header + * Sets a cookie for the given URL. Any existing cookie with the same host, + * path and name will be replaced with the new cookie. The cookie being set + * must not have expired and must not be a session cookie, otherwise it + * will be ignored. + * @param url The URL for which the cookie is set + * @param value The cookie as a string, using the format of the + * 'Set-Cookie' HTTP response header */ public void setCookie(String url, String value) { if (JniUtil.useChromiumHttpStack()) { @@ -310,15 +316,13 @@ public final class CookieManager { } /** - * Set cookie for a given url. The old cookie with same host/path/name will - * be removed. The new cookie will be added if it is not expired or it does - * not have expiration which implies it is session cookie. - * @param url The url which cookie is set for - * @param value The value for set-cookie: in http response header - * @param privateBrowsing cookie jar to use - * @hide hiding private browsing + * See {@link setCookie(String, String)} + * @param url The URL for which the cookie is set + * @param value The value of the cookie, as a string, using the format of + * the 'Set-Cookie' HTTP response header + * @param privateBrowsing Whether to use the private browsing cookie jar */ - public void setCookie(String url, String value, boolean privateBrowsing) { + void setCookie(String url, String value, boolean privateBrowsing) { if (!JniUtil.useChromiumHttpStack()) { setCookie(url, value); return; @@ -336,15 +340,12 @@ public final class CookieManager { } /** - * Set cookie for a given uri. The old cookie with same host/path/name will - * be removed. The new cookie will be added if it is not expired or it does - * not have expiration which implies it is session cookie. - * @param uri The uri which cookie is set for - * @param value The value for set-cookie: in http response header - * @hide - hide this because it takes in a parameter of type WebAddress, - * a system private class. + * See {@link setCookie(String, String)} + * @param uri The WebAddress for which the cookie is set + * @param value The value of the cookie, as a string, using the format of + * the 'Set-Cookie' HTTP response header */ - public synchronized void setCookie(WebAddress uri, String value) { + synchronized void setCookie(WebAddress uri, String value) { if (JniUtil.useChromiumHttpStack()) { nativeSetCookie(uri.toString(), value, false); return; @@ -450,10 +451,10 @@ public final class CookieManager { } /** - * Get cookie(s) for a given url so that it can be set to "cookie:" in http - * request header. - * @param url The url needs cookie - * @return The cookies in the format of NAME=VALUE [; NAME=VALUE] + * Gets the cookies for the given URL. + * @param url The URL for which the cookies are requested + * @return value The cookies as a string, using the format of the 'Cookie' + * HTTP request header */ public String getCookie(String url) { if (JniUtil.useChromiumHttpStack()) { @@ -472,12 +473,12 @@ public final class CookieManager { } /** - * Get cookie(s) for a given url so that it can be set to "cookie:" in http - * request header. - * @param url The url needs cookie - * @param privateBrowsing cookie jar to use - * @return The cookies in the format of NAME=VALUE [; NAME=VALUE] - * @hide Private mode is not very well exposed for now + * See {@link getCookie(String)} + * @param url The URL for which the cookies are requested + * @param privateBrowsing Whether to use the private browsing cookie jar + * @return value The cookies as a string, using the format of the 'Cookie' + * HTTP request header + * @hide Used by Browser, no intention to publish. */ public String getCookie(String url, boolean privateBrowsing) { if (!JniUtil.useChromiumHttpStack()) { @@ -499,10 +500,10 @@ public final class CookieManager { /** * Get cookie(s) for a given uri so that it can be set to "cookie:" in http * request header. - * @param uri The uri needs cookie - * @return The cookies in the format of NAME=VALUE [; NAME=VALUE] - * @hide - hide this because it has a parameter of type WebAddress, which - * is a system private class. + * @param uri The WebAddress for which the cookies are requested + * @return value The cookies as a string, using the format of the 'Cookie' + * HTTP request header + * @hide Used by RequestHandle, no intention to publish. */ public synchronized String getCookie(WebAddress uri) { if (JniUtil.useChromiumHttpStack()) { @@ -579,13 +580,12 @@ public final class CookieManager { /** * Waits for pending operations to completed. - * {@hide} Too late to release publically. */ - public void waitForCookieOperationsToComplete() { + void waitForCookieOperationsToComplete() { // Note that this function is applicable for both the java // and native http stacks, and works correctly with either. synchronized (this) { - while (pendingCookieOperations > 0) { + while (mPendingCookieOperations > 0) { try { wait(); } catch (InterruptedException e) { } @@ -594,17 +594,18 @@ public final class CookieManager { } private synchronized void signalCookieOperationsComplete() { - pendingCookieOperations--; - assert pendingCookieOperations > -1; + mPendingCookieOperations--; + assert mPendingCookieOperations > -1; notify(); } private synchronized void signalCookieOperationsStart() { - pendingCookieOperations++; + mPendingCookieOperations++; } /** - * Remove all session cookies, which are cookies without expiration date + * Removes all session cookies, which are cookies without an expiration + * date. */ public void removeSessionCookie() { signalCookieOperationsStart(); @@ -643,7 +644,7 @@ public final class CookieManager { } /** - * Remove all cookies + * Removes all cookies. */ public void removeAllCookie() { if (JniUtil.useChromiumHttpStack()) { @@ -664,7 +665,8 @@ public final class CookieManager { } /** - * Return true if there are stored cookies. + * Gets whether there are stored cookies. + * @return True if there are stored cookies. */ public synchronized boolean hasCookies() { if (JniUtil.useChromiumHttpStack()) { @@ -675,9 +677,9 @@ public final class CookieManager { } /** - * Return true if there are stored cookies. - * @param privateBrowsing cookie jar to use - * @hide Hiding private mode + * See {@link hasCookies()}. + * @param privateBrowsing Whether to use the private browsing cookie jar + * @hide Used by Browser, no intention to publish. */ public synchronized boolean hasCookies(boolean privateBrowsing) { if (!JniUtil.useChromiumHttpStack()) { @@ -688,7 +690,7 @@ public final class CookieManager { } /** - * Remove all expired cookies + * Removes all expired cookies. */ public void removeExpiredCookie() { if (JniUtil.useChromiumHttpStack()) { @@ -733,7 +735,10 @@ public final class CookieManager { } /** - * Whether cookies are accepted for file scheme URLs. + * Gets whether the application's {@link WebView} instances send and accept + * cookies for file scheme URLs. + * @return True if {@link WebView} instances send and accept cookies for + * file scheme URLs */ public static boolean allowFileSchemeCookies() { if (JniUtil.useChromiumHttpStack()) { @@ -744,13 +749,14 @@ public final class CookieManager { } /** - * Sets whether cookies are accepted for file scheme URLs. - * - * Use of cookies with file scheme URLs is potentially insecure. Do not use this feature unless - * you can be sure that no unintentional sharing of cookie data can take place. + * Sets whether the application's {@link WebView} instances should send and + * accept cookies for file scheme URLs. + * Use of cookies with file scheme URLs is potentially insecure. Do not use + * this feature unless you can be sure that no unintentional sharing of + * cookie data can take place. * <p> - * Note that calls to this method will have no effect if made after a WebView or CookieManager - * instance has been created. + * Note that calls to this method will have no effect if made after a + * {@link WebView} or CookieManager instance has been created. */ public static void setAcceptFileSchemeCookies(boolean accept) { if (JniUtil.useChromiumHttpStack()) { diff --git a/core/java/android/webkit/LoadListener.java b/core/java/android/webkit/LoadListener.java index 37e8bc090837..4d7ade517a60 100644 --- a/core/java/android/webkit/LoadListener.java +++ b/core/java/android/webkit/LoadListener.java @@ -985,7 +985,7 @@ class LoadListener extends Handler implements EventHandler { * be used. This is just for forward/back navigation to a POST * URL. */ - static boolean willLoadFromCache(String url, long identifier) { + private static boolean willLoadFromCache(String url, long identifier) { assert !JniUtil.useChromiumHttpStack(); boolean inCache = CacheManager.getCacheFile(url, identifier, null) != null; diff --git a/core/java/android/webkit/WebResourceResponse.java b/core/java/android/webkit/WebResourceResponse.java index e786838615a6..24e0d11b0562 100644 --- a/core/java/android/webkit/WebResourceResponse.java +++ b/core/java/android/webkit/WebResourceResponse.java @@ -21,9 +21,9 @@ import android.net.http.Headers; import java.io.InputStream; /** - * A WebResourceResponse is return by - * {@link WebViewClient#shouldInterceptRequest} and - * contains the response information for a particular resource. + * Encapsulates a resource response. Applications can return an instance of this + * class from {@link WebViewClient#shouldInterceptRequest} to provide a custom + * response when the WebView requests a particular resource. */ public class WebResourceResponse { @@ -50,11 +50,13 @@ public class WebResourceResponse { private InputStream mInputStream; /** - * Construct a response with the given mime type, encoding, and data. - * @param mimeType The mime type of the data (i.e. text/html). - * @param encoding The encoding of the bytes read from data. - * @param data An InputStream for reading custom data. The implementation - * must implement {@link InputStream#read(byte[])}. + * Constructs a resource response with the given MIME type, encoding, and + * input stream. Callers must implement + * {@link InputStream#read(byte[]) InputStream.read(byte[])} for the input + * stream. + * @param mimeType The resource response's MIME type, for example text/html + * @param encoding The resource response's encoding + * @param data The input stream that provides the resource response's data */ public WebResourceResponse(String mimeType, String encoding, InputStream data) { @@ -64,47 +66,50 @@ public class WebResourceResponse { } /** - * Set the mime type of the response data (i.e. text/html). - * @param mimeType + * Sets the resource response's MIME type, for example text/html. + * @param mimeType The resource response's MIME type */ public void setMimeType(String mimeType) { mMimeType = mimeType; } /** - * @see #setMimeType + * Gets the resource response's MIME type. + * @return The resource response's MIME type */ public String getMimeType() { return mMimeType; } /** - * Set the encoding of the response data (i.e. utf-8). This will be used to - * decode the raw bytes from the input stream. - * @param encoding + * Sets the resource response's encoding, for example UTF-8. This is used + * to decode the data from the input stream. + * @param encoding The resource response's encoding */ public void setEncoding(String encoding) { mEncoding = encoding; } /** - * @see #setEncoding + * Gets the resource response's encoding. + * @return The resource response's encoding */ public String getEncoding() { return mEncoding; } /** - * Set the input stream containing the data for this resource. - * @param data An InputStream for reading custom data. The implementation - * must implement {@link InputStream#read(byte[])}. + * Sets the input stream that provides the resource respone's data. Callers + * must implement {@link InputStream#read(byte[]) InputStream.read(byte[])}. + * @param data The input stream that provides the resource response's data */ public void setData(InputStream data) { mInputStream = data; } /** - * @see #setData + * Gets the input stream that provides the resource respone's data. + * @return The input stream that provides the resource response's data */ public InputStream getData() { return mInputStream; diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index fbafc648fb20..a35106a67833 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -59,6 +59,7 @@ import android.os.Message; import android.os.StrictMode; import android.os.SystemClock; import android.provider.Settings; +import android.security.KeyChain; import android.speech.tts.TextToSpeech; import android.text.Editable; import android.text.InputType; @@ -1303,6 +1304,7 @@ public class WebView extends AbsoluteLayout init(); setupPackageListener(context); setupProxyListener(context); + setupTrustStorageListener(context); updateMultiTouchSupport(context); if (privateBrowsing) { @@ -1312,6 +1314,41 @@ public class WebView extends AbsoluteLayout mAutoFillData = new WebViewCore.AutoFillData(); } + private static class TrustStorageListener extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(KeyChain.ACTION_STORAGE_CHANGED)) { + handleCertTrustChanged(); + } + } + } + private static TrustStorageListener sTrustStorageListener; + + /** + * Handles update to the trust storage. + */ + private static void handleCertTrustChanged() { + // send a message for indicating trust storage change + WebViewCore.sendStaticMessage(EventHub.TRUST_STORAGE_UPDATED, null); + } + + /* + * @param context This method expects this to be a valid context. + */ + private static void setupTrustStorageListener(Context context) { + if (sTrustStorageListener != null ) { + return; + } + IntentFilter filter = new IntentFilter(); + filter.addAction(KeyChain.ACTION_STORAGE_CHANGED); + sTrustStorageListener = new TrustStorageListener(); + Intent current = + context.getApplicationContext().registerReceiver(sTrustStorageListener, filter); + if (current != null) { + handleCertTrustChanged(); + } + } + private static class ProxyReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { @@ -1703,7 +1740,7 @@ public class WebView extends AbsoluteLayout } /** - * returns the height of the titlebarview (if any). Does not care about + * Returns the height (in pixels) of the embedded title bar (if any). Does not care about * scrolling * @hide */ @@ -1712,12 +1749,15 @@ public class WebView extends AbsoluteLayout } /** - * Return the amount of the titlebarview (if any) that is visible + * Return the visible height (in pixels) of the embedded title bar (if any). * + * @return This method is obsolete and always returns 0. * @deprecated This method is now obsolete. */ @Deprecated public int getVisibleTitleHeight() { + // Actually, this method returns the height of the embedded title bar if one is set via the + // hidden setEmbeddedTitleBar method. checkThread(); return getVisibleTitleHeightImpl(); } @@ -4803,7 +4843,9 @@ public class WebView extends AbsoluteLayout if (layer == 0 || isPictureAfterFirstLayout) { mWebViewCore.resumeWebKitDraw(); } else if (queueFull) { - mWebViewCore.pauseWebKitDraw(); + // temporarily disable webkit draw throttling + // TODO: re-enable + // mWebViewCore.pauseWebKitDraw(); } if (mHTML5VideoViewProxy != null) { @@ -5553,7 +5595,7 @@ public class WebView extends AbsoluteLayout return false; } - if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) { + if (isEnterActionKey(keyCode)) { switchOutDrawHistory(); boolean wantsKeyEvents = nativeCursorNodePointer() == 0 || nativeCursorWantsKeyEvents(); @@ -5702,33 +5744,35 @@ public class WebView extends AbsoluteLayout return true; // discard press if copy in progress } - // perform the single click - Rect visibleRect = sendOurVisibleRect(); - // Note that sendOurVisibleRect calls viewToContent, so the - // coordinates should be in content coordinates. - if (!nativeCursorIntersects(visibleRect)) { - return false; - } - WebViewCore.CursorData data = cursorData(); - mWebViewCore.sendMessage(EventHub.SET_MOVE_MOUSE, data); - playSoundEffect(SoundEffectConstants.CLICK); - if (nativeCursorIsTextInput()) { - rebuildWebTextView(); - centerKeyPressOnTextField(); - if (inEditingMode()) { - mWebTextView.setDefaultSelection(); + if (!sDisableNavcache) { + // perform the single click + Rect visibleRect = sendOurVisibleRect(); + // Note that sendOurVisibleRect calls viewToContent, so the + // coordinates should be in content coordinates. + if (!nativeCursorIntersects(visibleRect)) { + return false; + } + WebViewCore.CursorData data = cursorData(); + mWebViewCore.sendMessage(EventHub.SET_MOVE_MOUSE, data); + playSoundEffect(SoundEffectConstants.CLICK); + if (nativeCursorIsTextInput()) { + rebuildWebTextView(); + centerKeyPressOnTextField(); + if (inEditingMode()) { + mWebTextView.setDefaultSelection(); + } + return true; + } + clearTextEntry(); + nativeShowCursorTimed(); + if (mCallbackProxy.uiOverrideUrlLoading(nativeCursorText())) { + return true; + } + if (nativeCursorNodePointer() != 0 && !nativeCursorWantsKeyEvents()) { + mWebViewCore.sendMessage(EventHub.CLICK, data.mFrame, + nativeCursorNodePointer()); + return true; } - return true; - } - clearTextEntry(); - nativeShowCursorTimed(); - if (mCallbackProxy.uiOverrideUrlLoading(nativeCursorText())) { - return true; - } - if (nativeCursorNodePointer() != 0 && !nativeCursorWantsKeyEvents()) { - mWebViewCore.sendMessage(EventHub.CLICK, data.mFrame, - nativeCursorNodePointer()); - return true; } } @@ -6111,7 +6155,7 @@ public class WebView extends AbsoluteLayout calcOurContentVisibleRectF(mVisibleContentRect); nativeUpdateDrawGLFunction(mGLViewportEmpty ? null : mGLRectViewport, mGLViewportEmpty ? null : mViewRectViewport, - mVisibleContentRect); + mVisibleContentRect, getScale()); } /** @@ -9885,7 +9929,7 @@ public class WebView extends AbsoluteLayout private native int nativeGetDrawGLFunction(int nativeInstance, Rect rect, Rect viewRect, RectF visibleRect, float scale, int extras); private native void nativeUpdateDrawGLFunction(Rect rect, Rect viewRect, - RectF visibleRect); + RectF visibleRect, float scale); private native void nativeExtendSelection(int x, int y); private native int nativeFindAll(String findLower, String findUpper, boolean sameAsLastSearch); diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java index 8a9c12d43c74..b6c5612c7e6d 100644 --- a/core/java/android/webkit/WebViewCore.java +++ b/core/java/android/webkit/WebViewCore.java @@ -26,6 +26,7 @@ import android.graphics.Region; import android.media.MediaFile; import android.net.ProxyProperties; import android.net.Uri; +import android.net.http.CertificateChainValidator; import android.os.Bundle; import android.os.Handler; import android.os.Looper; @@ -333,6 +334,15 @@ public final class WebViewCore { } /** + * Called by JNI when the focus node changed. + */ + private void focusNodeChanged(WebKitHitTest hitTest) { + if (mWebView == null) return; + mWebView.mPrivateHandler.obtainMessage(WebView.HIT_TEST_RESULT, hitTest) + .sendToTarget(); + } + + /** * Called by JNI. Open a file chooser to upload a file. * @param acceptType The value of the 'accept' attribute of the * input tag associated with this file picker. @@ -614,7 +624,6 @@ public final class WebViewCore { int x, int y); private native String nativeRetrieveImageSource(int nativeClass, int x, int y); - private native void nativeStopPaintingCaret(int nativeClass); private native void nativeTouchUp(int nativeClass, int touchGeneration, int framePtr, int nodePtr, int x, int y); @@ -767,6 +776,11 @@ public final class WebViewCore { Message m = (Message)msg.obj; m.sendToTarget(); break; + case EventHub.TRUST_STORAGE_UPDATED: + // post a task to network thread for updating trust manager + nativeCertTrustChanged(); + CertificateChainValidator.handleTrustStorageUpdate(); + break; } } }; @@ -1125,6 +1139,9 @@ public final class WebViewCore { static final int SELECT_WORD_AT = 214; static final int SELECT_ALL = 215; + // for updating state on trust storage change + static final int TRUST_STORAGE_UPDATED = 220; + // Private handler for WebCore messages. private Handler mHandler; // Message queue for containing messages before the WebCore thread is @@ -1530,9 +1547,6 @@ public final class WebViewCore { nativeMoveMouseIfLatest(mNativeClass, cData.mMoveGeneration, cData.mFrame, cData.mX, cData.mY); - if (msg.arg1 == 1) { - nativeStopPaintingCaret(mNativeClass); - } break; case REQUEST_CURSOR_HREF: { @@ -3077,4 +3091,6 @@ public final class WebViewCore { private native void nativeClearTextSelection(int nativeClass); private native void nativeSelectWordAt(int nativeClass, int x, int y); private native void nativeSelectAll(int nativeClass); + + private static native void nativeCertTrustChanged(); } diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index e94b1cb12d36..e7bc1e1f661b 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -36,6 +36,7 @@ import android.text.TextWatcher; import android.util.AttributeSet; import android.util.Log; import android.util.LongSparseArray; +import android.util.SparseArray; import android.util.SparseBooleanArray; import android.util.StateSet; import android.view.ActionMode; @@ -87,6 +88,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te ViewTreeObserver.OnTouchModeChangeListener, RemoteViewsAdapter.RemoteAdapterConnectionCallback { + private static final String TAG = "AbsListView"; + /** * Disables the transcript mode. * @@ -263,6 +266,11 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te private RemoteViewsAdapter mRemoteAdapter; /** + * If mAdapter != null, whenever this is true the adapter has stable IDs. + */ + boolean mAdapterHasStableIds; + + /** * This flag indicates the a full notify is required when the RemoteViewsAdapter connects */ private boolean mDeferNotifyDataSetChanged = false; @@ -812,7 +820,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te @Override public void setAdapter(ListAdapter adapter) { if (adapter != null) { - if (mChoiceMode != CHOICE_MODE_NONE && mAdapter.hasStableIds() && + mAdapterHasStableIds = mAdapter.hasStableIds(); + if (mChoiceMode != CHOICE_MODE_NONE && mAdapterHasStableIds && mCheckedIdStates == null) { mCheckedIdStates = new LongSparseArray<Integer>(); } @@ -2011,6 +2020,11 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te isScrap[0] = false; View scrapView; + scrapView = mRecycler.getTransientStateView(position); + if (scrapView != null) { + return scrapView; + } + scrapView = mRecycler.getScrapView(position); View child; @@ -2021,6 +2035,13 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } child = mAdapter.getView(position, scrapView, this); + if (mAdapterHasStableIds) { + LayoutParams lp = (LayoutParams) child.getLayoutParams(); + if (lp == null) { + lp = (LayoutParams) generateDefaultLayoutParams(); + } + lp.itemId = mAdapter.getItemId(position); + } if (ViewDebug.TRACE_RECYCLER) { ViewDebug.trace(child, ViewDebug.RecyclerTraceType.BIND_VIEW, @@ -4543,7 +4564,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te if (count > 0) { detachViewsFromParent(start, count); + mRecycler.removeSkippedScrap(); } + offsetChildrenTopAndBottom(incrementalDeltaY); if (down) { @@ -4853,6 +4876,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te confirmCheckedPositionsById(); } + // TODO: In the future we can recycle these views based on stable ID instead. + mRecycler.clearTransientStateViews(); + if (count > 0) { int newPos; int selectablePos; @@ -5735,6 +5761,11 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te */ int scrappedFromPosition; + /** + * The ID the view represents + */ + long itemId = -1; + public LayoutParams(Context c, AttributeSet attrs) { super(c, attrs); } @@ -5807,6 +5838,10 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te private ArrayList<View> mCurrentScrap; + private ArrayList<View> mSkippedScrap; + + private SparseArray<View> mTransientStateViews; + public void setViewTypeCount(int viewTypeCount) { if (viewTypeCount < 1) { throw new IllegalArgumentException("Can't have a viewTypeCount < 1"); @@ -5838,6 +5873,12 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } } } + if (mTransientStateViews != null) { + final int count = mTransientStateViews.size(); + for (int i = 0; i < count; i++) { + mTransientStateViews.valueAt(i).forceLayout(); + } + } } public boolean shouldRecycleViewType(int viewType) { @@ -5864,6 +5905,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } } } + if (mTransientStateViews != null) { + mTransientStateViews.clear(); + } } /** @@ -5910,6 +5954,28 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te return null; } + View getTransientStateView(int position) { + if (mTransientStateViews == null) { + return null; + } + final int index = mTransientStateViews.indexOfKey(position); + if (index < 0) { + return null; + } + final View result = mTransientStateViews.valueAt(index); + mTransientStateViews.removeAt(index); + return result; + } + + /** + * Dump any currently saved views with transient state. + */ + void clearTransientStateViews() { + if (mTransientStateViews != null) { + mTransientStateViews.clear(); + } + } + /** * @return A view from the ScrapViews collection. These are unordered. */ @@ -5926,7 +5992,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } /** - * Put a view into the ScapViews list. These views are unordered. + * Put a view into the ScrapViews list. These views are unordered. * * @param scrap The view to add */ @@ -5936,23 +6002,32 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te return; } + lp.scrappedFromPosition = position; + // Don't put header or footer views or views that should be ignored // into the scrap heap int viewType = lp.viewType; - if (!shouldRecycleViewType(viewType)) { - if (viewType != ITEM_VIEW_TYPE_HEADER_OR_FOOTER) { - removeDetachedView(scrap, false); + final boolean scrapHasTransientState = scrap.hasTransientState(); + if (!shouldRecycleViewType(viewType) || scrapHasTransientState) { + if (viewType != ITEM_VIEW_TYPE_HEADER_OR_FOOTER || scrapHasTransientState) { + if (mSkippedScrap == null) { + mSkippedScrap = new ArrayList<View>(); + } + mSkippedScrap.add(scrap); + } + if (scrapHasTransientState) { + if (mTransientStateViews == null) { + mTransientStateViews = new SparseArray<View>(); + } + mTransientStateViews.put(position, scrap); } return; } - lp.scrappedFromPosition = position; - + scrap.dispatchStartTemporaryDetach(); if (mViewTypeCount == 1) { - scrap.dispatchStartTemporaryDetach(); mCurrentScrap.add(scrap); } else { - scrap.dispatchStartTemporaryDetach(); mScrapViews[viewType].add(scrap); } @@ -5962,6 +6037,20 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } /** + * Finish the removal of any views that skipped the scrap heap. + */ + void removeSkippedScrap() { + if (mSkippedScrap == null) { + return; + } + final int count = mSkippedScrap.size(); + for (int i = 0; i < count; i++) { + removeDetachedView(mSkippedScrap.get(i), false); + } + mSkippedScrap.clear(); + } + + /** * Move all views remaining in mActiveViews to mScrapViews. */ void scrapActiveViews() { @@ -5980,11 +6069,19 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te activeViews[i] = null; - if (!shouldRecycleViewType(whichScrap)) { + final boolean scrapHasTransientState = victim.hasTransientState(); + if (!shouldRecycleViewType(whichScrap) || scrapHasTransientState) { // Do not move views that should be ignored - if (whichScrap != ITEM_VIEW_TYPE_HEADER_OR_FOOTER) { + if (whichScrap != ITEM_VIEW_TYPE_HEADER_OR_FOOTER || + scrapHasTransientState) { removeDetachedView(victim, false); } + if (scrapHasTransientState) { + if (mTransientStateViews == null) { + mTransientStateViews = new SparseArray<View>(); + } + mTransientStateViews.put(mFirstActivePosition + i, victim); + } continue; } diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java index f7a6b2720ce8..de11fe957d3e 100644 --- a/core/java/android/widget/AutoCompleteTextView.java +++ b/core/java/android/widget/AutoCompleteTextView.java @@ -1031,7 +1031,9 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe public void ensureImeVisible(boolean visible) { mPopup.setInputMethodMode(visible ? ListPopupWindow.INPUT_METHOD_NEEDED : ListPopupWindow.INPUT_METHOD_NOT_NEEDED); - showDropDown(); + if (mPopup.isDropDownAlwaysVisible() || (mFilter != null && enoughToFilter())) { + showDropDown(); + } } /** diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java index 5c7e5a36c31c..dd5332586b3d 100644 --- a/core/java/android/widget/CheckedTextView.java +++ b/core/java/android/widget/CheckedTextView.java @@ -142,12 +142,8 @@ public class CheckedTextView extends TextView implements Checkable { resolvePadding(); } - /** - * @hide - */ @Override - protected void resolvePadding() { - super.resolvePadding(); + public void onResolvePadding(int layoutDirection) { int newPadding = (mCheckMarkDrawable != null) ? mCheckMarkWidth + mBasePadding : mBasePadding; mNeedRequestlayout |= (mPaddingRight != newPadding); diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java index 326587e6e7cb..83aa8ba3a908 100644 --- a/core/java/android/widget/EdgeEffect.java +++ b/core/java/android/widget/EdgeEffect.java @@ -56,7 +56,7 @@ public class EdgeEffect { // Time it will take in ms for a pulled glow to decay to partial strength before release private static final int PULL_DECAY_TIME = 1000; - private static final float MAX_ALPHA = 0.8f; + private static final float MAX_ALPHA = 1.f; private static final float HELD_EDGE_ALPHA = 0.7f; private static final float HELD_EDGE_SCALE_Y = 0.5f; private static final float HELD_GLOW_ALPHA = 0.5f; diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java index ea40dc24f1b7..fc08cc5bfeab 100644 --- a/core/java/android/widget/GridLayout.java +++ b/core/java/android/widget/GridLayout.java @@ -127,8 +127,7 @@ import static java.lang.Math.min; * * GridLayout does not provide support for the principle of <em>weight</em>, as defined in * {@link LinearLayout.LayoutParams#weight}. In general, it is not therefore possible - * to configure a GridLayout to distribute excess space in non-trivial proportions between - * multiple rows or columns. + * to configure a GridLayout to distribute excess space between multiple components. * <p> * Some common use-cases may nevertheless be accommodated as follows. * To place equal amounts of space around a component in a cell group; @@ -209,7 +208,6 @@ public class GridLayout extends ViewGroup { static final String TAG = GridLayout.class.getName(); static final boolean DEBUG = false; - static final int PRF = 1; static final int MAX_SIZE = 100000; static final int DEFAULT_CONTAINER_MARGIN = 0; static final int UNINITIALIZED_HASH = 0; @@ -779,7 +777,7 @@ public class GridLayout extends ViewGroup { } } - private void drawRect(Canvas canvas, int x1, int y1, int x2, int y2, Paint paint) { + private static void drawRect(Canvas canvas, int x1, int y1, int x2, int y2, Paint paint) { canvas.drawRect(x1, y1, x2 - 1, y2 - 1, paint); } @@ -957,10 +955,6 @@ public class GridLayout extends ViewGroup { resolveSizeAndState(measuredHeight, heightSpec, 0)); } - private int protect(int alignment) { - return (alignment == UNDEFINED) ? 0 : alignment; - } - private int getMeasurement(View c, boolean horizontal) { return horizontal ? c.getMeasuredWidth() : c.getMeasuredHeight(); } @@ -1040,42 +1034,31 @@ public class GridLayout extends ViewGroup { Alignment hAlign = getAlignment(columnSpec.alignment, true); Alignment vAlign = getAlignment(rowSpec.alignment, false); - Bounds colBounds = horizontalAxis.getGroupBounds().getValue(i); - Bounds rowBounds = verticalAxis.getGroupBounds().getValue(i); + Bounds boundsX = horizontalAxis.getGroupBounds().getValue(i); + Bounds boundsY = verticalAxis.getGroupBounds().getValue(i); // Gravity offsets: the location of the alignment group relative to its cell group. - //noinspection NullableProblems - int gravityOffsetX = protect(hAlign.getAlignmentValue(null, - cellWidth - colBounds.size(true))); - //noinspection NullableProblems - int gravityOffsetY = protect(vAlign.getAlignmentValue(null, - cellHeight - rowBounds.size(true))); - - boolean rtl = isLayoutRtl(); - int startMargin = getMargin(c, true, !rtl); + int gravityOffsetX = hAlign.getGravityOffset(c, cellWidth - boundsX.size(true)); + int gravityOffsetY = vAlign.getGravityOffset(c, cellHeight - boundsY.size(true)); + + int leftMargin = getMargin(c, true, true); int topMargin = getMargin(c, false, true); - int endMargin = getMargin(c, true, rtl); + int rightMargin = getMargin(c, true, false); int bottomMargin = getMargin(c, false, false); - // Same calculation as getMeasurementIncludingMargin() - int mWidth = startMargin + pWidth + endMargin; - int mHeight = topMargin + pHeight + bottomMargin; - // Alignment offsets: the location of the view relative to its alignment group. - int alignmentOffsetX = colBounds.getOffset(c, hAlign, mWidth); - int alignmentOffsetY = rowBounds.getOffset(c, vAlign, mHeight); + int alignmentOffsetX = boundsX.getOffset(c, hAlign, leftMargin + pWidth + rightMargin); + int alignmentOffsetY = boundsY.getOffset(c, vAlign, topMargin + pHeight + bottomMargin); - int dx = gravityOffsetX + alignmentOffsetX + startMargin; - int dy = gravityOffsetY + alignmentOffsetY + topMargin; + int width = hAlign.getSizeInCell(c, pWidth, cellWidth - leftMargin - rightMargin); + int height = vAlign.getSizeInCell(c, pHeight, cellHeight - topMargin - bottomMargin); - cellWidth -= startMargin + endMargin; - cellHeight -= topMargin + bottomMargin; + int dx = x1 + gravityOffsetX + alignmentOffsetX; - int width = hAlign.getSizeInCell(c, pWidth, cellWidth, PRF); - int height = vAlign.getSizeInCell(c, pHeight, cellHeight, PRF); + int cx = !isLayoutRtl() ? paddingLeft + leftMargin + dx : + targetWidth - width - paddingRight - rightMargin - dx; + int cy = paddingTop + y1 + gravityOffsetY + alignmentOffsetY + topMargin; - int cx = rtl ? targetWidth - paddingRight - x1 - dx - width : paddingLeft + x1 + dx; - int cy = paddingTop + y1 + dy; if (width != c.getMeasuredWidth() || height != c.getMeasuredHeight()) { c.measure(makeMeasureSpec(width, EXACTLY), makeMeasureSpec(height, EXACTLY)); } @@ -1694,7 +1677,7 @@ public class GridLayout extends ViewGroup { * each cell group. The fundamental parameters associated with each cell group are * gathered into their vertical and horizontal components and stored * in the {@link #rowSpec} and {@link #columnSpec} layout parameters. - * {@link android.widget.GridLayout.Spec Specs} are immutable structures + * {@link GridLayout.Spec Specs} are immutable structures * and may be shared between the layout parameters of different children. * <p> * The row and column specs contain the leading and trailing indices along each axis @@ -1747,7 +1730,7 @@ public class GridLayout extends ViewGroup { * <li>{@link #rowSpec}<code>.alignment</code> = {@link #BASELINE} </li> * <li>{@link #columnSpec}<code>.column</code> = {@link #UNDEFINED} </li> * <li>{@link #columnSpec}<code>.columnSpan</code> = 1 </li> - * <li>{@link #columnSpec}<code>.alignment</code> = {@link #LEFT} </li> + * <li>{@link #columnSpec}<code>.alignment</code> = {@link #START} </li> * </ul> * * See {@link GridLayout} for a more complete description of the conventions @@ -1936,7 +1919,7 @@ public class GridLayout extends ViewGroup { /** * Describes how the child views are positioned. Default is {@code LEFT | BASELINE}. - * See {@link android.view.Gravity}. + * See {@link Gravity}. * * @param gravity the new gravity value * @@ -2426,8 +2409,8 @@ public class GridLayout extends ViewGroup { * group is specified by the two alignments which act along each axis independently. * <p> * The GridLayout class defines the most common alignments used in general layout: - * {@link #TOP}, {@link #LEFT}, {@link #BOTTOM}, {@link #RIGHT}, {@link #CENTER}, {@link - * #BASELINE} and {@link #FILL}. + * {@link #TOP}, {@link #LEFT}, {@link #BOTTOM}, {@link #RIGHT}, {@link #START}, + * {@link #END}, {@link #CENTER}, {@link #BASELINE} and {@link #FILL}. */ /* * An Alignment implementation must define {@link #getAlignmentValue(View, int, int)}, @@ -2441,6 +2424,8 @@ public class GridLayout extends ViewGroup { Alignment() { } + abstract int getGravityOffset(View view, int cellDelta); + /** * Returns an alignment value. In the case of vertical alignments the value * returned should indicate the distance from the top of the view to the @@ -2463,12 +2448,9 @@ public class GridLayout extends ViewGroup { * @param view the view to which this alignment should be applied * @param viewSize the measured size of the view * @param cellSize the size of the cell into which this view will be placed - * @param measurementType This parameter is currently unused as GridLayout only supports - * one type of measurement: {@link View#measure(int, int)}. - * * @return the aligned size */ - int getSizeInCell(View view, int viewSize, int cellSize, int measurementType) { + int getSizeInCell(View view, int viewSize, int cellSize) { return viewSize; } @@ -2479,6 +2461,11 @@ public class GridLayout extends ViewGroup { static final Alignment UNDEFINED_ALIGNMENT = new Alignment() { @Override + int getGravityOffset(View view, int cellDelta) { + return UNDEFINED; + } + + @Override public int getAlignmentValue(View view, int viewSize) { return UNDEFINED; } @@ -2490,6 +2477,11 @@ public class GridLayout extends ViewGroup { */ private static final Alignment LEADING = new Alignment() { @Override + int getGravityOffset(View view, int cellDelta) { + return 0; + } + + @Override public int getAlignmentValue(View view, int viewSize) { return 0; } @@ -2501,6 +2493,11 @@ public class GridLayout extends ViewGroup { */ private static final Alignment TRAILING = new Alignment() { @Override + int getGravityOffset(View view, int cellDelta) { + return cellDelta; + } + + @Override public int getAlignmentValue(View view, int viewSize) { return viewSize; } @@ -2530,15 +2527,16 @@ public class GridLayout extends ViewGroup { */ public static final Alignment END = TRAILING; - private static Alignment getAbsoluteAlignment(final Alignment a1, final Alignment a2) { + private static Alignment createSwitchingAlignment(final Alignment ltr, final Alignment rtl) { return new Alignment() { @Override + int getGravityOffset(View view, int cellDelta) { + return (!view.isLayoutRtl() ? ltr : rtl).getGravityOffset(view, cellDelta); + } + + @Override public int getAlignmentValue(View view, int viewSize) { - if (view == null) { - return UNDEFINED; - } - Alignment alignment = view.isLayoutRtl() ? a2 : a1; - return alignment.getAlignmentValue(view, viewSize); + return (!view.isLayoutRtl() ? ltr : rtl).getAlignmentValue(view, viewSize); } }; } @@ -2547,13 +2545,13 @@ public class GridLayout extends ViewGroup { * Indicates that a view should be aligned with the <em>left</em> * edges of the other views in its cell group. */ - public static final Alignment LEFT = getAbsoluteAlignment(START, END); + public static final Alignment LEFT = createSwitchingAlignment(START, END); /** * Indicates that a view should be aligned with the <em>right</em> * edges of the other views in its cell group. */ - public static final Alignment RIGHT = getAbsoluteAlignment(END, START); + public static final Alignment RIGHT = createSwitchingAlignment(END, START); /** * Indicates that a view should be <em>centered</em> with the other views in its cell group. @@ -2562,6 +2560,11 @@ public class GridLayout extends ViewGroup { */ public static final Alignment CENTER = new Alignment() { @Override + int getGravityOffset(View view, int cellDelta) { + return cellDelta >> 1; + } + + @Override public int getAlignmentValue(View view, int viewSize) { return viewSize >> 1; } @@ -2576,10 +2579,12 @@ public class GridLayout extends ViewGroup { */ public static final Alignment BASELINE = new Alignment() { @Override + int getGravityOffset(View view, int cellDelta) { + return 0; // baseline gravity is top + } + + @Override public int getAlignmentValue(View view, int viewSize) { - if (view == null) { - return UNDEFINED; - } int baseline = view.getBaseline(); return (baseline == -1) ? UNDEFINED : baseline; } @@ -2627,12 +2632,17 @@ public class GridLayout extends ViewGroup { */ public static final Alignment FILL = new Alignment() { @Override + int getGravityOffset(View view, int cellDelta) { + return 0; + } + + @Override public int getAlignmentValue(View view, int viewSize) { return UNDEFINED; } @Override - public int getSizeInCell(View view, int viewSize, int cellSize, int measurementType) { + public int getSizeInCell(View view, int viewSize, int cellSize) { return cellSize; } }; diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java index be2df8ef4607..6bc5a15f531d 100644 --- a/core/java/android/widget/GridView.java +++ b/core/java/android/widget/GridView.java @@ -1205,6 +1205,7 @@ public class GridView extends AbsListView { // Clear out old views //removeAllViewsInLayout(); detachAllViewsFromParent(); + recycleBin.removeSkippedScrap(); switch (mLayoutMode) { case LAYOUT_SET_SELECTION: diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java index 67fd059f1955..46c2c0725d0d 100644 --- a/core/java/android/widget/ListView.java +++ b/core/java/android/widget/ListView.java @@ -1591,6 +1591,7 @@ public class ListView extends AbsListView { // Clear out old views detachAllViewsFromParent(); + recycleBin.removeSkippedScrap(); switch (mLayoutMode) { case LAYOUT_SET_SELECTION: diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java index 570f0f95d603..909f383f1171 100644 --- a/core/java/android/widget/SpellChecker.java +++ b/core/java/android/widget/SpellChecker.java @@ -426,7 +426,8 @@ public class SpellChecker implements SpellCheckerSessionListener { } // A new word has been created across the interval boundaries with this edit. - // Previous spans (ended on start / started on end) removed, not valid anymore + // The previous spans (that ended on start / started on end) are not valid + // anymore and must be removed. if (wordStart < start && wordEnd > start) { removeSpansAt(editable, start, spellCheckSpans); removeSpansAt(editable, start, suggestionSpans); diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 99349b0473ea..f66da2959b42 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -3472,6 +3472,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (mText.length() == 0) { invalidate(); } + + // Invalidate display list if hint will be used + if (mText.length() == 0 && mHint != null) mTextDisplayListIsValid = false; } /** @@ -3804,21 +3807,21 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } - Handler h = getHandler(); - if (h != null) { + ViewRootImpl viewRootImpl = getViewRootImpl(); + if (viewRootImpl != null) { long eventTime = SystemClock.uptimeMillis(); - h.sendMessage(h.obtainMessage(ViewRootImpl.DISPATCH_KEY_FROM_IME, + viewRootImpl.dispatchKeyFromIme( new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE - | KeyEvent.FLAG_EDITOR_ACTION))); - h.sendMessage(h.obtainMessage(ViewRootImpl.DISPATCH_KEY_FROM_IME, + | KeyEvent.FLAG_EDITOR_ACTION)); + viewRootImpl.dispatchKeyFromIme( new KeyEvent(SystemClock.uptimeMillis(), eventTime, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE - | KeyEvent.FLAG_EDITOR_ACTION))); + | KeyEvent.FLAG_EDITOR_ACTION)); } } @@ -4634,19 +4637,25 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // Alpha is supported if and only if the drawing can be done in one pass. // TODO text with spans with a background color currently do not respect this alpha. if (getBackground() == null) { - mCurrentAlpha = alpha; - final Drawables dr = mDrawables; - if (dr != null) { - if (dr.mDrawableLeft != null) dr.mDrawableLeft.mutate().setAlpha(alpha); - if (dr.mDrawableTop != null) dr.mDrawableTop.mutate().setAlpha(alpha); - if (dr.mDrawableRight != null) dr.mDrawableRight.mutate().setAlpha(alpha); - if (dr.mDrawableBottom != null) dr.mDrawableBottom.mutate().setAlpha(alpha); - if (dr.mDrawableStart != null) dr.mDrawableStart.mutate().setAlpha(alpha); - if (dr.mDrawableEnd != null) dr.mDrawableEnd.mutate().setAlpha(alpha); + if (mCurrentAlpha != alpha) { + mCurrentAlpha = alpha; + final Drawables dr = mDrawables; + if (dr != null) { + if (dr.mDrawableLeft != null) dr.mDrawableLeft.mutate().setAlpha(alpha); + if (dr.mDrawableTop != null) dr.mDrawableTop.mutate().setAlpha(alpha); + if (dr.mDrawableRight != null) dr.mDrawableRight.mutate().setAlpha(alpha); + if (dr.mDrawableBottom != null) dr.mDrawableBottom.mutate().setAlpha(alpha); + if (dr.mDrawableStart != null) dr.mDrawableStart.mutate().setAlpha(alpha); + if (dr.mDrawableEnd != null) dr.mDrawableEnd.mutate().setAlpha(alpha); + } + mTextDisplayListIsValid = false; } return true; } + if (mCurrentAlpha != 255) { + mTextDisplayListIsValid = false; + } mCurrentAlpha = 255; return false; } @@ -5013,15 +5022,19 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener hardwareCanvas.setViewport(width, height); // The dirty rect should always be null for a display list hardwareCanvas.onPreDraw(null); + hardwareCanvas.translate(-mScrollX, -mScrollY); layout.draw(hardwareCanvas, highlight, mHighlightPaint, cursorOffsetVertical); + hardwareCanvas.translate(mScrollX, mScrollY); } finally { hardwareCanvas.onPostDraw(); mTextDisplayList.end(); mTextDisplayListIsValid = true; } } - ((HardwareCanvas) canvas).drawDisplayList(mTextDisplayList, - mScrollX + width, mScrollY + height, null); + canvas.translate(mScrollX, mScrollY); + ((HardwareCanvas) canvas).drawDisplayList(mTextDisplayList, width, height, null, + DisplayList.FLAG_CLIP_CHILDREN); + canvas.translate(-mScrollX, -mScrollY); } else { layout.draw(canvas, highlight, mHighlightPaint, cursorOffsetVertical); } @@ -11398,7 +11411,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } @Override - protected void resolveTextDirection() { + public void onResolveTextDirection() { if (hasPasswordTransformationMethod()) { mTextDir = TextDirectionHeuristics.LOCALE; return; @@ -11407,9 +11420,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // Always need to resolve layout direction first final boolean defaultIsRtl = (getResolvedLayoutDirection() == LAYOUT_DIRECTION_RTL); - // Then resolve text direction on the parent - super.resolveTextDirection(); - // Now, we can select the heuristic int textDir = getResolvedTextDirection(); switch (textDir) { @@ -11438,7 +11448,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * drawables depending on the layout direction. * * A call to the super method will be required from the subclasses implementation. - * */ protected void resolveDrawables() { // No need to resolve twice diff --git a/core/java/android/widget/ZoomButtonsController.java b/core/java/android/widget/ZoomButtonsController.java index f3d891d11989..02dc27bef3e9 100644 --- a/core/java/android/widget/ZoomButtonsController.java +++ b/core/java/android/widget/ZoomButtonsController.java @@ -501,7 +501,7 @@ public class ZoomButtonsController implements View.OnTouchListener { } else { - ViewRootImpl viewRoot = getOwnerViewRootImpl(); + ViewRootImpl viewRoot = mOwnerView.getViewRootImpl(); if (viewRoot != null) { viewRoot.dispatchKey(event); } @@ -526,20 +526,6 @@ public class ZoomButtonsController implements View.OnTouchListener { } } - private ViewRootImpl getOwnerViewRootImpl() { - View rootViewOfOwner = mOwnerView.getRootView(); - if (rootViewOfOwner == null) { - return null; - } - - ViewParent parentOfRootView = rootViewOfOwner.getParent(); - if (parentOfRootView instanceof ViewRootImpl) { - return (ViewRootImpl) parentOfRootView; - } else { - return null; - } - } - /** * @hide The ZoomButtonsController implements the OnTouchListener, but this * does not need to be shown in its public API. diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index 6893ffbaf6c5..acc3c1c39de1 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -857,11 +857,6 @@ public class LockPatternUtils { * @return Whether biometric weak lock is installed and that the front facing camera exists */ public boolean isBiometricWeakInstalled() { - // Check that the system flag was set - if (!OPTION_ENABLE_FACELOCK.equals(getString(LOCKSCREEN_OPTIONS))) { - return false; - } - // Check that it's installed PackageManager pm = mContext.getPackageManager(); try { diff --git a/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java b/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java index 2e7810fa1139..26518ebdd2a7 100644 --- a/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java +++ b/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java @@ -147,7 +147,7 @@ public class PasswordEntryKeyboardHelper implements OnKeyboardActionListener { } private void sendKeyEventsToTarget(int character) { - Handler handler = mTargetView.getHandler(); + ViewRootImpl viewRootImpl = mTargetView.getViewRootImpl(); KeyEvent[] events = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD).getEvents( new char[] { (char) character }); if (events != null) { @@ -156,22 +156,22 @@ public class PasswordEntryKeyboardHelper implements OnKeyboardActionListener { KeyEvent event = events[i]; event = KeyEvent.changeFlags(event, event.getFlags() | KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE); - handler.sendMessage(handler.obtainMessage(ViewRootImpl.DISPATCH_KEY, event)); + viewRootImpl.dispatchKey(event); } } } public void sendDownUpKeyEvents(int keyEventCode) { long eventTime = SystemClock.uptimeMillis(); - Handler handler = mTargetView.getHandler(); - handler.sendMessage(handler.obtainMessage(ViewRootImpl.DISPATCH_KEY_FROM_IME, + ViewRootImpl viewRootImpl = mTargetView.getViewRootImpl(); + viewRootImpl.dispatchKeyFromIme( new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_DOWN, keyEventCode, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, - KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE))); - handler.sendMessage(handler.obtainMessage(ViewRootImpl.DISPATCH_KEY_FROM_IME, + KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE)); + viewRootImpl.dispatchKeyFromIme( new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_UP, keyEventCode, 0, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, - KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE))); + KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE)); } public void onKey(int primaryCode, int[] keyCodes) { diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp index ea35006f65a3..4b64bf3b38d6 100644 --- a/core/jni/android/graphics/BitmapFactory.cpp +++ b/core/jni/android/graphics/BitmapFactory.cpp @@ -15,8 +15,8 @@ #include "JNIHelp.h" #include <android_runtime/AndroidRuntime.h> -#include <utils/Asset.h> -#include <utils/ResourceTypes.h> +#include <androidfw/Asset.h> +#include <androidfw/ResourceTypes.h> #include <netinet/in.h> #include <sys/mman.h> #include <sys/stat.h> diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp index d43792939e72..682877a97b0e 100644 --- a/core/jni/android/graphics/BitmapRegionDecoder.cpp +++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp @@ -37,7 +37,7 @@ #include <binder/Parcel.h> #include <jni.h> -#include <utils/Asset.h> +#include <androidfw/Asset.h> #include <sys/stat.h> #if 0 diff --git a/core/jni/android/graphics/Movie.cpp b/core/jni/android/graphics/Movie.cpp index c1acaa3e4683..4f64ff8f47b0 100644 --- a/core/jni/android/graphics/Movie.cpp +++ b/core/jni/android/graphics/Movie.cpp @@ -5,8 +5,8 @@ #include "SkUtils.h" #include "CreateJavaOutputStreamAdaptor.h" -#include <utils/Asset.h> -#include <utils/ResourceTypes.h> +#include <androidfw/Asset.h> +#include <androidfw/ResourceTypes.h> #include <netinet/in.h> #if 0 diff --git a/core/jni/android/graphics/NinePatch.cpp b/core/jni/android/graphics/NinePatch.cpp index f3b28a9e2e9c..684b1c1d3579 100644 --- a/core/jni/android/graphics/NinePatch.cpp +++ b/core/jni/android/graphics/NinePatch.cpp @@ -18,7 +18,7 @@ #define LOG_TAG "9patch" #define LOG_NDEBUG 1 -#include <utils/ResourceTypes.h> +#include <androidfw/ResourceTypes.h> #include <utils/Log.h> #include "SkCanvas.h" diff --git a/core/jni/android/graphics/NinePatchImpl.cpp b/core/jni/android/graphics/NinePatchImpl.cpp index 1d0bb50613d1..ff0eb45b986d 100644 --- a/core/jni/android/graphics/NinePatchImpl.cpp +++ b/core/jni/android/graphics/NinePatchImpl.cpp @@ -18,7 +18,7 @@ #define LOG_TAG "NinePatch" #define LOG_NDEBUG 1 -#include <utils/ResourceTypes.h> +#include <androidfw/ResourceTypes.h> #include <utils/Log.h> #include "SkBitmap.h" diff --git a/core/jni/android/graphics/NinePatchPeeker.h b/core/jni/android/graphics/NinePatchPeeker.h index 8567e23f07fa..207536c2b324 100644 --- a/core/jni/android/graphics/NinePatchPeeker.h +++ b/core/jni/android/graphics/NinePatchPeeker.h @@ -18,7 +18,7 @@ #define NinePatchPeeker_h #include "SkImageDecoder.h" -#include <utils/ResourceTypes.h> +#include <androidfw/ResourceTypes.h> using namespace android; diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp index b25598aecf2a..7f4c37bff34d 100644 --- a/core/jni/android/graphics/Typeface.cpp +++ b/core/jni/android/graphics/Typeface.cpp @@ -2,10 +2,10 @@ #include <android_runtime/AndroidRuntime.h> #include "GraphicsJNI.h" -#include <android_runtime/android_util_AssetManager.h> #include "SkStream.h" #include "SkTypeface.h" -#include <utils/AssetManager.h> +#include <android_runtime/android_util_AssetManager.h> +#include <androidfw/AssetManager.h> using namespace android; diff --git a/core/jni/android/graphics/Utils.h b/core/jni/android/graphics/Utils.h index 9a7a69703c2d..75ceaa25e4be 100644 --- a/core/jni/android/graphics/Utils.h +++ b/core/jni/android/graphics/Utils.h @@ -22,7 +22,7 @@ #include "android_util_Binder.h" #include <jni.h> -#include <utils/Asset.h> +#include <androidfw/Asset.h> namespace android { diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp index 536681b0452f..4b3324b7f16f 100644 --- a/core/jni/android_app_NativeActivity.cpp +++ b/core/jni/android_app_NativeActivity.cpp @@ -27,7 +27,7 @@ #include <android_runtime/android_util_AssetManager.h> #include <surfaceflinger/Surface.h> #include <ui/egl/android_natives.h> -#include <ui/InputTransport.h> +#include <androidfw/InputTransport.h> #include <utils/Looper.h> #include "JNIHelp.h" diff --git a/core/jni/android_app_backup_FullBackup.cpp b/core/jni/android_app_backup_FullBackup.cpp index 066a23e38e03..2ca645a6ee03 100644 --- a/core/jni/android_app_backup_FullBackup.cpp +++ b/core/jni/android_app_backup_FullBackup.cpp @@ -21,7 +21,7 @@ #include "JNIHelp.h" #include <android_runtime/AndroidRuntime.h> -#include <utils/BackupHelpers.h> +#include <androidfw/BackupHelpers.h> #include <string.h> diff --git a/core/jni/android_backup_BackupDataInput.cpp b/core/jni/android_backup_BackupDataInput.cpp index 2fb0076ff1e1..25b0007fa15f 100644 --- a/core/jni/android_backup_BackupDataInput.cpp +++ b/core/jni/android_backup_BackupDataInput.cpp @@ -20,7 +20,7 @@ #include "JNIHelp.h" #include <android_runtime/AndroidRuntime.h> -#include <utils/BackupHelpers.h> +#include <androidfw/BackupHelpers.h> namespace android { diff --git a/core/jni/android_backup_BackupDataOutput.cpp b/core/jni/android_backup_BackupDataOutput.cpp index abe0104cfcf5..e8f0fb85e29b 100644 --- a/core/jni/android_backup_BackupDataOutput.cpp +++ b/core/jni/android_backup_BackupDataOutput.cpp @@ -20,7 +20,7 @@ #include "JNIHelp.h" #include <android_runtime/AndroidRuntime.h> -#include <utils/BackupHelpers.h> +#include <androidfw/BackupHelpers.h> namespace android { diff --git a/core/jni/android_backup_FileBackupHelperBase.cpp b/core/jni/android_backup_FileBackupHelperBase.cpp index 0dfd8dbfb29d..bb3a751ae8e6 100644 --- a/core/jni/android_backup_FileBackupHelperBase.cpp +++ b/core/jni/android_backup_FileBackupHelperBase.cpp @@ -20,7 +20,7 @@ #include "JNIHelp.h" #include <android_runtime/AndroidRuntime.h> -#include <utils/BackupHelpers.h> +#include <androidfw/BackupHelpers.h> namespace android { diff --git a/core/jni/android_bluetooth_BluetoothAudioGateway.cpp b/core/jni/android_bluetooth_BluetoothAudioGateway.cpp index 3b8fb7974140..3b8fb7974140 100755..100644 --- a/core/jni/android_bluetooth_BluetoothAudioGateway.cpp +++ b/core/jni/android_bluetooth_BluetoothAudioGateway.cpp diff --git a/core/jni/android_bluetooth_c.c b/core/jni/android_bluetooth_c.c index b4c672711594..b4c672711594 100755..100644 --- a/core/jni/android_bluetooth_c.c +++ b/core/jni/android_bluetooth_c.c diff --git a/core/jni/android_content_res_ObbScanner.cpp b/core/jni/android_content_res_ObbScanner.cpp index 883753843233..5d51ee2d82f5 100644 --- a/core/jni/android_content_res_ObbScanner.cpp +++ b/core/jni/android_content_res_ObbScanner.cpp @@ -18,7 +18,7 @@ #include <utils/Log.h> #include <utils/String8.h> -#include <utils/ObbFile.h> +#include <androidfw/ObbFile.h> #include "jni.h" #include "JNIHelp.h" diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp index 547607ec2947..68a8de8f7c70 100644 --- a/core/jni/android_media_AudioRecord.cpp +++ b/core/jni/android_media_AudioRecord.cpp @@ -220,7 +220,7 @@ android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this, ALOGE("Error creating AudioRecord: Error retrieving session id pointer"); goto native_init_failure; } - // read the audio session ID back from AudioTrack in case a new session was created during set() + // read the audio session ID back from AudioRecord in case a new session was created during set() nSession[0] = lpRecorder->getSessionId(); env->ReleasePrimitiveArrayCritical(jSession, nSession, 0); nSession = NULL; diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp index 31c5ed482a3d..ee5eb7e87506 100644 --- a/core/jni/android_media_AudioSystem.cpp +++ b/core/jni/android_media_AudioSystem.cpp @@ -1,4 +1,4 @@ -/* //device/libs/android_runtime/android_media_AudioSystem.cpp +/* ** ** Copyright 2006, The Android Open Source Project ** diff --git a/core/jni/android_media_ToneGenerator.cpp b/core/jni/android_media_ToneGenerator.cpp index 0a337fae781e..544b4c09661f 100644 --- a/core/jni/android_media_ToneGenerator.cpp +++ b/core/jni/android_media_ToneGenerator.cpp @@ -1,4 +1,4 @@ -/* //device/libs/android_runtime/android_media_AudioSystem.cpp +/* ** ** Copyright 2008, The Android Open Source Project ** diff --git a/core/jni/android_net_wifi_Wifi.cpp b/core/jni/android_net_wifi_Wifi.cpp index 2ac3ca8d8da4..c5ff16e4baa6 100644 --- a/core/jni/android_net_wifi_Wifi.cpp +++ b/core/jni/android_net_wifi_Wifi.cpp @@ -116,14 +116,9 @@ static jboolean android_net_wifi_unloadDriver(JNIEnv* env, jobject) return (jboolean)(::wifi_unload_driver() == 0); } -static jboolean android_net_wifi_startSupplicant(JNIEnv* env, jobject) +static jboolean android_net_wifi_startSupplicant(JNIEnv* env, jobject, jboolean p2pSupported) { - return (jboolean)(::wifi_start_supplicant() == 0); -} - -static jboolean android_net_wifi_startP2pSupplicant(JNIEnv* env, jobject) -{ - return (jboolean)(::wifi_start_p2p_supplicant() == 0); + return (jboolean)(::wifi_start_supplicant(p2pSupported) == 0); } static jboolean android_net_wifi_killSupplicant(JNIEnv* env, jobject) @@ -207,8 +202,7 @@ static JNINativeMethod gWifiMethods[] = { { "loadDriver", "()Z", (void *)android_net_wifi_loadDriver }, { "isDriverLoaded", "()Z", (void *)android_net_wifi_isDriverLoaded }, { "unloadDriver", "()Z", (void *)android_net_wifi_unloadDriver }, - { "startSupplicant", "()Z", (void *)android_net_wifi_startSupplicant }, - { "startP2pSupplicant", "()Z", (void *)android_net_wifi_startP2pSupplicant }, + { "startSupplicant", "(Z)Z", (void *)android_net_wifi_startSupplicant }, { "killSupplicant", "()Z", (void *)android_net_wifi_killSupplicant }, { "connectToSupplicant", "(Ljava/lang/String;)Z", (void *)android_net_wifi_connectToSupplicant }, diff --git a/core/jni/android_os_Power.cpp b/core/jni/android_os_Power.cpp index dc1699089e38..48845f6f402e 100644 --- a/core/jni/android_os_Power.cpp +++ b/core/jni/android_os_Power.cpp @@ -15,13 +15,18 @@ ** limitations under the License. */ +#define LOG_TAG "Power-JNI" + #include "JNIHelp.h" #include "jni.h" #include "android_runtime/AndroidRuntime.h" #include <utils/misc.h> +#include <hardware/power.h> #include <hardware_legacy/power.h> #include <cutils/android_reboot.h> +static struct power_module *sPowerModule; + namespace android { @@ -65,7 +70,9 @@ setLastUserActivityTimeout(JNIEnv *env, jobject clazz, jlong timeMS) static int setScreenState(JNIEnv *env, jobject clazz, jboolean on) { - return set_screen_state(on); + if (sPowerModule) + sPowerModule->setInteractive(sPowerModule, on); + return 0; } static void android_os_Power_shutdown(JNIEnv *env, jobject clazz) @@ -85,12 +92,26 @@ static void android_os_Power_reboot(JNIEnv *env, jobject clazz, jstring reason) jniThrowIOException(env, errno); } +static int android_os_Power_init(JNIEnv *env, jobject clazz) +{ + status_t err = hw_get_module(POWER_HARDWARE_MODULE_ID, + (hw_module_t const**)&sPowerModule); + ALOGE_IF(err, "couldn't load %s module (%s)", + POWER_HARDWARE_MODULE_ID, strerror(-err)); + + if (!err) + sPowerModule->init(sPowerModule); + + return err; +} + static JNINativeMethod method_table[] = { { "acquireWakeLock", "(ILjava/lang/String;)V", (void*)acquireWakeLock }, { "releaseWakeLock", "(Ljava/lang/String;)V", (void*)releaseWakeLock }, { "setLastUserActivityTimeout", "(J)I", (void*)setLastUserActivityTimeout }, { "setScreenState", "(Z)I", (void*)setScreenState }, { "shutdown", "()V", (void*)android_os_Power_shutdown }, + { "powerInitNative", "()I", (void*)android_os_Power_init }, { "rebootNative", "(Ljava/lang/String;)V", (void*)android_os_Power_reboot }, }; diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp index 9292fc02113c..8a69ba438460 100644 --- a/core/jni/android_server_BluetoothEventLoop.cpp +++ b/core/jni/android_server_BluetoothEventLoop.cpp @@ -164,7 +164,6 @@ static void initializeNativeDataNative(JNIEnv* env, jobject object) { ALOGE("%s: out of memory!", __FUNCTION__); return; } - memset(nat, 0, sizeof(native_data_t)); pthread_mutex_init(&(nat->thread_mutex), NULL); @@ -722,24 +721,20 @@ static jboolean startEventLoopNative(JNIEnv *env, jobject object) { return JNI_FALSE; } - nat->pollData = (struct pollfd *)malloc(sizeof(struct pollfd) * - DEFAULT_INITIAL_POLLFD_COUNT); + nat->pollData = (struct pollfd *)calloc( + DEFAULT_INITIAL_POLLFD_COUNT, sizeof(struct pollfd)); if (!nat->pollData) { ALOGE("out of memory error starting EventLoop!"); goto done; } - nat->watchData = (DBusWatch **)malloc(sizeof(DBusWatch *) * - DEFAULT_INITIAL_POLLFD_COUNT); + nat->watchData = (DBusWatch **)calloc( + DEFAULT_INITIAL_POLLFD_COUNT, sizeof(DBusWatch *)); if (!nat->watchData) { ALOGE("out of memory error starting EventLoop!"); goto done; } - memset(nat->pollData, 0, sizeof(struct pollfd) * - DEFAULT_INITIAL_POLLFD_COUNT); - memset(nat->watchData, 0, sizeof(DBusWatch *) * - DEFAULT_INITIAL_POLLFD_COUNT); nat->pollDataSize = DEFAULT_INITIAL_POLLFD_COUNT; nat->pollMemberCount = 1; diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index 17130af39450..7146667472ab 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -31,9 +31,9 @@ #include <android_runtime/AndroidRuntime.h> #include <utils/Log.h> -#include <utils/Asset.h> -#include <utils/AssetManager.h> -#include <utils/ResourceTypes.h> +#include <androidfw/Asset.h> +#include <androidfw/AssetManager.h> +#include <androidfw/ResourceTypes.h> #include <stdio.h> diff --git a/core/jni/android_util_StringBlock.cpp b/core/jni/android_util_StringBlock.cpp index 958ddb22cbc7..28746ce1eea4 100644 --- a/core/jni/android_util_StringBlock.cpp +++ b/core/jni/android_util_StringBlock.cpp @@ -23,7 +23,7 @@ #include <android_runtime/AndroidRuntime.h> #include <utils/Log.h> -#include <utils/ResourceTypes.h> +#include <androidfw/ResourceTypes.h> #include <stdio.h> diff --git a/core/jni/android_util_XmlBlock.cpp b/core/jni/android_util_XmlBlock.cpp index 45728dbb1bc5..ad6033b1c175 100644 --- a/core/jni/android_util_XmlBlock.cpp +++ b/core/jni/android_util_XmlBlock.cpp @@ -19,12 +19,11 @@ #include "jni.h" #include "JNIHelp.h" -#include <utils/misc.h> #include <android_runtime/AndroidRuntime.h> -#include <utils/AssetManager.h> +#include <androidfw/AssetManager.h> +#include <androidfw/ResourceTypes.h> #include <utils/Log.h> - -#include <utils/ResourceTypes.h> +#include <utils/misc.h> #include <stdio.h> diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp index e19bb38dc53d..cdce4f9e1984 100644 --- a/core/jni/android_view_GLES20Canvas.cpp +++ b/core/jni/android_view_GLES20Canvas.cpp @@ -24,7 +24,7 @@ #include <android_runtime/AndroidRuntime.h> #include <android_runtime/android_graphics_SurfaceTexture.h> #include <cutils/properties.h> -#include <utils/ResourceTypes.h> +#include <androidfw/ResourceTypes.h> #include <gui/SurfaceTexture.h> @@ -652,9 +652,9 @@ static void android_view_GLES20Canvas_destroyDisplayList(JNIEnv* env, static bool android_view_GLES20Canvas_drawDisplayList(JNIEnv* env, jobject clazz, OpenGLRenderer* renderer, DisplayList* displayList, - jint width, jint height, jobject dirty) { + jint width, jint height, jobject dirty, jint flags) { android::uirenderer::Rect bounds; - bool redraw = renderer->drawDisplayList(displayList, width, height, bounds); + bool redraw = renderer->drawDisplayList(displayList, width, height, bounds, flags); if (redraw && dirty != NULL) { env->CallVoidMethod(dirty, gRectClassInfo.set, int(bounds.left), int(bounds.top), int(bounds.right), int(bounds.bottom)); @@ -901,7 +901,7 @@ static JNINativeMethod gMethods[] = { { "nGetDisplayListSize", "(I)I", (void*) android_view_GLES20Canvas_getDisplayListSize }, { "nSetDisplayListName", "(ILjava/lang/String;)V", (void*) android_view_GLES20Canvas_setDisplayListName }, - { "nDrawDisplayList", "(IIIILandroid/graphics/Rect;)Z", + { "nDrawDisplayList", "(IIIILandroid/graphics/Rect;I)Z", (void*) android_view_GLES20Canvas_drawDisplayList }, { "nCreateDisplayListRenderer", "()I", (void*) android_view_GLES20Canvas_createDisplayListRenderer }, diff --git a/core/jni/android_view_InputChannel.cpp b/core/jni/android_view_InputChannel.cpp index 53774251a43e..8350e73f91dc 100644 --- a/core/jni/android_view_InputChannel.cpp +++ b/core/jni/android_view_InputChannel.cpp @@ -21,7 +21,7 @@ #include <android_runtime/AndroidRuntime.h> #include <binder/Parcel.h> #include <utils/Log.h> -#include <ui/InputTransport.h> +#include <androidfw/InputTransport.h> #include "android_view_InputChannel.h" #include "android_util_Binder.h" @@ -199,9 +199,9 @@ static void android_view_InputChannel_nativeReadFromParcel(JNIEnv* env, jobject bool isInitialized = parcel->readInt32(); if (isInitialized) { String8 name = parcel->readString8(); - int32_t rawFd = parcel->readFileDescriptor(); - int32_t dupFd = dup(rawFd); - if (rawFd < 0) { + int rawFd = parcel->readFileDescriptor(); + int dupFd = dup(rawFd); + if (dupFd < 0) { ALOGE("Error %d dup channel fd %d.", errno, rawFd); jniThrowRuntimeException(env, "Could not read input channel file descriptors from parcel."); diff --git a/core/jni/android_view_InputChannel.h b/core/jni/android_view_InputChannel.h index fa2d28288923..096702140a2a 100644 --- a/core/jni/android_view_InputChannel.h +++ b/core/jni/android_view_InputChannel.h @@ -19,7 +19,7 @@ #include "jni.h" -#include <ui/InputTransport.h> +#include <androidfw/InputTransport.h> namespace android { diff --git a/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp index 4b737edeea09..e7d424472831 100644 --- a/core/jni/android_view_InputEventReceiver.cpp +++ b/core/jni/android_view_InputEventReceiver.cpp @@ -28,7 +28,7 @@ #include <utils/Log.h> #include <utils/Looper.h> #include <utils/threads.h> -#include <ui/InputTransport.h> +#include <androidfw/InputTransport.h> #include "android_os_MessageQueue.h" #include "android_view_InputChannel.h" #include "android_view_KeyEvent.h" @@ -93,7 +93,7 @@ NativeInputEventReceiver::~NativeInputEventReceiver() { } status_t NativeInputEventReceiver::initialize() { - int32_t receiveFd = mInputConsumer.getChannel()->getFd(); + int receiveFd = mInputConsumer.getChannel()->getFd(); mLooper->addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this); return OK; } @@ -264,7 +264,7 @@ static void nativeFinishInputEvent(JNIEnv* env, jclass clazz, jint receiverPtr, sp<NativeInputEventReceiver> receiver = reinterpret_cast<NativeInputEventReceiver*>(receiverPtr); status_t status = receiver->finishInputEvent(seq, handled); - if (status) { + if (status && status != DEAD_OBJECT) { String8 message; message.appendFormat("Failed to finish input event. status=%d", status); jniThrowRuntimeException(env, message.string()); @@ -275,7 +275,7 @@ static void nativeConsumeBatchedInputEvents(JNIEnv* env, jclass clazz, jint rece sp<NativeInputEventReceiver> receiver = reinterpret_cast<NativeInputEventReceiver*>(receiverPtr); status_t status = receiver->consumeEvents(true /*consumeBatches*/); - if (status) { + if (status && status != DEAD_OBJECT) { String8 message; message.appendFormat("Failed to consume batched input event. status=%d", status); jniThrowRuntimeException(env, message.string()); diff --git a/core/jni/android_view_KeyCharacterMap.cpp b/core/jni/android_view_KeyCharacterMap.cpp index b9f373882440..7245d9de134c 100644 --- a/core/jni/android_view_KeyCharacterMap.cpp +++ b/core/jni/android_view_KeyCharacterMap.cpp @@ -14,8 +14,8 @@ * limitations under the License. */ -#include <ui/KeyCharacterMap.h> -#include <ui/Input.h> +#include <androidfw/KeyCharacterMap.h> +#include <androidfw/Input.h> #include <android_runtime/AndroidRuntime.h> #include <nativehelper/jni.h> diff --git a/core/jni/android_view_KeyEvent.cpp b/core/jni/android_view_KeyEvent.cpp index 27469a22f06f..36a98f94e2fd 100644 --- a/core/jni/android_view_KeyEvent.cpp +++ b/core/jni/android_view_KeyEvent.cpp @@ -20,7 +20,7 @@ #include <android_runtime/AndroidRuntime.h> #include <utils/Log.h> -#include <ui/Input.h> +#include <androidfw/Input.h> #include "android_view_KeyEvent.h" namespace android { diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp index 2def1d14b7f3..0fb1b17a2b8e 100644 --- a/core/jni/android_view_MotionEvent.cpp +++ b/core/jni/android_view_MotionEvent.cpp @@ -20,7 +20,7 @@ #include <android_runtime/AndroidRuntime.h> #include <utils/Log.h> -#include <ui/Input.h> +#include <androidfw/Input.h> #include "android_view_MotionEvent.h" #include "android_util_Binder.h" #include "android/graphics/Matrix.h" diff --git a/core/jni/android_view_VelocityTracker.cpp b/core/jni/android_view_VelocityTracker.cpp index 0da90d7c66c7..668d3bb7dfdd 100644 --- a/core/jni/android_view_VelocityTracker.cpp +++ b/core/jni/android_view_VelocityTracker.cpp @@ -20,7 +20,7 @@ #include <android_runtime/AndroidRuntime.h> #include <utils/Log.h> -#include <ui/Input.h> +#include <androidfw/Input.h> #include "android_view_MotionEvent.h" diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp index b68c97a6cd5d..afbcfc259529 100644 --- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp +++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp @@ -21,7 +21,7 @@ #include <utils/Log.h> #include <ScopedUtfChars.h> -#include <utils/ZipFileRO.h> +#include <androidfw/ZipFileRO.h> #include <zlib.h> diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 68c919e92cb3..a2b1117ddf95 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1521,6 +1521,17 @@ android:description="@string/permdesc_serialPort" android:protectionLevel="normal" /> + <!-- Allows the holder to access content providers from outside an ApplicationThread. + This permission is enforced by the ActivityManagerService on the corresponding APIs, + in particular ActivityManagerService#getContentProviderExternal(String) and + ActivityManagerService#removeContentProviderExternal(String). + @hide + --> + <permission android:name="android.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY" + android:label="@string/permlab_accessContentProvidersExternally" + android:description="@string/permdesc_accessContentProvidersExternally" + android:protectionLevel="signature" /> + <!-- The system process is explicitly the only one allowed to launch the confirmation UI for full backup/restore --> <uses-permission android:name="android.permission.CONFIRM_FULL_BACKUP"/> diff --git a/core/res/res/anim/recents_fade_in.xml b/core/res/res/anim/recents_fade_in.xml new file mode 100644 index 000000000000..c516fadb77f9 --- /dev/null +++ b/core/res/res/anim/recents_fade_in.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* //device/apps/common/res/anim/recents_fade_in.xml +** +** Copyright 2012, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<alpha xmlns:android="http://schemas.android.com/apk/res/android" + android:interpolator="@interpolator/decelerate_quad" + android:fromAlpha="0.0" android:toAlpha="1.0" + android:duration="150" /> diff --git a/core/res/res/anim/recents_fade_out.xml b/core/res/res/anim/recents_fade_out.xml new file mode 100644 index 000000000000..7468cc1912f7 --- /dev/null +++ b/core/res/res/anim/recents_fade_out.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* //device/apps/common/res/anim/recents_fade_out.xml +** +** Copyright 2012, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<alpha xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@interpolator/accelerate_quad" + android:fromAlpha="1.0" + android:toAlpha="0.0" + android:duration="150" /> diff --git a/core/res/res/drawable-hdpi/stat_sys_data_wimax_signal_3_fully.png b/core/res/res/drawable-hdpi/stat_sys_data_wimax_signal_3_fully.png Binary files differindex c2e4b783c31e..cb08eed75658 100644 --- a/core/res/res/drawable-hdpi/stat_sys_data_wimax_signal_3_fully.png +++ b/core/res/res/drawable-hdpi/stat_sys_data_wimax_signal_3_fully.png diff --git a/core/res/res/drawable-hdpi/stat_sys_data_wimax_signal_disconnected.png b/core/res/res/drawable-hdpi/stat_sys_data_wimax_signal_disconnected.png Binary files differindex 51b839fd5572..ea065c36e742 100644 --- a/core/res/res/drawable-hdpi/stat_sys_data_wimax_signal_disconnected.png +++ b/core/res/res/drawable-hdpi/stat_sys_data_wimax_signal_disconnected.png diff --git a/core/res/res/drawable-mdpi/stat_sys_data_wimax_signal_3_fully.png b/core/res/res/drawable-mdpi/stat_sys_data_wimax_signal_3_fully.png Binary files differnew file mode 100644 index 000000000000..d3ba98c3ebc2 --- /dev/null +++ b/core/res/res/drawable-mdpi/stat_sys_data_wimax_signal_3_fully.png diff --git a/core/res/res/drawable-mdpi/stat_sys_data_wimax_signal_disconnected.png b/core/res/res/drawable-mdpi/stat_sys_data_wimax_signal_disconnected.png Binary files differnew file mode 100644 index 000000000000..153c6ad1f6cf --- /dev/null +++ b/core/res/res/drawable-mdpi/stat_sys_data_wimax_signal_disconnected.png diff --git a/core/res/res/drawable-xhdpi/stat_sys_data_wimax_signal_3_fully.png b/core/res/res/drawable-xhdpi/stat_sys_data_wimax_signal_3_fully.png Binary files differnew file mode 100644 index 000000000000..ec6bc54d77e2 --- /dev/null +++ b/core/res/res/drawable-xhdpi/stat_sys_data_wimax_signal_3_fully.png diff --git a/core/res/res/drawable-xhdpi/stat_sys_data_wimax_signal_disconnected.png b/core/res/res/drawable-xhdpi/stat_sys_data_wimax_signal_disconnected.png Binary files differnew file mode 100644 index 000000000000..9fd4f33bbf78 --- /dev/null +++ b/core/res/res/drawable-xhdpi/stat_sys_data_wimax_signal_disconnected.png diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index 19398cf3bebd..6f861fb82357 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -766,6 +766,10 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Laat die houer toe om versoeke aan pakketverifieerders te rig. Dit moet nooit vir normale programme nodig wees nie."</string> <string name="permlab_serialPort" msgid="546083327654631076">"kry toegang tot reekspoorte"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"Laat die houer toe om toegang te verkry tot reekspoorte wat die SerialManager API gebruik."</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"Wil jy hê die blaaier moet hierdie wagwoord onthou?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"Nie nou nie"</string> <string name="save_password_remember" msgid="6491879678996749466">"Onthou"</string> @@ -978,6 +982,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Begin Wi-Fi Direct. Dit sal die Wi-Fi-kliënt/warmkol afskakel."</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Kon nie Wi-Fi Direct begin nie."</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direk is aan"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Raak vir instellings"</string> <string name="accept" msgid="1645267259272829559">"Aanvaar"</string> <string name="decline" msgid="2112225451706137894">"Weier"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Uitnodiging gestuur"</string> @@ -986,8 +992,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"Aan:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Voer die vereiste PIN in:"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direk is aan"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Raak vir instellings"</string> <string name="select_character" msgid="3365550120617701745">"Voeg karakter in"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"Onbekend program"</string> <string name="sms_control_title" msgid="7296612781128917719">"Stuur SMS-boodskappe"</string> diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index 8f7b70f10c7b..bb6246a2739f 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -764,6 +764,10 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"የፓኬጅ አረጋጋጮችን ጥየቃ ለማድረግ ያዡ ይፈቅዳሉ። ለመደበኛ ትግበራዎች በፍፁም አያስፈልግም።"</string> <string name="permlab_serialPort" msgid="546083327654631076">"ተከታታይ ወደቦችን ድረስ"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"Allows the holder to access serial ports using the SerialManager API. የተከታታይ አደራጅ APIን በመጠቀም ያዡ የተከታታይ ወደቦችን እንዲደርስ ይፈቅዳል።"</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"አሳሹ ይህን ይለፍ ቃል እንዲያስታወስ ይፈልጋሉ?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"አሁን አይደለም"</string> <string name="save_password_remember" msgid="6491879678996749466">"አስታውስ"</string> @@ -976,6 +980,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi ቀጥታ"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"የWi-Fi በቀጥታ ጀምር።ይህ የWi-Fi ደንበኛ /ድረስ ነጥብ ያጠፋል።"</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"በቀጥታ Wi-Fi ማስጀመር አልተቻለም።"</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"የWi-Fi ቀጥታ በርቷል"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"ለቅንብሮች ንካ"</string> <string name="accept" msgid="1645267259272829559">"ተቀበል"</string> <string name="decline" msgid="2112225451706137894">"ውድቅ አድርግ"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"ግብዣ ተልኳል"</string> @@ -984,8 +990,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"ለ፦"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"የሚፈለገውን ፒን ተይብ፦"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"ፒን፦"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"የWi-Fi ቀጥታ በርቷል"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"ለቅንብሮች ንካ"</string> <string name="select_character" msgid="3365550120617701745">"ቁምፊ አስገባ"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"ያልታወቀ መተግበሪያ"</string> <string name="sms_control_title" msgid="7296612781128917719">"የSMS መልዕክቶች መበላክ ላይ"</string> diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index c9de7de2cc31..580f9bc78f19 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -764,6 +764,10 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"السماح للمالك بإجراء طلبات محققي الحزمة. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string> <string name="permlab_serialPort" msgid="546083327654631076">"الدخول إلى المنافذ التسلسلية"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"يسمح لحامله بالدخول إلى المنافذ التسلسلية باستخدام واجهة برمجة التطبيقات."</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"هل تريد من المتصفح تذكر كلمة المرور هذه؟"</string> <string name="save_password_notnow" msgid="6389675316706699758">"ليس الآن"</string> <string name="save_password_remember" msgid="6491879678996749466">"تذكّر"</string> @@ -976,6 +980,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"اتصال Wi-Fi مباشر"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"ابدأ Wi-Fi Direct. يؤدي هذا إلى إيقاف عميل/نقطة اتصال Wi-Fi."</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"تعذر بدء Wi-Fi Direct."</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"تم تشغيل اتصال Wi-Fi المباشر"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"المس للحصول على الإعدادات"</string> <string name="accept" msgid="1645267259272829559">"قبول"</string> <string name="decline" msgid="2112225451706137894">"رفض"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"تم إرسال الدعوة"</string> @@ -984,8 +990,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"إلى:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"اكتب رقم التعريف الشخصي المطلوب:"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"رقم التعريف الشخصي:"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"تم تشغيل اتصال Wi-Fi المباشر"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"المس للحصول على الإعدادات"</string> <string name="select_character" msgid="3365550120617701745">"إدراج حرف"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"تطبيق غير معروف"</string> <string name="sms_control_title" msgid="7296612781128917719">"إرسال رسائل قصيرة SMS"</string> diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml index adb13388b67f..8de1cf51c625 100644 --- a/core/res/res/values-be/strings.xml +++ b/core/res/res/values-be/strings.xml @@ -764,6 +764,10 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Дазваляе ўладальніку рабіць запыты верыфікатараў пакету. Не патрабуецца для звычайных прыкладанняў."</string> <string name="permlab_serialPort" msgid="546083327654631076">"атрымаць доступ да паслядоўных партоў"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"Дазваляе ўладальніку атрымліваць доступ да паслядоўных партоў з дапамогай API SerialManager."</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"Вы хочаце, каб браўзэр запомніў гэты пароль?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"Не цяпер"</string> <string name="save_password_remember" msgid="6491879678996749466">"Запомніць"</string> @@ -976,6 +980,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Пачаць работу Wi-Fi Direct. Гэта адключыць кліента або кропку доступу Wi-Fi."</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Немагчыма запусціць Wi-Fi Direct."</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct уключаны"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Дакраніцеся, каб наладзіць"</string> <string name="accept" msgid="1645267259272829559">"Прыняць"</string> <string name="decline" msgid="2112225451706137894">"Адхіліць"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Запрашэнне адпраўлена"</string> @@ -984,8 +990,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"Каму:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Увядзіце патрэбны PIN-код:"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN-код"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct уключаны"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Дакраніцеся, каб наладзіць"</string> <string name="select_character" msgid="3365550120617701745">"Уставіць сімвал"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"Невядомае прыкладанне"</string> <string name="sms_control_title" msgid="7296612781128917719">"Адпраўка SMS"</string> diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index 23ae6c22ad24..ec2e0bf994dc 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -215,10 +215,8 @@ <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Разрешава на приложението да прехвърля задачи на преден и на заден план. Злонамерените приложения могат сами да се изведат на преден план без ваша намеса."</string> <string name="permlab_removeTasks" msgid="6821513401870377403">"спиране на изпълняваните приложения"</string> <string name="permdesc_removeTasks" msgid="1394714352062635493">"Разрешава на приложението да премахва задачи и да прекратява приложенията им. Злонамерените приложения могат да нарушат поведението на други приложения."</string> - <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) --> - <skip /> - <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) --> - <skip /> + <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"задаване на съвместимост на екрана"</string> + <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Разрешава на приложението да контролира режима на съвместимост на екрана на други приложения. Злонамерените програми могат да нарушат поведението на други приложения."</string> <string name="permlab_setDebugApp" msgid="3022107198686584052">"активиране на отстраняването на грешки в приложения"</string> <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Разрешава на приложението да включва отстраняването на грешки за друго приложение. Злонамерените приложения могат да използват това, за да прекратят други приложения."</string> <string name="permlab_changeConfiguration" msgid="8214475779521218295">"промяна на настройките ви за потребителския интерфейс"</string> @@ -766,6 +764,10 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Разрешава на притежателя да прави заявки за верификатори на пакета. Нормалните приложения би трябвало никога да не се нуждаят от това."</string> <string name="permlab_serialPort" msgid="546083327654631076">"достъп до серийни портове"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"Разрешава на притежателя достъп до серийни портове посредством приложния програмен интерфейс (API) SerialManager."</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"Искате ли браузърът да запомни тази парола?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"Не сега"</string> <string name="save_password_remember" msgid="6491879678996749466">"Запомняне"</string> @@ -978,6 +980,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Стартиране на Wi-Fi Direct. Това ще изключи клиентската програма/точката за достъп до Wi-Fi."</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Direct не можа да се стартира."</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct е включено"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Докоснете за настройки"</string> <string name="accept" msgid="1645267259272829559">"Приемам"</string> <string name="decline" msgid="2112225451706137894">"Отхвърлям"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Поканата е изпратена"</string> @@ -986,8 +990,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"До:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Въведете задължителния ПИН:"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"ПИН:"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct е включено"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Докоснете за настройки"</string> <string name="select_character" msgid="3365550120617701745">"Вмъкване на знак"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"Неизвестно приложение"</string> <string name="sms_control_title" msgid="7296612781128917719">"Изпращане на SMS съобщения"</string> diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index 460fcb7f504a..173f1fc6d9db 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -764,6 +764,10 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permet que el titular sol·liciti verificadors de paquets. No s\'hauria de necessitar mai per a les aplicacions normals."</string> <string name="permlab_serialPort" msgid="546083327654631076">"accedeix a ports sèrie"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"Permet que el titular accedeixi a ports sèrie amb l\'API SerialManager."</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"Voleu que el navegador recordi aquesta contrasenya?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"Ara no"</string> <string name="save_password_remember" msgid="6491879678996749466">"Recorda-ho"</string> @@ -976,6 +980,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Inicia Wi-Fi Direct. Això desactivarà el client/la zona Wi-Fi."</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"No s\'ha pogut iniciar Wi-Fi Direct."</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct està activat"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Toca per accedir a la configuració"</string> <string name="accept" msgid="1645267259272829559">"Accepta"</string> <string name="decline" msgid="2112225451706137894">"Rebutja"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"S\'ha enviat la invitació"</string> @@ -984,8 +990,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"Per a:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Introdueix el PIN sol·licitat:"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct està activat"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Toca per accedir a la configuració"</string> <string name="select_character" msgid="3365550120617701745">"Insereix un caràcter"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"Aplicació desconeguda"</string> <string name="sms_control_title" msgid="7296612781128917719">"S\'estan enviant missatges SMS"</string> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index c801fb4bb67f..d3b527666804 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -215,10 +215,8 @@ <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Umožňuje aplikaci přesunout úlohy na popředí nebo pozadí. Škodlivé aplikace mohou vynutit zobrazení na popředí bez vašeho svolení."</string> <string name="permlab_removeTasks" msgid="6821513401870377403">"zastavení činnosti aplikací"</string> <string name="permdesc_removeTasks" msgid="1394714352062635493">"Umožňuje aplikaci odstranit úlohy a ukončit jejich aplikace. Škodlivé aplikace mohou narušit chování ostatních aplikací."</string> - <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) --> - <skip /> - <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) --> - <skip /> + <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"nastavit kompatibilitu obrazovky"</string> + <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Umožňuje aplikaci ovládat režim kompatibility obrazovky v ostatních aplikacích. Škodlivé aplikace mohou narušit chování ostatních aplikací."</string> <string name="permlab_setDebugApp" msgid="3022107198686584052">"povolení ladění aplikací"</string> <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Umožňuje aplikaci zapnout ladění jiné aplikace. Škodlivé aplikace mohou toto oprávnění použít k ukončení ostatních aplikací."</string> <string name="permlab_changeConfiguration" msgid="8214475779521218295">"změna vašeho nastavení uživatelského rozhraní"</string> @@ -766,6 +764,10 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Umožňuje držiteli podávat žádosti o ověření balíčků. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string> <string name="permlab_serialPort" msgid="546083327654631076">"přístup k sériovým portům"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"Umožňuje držiteli přístup k sériovým portům pomocí rozhraní SerialManager API."</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"Chcete, aby si prohlížeč zapamatoval toto heslo?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"Nyní ne"</string> <string name="save_password_remember" msgid="6491879678996749466">"Zapamatovat"</string> @@ -978,6 +980,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Přímé připojení sítě Wi-Fi"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Spustit přímé připojení sítě Wi-Fi. Tato možnost vypne provoz sítě Wi-Fi v režimu klient/hotspot."</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Přímé připojení sítě Wi-Fi se nepodařilo spustit."</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Přímé připojení sítě Wi-Fi je zapnuto"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Nastavení otevřete dotykem"</string> <string name="accept" msgid="1645267259272829559">"Přijmout"</string> <string name="decline" msgid="2112225451706137894">"Odmítnout"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Pozvánka odeslána."</string> @@ -986,8 +990,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"Komu:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Zadejte požadovaný kód PIN:"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Přímé připojení sítě Wi-Fi je zapnuto"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Nastavení otevřete dotykem"</string> <string name="select_character" msgid="3365550120617701745">"Vkládání znaků"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"Neznámá aplikace"</string> <string name="sms_control_title" msgid="7296612781128917719">"Odesílání zpráv SMS"</string> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index 65d7cdce5f13..78aff335f1d0 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -757,13 +757,17 @@ <string name="permlab_addVoicemail" msgid="5525660026090959044">"tilføj telefonsvarer"</string> <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Tillader, at appen kan tilføje beskeder på din telefonsvarer."</string> <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"skifte tilladelser til geografisk placering i Browser"</string> - <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Tillader, at appen kan ændre browserens tilladelser angående geografisk placering. Ondsindede apps kan benytte dette til at sende oplysninger om placering til vilkårlige websteder."</string> + <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Tillader, at appen kan ændre browserens tilladelser angående geografisk placering. Ondsindede apps kan benytte dette til at sende oplysninger om placering til vilkårlige websites."</string> <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"bekræft pakker"</string> <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Tillader, at appen kan bekræfte, at en pakke kan installeres."</string> <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"bind til en bekræftelse af pakker"</string> <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Tillader, at indehaveren kan sende anmodninger om bekræftelser af pakker. Dette bør aldrig være nødvendigt for almindelige apps."</string> <string name="permlab_serialPort" msgid="546083327654631076">"adgang til serielle porte"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"Tillader, at indehaveren kan få adgang til serielle porte ved hjælp af SerialManager API."</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"Ønsker du, at browseren skal huske denne adgangskode?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"Ikke nu"</string> <string name="save_password_remember" msgid="6491879678996749466">"Husk"</string> @@ -976,6 +980,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Start Wi-Fi Direct. Dette slår Wi-Fi-klient/hotspot fra."</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Direct kunne ikke startes."</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct er slået til"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Tryk for indstillinger"</string> <string name="accept" msgid="1645267259272829559">"Accepter"</string> <string name="decline" msgid="2112225451706137894">"Afvis"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Invitationen er sendt"</string> @@ -984,8 +990,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"Til:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Skriv den påkrævede pinkode:"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"Pinkode:"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct er slået til"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Tryk for indstillinger"</string> <string name="select_character" msgid="3365550120617701745">"Indsæt tegn"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"Ukendt app"</string> <string name="sms_control_title" msgid="7296612781128917719">"Sender sms-beskeder"</string> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index dbe81373bcfc..78845c47dcf4 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -764,6 +764,10 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Ermöglicht dem Halter, Anfragen für die Paketprüfung zu senden. Sollte nie für normale Apps benötigt werden."</string> <string name="permlab_serialPort" msgid="546083327654631076">"Zugriff auf serielle Schnittstellen"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"Ermöglicht dem Inhaber den Zugriff auf serielle Schnittstellen über das SerialManager-API"</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"Möchten Sie, dass der Browser dieses Passwort speichert?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"Nicht jetzt"</string> <string name="save_password_remember" msgid="6491879678996749466">"Speichern"</string> @@ -976,6 +980,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Direct-Betrieb starten. Hierdurch wird der WLAN-Client-/-Hotspot-Betrieb deaktiviert."</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Starten von Wi-Fi Direct nicht möglich"</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct ist aktiviert."</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Zum Aufrufen der Einstellungen berühren"</string> <string name="accept" msgid="1645267259272829559">"Akzeptieren"</string> <string name="decline" msgid="2112225451706137894">"Ablehnen"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Einladung gesendet"</string> @@ -984,8 +990,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"An:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Geben Sie die erforderliche PIN ein:"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct ist aktiviert."</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Zum Aufrufen der Einstellungen berühren"</string> <string name="select_character" msgid="3365550120617701745">"Zeichen einfügen"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"Unbekannte App"</string> <string name="sms_control_title" msgid="7296612781128917719">"Kurznachrichten werden gesendet"</string> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index 154ca55f578a..9244dab11903 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -215,10 +215,8 @@ <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Επιτρέπει στην εφαρμογή τη μετακίνηση εργασιών στο προσκήνιο και στο φόντο. Τυχόν κακόβουλες εφαρμογές μπορούν να προωθηθούν στο προσκήνιο χωρίς να μπορείτε να τις ελέγξετε."</string> <string name="permlab_removeTasks" msgid="6821513401870377403">"διακοπή εκτέλεσης εφαρμογών"</string> <string name="permdesc_removeTasks" msgid="1394714352062635493">"Επιτρέπει στην εφαρμογή την κατάργηση ενεργειών και την απομάκρυνση των εφαρμογών τους. Τυχόν κακόβουλες εφαρμογές ενδέχεται να διαταράξουν τη λειτουργία άλλων εφαρμογών."</string> - <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) --> - <skip /> - <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) --> - <skip /> + <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"ρύθμιση συμβατότητας οθόνης"</string> + <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Επιτρέπει στην εφαρμογή να ελέγξει τη λειτουργία συμβατότητας της οθόνης με άλλες εφαρμογές. Οι κακόβουλες εφαρμογές μπορεί να επηρεάσουν τη συμπεριφορά άλλων εφαρμογών."</string> <string name="permlab_setDebugApp" msgid="3022107198686584052">"ενεργοποίηση εντοπισμού σφαλμάτων εφαρμογής"</string> <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Επιτρέπει στην εφαρμογή να ενεργοποιήσει τον εντοπισμό σφαλμάτων για μια άλλη εφαρμογή. Τυχόν κακόβουλες εφαρμογές ενδέχεται να χρησιμοποιήσουν αυτήν τη δυνατότητα για τον τερματισμό άλλων εφαρμογών."</string> <string name="permlab_changeConfiguration" msgid="8214475779521218295">"αλλαγή των ρυθμίσεων του UI"</string> @@ -766,6 +764,10 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Επιτρέπει στον κάτοχο να υποβάλλει ερωτήματα σε προγράμματα επαλήθευσης πακέτου. Δεν απαιτείται για συνήθεις εφαρμογές."</string> <string name="permlab_serialPort" msgid="546083327654631076">"πρόσβαση στις σειριακές θύρες"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"Επιτρέπει στον κάτοχο την πρόσβαση στις σειριακές θύρες με τη χρήση του SerialManager API."</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"Θέλετε το πρόγραμμα περιήγησης να διατηρήσει αυτόν τον κωδικό πρόσβασης;"</string> <string name="save_password_notnow" msgid="6389675316706699758">"Να μην γίνει τώρα"</string> <string name="save_password_remember" msgid="6491879678996749466">"Διατήρηση"</string> @@ -978,6 +980,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Ξεκινήστε τη λειτουργία Wi-Fi Direct. Θα απενεργοποιηθεί η λειτουργία πελάτη/φορητού σημείου πρόσβασης Wi-Fi."</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Δεν ήταν δυνατή η εκκίνηση του Wi-Fi Direct."</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Το Wi-Fi Direct έχει ενεργοποιηθεί"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Αγγίξτε για ρυθμίσεις"</string> <string name="accept" msgid="1645267259272829559">"Αποδοχή"</string> <string name="decline" msgid="2112225451706137894">"Απόρριψη"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Η πρόσκληση στάλθηκε"</string> @@ -986,8 +990,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"Προς:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Πληκτρολογήστε τον απαιτούμενο κωδικό PIN:"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Το Wi-Fi Direct έχει ενεργοποιηθεί"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Αγγίξτε για ρυθμίσεις"</string> <string name="select_character" msgid="3365550120617701745">"Εισαγωγή χαρακτήρα"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"Άγνωστη εφαρμογή"</string> <string name="sms_control_title" msgid="7296612781128917719">"Αποστολή μηνυμάτων SMS"</string> diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml index 0429c8b7f3f6..dbd221818ede 100644 --- a/core/res/res/values-en-rGB/strings.xml +++ b/core/res/res/values-en-rGB/strings.xml @@ -764,6 +764,10 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Allows the holder to make requests of package verifiers. Should never be needed for normal apps."</string> <string name="permlab_serialPort" msgid="546083327654631076">"access serial ports"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"Allows the holder to access serial ports using the SerialManager API."</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"Do you want the browser to remember this password?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"Not now"</string> <string name="save_password_remember" msgid="6491879678996749466">"Remember"</string> @@ -976,6 +980,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Start Wi-Fi Direct. This will turn off Wi-Fi client/hotspot."</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Couldn\'t start Wi-Fi Direct."</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct is on"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Touch for settings"</string> <string name="accept" msgid="1645267259272829559">"Accept"</string> <string name="decline" msgid="2112225451706137894">"Decline"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Invitation sent"</string> @@ -984,8 +990,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"To:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Type the required PIN:"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct is on"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Touch for settings"</string> <string name="select_character" msgid="3365550120617701745">"Insert character"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"Unknown app"</string> <string name="sms_control_title" msgid="7296612781128917719">"Sending SMS messages"</string> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index ad3e949899a8..42cc24a3d689 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -215,8 +215,8 @@ <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Permite que la aplicación mueva tareas al primero o segundo plano. Las aplicaciones maliciosas pueden forzar su paso al primer plano sin que tú las controles."</string> <string name="permlab_removeTasks" msgid="6821513401870377403">"detener las aplicaciones en ejecución"</string> <string name="permdesc_removeTasks" msgid="1394714352062635493">"Permite que la aplicación elimine tareas y cierre sus aplicaciones. Las aplicaciones malintencionadas pueden usar este permiso para interferir en el comportamiento de otras aplicaciones."</string> - <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"Configurar el modo de la compatibilidad de otras pantalla"</string> - <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Permite a la aplicación controlar el modo de la compatibilidad de las pantallas de otras aplicaciones. Las aplicaciones malintencionadas pueden interrumpir el funcionamiento de otras aplicaciones."</string> + <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"Definir compatibilidad de pantalla"</string> + <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Permite a la aplicación controlar el modo de compatibilidad de las pantallas de otras aplicaciones. Las aplicaciones malintencionadas pueden interrumpir el funcionamiento de otras aplicaciones."</string> <string name="permlab_setDebugApp" msgid="3022107198686584052">"activar depuración de aplicación"</string> <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Permite que la aplicación active la depuración de otra aplicación. Las aplicaciones malintencionadas pueden usar este permiso para interrumpir la ejecución de otras aplicaciones."</string> <string name="permlab_changeConfiguration" msgid="8214475779521218295">"cambiar tu configuración de la interfaz de usuario"</string> @@ -764,6 +764,10 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permite que el titular solicite verificadores de paquetes. Las aplicaciones normales no deberían necesitar este permiso."</string> <string name="permlab_serialPort" msgid="546083327654631076">"Acceder a los puertos serie"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"Permite acceder a puertos serie a través de la API SerialManager."</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"¿Quieres recordar esta contraseña en el navegador?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"Ahora no."</string> <string name="save_password_remember" msgid="6491879678996749466">"Recuerda"</string> @@ -976,6 +980,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Iniciar Wi-Fi Direct. Se desactivará el funcionamiento de la zona o del cliente Wi-Fi."</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"No se pudo iniciar Wi-Fi Direct."</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Se activó Wi-Fi Direct."</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Tocar para ajustar los parámetros de configuración"</string> <string name="accept" msgid="1645267259272829559">"Aceptar"</string> <string name="decline" msgid="2112225451706137894">"Rechazar"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Se envió la invitación."</string> @@ -984,8 +990,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"Para:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Escribe el PIN solicitado:"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Se activó Wi-Fi Direct."</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Tocar para ajustar los parámetros de configuración"</string> <string name="select_character" msgid="3365550120617701745">"Insertar caracteres"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"Aplicación desconocida"</string> <string name="sms_control_title" msgid="7296612781128917719">"Enviando mensajes SMS"</string> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index 1bd13bd2b320..a09a6bfb1e5a 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -764,6 +764,10 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permite que se envíen solicitudes de detectores de paquetes. Las aplicaciones normales no deberían necesitar este permiso."</string> <string name="permlab_serialPort" msgid="546083327654631076">"acceder a puertos serie"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"Permite acceder a puertos serie a través de SerialManager API."</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"¿Quieres que el navegador recuerde esta contraseña?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"Ahora no"</string> <string name="save_password_remember" msgid="6491879678996749466">"Recordar"</string> @@ -976,6 +980,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Iniciar Wi-Fi Direct. Se desactivará el funcionamiento de la zona o del cliente Wi-Fi."</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"No se ha podido iniciar Wi-Fi Direct."</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct activado"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Toca para acceder a Ajustes"</string> <string name="accept" msgid="1645267259272829559">"Aceptar"</string> <string name="decline" msgid="2112225451706137894">"Rechazar"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Invitación enviada"</string> @@ -984,8 +990,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"Para:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Escribe el PIN solicitado:"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct activado"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Toca para acceder a Ajustes"</string> <string name="select_character" msgid="3365550120617701745">"Insertar carácter"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"Aplicación desconocida"</string> <string name="sms_control_title" msgid="7296612781128917719">"Enviando mensajes SMS..."</string> diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml index 2f42a70d72e9..07e732ac9bd3 100644 --- a/core/res/res/values-et/strings.xml +++ b/core/res/res/values-et/strings.xml @@ -764,6 +764,10 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Lubab omanikul teha taotlusi paketi kinnitajate kohta. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string> <string name="permlab_serialPort" msgid="546083327654631076">"juurdepääs jadaportidele"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"Võimaldab omanikul SerialManageri API-liidese abil jadaportidele juurde pääseda."</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"Kas soovite, et brauser jätaks selle parooli meelde?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"Mitte praegu"</string> <string name="save_password_remember" msgid="6491879678996749466">"Pidage meeles"</string> @@ -976,6 +980,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"WiFi Direct"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Käivitage WiFi otseühendus. See lülitab välja WiFi kliendi/leviala."</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"WiFi otseühenduse käivitamine ebaõnnestus."</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"WiFi Direct on sees"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Puuted seadete jaoks"</string> <string name="accept" msgid="1645267259272829559">"Nõustu"</string> <string name="decline" msgid="2112225451706137894">"Keeldu"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Kutse on saadetud"</string> @@ -984,8 +990,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"Saaja:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Sisestage nõutav PIN-kood:"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN-kood:"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"WiFi Direct on sees"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Puuted seadete jaoks"</string> <string name="select_character" msgid="3365550120617701745">"Sisesta tähemärk"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"Tundmatu rakendus"</string> <string name="sms_control_title" msgid="7296612781128917719">"SMS-sõnumite saatmine"</string> diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index fd7a77190b7e..ddb0438d7c74 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -764,6 +764,10 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"به دارنده اجازه میدهد تا تاییدکنندگان بسته را درخواست کند. برای برنامههای عادی نیاز نیست."</string> <string name="permlab_serialPort" msgid="546083327654631076">"دسترسی به درگاههای سریال"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"به دارنده اجازه میدهد با استفاده از SerialManager API به درگاههای سریال دسترسی داشته باشد."</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"می خواهید مرورگر این رمز ورود را به خاطر داشته باشد؟"</string> <string name="save_password_notnow" msgid="6389675316706699758">"اکنون خیر"</string> <string name="save_password_remember" msgid="6491879678996749466">"به خاطر سپردن"</string> @@ -976,6 +980,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Direct را شروع کنید. این کار نقطه اتصال/سرویس گیرنده Wi-Fi را غیرفعال خواهد کرد."</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Direct شروع نشد."</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct روشن است"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"لمس کردن برای تنظیمات"</string> <string name="accept" msgid="1645267259272829559">"پذیرش"</string> <string name="decline" msgid="2112225451706137894">"عدم پذیرش"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"دعوتنامه ارسال شد"</string> @@ -984,8 +990,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"به:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"پین لازم را تایپ کنید:"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"پین:"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct روشن است"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"لمس کردن برای تنظیمات"</string> <string name="select_character" msgid="3365550120617701745">"درج نویسه"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"برنامه ناشناخته"</string> <string name="sms_control_title" msgid="7296612781128917719">"ارسال پیامک ها"</string> diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index 9cf18ecc6237..b837c5a5edee 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -764,6 +764,10 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Antaa sovelluksen tehdä pakettien vahvistuspyyntöjä. Ei tavallisten sovellusten käyttöön."</string> <string name="permlab_serialPort" msgid="546083327654631076">"käytä sarjaportteja"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"Luvan haltija voi käyttää sarjaportteja SerialManager-sovellusliittymän avulla."</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"Haluatko selaimen muistavan tämän salasanan?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"Ei nyt"</string> <string name="save_password_remember" msgid="6491879678996749466">"Muista"</string> @@ -976,6 +980,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Suora wifi-yhteys"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Käynnistä suora wifi-yhteys. Wifi-asiakas/-hotspot poistetaan käytöstä."</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Suoran wifi-yhteyden käynnistäminen epäonnistui."</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct on käytössä"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Tarkastele asetuksia koskettamalla"</string> <string name="accept" msgid="1645267259272829559">"Hyväksy"</string> <string name="decline" msgid="2112225451706137894">"Hylkää"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Kutsu lähetetty."</string> @@ -984,8 +990,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"Kohde:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Kirjoita pyydetty PIN-koodi:"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN-koodi:"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct on käytössä"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Tarkastele asetuksia koskettamalla"</string> <string name="select_character" msgid="3365550120617701745">"Lisää merkki"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"Tuntematon sovellus"</string> <string name="sms_control_title" msgid="7296612781128917719">"Tekstiviestien lähettäminen"</string> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index 33b0f45bd664..aebe4604d00b 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -764,6 +764,10 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permet à l\'application autorisée d\'effectuer des requêtes de vérificateurs de package. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string> <string name="permlab_serialPort" msgid="546083327654631076">"accéder aux ports série"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"Permet à l\'application autorisée d\'accéder aux ports série avec l\'API SerialManager."</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"Voulez-vous que le navigateur se souvienne de ce mot de passe ?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"Pas maintenant"</string> <string name="save_password_remember" msgid="6491879678996749466">"Mémoriser"</string> @@ -976,6 +980,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Lancer le Wi-Fi Direct. Cela désactive le fonctionnement du Wi-Fi client ou via un point d\'accès."</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Impossible d\'activer le Wi-Fi Direct."</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct activé"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Appuyez pour accéder aux paramètres."</string> <string name="accept" msgid="1645267259272829559">"Accepter"</string> <string name="decline" msgid="2112225451706137894">"Refuser"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Invitation envoyée"</string> @@ -984,8 +990,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"À :"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Saisissez le code PIN requis :"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"Code PIN :"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct activé"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Appuyez pour accéder aux paramètres."</string> <string name="select_character" msgid="3365550120617701745">"Insérer un caractère"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"Application inconnue"</string> <string name="sms_control_title" msgid="7296612781128917719">"Envoi de messages SMS"</string> diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index 91ac5a370f31..11bad079e1a5 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -764,6 +764,10 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"धारक को पैकेज प्रमाणक के अनुरोध की अनुमति देता है. सामान्य एप्लिकेशन के लिए कभी भी आवश्यक नहीं होना चाहिए."</string> <string name="permlab_serialPort" msgid="546083327654631076">"सीरियल पोर्ट पर पहुंचें"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"SerialManager API का उपयोग करके धारक को सीरियल पोर्ट पर पहुंच प्रदान करता है."</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"क्या आप चाहते हैं कि ब्राउज़र पासवर्ड को याद रखे?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"अभी नहीं"</string> <string name="save_password_remember" msgid="6491879678996749466">"याद रखें"</string> @@ -976,6 +980,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi प्रत्यक्ष"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi डायरेक्ट प्रारंभ करें. इससे Wi-Fi क्लाइंट/हॉटस्पॉट कार्यवाही बंद हो जाएगी."</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi डायरेक्ट प्रारंभ नहीं किया जा सका."</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi प्रत्यक्ष चालू है"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"सेटिंग के लिए स्पर्श करें"</string> <string name="accept" msgid="1645267259272829559">"स्वीकार करें"</string> <string name="decline" msgid="2112225451706137894">"अस्वीकार करें"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"आमंत्रण भेजा गया"</string> @@ -984,8 +990,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"प्रति:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"आवश्यक पिन लिखें:"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"पिन:"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi प्रत्यक्ष चालू है"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"सेटिंग के लिए स्पर्श करें"</string> <string name="select_character" msgid="3365550120617701745">"वर्ण सम्मिलित करें"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"अज्ञात एप्लिकेशन"</string> <string name="sms_control_title" msgid="7296612781128917719">"SMS संदेश भेज रहा है"</string> diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index a60dcfaddff7..462cb5286fef 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -215,8 +215,8 @@ <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Omogućuje aplikaciji da premjesti zadatke u prednji plan ili pozadinu. Zlonamjerne aplikacije mogu na silu doći u prednji plan bez vašeg nadzora."</string> <string name="permlab_removeTasks" msgid="6821513401870377403">"zaustavljanje pokrenutih aplikacija"</string> <string name="permdesc_removeTasks" msgid="1394714352062635493">"Omogućuje aplikaciji uklanjanje zadataka i uklanjanje njihovih aplikacija. Zlonamjerne aplikacije mogu poremetiti rad drugih aplikacija."</string> - <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"postavljanje zaslona kompatibilnost"</string> - <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Aplikaciji omogućuje upravljanje načinom kompatibilnosti zaslona drugih aplikacija. Zlonamjerne aplikacije mogu prekinuti takvo ponašanje ostalih aplikacija."</string> + <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"postavljanje kompatibilnosti sa zaslonom"</string> + <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Aplikaciji omogućuje upravljanje načinom kompatibilnosti aplikacija sa zaslonom. Zlonamjerne aplikacije mogu prekinuti takvo ponašanje ostalih aplikacija."</string> <string name="permlab_setDebugApp" msgid="3022107198686584052">"omogućavanje rješavanja programskih pogrešaka u aplikaciji"</string> <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Omogućuje aplikaciji uključivanje uklanjanja programskih pogrešaka za drugu aplikaciju. Zlonamjerne aplikacije mogu na taj način ukloniti druge aplikacije."</string> <string name="permlab_changeConfiguration" msgid="8214475779521218295">"promjena postavki korisničkog sučelja"</string> @@ -764,6 +764,10 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Nositelju omogućuje da traži paketnu provjeru. Ne bi smjelo biti potrebno za normalne aplikacije."</string> <string name="permlab_serialPort" msgid="546083327654631076">"pristup serijskim priključcima"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"Rukovatelju omogućuje pristup serijskim priključcima pomoću značajke SerialManager API."</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"Želite li da preglednik zapamti ovu zaporku?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"Ne sada"</string> <string name="save_password_remember" msgid="6491879678996749466">"Zapamti"</string> @@ -976,6 +980,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Izravni Wi-Fi"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Pokreni izravan rad s Wi-Fi mrežom. To će isključiti rad s Wi-Fi klijentom/žarišnom točkom."</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Pokretanje izravne Wi-Fi veze nije moguće."</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct uključen"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Dodirnite za postavke"</string> <string name="accept" msgid="1645267259272829559">"Prihvaćam"</string> <string name="decline" msgid="2112225451706137894">"Odbaci"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Pozivnica je poslana"</string> @@ -984,8 +990,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"Prima:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Upišite potreban PIN:"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct uključen"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Dodirnite za postavke"</string> <string name="select_character" msgid="3365550120617701745">"Umetni znak"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"Nepoznata aplikacija"</string> <string name="sms_control_title" msgid="7296612781128917719">"Slanje SMS poruka"</string> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index 6b789ea5da70..c74ef36c2dee 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -764,6 +764,10 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Lehetővé teszi, hogy a tulajdonos kérelmeket nyújtson be a csomag hitelesítőivel kapcsolatban. A normál alkalmazásoknak erre soha nincs szüksége."</string> <string name="permlab_serialPort" msgid="546083327654631076">"soros portok elérése"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"Lehetővé teszi a tulajdonos számára a soros portok elérését a SerialManager API segítségével."</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"Szeretné, hogy a böngésző megjegyezze a jelszót?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"Most nem"</string> <string name="save_password_remember" msgid="6491879678996749466">"Megjegyzés"</string> @@ -976,6 +980,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Direct elindítása. A Wi-Fi kliens/hotspot ettől leáll."</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Nem sikerült elindítani a Wi-Fi Direct kapcsolatot."</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"A Wi-Fi Direct be van kapcsolva"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"A beállításokhoz érintse meg"</string> <string name="accept" msgid="1645267259272829559">"Elfogadás"</string> <string name="decline" msgid="2112225451706137894">"Elutasítás"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Meghívó elküldve"</string> @@ -984,8 +990,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"Címzett:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Adja meg a szükséges PIN kódot:"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN kód:"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"A Wi-Fi Direct be van kapcsolva"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"A beállításokhoz érintse meg"</string> <string name="select_character" msgid="3365550120617701745">"Karakter beszúrása"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"Ismeretlen alkalmazás"</string> <string name="sms_control_title" msgid="7296612781128917719">"SMS-ek küldése"</string> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index 6ed5c0e4b600..068356ea169c 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -764,6 +764,10 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Mengizinkan pemegang mengajukan permintaan pemverifikasian paket. Tidak pernah dibutuhkan oleh apl normal."</string> <string name="permlab_serialPort" msgid="546083327654631076">"akses port serial"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"Memungkinkan pemegangnya mengakses port serial menggunakan API SerialManager."</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"Apakah Anda ingin peramban menyimpan sandi ini?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"Tidak sekarang"</string> <string name="save_password_remember" msgid="6491879678996749466">"Ingat"</string> @@ -976,6 +980,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Langsung"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Memulai Wi-Fi Langsung. Opsi ini akan mematikan hotspot/klien Wi-Fi."</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Tidak dapat memulai Wi-Fi Langsung."</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Langsung aktif"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Sentuh untuk setelan"</string> <string name="accept" msgid="1645267259272829559">"Terima"</string> <string name="decline" msgid="2112225451706137894">"Tolak"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Undangan terkirim"</string> @@ -984,8 +990,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"Kepada:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Ketik PIN yang diminta:"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Langsung aktif"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Sentuh untuk setelan"</string> <string name="select_character" msgid="3365550120617701745">"Sisipkan huruf"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"Apl tak dikenal"</string> <string name="sms_control_title" msgid="7296612781128917719">"Mengirim pesan SMS"</string> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index 8af1f5eee701..221fff0f4f89 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -764,6 +764,10 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Consente al proprietario di effettuare richieste relative alle verifiche dei pacchetti. Non dovrebbe mai essere necessario per le normali applicazioni."</string> <string name="permlab_serialPort" msgid="546083327654631076">"accesso alle porte seriali"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"Permette al proprietario di accedere alle porte seriali utilizzando l\'API SerialManager."</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"Memorizzare la password nel browser?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"Non ora"</string> <string name="save_password_remember" msgid="6491879678996749466">"Memorizza"</string> @@ -976,6 +980,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Avvia Wi-Fi Direct. Verrà disattivato il client/hotspot Wi-Fi."</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Avvio di Wi-Fi Direct non riuscito."</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct è attivo"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Tocca per le impostazioni"</string> <string name="accept" msgid="1645267259272829559">"Accetto"</string> <string name="decline" msgid="2112225451706137894">"Rifiuto"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Invito inviato"</string> @@ -984,8 +990,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"A:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Inserisci il PIN richiesto:"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct è attivo"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Tocca per le impostazioni"</string> <string name="select_character" msgid="3365550120617701745">"Inserisci carattere"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"Applicazione sconosciuta"</string> <string name="sms_control_title" msgid="7296612781128917719">"Invio SMS"</string> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index 5d5b9daed4d2..c1d7d82331db 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -764,6 +764,10 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"מאפשר למשתמש להגיש בקשות של מאמתי חבילות. הרשאה זו לעולם אינה נחוצה ליישומים רגילים."</string> <string name="permlab_serialPort" msgid="546083327654631076">"גישה ליציאות טוריות"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"מאפשר לבעלים לגשת ליציאות טוריות באמצעות ממשק ה- API של SerialManager."</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"האם ברצונך שהדפדפן יזכור סיסמה זו?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"לא כעת"</string> <string name="save_password_remember" msgid="6491879678996749466">"זכור"</string> @@ -976,6 +980,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi ישיר"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"הפעל Wi-Fi ישיר. פעולה זו תכבה את הלקוח/הנקודה החמה של ה-Wi-Fi."</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"לא ניתן להפעיל Wi-Fi ישיר"</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi ישיר מופעל"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"גע עבור הגדרות"</string> <string name="accept" msgid="1645267259272829559">"קבל"</string> <string name="decline" msgid="2112225451706137894">"דחה"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"ההזמנה נשלחה"</string> @@ -984,8 +990,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"אל:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"הקלד את קוד ה-PIN הנדרש."</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi ישיר מופעל"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"גע עבור הגדרות"</string> <string name="select_character" msgid="3365550120617701745">"הוסף תו"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"יישום לא ידוע"</string> <string name="sms_control_title" msgid="7296612781128917719">"שולח הודעות SMS"</string> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index ea4af6610ae0..b3476dbbb2c4 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -215,10 +215,8 @@ <string name="permdesc_reorderTasks" msgid="4175137612205663399">"タスクをフォアグラウンドやバックグラウンドに移動することをアプリに許可します。この許可を悪意のあるアプリに利用されると、悪意のあるアプリが強制的に優先される恐れがあります。"</string> <string name="permlab_removeTasks" msgid="6821513401870377403">"実行中のアプリの停止"</string> <string name="permdesc_removeTasks" msgid="1394714352062635493">"タスクの削除とアプリの終了をアプリに許可します。この許可を悪意のあるアプリケーションに利用されると、他のアプリの動作が妨害される恐れがあります。"</string> - <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) --> - <skip /> - <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) --> - <skip /> + <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"画面互換性の設定"</string> + <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"他のアプリの画面互換性モードをコントロールすることをアプリに許可します。この許可を悪意のあるアプリに利用されると、他のアプリの動作が中断される恐れがあります。"</string> <string name="permlab_setDebugApp" msgid="3022107198686584052">"アプリのデバッグの有効化"</string> <string name="permdesc_setDebugApp" msgid="4474512416299013256">"別のアプリをデバッグモードにすることをアプリに許可します。この許可を悪意のあるアプリに利用されると、他のアプリが強制終了される恐れがあります。"</string> <string name="permlab_changeConfiguration" msgid="8214475779521218295">"UI設定の変更"</string> @@ -766,6 +764,10 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"パッケージベリファイアのリクエストを所有者に許可します。通常のアプリでは不要です。"</string> <string name="permlab_serialPort" msgid="546083327654631076">"シリアルポートへのアクセス"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"SerialManager APIを使用してシリアルポートにアクセスすることを所有者に許可します。"</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"このパスワードをブラウザで保存しますか?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"今は保存しない"</string> <string name="save_password_remember" msgid="6491879678996749466">"保存"</string> @@ -978,6 +980,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Directを開始します。これによりWi-Fiクライアント/アクセスポイントがOFFになります。"</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Directを開始できませんでした。"</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi DirectはONです"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"設定を表示するにはタップしてください"</string> <string name="accept" msgid="1645267259272829559">"同意する"</string> <string name="decline" msgid="2112225451706137894">"同意しない"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"招待状を送信しました"</string> @@ -986,8 +990,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"To:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"必要なPINを入力してください:"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi DirectはONです"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"設定を表示するにはタップしてください"</string> <string name="select_character" msgid="3365550120617701745">"文字を挿入"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"不明なアプリ"</string> <string name="sms_control_title" msgid="7296612781128917719">"SMSメッセージの送信中"</string> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index 2c664c9be230..aeca1ed84a8e 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -215,10 +215,8 @@ <string name="permdesc_reorderTasks" msgid="4175137612205663399">"앱이 작업을 포그라운드나 백그라운드로 이동할 수 있도록 허용합니다. 이 경우 악성 앱이 사용자의 조작 없이 앞으로 이동할 수 있습니다."</string> <string name="permlab_removeTasks" msgid="6821513401870377403">"실행 중인 앱 중지"</string> <string name="permdesc_removeTasks" msgid="1394714352062635493">"애플리케이션이 작업을 삭제하거나 다른 애플리케이션을 중지시킬 수 있도록 허용합니다. 이 경우 악성 애플리케이션이 다른 애플리케이션의 동작을 멈추게 할 수 있습니다."</string> - <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) --> - <skip /> - <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) --> - <skip /> + <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"화면 호환성 설정"</string> + <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"앱이 다른 애플리케이션의 화면 호환성 모드를 제어할 수 있도록 허용합니다. 이 경우 악성 애플리케이션이 다른 애플리케이션의 동작을 멈추게 할 수 있습니다."</string> <string name="permlab_setDebugApp" msgid="3022107198686584052">"앱 디버깅 사용"</string> <string name="permdesc_setDebugApp" msgid="4474512416299013256">"애플리케이션이 다른 애플리케이션에 대해 디버깅을 사용할 수 있도록 허용합니다. 이 경우 악성 애플리케이션이 다른 애플리케이션을 중지시킬 수 있습니다."</string> <string name="permlab_changeConfiguration" msgid="8214475779521218295">"UI 설정 변경"</string> @@ -766,6 +764,10 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"권한을 가진 프로그램이 패키지 인증을 요청할 수 있도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string> <string name="permlab_serialPort" msgid="546083327654631076">"직렬 포트에 액세스"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"SerialManager API를 사용하여 권한을 가진 프로그램이 직렬 포트에 액세스할 수 있도록 합니다."</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"브라우저에 이 비밀번호를 저장하시겠습니까?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"나중에"</string> <string name="save_password_remember" msgid="6491879678996749466">"저장"</string> @@ -978,6 +980,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Direct 작업을 시작합니다. 이 작업을 하면 Wi-Fi 클라이언트/핫스팟 작업이 중지됩니다."</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Direct를 시작하지 못했습니다."</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct 켜짐"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"설정으로 이동하려면 터치하세요."</string> <string name="accept" msgid="1645267259272829559">"동의"</string> <string name="decline" msgid="2112225451706137894">"거부"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"초대장을 보냈습니다."</string> @@ -986,8 +990,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"받는사람:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"필수 PIN 입력:"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct 켜짐"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"설정으로 이동하려면 터치하세요."</string> <string name="select_character" msgid="3365550120617701745">"문자 삽입"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"알 수 없는 앱"</string> <string name="sms_control_title" msgid="7296612781128917719">"SMS 메시지를 보내는 중"</string> diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index 22830ac6a146..739dca8d83b9 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -764,6 +764,10 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Savininkui leidžiama teikti užklausas patikrinti paketą. Įprastoms programoms to neturėtų prireikti."</string> <string name="permlab_serialPort" msgid="546083327654631076">"pasiekti nuosekliuosius prievadus"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"Leidžiama savininkui pasiekti nuosekliuosius prievadus naudojant „SerialManager“ API."</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"Ar norite, kad naršyklė atsimintų šį slaptažodį?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"Ne dabar"</string> <string name="save_password_remember" msgid="6491879678996749466">"Atsiminti"</string> @@ -976,6 +980,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Tiesioginis „Wi-Fi“ ryšys"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Paleiskite „Wi-Fi Direct“. Bus išjungta „Wi-Fi“ programa / viešosios interneto prieigos taškas."</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Nepavyko paleisti „Wi-Fi Direct“."</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"„Wi-Fi Direct“ įjungta"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Jei norite peržiūrėti nustatymus, palieskite"</string> <string name="accept" msgid="1645267259272829559">"Sutikti"</string> <string name="decline" msgid="2112225451706137894">"Atmesti"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Pakvietimas išsiųstas"</string> @@ -984,8 +990,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"Skirta:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Įveskite reikiamą PIN kodą:"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN kodas:"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"„Wi-Fi Direct“ įjungta"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Jei norite peržiūrėti nustatymus, palieskite"</string> <string name="select_character" msgid="3365550120617701745">"Įterpti simbolį"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"Nežinoma programa"</string> <string name="sms_control_title" msgid="7296612781128917719">"SMS pranešimų siuntimas"</string> diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index f716cb99f65c..c36434cdb06f 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -764,6 +764,10 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Ļauj īpašniekam sūtīt pakotņu verificētāju pieprasījumus. Parastajām lietotnēm tas nekad nav nepieciešams."</string> <string name="permlab_serialPort" msgid="546083327654631076">"piekļuve seriālajiem portiem"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"Ļauj īpašniekam piekļūt seriālajiem portiem, izmantojot SerialManager API."</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"Vai vēlaties, lai pārlūkprogrammā tiktu saglabāta šī parole?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"Ne tagad"</string> <string name="save_password_remember" msgid="6491879678996749466">"Atcerēties"</string> @@ -976,6 +980,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Palaist programmu Wi-Fi Direct. Tādējādi tiks izslēgta Wi-Fi klienta/tīklāja darbība."</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Nevarēja palaist programmu Wi-Fi Direct."</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct ir ieslēgts"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Pieskarieties, lai piekļūtu iestatījumiem."</string> <string name="accept" msgid="1645267259272829559">"Piekrist"</string> <string name="decline" msgid="2112225451706137894">"Noraidīt"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Ielūgums ir nosūtīts."</string> @@ -984,8 +990,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"Kam:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Ierakstiet pieprasīto PIN:"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct ir ieslēgts"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Pieskarieties, lai piekļūtu iestatījumiem."</string> <string name="select_character" msgid="3365550120617701745">"Ievietojiet rakstzīmi"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"Nezināma lietotne"</string> <string name="sms_control_title" msgid="7296612781128917719">"Īsziņu sūtīšana"</string> diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml index 659a7ad9efdc..6d0f5fd7155c 100644 --- a/core/res/res/values-ms/strings.xml +++ b/core/res/res/values-ms/strings.xml @@ -215,10 +215,8 @@ <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Membenarkan apl untuk memindahkan tugasan ke latar depan dan latar belakang. Apl hasad boleh memaksa diri mereka ke hadapan tanpa kawalan anda."</string> <string name="permlab_removeTasks" msgid="6821513401870377403">"hentikan apl yang sedang dijalankan"</string> <string name="permdesc_removeTasks" msgid="1394714352062635493">"Membenarkan apl untuk mengalih keluar tugasan dan melupuskan aplnya. Apl hasad boleh mengganggu tingkah laku apl lain."</string> - <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) --> - <skip /> - <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) --> - <skip /> + <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"tetapkan keserasian skrin"</string> + <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Membenarkan apl mengawal mod keserasian skrin aplikasi lain. Aplikasi hasad mungkin mematahkan kelakuan aplikasi lain."</string> <string name="permlab_setDebugApp" msgid="3022107198686584052">"dayakan penyahpepijatan apl"</string> <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Membenarkan apl untuk menghidupkan penyahpepijatan untuk apl lain. Apl hasad boleh menggunakannya untuk menghapuskan apl lain."</string> <string name="permlab_changeConfiguration" msgid="8214475779521218295">"tukar tetapan UI anda"</string> @@ -766,6 +764,10 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Membenarkan pemegang membuat permintaan pengesah pakej. Tidak sekali-kali diperlukan untuk apl normal."</string> <string name="permlab_serialPort" msgid="546083327654631076">"akses port bersiri"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"Membenarkan pemegang mengakses port bersiri menggunakan API SerialManager."</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"Adakah anda mahu penyemak imbas mengingati kata laluan ini?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"Bukan sekarang"</string> <string name="save_password_remember" msgid="6491879678996749466">"Ingat"</string> @@ -978,6 +980,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Langsung"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Mulakan Wi-Fi Langsung. Hal ini akan mematikan pengendalian klien/liputan Wi-Fi."</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Tidak dapat memulakan Wi-Fi Langsung."</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct dihidupkan"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Sentuh untuk tetapan"</string> <string name="accept" msgid="1645267259272829559">"Terima"</string> <string name="decline" msgid="2112225451706137894">"Tolak"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Jemputan dihantar"</string> @@ -986,8 +990,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"Kepada:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Taipkan PIN yang diperlukan:"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct dihidupkan"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Sentuh untuk tetapan"</string> <string name="select_character" msgid="3365550120617701745">"Masukkan aksara"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"Apl tidak diketahui"</string> <string name="sms_control_title" msgid="7296612781128917719">"Menghantar mesej SMS"</string> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index b1b3cbef1cbb..41ff0468312d 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -764,6 +764,10 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Lar innehaveren sende forespørsler om pakkeverifikatorer. Skal aldri være nødvendig for normale apper."</string> <string name="permlab_serialPort" msgid="546083327654631076">"tilgang til serielle porter"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"Gir innehaveren tilgang til serielle porter ved hjelp av SerialManager API."</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"Ønsker du at nettleseren skal huske dette passordet?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"Ikke nå"</string> <string name="save_password_remember" msgid="6491879678996749466">"Husk"</string> @@ -976,6 +980,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Start Wi-Fi Direct. Dette deaktiverer Wi-Fi-klienten/-sonen."</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Kunne ikke starte Wi-Fi Direct."</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct er slått på"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Berør for å se innstillinger"</string> <string name="accept" msgid="1645267259272829559">"Godta"</string> <string name="decline" msgid="2112225451706137894">"Avslå"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Invitasjonen er sendt"</string> @@ -984,8 +990,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"Til:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Skriv inn påkrevd PIN-kode:"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct er slått på"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Berør for å se innstillinger"</string> <string name="select_character" msgid="3365550120617701745">"Sett inn tegn"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"Ukjent app"</string> <string name="sms_control_title" msgid="7296612781128917719">"Sender SMS-meldinger"</string> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index 94094455845d..8e5e8bc54e59 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -764,6 +764,8 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Hiermee kan de houder verzoeken indienen voor pakketcontroles. Nooit vereist voor normale apps."</string> <string name="permlab_serialPort" msgid="546083327654631076">"toegang krijgen tot seriële poorten"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"De houder toestaan toegang tot seriële poorten te krijgen met de SerialManager API."</string> + <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"externe toegang tot inhoudsproviders"</string> + <string name="permdesc_accessContentProvidersExternally" msgid="4544346486697853685">"Hiermee kan de houder toegang krijgen tot inhoudsproviders via de shell. Nooit vereist voor normale apps."</string> <string name="save_password_message" msgid="767344687139195790">"Wilt u dat de browser dit wachtwoord onthoudt?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"Niet nu"</string> <string name="save_password_remember" msgid="6491879678996749466">"Onthouden"</string> @@ -976,6 +978,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wifi Direct starten. Hierdoor wordt de wifi-client/hotspot uitgeschakeld."</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Kan Wifi Direct niet starten."</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct is actief"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Aanraken voor instellingen"</string> <string name="accept" msgid="1645267259272829559">"Accepteren"</string> <string name="decline" msgid="2112225451706137894">"Weigeren"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Uitnodiging verzonden"</string> @@ -984,8 +988,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"Naar:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Voer de gewenste pincode in:"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"Pincode"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct is actief"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Aanraken voor instellingen"</string> <string name="select_character" msgid="3365550120617701745">"Teken invoegen"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"Onbekende app"</string> <string name="sms_control_title" msgid="7296612781128917719">"SMS-berichten verzenden"</string> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index 8564dc793658..694ed759e0e8 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -216,7 +216,7 @@ <string name="permlab_removeTasks" msgid="6821513401870377403">"zatrzymywanie uruchomionych aplikacji"</string> <string name="permdesc_removeTasks" msgid="1394714352062635493">"Umożliwia aplikacji usuwanie zadań i kończenie powiązanych z nimi aplikacji. Złośliwe aplikacje mogą zakłócić działanie innych aplikacji."</string> <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"ustaw zgodność ekranu"</string> - <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Pozwala aplikacji na sterowanie trybem zgodności ekranu innych aplikacji. Złośliwe aplikacje mogą zmienić zachowanie innych aplikacji."</string> + <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Pozwala aplikacji na sterowanie trybem zgodności ekranu innych aplikacji. Złośliwe aplikacje mogą zmienić zachowanie innych programów."</string> <string name="permlab_setDebugApp" msgid="3022107198686584052">"włączenie debugowania aplikacji"</string> <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Pozwala aplikacji na włączenie debugowania innej aplikacji. Złośliwe aplikacje mogą to wykorzystać do kończenia pracy innych programów."</string> <string name="permlab_changeConfiguration" msgid="8214475779521218295">"zmienianie ustawień interfejsu użytkownika"</string> @@ -764,6 +764,10 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Pozwala na wysyłanie żądań weryfikacji pakietu. To uprawnienie nie powinno być potrzebne zwykłym aplikacjom."</string> <string name="permlab_serialPort" msgid="546083327654631076">"dostęp do portów szeregowych"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"Umożliwia posiadaczowi dostęp do portów szeregowych przy użyciu interfejsu API narzędzia SerialManager."</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"Czy chcesz, aby zapamiętać to hasło w przeglądarce?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"Nie teraz"</string> <string name="save_password_remember" msgid="6491879678996749466">"Zapamiętaj"</string> @@ -976,6 +980,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Uruchom Wi-Fi Direct. Spowoduje to wyłączenie klienta lub punktu dostępu Wi-Fi."</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Nie można uruchomić Wi-Fi Direct."</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct włączone"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Dotknij, aby zmienić ustawienia"</string> <string name="accept" msgid="1645267259272829559">"Akceptuj"</string> <string name="decline" msgid="2112225451706137894">"Odrzuć"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Wysłano zaproszenie"</string> @@ -984,8 +990,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"Do:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Wpisz wymagany kod PIN:"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"Kod PIN:"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct włączone"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Dotknij, aby zmienić ustawienia"</string> <string name="select_character" msgid="3365550120617701745">"Wstaw znak"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"Nieznana aplikacja"</string> <string name="sms_control_title" msgid="7296612781128917719">"Wysyłanie wiadomości SMS"</string> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index a162aa086f3c..3fa89d31a7e7 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -764,6 +764,10 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permite ao titular solicitar verificadores de pacotes. Nunca deverá ser necessário para aplicações normais."</string> <string name="permlab_serialPort" msgid="546083327654631076">"aceder a portas série"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"Permite ao titular aceder a portas de série através da API SerialManager."</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"Quer que o browser memorize esta palavra-passe?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"Agora não"</string> <string name="save_password_remember" msgid="6491879678996749466">"Lembrar"</string> @@ -976,6 +980,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Iniciar o Wi-Fi Direct. Esta opção desativará o cliente/zona Wi-Fi."</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Não foi possível iniciar o Wi-Fi Direct."</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"O Wi-Fi Direct está ativado"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Toque para aceder às definições"</string> <string name="accept" msgid="1645267259272829559">"Aceitar"</string> <string name="decline" msgid="2112225451706137894">"Recusar"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Convite enviado"</string> @@ -984,8 +990,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"Para:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Introduza o PIN solicitado:"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"O Wi-Fi Direct está ativado"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Toque para aceder às definições"</string> <string name="select_character" msgid="3365550120617701745">"Introduzir carácter"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"Aplicação desconhecida"</string> <string name="sms_control_title" msgid="7296612781128917719">"A enviar mensagens SMS"</string> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index 4915a2337bec..d99bc60b3835 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -215,10 +215,8 @@ <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Permite que o aplicativo mova tarefas para o primeiro plano e para o plano de fundo. Aplicativos maliciosos podem forçar-se para a primeiro plano sem que você tenha controle sobre a ação."</string> <string name="permlab_removeTasks" msgid="6821513401870377403">"parar os aplicativos em execução"</string> <string name="permdesc_removeTasks" msgid="1394714352062635493">"Permite que um aplicativo remova tarefas e elimine seus aplicativos. Aplicativos maliciosos podem interferir no comportamento de outros aplicativos."</string> - <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) --> - <skip /> - <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) --> - <skip /> + <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"definir a compatibilidade de tela"</string> + <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Permite que o aplicativo controle o modo de compatibilidade de tela de outros aplicativos. Aplicativos maliciosos podem interromper o comportamento de outros aplicativos."</string> <string name="permlab_setDebugApp" msgid="3022107198686584052">"ativar depuração do aplicativo"</string> <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Permite que o aplicativo ative a depuração para outro aplicativo. Aplicativos maliciosos podem usar esse recurso para cancelar outros aplicativos."</string> <string name="permlab_changeConfiguration" msgid="8214475779521218295">"alterar as suas configurações de UI"</string> @@ -766,6 +764,10 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permite que o titular solicite verificadores de pacote. Nunca deve ser necessário para aplicativos normais."</string> <string name="permlab_serialPort" msgid="546083327654631076">"acessar portas seriais"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"Permite que o detentor tenha acesso a portas seriais usando a API SerialManager."</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"Deseja que o navegador lembre desta senha?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"Agora não"</string> <string name="save_password_remember" msgid="6491879678996749466">"Lembrar"</string> @@ -978,6 +980,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Iniciar o Wi-Fi Direct. Isso desativará o ponto de acesso/cliente Wi-Fi."</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Não foi possível iniciar o Wi-Fi Direct."</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct ativado"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Tocar para acessar configurações"</string> <string name="accept" msgid="1645267259272829559">"Aceitar"</string> <string name="decline" msgid="2112225451706137894">"Recusar"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Convite enviado"</string> @@ -986,8 +990,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"Para:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Digite o PIN obrigatório:"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct ativado"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Tocar para acessar configurações"</string> <string name="select_character" msgid="3365550120617701745">"Inserir caractere"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"Aplicativo desconhecido"</string> <string name="sms_control_title" msgid="7296612781128917719">"Enviando mensagens SMS"</string> diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml index 57daee71770e..5b8efa61ed6c 100644 --- a/core/res/res/values-rm/strings.xml +++ b/core/res/res/values-rm/strings.xml @@ -1155,6 +1155,10 @@ <skip /> <!-- no translation found for permdesc_serialPort (2991639985224598193) --> <skip /> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"Vulais Vus ch\'il navigatur memorisescha quest pled-clav?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"Betg ussa"</string> <string name="save_password_remember" msgid="6491879678996749466">"Memorisar"</string> @@ -1424,6 +1428,10 @@ <skip /> <!-- no translation found for wifi_p2p_failed_message (3763669677935623084) --> <skip /> + <!-- no translation found for wifi_p2p_enabled_notification_title (2068321881673734886) --> + <skip /> + <!-- no translation found for wifi_p2p_enabled_notification_message (1638949953993894335) --> + <skip /> <!-- no translation found for accept (1645267259272829559) --> <skip /> <!-- no translation found for decline (2112225451706137894) --> @@ -1440,10 +1448,6 @@ <skip /> <!-- no translation found for wifi_p2p_show_pin_message (8530563323880921094) --> <skip /> - <!-- no translation found for wifi_p2p_enabled_notification_title (2068321881673734886) --> - <skip /> - <!-- no translation found for wifi_p2p_enabled_notification_message (1638949953993894335) --> - <skip /> <string name="select_character" msgid="3365550120617701745">"Inserir in caracter"</string> <!-- no translation found for sms_control_default_app_name (3058577482636640465) --> <skip /> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index fe3687fbfd79..d870d587a63e 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -764,6 +764,10 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permite proprietarului să efectueze solicitări pentru verificatori de pachete. Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string> <string name="permlab_serialPort" msgid="546083327654631076">"acces la porturi seriale"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"Permite posesorului accesul la porturile serial utilizând API-ul SerialManager."</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"Doriţi ca browserul să reţină această parolă?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"Nu acum"</string> <string name="save_password_remember" msgid="6491879678996749466">"Reţineţi"</string> @@ -976,6 +980,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Porniţi Wi-Fi Direct. Acest lucru va dezactiva clientul/hotspotul Wi-Fi."</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Direct nu a putut porni."</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct este activat"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Atingeţi pentru setări"</string> <string name="accept" msgid="1645267259272829559">"Acceptaţi"</string> <string name="decline" msgid="2112225451706137894">"Refuzaţi"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Invitaţia a fost trimisă."</string> @@ -984,8 +990,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"Către:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Introduceţi codul PIN necesar:"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"Cod PIN:"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct este activat"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Atingeţi pentru setări"</string> <string name="select_character" msgid="3365550120617701745">"Introduceţi caracterul"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"Aplicaţie necunoscută"</string> <string name="sms_control_title" msgid="7296612781128917719">"Se trimit mesaje SMS"</string> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index 55468a07c6b2..0b63de11bdef 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -764,6 +764,10 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Приложение сможет запрашивать проверку пакетов. Это разрешение не используется обычными приложениями."</string> <string name="permlab_serialPort" msgid="546083327654631076">"доступ к последовательным портам"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"Открыть владельцу доступ к последовательным портам с помощью SerialManager API."</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"Вы хотите, чтобы браузер запомнил этот пароль?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"Не сейчас"</string> <string name="save_password_remember" msgid="6491879678996749466">"Запомнить"</string> @@ -976,6 +980,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Начать соединение через Wi-Fi Direct. Модуль Wi-Fi будет отключен."</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Не удалось запустить Wi-Fi Direct."</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct включен"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Нажмите, чтобы открыть настройки"</string> <string name="accept" msgid="1645267259272829559">"Принять"</string> <string name="decline" msgid="2112225451706137894">"Отклонить"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Приглашение отправлено"</string> @@ -984,8 +990,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"Кому:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Введите PIN-код:"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN-код:"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct включен"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Нажмите, чтобы открыть настройки"</string> <string name="select_character" msgid="3365550120617701745">"Введите символ"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"Неизвестное приложение"</string> <string name="sms_control_title" msgid="7296612781128917719">"Отправка SMS-сообщений"</string> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index 69bc4b84a5c9..df25ac7a296a 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -215,10 +215,8 @@ <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Umožňuje aplikácii presúvať úlohy do popredia a pozadia. Škodlivé aplikácie sa môžu pretlačiť do popredia bez vášho vedomia."</string> <string name="permlab_removeTasks" msgid="6821513401870377403">"zastaviť spustené aplikácie"</string> <string name="permdesc_removeTasks" msgid="1394714352062635493">"Umožňuje aplikácii odstrániť úlohy a ukončiť ich aplikácie. Škodlivé aplikácie môžu narušiť správanie iných aplikácií."</string> - <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) --> - <skip /> - <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) --> - <skip /> + <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"nastaviť kompatibilitu obrazovky"</string> + <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Umožňuje aplikácii ovládať režim kompatibility obrazovky v ostatných aplikáciách. Škodlivé aplikácie môžu narušiť správanie ostatných aplikácií."</string> <string name="permlab_setDebugApp" msgid="3022107198686584052">"povoliť ladenie aplikácií"</string> <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Umožňuje aplikácii zapnúť ladenie inej aplikácie. Škodlivé aplikácie môžu pomocou tohto nastavenia ukončiť iné aplikácie."</string> <string name="permlab_changeConfiguration" msgid="8214475779521218295">"zmeny vašich nastavení používateľského rozhrania"</string> @@ -766,6 +764,10 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Umožňuje držiteľovi podávať žiadosti o overenie balíkov. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string> <string name="permlab_serialPort" msgid="546083327654631076">"prístup k sériovým portom"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"Držiteľa oprávňuje na prístup k sériovým portom pomocou rozhrania API SerialManager."</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"Chcete, aby si prehliadač zapamätal toto heslo?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"Teraz nie"</string> <string name="save_password_remember" msgid="6491879678996749466">"Zapamätať"</string> @@ -978,6 +980,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Priame pripojenie Wi-Fi"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Spustiť priame pripojenie siete Wi-Fi. Táto možnosť vypne sieť Wi-Fi v režime klient alebo hotspot."</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Priame pripojenie siete Wi-Fi sa nepodarilo spustiť"</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Priame pripojenie siete Wi-Fi je zapnuté"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Nastavenia otvoríte dotykom"</string> <string name="accept" msgid="1645267259272829559">"Prijať"</string> <string name="decline" msgid="2112225451706137894">"Odmietnuť"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Pozvánka bola odoslaná"</string> @@ -986,8 +990,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"Komu:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Zadajte požadovaný kód PIN:"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Priame pripojenie siete Wi-Fi je zapnuté"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Nastavenia otvoríte dotykom"</string> <string name="select_character" msgid="3365550120617701745">"Vkladanie znakov"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"Neznáma aplikácia"</string> <string name="sms_control_title" msgid="7296612781128917719">"Odosielanie správ SMS"</string> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index dfedb9af8372..88d02ab4a1c0 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -764,6 +764,10 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Imetniku omogoča zahtevanje preverjanja paketov. Tega nikoli ni treba uporabiti za navadne programe."</string> <string name="permlab_serialPort" msgid="546083327654631076">"dostop do serijskih vrat"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"Imetniku omogoča, da z API-jem za SerialManager dostopa do serijskih vrat."</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"Ali želite, da si brskalnik zapomni to geslo?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"Ne zdaj"</string> <string name="save_password_remember" msgid="6491879678996749466">"Zapomni si"</string> @@ -976,6 +980,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Zaženite Wi-Fi Direct. S tem boste izklopili odjemalca/dostopno točko Wi-Fi."</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Direct ni bilo mogoče zagnati."</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct je vklopljen"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Dotaknite se za nastavitve"</string> <string name="accept" msgid="1645267259272829559">"Sprejmi"</string> <string name="decline" msgid="2112225451706137894">"Zavrni"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Povabilo je poslano"</string> @@ -984,8 +990,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"Za:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Vnesite zahtevano kodo PIN:"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct je vklopljen"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Dotaknite se za nastavitve"</string> <string name="select_character" msgid="3365550120617701745">"Vstavljanje znaka"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"Neznan program"</string> <string name="sms_control_title" msgid="7296612781128917719">"Pošiljanje sporočil SMS"</string> diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index 2a2104fc1631..7d0b9f5aa954 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -764,6 +764,10 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Омогућава да власник упућује захтеве верификаторима пакета. Уобичајене апликације никада не би требало да је користе."</string> <string name="permlab_serialPort" msgid="546083327654631076">"приступ серијским портовима"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"Омогућава власнику да приступи серијским портовима помоћу SerialManager API-ја."</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"Желите ли да прегледач запамти ову лозинку?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"Не сада"</string> <string name="save_password_remember" msgid="6491879678996749466">"Запамти"</string> @@ -976,6 +980,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Покрените Wi-Fi Direct. Тиме ћете искључити клијента/хотспот за Wi-Fi."</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Није могуће покренути Wi-Fi Direct."</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct је укључен"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Додирните за подешавања"</string> <string name="accept" msgid="1645267259272829559">"Прихвати"</string> <string name="decline" msgid="2112225451706137894">"Одбиј"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Позивница је послата"</string> @@ -984,8 +990,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"Коме:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Унесите потребни PIN:"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct је укључен"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Додирните за подешавања"</string> <string name="select_character" msgid="3365550120617701745">"Уметање знака"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"Непозната апликација"</string> <string name="sms_control_title" msgid="7296612781128917719">"Слање SMS порука"</string> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index 0067a12f4b09..ee6295f8437b 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -764,6 +764,10 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Tillåter att innehavaren skickar förfrågningar till paketverifierare. Det ska inte behövas för vanliga appar."</string> <string name="permlab_serialPort" msgid="546083327654631076">"åtkomst till serieportar"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"Innebär att innehavaren får åtkomst till serieportar med programmeringsgränssnittet för SerialManager."</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"Vill du att webbläsaren ska komma ihåg lösenordet?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"Inte nu"</string> <string name="save_password_remember" msgid="6491879678996749466">"Kom ihåg"</string> @@ -976,6 +980,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi direkt"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Starta direkt Wi-Fi-användning. Detta inaktiverar Wi-Fi-användning med klient/trådlös surfzon."</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Det gick inte att starta Wi-Fi direkt."</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct är aktiverat"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Tryck om du vill visa inställningar"</string> <string name="accept" msgid="1645267259272829559">"Godkänn"</string> <string name="decline" msgid="2112225451706137894">"Avvisa"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Inbjudan har skickats"</string> @@ -984,8 +990,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"Till:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Ange den obligatoriska PIN-koden:"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN-kod:"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct är aktiverat"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Tryck om du vill visa inställningar"</string> <string name="select_character" msgid="3365550120617701745">"Infoga tecken"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"Okänd app"</string> <string name="sms_control_title" msgid="7296612781128917719">"Skickar SMS"</string> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index 369853c34966..70b7c2e0213d 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -764,6 +764,10 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Inaruhusu mmiliki kutuma maombi ya vibainishi furushi. Kamwe hazitahitajika kwa programu za kawaida."</string> <string name="permlab_serialPort" msgid="546083327654631076">"kituo tambulishi cha ufikivu"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"Inaruhusu mmiliki kufikia vituo tambulishi kwa kutumia KisimamiziTambulishi cha API."</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"Unataka kuvinjari ili ukumbuke nenosiri hili?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"Si Sasa"</string> <string name="save_password_remember" msgid="6491879678996749466">"Kumbuka"</string> @@ -976,6 +980,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Mtandao hewa Moja kwa moja"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Anzisha Wi-Fi Moja kwa Moja. Hii itazima mteja/mtandao-hewa wa Wi-Fi."</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Haikuweza kuanzisha Wi-Fi Moja kwa Moja."</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi ya Moja kwa Moja imewashwa"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Gusa kwa ajili ya mipangilio"</string> <string name="accept" msgid="1645267259272829559">"Kubali"</string> <string name="decline" msgid="2112225451706137894">"Kataa"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Mwaliko umetumwa"</string> @@ -984,8 +990,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"Kwa:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Charaza PIN inayohitajika:"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi ya Moja kwa Moja imewashwa"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Gusa kwa ajili ya mipangilio"</string> <string name="select_character" msgid="3365550120617701745">"Ingiza kibambo"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"Programu isiyojulikana"</string> <string name="sms_control_title" msgid="7296612781128917719">"Inatuma ujumbe wa SMS"</string> diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index debe568bc8c3..0acd104ee10a 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -764,6 +764,10 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"อนุญาตให้ผู้ใช้ส่งคำขอให้มีการยืนยันแพคเกจ ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string> <string name="permlab_serialPort" msgid="546083327654631076">"เข้าถึงพอร์ตอนุกรม"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"อนุญาตให้ผู้ถือสามารถเข้าถึงพอร์ตอนุกรมโดยใช้ SerialManager API"</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"คุณต้องการให้เบราว์เซอร์จำรหัสผ่านนี้หรือไม่"</string> <string name="save_password_notnow" msgid="6389675316706699758">"ยังไม่ใช้งานขณะนี้"</string> <string name="save_password_remember" msgid="6491879678996749466">"จำไว้"</string> @@ -976,6 +980,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"เริ่มการทำงาน WiFi Direct ซึ่งจะเป็นการปิดการทำงาน WiFi ไคลเอ็นต์/ฮอตสปอต"</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"ไม่สามารถเริ่ม WiFi Direct ได้"</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"เปิด Wi-Fi Direct อยู่"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"แตะเพื่อตั้งค่า"</string> <string name="accept" msgid="1645267259272829559">"ยอมรับ"</string> <string name="decline" msgid="2112225451706137894">"ปฏิเสธ"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"ส่งข้อความเชิญแล้ว"</string> @@ -984,8 +990,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"ถึง:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"พิมพ์ PIN ที่ต้องการ:"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"เปิด Wi-Fi Direct อยู่"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"แตะเพื่อตั้งค่า"</string> <string name="select_character" msgid="3365550120617701745">"ใส่อักขระ"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"แอปพลิเคชันที่ไม่รู้จัก"</string> <string name="sms_control_title" msgid="7296612781128917719">"กำลังส่งข้อความ SMS"</string> diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index e74e309c3b1e..3bde5c8f910b 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -764,6 +764,10 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Pinapayagan ang may-ari na gumawa ng mga kahilingan ng mga taga-verify ng package. Hindi kailanman dapat na kailanganin para sa normal na apps."</string> <string name="permlab_serialPort" msgid="546083327654631076">"mag-access sa mga serial port"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"Binibigyang-daan ang may-ari na mag-access ng mga serial port gamit ang SerialManager API."</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"Gusto mo bang tandaan ng browser ang password na ito?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"Hindi ngayon"</string> <string name="save_password_remember" msgid="6491879678996749466">"Tandaan"</string> @@ -976,6 +980,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Simulan ang Wi-Fi Direct. I-o-off nito ang client/hotspot ng Wi-Fi."</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Hindi masimulan ang Wi-Fi Direct"</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Ang Wi-Fi Direct ay naka-on"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Pindutin para sa mga setting"</string> <string name="accept" msgid="1645267259272829559">"Tanggapin"</string> <string name="decline" msgid="2112225451706137894">"Tanggihan"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Naipadala ang imbitasyon"</string> @@ -984,8 +990,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"Kay:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"I-type ang kinakailangang PIN:"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Ang Wi-Fi Direct ay naka-on"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Pindutin para sa mga setting"</string> <string name="select_character" msgid="3365550120617701745">"Magpasok ng character"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"Hindi kilalang app"</string> <string name="sms_control_title" msgid="7296612781128917719">"Nagpapadala ng mga SMS na mensahe"</string> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index 20d3e15cc40d..1b27dbd63ca4 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -215,10 +215,8 @@ <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Uygulamaya, görevleri ön plana ve arka plana taşıma izni verir. Kötü amaçlı uygulamalar kendilerini sizin denetiminiz dışında ön plana taşıyabilir."</string> <string name="permlab_removeTasks" msgid="6821513401870377403">"çalışan uygulamaları durdur"</string> <string name="permdesc_removeTasks" msgid="1394714352062635493">"Uygulamaya, görevleri kaldırma ve bunlara ait uygulamaları kapatma izni verir. Kötü amaçlı uygulamalar diğer uygulamaların çalışmasını bozabilir."</string> - <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) --> - <skip /> - <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) --> - <skip /> + <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"ekran uyumluluğunu ayarla"</string> + <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Uygulamaya diğer uygulamaların ekran uyumluluk modunu denetleme izni verir. Kötü amaçlı uygulamalar diğer uygulamaların çalışma şeklini bozabilir."</string> <string name="permlab_setDebugApp" msgid="3022107198686584052">"uygulama hata ayıklamayı etkinleştir"</string> <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Uygulamaya, başka bir uygulama için hata ayıklamayı açma izni verir. Kötü amaçlı uygulamalar diğer uygulamaları kaldırmak için bunu kullanabilir."</string> <string name="permlab_changeConfiguration" msgid="8214475779521218295">"kullanıcı arayüzü ayarlarınızı değiştirin"</string> @@ -766,6 +764,10 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Cihazın sahibine, paket doğrulayıcıları için istek yapma izni verir. Normal uygulamalar için gerekli olmaz."</string> <string name="permlab_serialPort" msgid="546083327654631076">"seri bağlantı noktalarına eriş"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"İzin sahibinin, SerialManager API\'sını kullanarak seri bağlantı noktalarına erişmesine olanak sağlar."</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"Tarayıcının bu şifreyi anımsamasını istiyor musunuz?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"Şimdi değil"</string> <string name="save_password_remember" msgid="6491879678996749466">"Anımsa"</string> @@ -978,6 +980,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Kablosuz Doğrudan Bağlantı"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Kablosuz Doğrudan Bağlantıyı başlat. Bu işlem, Kablosuz istemci/hotspot kullanımını kapatacak."</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Kablosuz Doğrudan bağlantı başlatılamadı."</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Kablosuz Doğrudan özelliği açık"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Ayarlar için dokunun"</string> <string name="accept" msgid="1645267259272829559">"Kabul et"</string> <string name="decline" msgid="2112225451706137894">"Reddet"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Davetiye gönderildi"</string> @@ -986,8 +990,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"Alıcı:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Gerekli PIN\'i yazın:"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Kablosuz Doğrudan özelliği açık"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Ayarlar için dokunun"</string> <string name="select_character" msgid="3365550120617701745">"Karakter ekle"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"Bilinmeyen uygulama"</string> <string name="sms_control_title" msgid="7296612781128917719">"SMS mesajları gönderiliyor"</string> diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index 9d049cf05cf1..eb22ec821b12 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -764,6 +764,10 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Дозволяє власникові робити запити на програми перевірки пакетів. Ніколи не застосовується для звичайних програм."</string> <string name="permlab_serialPort" msgid="546083327654631076">"отримувати доступ до послідовних портів"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"Дозволяє власнику отримувати доступ до послідовних портів за допомогою API SerialManager."</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"Хочете, щоб переглядач запам\'ятав цей пароль?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"Не зараз"</string> <string name="save_password_remember" msgid="6491879678996749466">"Запам\'ятати"</string> @@ -976,6 +980,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Запустити Wi-Fi Direct. Це вимкне з’єднання Wi-Fi клієнт/точка доступу."</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Не вдалося запустити Wi-Fi Direct."</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct увімкнено"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Торкніться, щоб побачити налаштування"</string> <string name="accept" msgid="1645267259272829559">"Прийняти"</string> <string name="decline" msgid="2112225451706137894">"Відхилити"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Запрошення надіслано"</string> @@ -984,8 +990,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"Кому:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Введіть потрібний PIN-код:"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN-код:"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct увімкнено"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Торкніться, щоб побачити налаштування"</string> <string name="select_character" msgid="3365550120617701745">"Вставл-ня символу"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"Невідома програма"</string> <string name="sms_control_title" msgid="7296612781128917719">"Надсил. SMS повідомлень"</string> diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index 81666068ae8e..583d21636727 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -764,6 +764,10 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Cho phép chủ sở hữu yêu cầu trình xác minh gói. Không cần thiết cho các ứng dụng thông thường."</string> <string name="permlab_serialPort" msgid="546083327654631076">"truy cập cổng nối tiếp"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"Cho phép chủ sở hữu truy cập cổng nối tiếp sử dụng API SerialManager."</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"Bạn có muốn trình duyệt nhớ mật khẩu này không?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"Không phải bây giờ"</string> <string name="save_password_remember" msgid="6491879678996749466">"Nhớ"</string> @@ -976,6 +980,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Khởi động Wi-Fi Direct. Việc này sẽ tắt hoạt động của ứng dụng khách/điểm phát sóng Wi-Fi."</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Không thể khởi động Wi-Fi Direct."</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct được bật"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Chạm để cài đặt"</string> <string name="accept" msgid="1645267259272829559">"Đồng ý"</string> <string name="decline" msgid="2112225451706137894">"Từ chối"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Đã gửi thư mời"</string> @@ -984,8 +990,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"Người nhận:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Nhập PIN bắt buộc:"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"Mã PIN:"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct được bật"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Chạm để cài đặt"</string> <string name="select_character" msgid="3365550120617701745">"Chèn ký tự"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"Ứng dụng không xác định"</string> <string name="sms_control_title" msgid="7296612781128917719">"Đang gửi tin nhắn SMS"</string> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index 1065183b52b3..ca3c65c03c30 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -215,10 +215,8 @@ <string name="permdesc_reorderTasks" msgid="4175137612205663399">"允许应用程序将任务移动到前台和后台。恶意应用程序可能会不受您的控制,强行让自己处于前台。"</string> <string name="permlab_removeTasks" msgid="6821513401870377403">"停止正在运行的应用程序"</string> <string name="permdesc_removeTasks" msgid="1394714352062635493">"允许该应用程序删除任务并终止这些任务的应用程序。恶意应用程序可以籍此影响其他应用程序的行为。"</string> - <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) --> - <skip /> - <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) --> - <skip /> + <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"设置屏幕兼容性"</string> + <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"允许应用程序控制其他应用程序的屏幕兼容模式。恶意应用程序可以籍此影响其他应用程序的行为。"</string> <string name="permlab_setDebugApp" msgid="3022107198686584052">"启用应用程序调试"</string> <string name="permdesc_setDebugApp" msgid="4474512416299013256">"允许该应用程序对其他应用程序启用调试。恶意应用程序可以籍此终止其他的应用程序。"</string> <string name="permlab_changeConfiguration" msgid="8214475779521218295">"更改用户界面设置"</string> @@ -766,6 +764,10 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"允许用户请求使用程序包验证程序。普通应用程序绝不需要此权限。"</string> <string name="permlab_serialPort" msgid="546083327654631076">"访问串行端口"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"允许持有人使用 SerialManager API 访问串行端口。"</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"是否希望浏览器记住此密码?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"暂不保存"</string> <string name="save_password_remember" msgid="6491879678996749466">"记住"</string> @@ -978,6 +980,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"启动 Wi-Fi Direct。此操作将会关闭 Wi-Fi 客户端/热点。"</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"无法启动 Wi-Fi Direct。"</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"已启用 Wi-Fi Direct"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"通过触摸进行设置"</string> <string name="accept" msgid="1645267259272829559">"接受"</string> <string name="decline" msgid="2112225451706137894">"拒绝"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"邀请已发送"</string> @@ -986,8 +990,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"收件人:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"键入所需的 PIN:"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"已启用 Wi-Fi Direct"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"通过触摸进行设置"</string> <string name="select_character" msgid="3365550120617701745">"插入字符"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"未知应用程序"</string> <string name="sms_control_title" msgid="7296612781128917719">"正在发送短信"</string> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index 659c2de62049..9b11c43efc23 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -215,10 +215,8 @@ <string name="permdesc_reorderTasks" msgid="4175137612205663399">"允許應用程式將工作移至前景或背景。請注意,惡意應用程式可能利用此功能自行移動至前景。"</string> <string name="permlab_removeTasks" msgid="6821513401870377403">"停止執行中的應用程式"</string> <string name="permdesc_removeTasks" msgid="1394714352062635493">"允許應用程式移除工作並終止執行工作的應用程式。請注意,惡意應用程式可能利用此功能干擾其他應用程式的行為。"</string> - <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) --> - <skip /> - <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) --> - <skip /> + <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"設定螢幕相容性"</string> + <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"允許應用程式控制其他應用程式的螢幕相容性模式。惡意應用程式可能藉此破壞其他應用程式的正常運作。"</string> <string name="permlab_setDebugApp" msgid="3022107198686584052">"啟用應用程式偵錯"</string> <string name="permdesc_setDebugApp" msgid="4474512416299013256">"允許應用程式為其他程式開啟偵錯功能。提醒您,惡意應用程式可能會利用這個功能終止其他應用程式。"</string> <string name="permlab_changeConfiguration" msgid="8214475779521218295">"變更介面設定"</string> @@ -766,6 +764,10 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"允許應用程式要求驗證套件 (一般應用程式不需使用)。"</string> <string name="permlab_serialPort" msgid="546083327654631076">"存取序列埠"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"允許應用程式使用 SerialManager API 存取序列埠。"</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"是否記住此密碼?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"現在不要"</string> <string name="save_password_remember" msgid="6491879678996749466">"記住"</string> @@ -978,6 +980,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"啟動 WiFi Direct 作業,這會關閉 WiFi 用戶端/無線基地台作業。"</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"無法啟動 WiFi Direct。"</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct 已開啟"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"輕觸即可設定"</string> <string name="accept" msgid="1645267259272829559">"接受"</string> <string name="decline" msgid="2112225451706137894">"拒絕"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"邀請函已傳送"</string> @@ -986,8 +990,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"收件者:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"請輸入必要的 PIN:"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct 已開啟"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"輕觸即可設定"</string> <string name="select_character" msgid="3365550120617701745">"插入字元"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"不明的應用程式"</string> <string name="sms_control_title" msgid="7296612781128917719">"傳送 SMS 簡訊"</string> diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml index 84f4319b57e9..8d02eff72943 100644 --- a/core/res/res/values-zu/strings.xml +++ b/core/res/res/values-zu/strings.xml @@ -215,10 +215,8 @@ <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Ivumela insiza ukuthi ihambise izenzo ziye ngaphambili kanye nasemumva. Izinsiza ezinobungozi zingaziphoqelela ukuth iziye phambili ngaphandle kokulawula kwakho."</string> <string name="permlab_removeTasks" msgid="6821513401870377403">"misa izinsiza ezisebenzayo"</string> <string name="permdesc_removeTasks" msgid="1394714352062635493">"Vumela ukuthi insiza isuse okumele kwenziwe ibulale nezinsiza zakho. Izinsiza eziwubungozi zingaphazamisa ukusebenza kwezinye izinsiza."</string> - <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) --> - <skip /> - <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) --> - <skip /> + <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"setha ukuhambelana kwesikrini"</string> + <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Ivumela uhlelo lokusebenza ukulawula imodi yokuhambelana kwesikrini kwezinye izinhlelo zokusebenza. Izinhlelo zokusebenza ezinonya zingase zephule ukuziphatha kwezinye izinhlelo zokusebenza."</string> <string name="permlab_setDebugApp" msgid="3022107198686584052">"vumela insiza ilungise inkinga"</string> <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Ivumela insiza ukuthi ivule uhlelo lokulungisa lwenye insiza. Izinsiza ezinobungozi zingasebenzisa lokhu ukubulala ezinye izinsiza."</string> <string name="permlab_changeConfiguration" msgid="8214475779521218295">"shintsha izilungiselelo zakho ze-UI"</string> @@ -766,6 +764,10 @@ <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Ivumela umnikazi ukuthi enze izicelo zezinsiza eziqinisekisa iphakheji. Akumele kudingeke ekusetshenzisweni okujwayelekile."</string> <string name="permlab_serialPort" msgid="546083327654631076">"finyelela kuma- serial port"</string> <string name="permdesc_serialPort" msgid="2991639985224598193">"Ivumela umnikai ukuthi athole inombolo ye-serial ukue angene kwiindawo ze-serial esebenzisa i-SerialManager API."</string> + <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) --> + <skip /> + <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) --> + <skip /> <string name="save_password_message" msgid="767344687139195790">"Ingabe ufuna ukuba isiphequluli sikhumbule lephasiwedi?"</string> <string name="save_password_notnow" msgid="6389675316706699758">"Hha yi manje"</string> <string name="save_password_remember" msgid="6491879678996749466">"Khumbula"</string> @@ -978,6 +980,8 @@ <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"I-WiFi Eqondile"</string> <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Qala ukusebenza kwe-WiFi Okuqondile. Lokhu kuzocima ikhasimende le-WiFi/Ukusebenza okwe-hotspot"</string> <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Yehlulekile ukuqala i-Wi-Fi Ngqo"</string> + <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"I-Wi-Fi Direct ivulekile"</string> + <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Thinta ukuze uthole izilungiselelo"</string> <string name="accept" msgid="1645267259272829559">"Yamukela"</string> <string name="decline" msgid="2112225451706137894">"Nqaba"</string> <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Isimemo sithunyelwe"</string> @@ -986,8 +990,6 @@ <string name="wifi_p2p_to_message" msgid="248968974522044099">"Ku:"</string> <string name="wifi_p2p_enter_pin_message" msgid="5920929550367828970">"Faka i-PIN edingekayo:"</string> <string name="wifi_p2p_show_pin_message" msgid="8530563323880921094">"PIN:"</string> - <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"I-Wi-Fi Direct ivulekile"</string> - <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Thinta ukuze uthole izilungiselelo"</string> <string name="select_character" msgid="3365550120617701745">"Faka uhlamvu"</string> <string name="sms_control_default_app_name" msgid="3058577482636640465">"insiza engaziwa"</string> <string name="sms_control_title" msgid="7296612781128917719">"Ithumela imiyalezo ye-SMS"</string> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 3a7225ed1daf..1eab01aa7e58 100755 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -246,6 +246,13 @@ <item>4</item> </integer-array> + <!-- If the DUN connection for this CDMA device supports more than just DUN --> + <!-- traffic you should list them here. --> + <!-- If this device is not CDMA this is ignored. If this list is empty on --> + <!-- a DUN-requiring CDMA device, the DUN APN will just support just DUN. --> + <string-array translatable="false" name="config_cdma_dun_supported_types"> + </string-array> + <!-- String containing the apn value for tethering. May be overriden by secure settings TETHER_DUN_APN. Value is a comma separated series of strings: "name,apn,proxy,port,username,password,server,mmsc,mmsproxy,mmsport,mcc,mnc,auth,type" diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index e84cb5c2ee6b..f347a4e3f3cf 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -863,6 +863,7 @@ <java-symbol type="array" name="special_locale_codes" /> <java-symbol type="array" name="special_locale_names" /> <java-symbol type="array" name="config_masterVolumeRamp" /> + <java-symbol type="array" name="config_cdma_dun_supported_types" /> <java-symbol type="drawable" name="default_wallpaper" /> <java-symbol type="drawable" name="ic_suggestions_add" /> @@ -1438,6 +1439,7 @@ <java-symbol type="anim" name="push_down_out" /> <java-symbol type="anim" name="push_up_in" /> <java-symbol type="anim" name="push_up_out" /> + <java-symbol type="bool" name="config_alwaysUseCdmaRssi" /> <java-symbol type="dimen" name="status_bar_icon_size" /> <java-symbol type="dimen" name="system_bar_icon_size" /> <java-symbol type="drawable" name="list_selector_pressed_holo_dark" /> @@ -1475,6 +1477,7 @@ <java-symbol type="string" name="usb_storage_stop_notification_title" /> <java-symbol type="string" name="usb_storage_stop_title" /> <java-symbol type="string" name="usb_storage_title" /> + <java-symbol type="style" name="Animation.RecentApplications" /> <!-- ImfTest --> <java-symbol type="layout" name="auto_complete_list" /> @@ -3494,4 +3497,12 @@ =============================================================== --> <public type="attr" name="isolatedProcess" id="0x010103a7" /> + <public type="attr" name="textDirection"/> + + <public type="attr" name="paddingStart"/> + <public type="attr" name="paddingEnd"/> + + <public type="attr" name="layout_marginStart"/> + <public type="attr" name="layout_marginEnd"/> + </resources> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 4995d2c743f7..3c1f50d11b6d 100755 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -2248,6 +2248,14 @@ <!-- Description of an application permission which allows the application access serial ports via the SerialManager. [CHAR LIMIT=NONE] --> <string name="permdesc_serialPort">Allows the holder to access serial ports using the SerialManager API.</string> + <!-- Title of an application permission which allows the holder to access content + providers from outside an ApplicationThread. [CHAR LIMIT=40] --> + <string name="permlab_accessContentProvidersExternally">access content providers externally</string> + <!-- Description of an application permission which allows the holder to access + content providers from outside an ApplicationThread. [CHAR LIMIT=NONE] --> + <string name="permdesc_accessContentProvidersExternally">Allows the holder to access content + providers from the shell. Should never be needed for normal apps.</string> + <!-- If the user enters a password in a form on a website, a dialog will come up asking if they want to save the password. Text in the save password dialog, asking if the browser should remember a password. --> <string name="save_password_message">Do you want the browser to remember this password?</string> <!-- If the user enters a password in a form on a website, a dialog will come up asking if they want to save the password. Button in the save password dialog, saying not to remember this password. --> @@ -2708,10 +2716,11 @@ <!-- Do not translate. Default access point SSID used for tethering --> <string name="wifi_tether_configure_ssid_default" translatable="false">AndroidAP</string> - <!-- Wi-Fi p2p dialog title--> <string name="wifi_p2p_dialog_title">Wi-Fi Direct</string> <string name="wifi_p2p_turnon_message">Start Wi-Fi Direct. This will turn off Wi-Fi client/hotspot.</string> <string name="wifi_p2p_failed_message">Couldn\'t start Wi-Fi Direct.</string> + <string name="wifi_p2p_enabled_notification_title">Wi-Fi Direct is on</string> + <string name="wifi_p2p_enabled_notification_message">Touch for settings</string> <string name="accept">Accept</string> <string name="decline">Decline</string> @@ -2723,9 +2732,6 @@ <string name="wifi_p2p_enter_pin_message">Type the required PIN: </string> <string name="wifi_p2p_show_pin_message">PIN: </string> - <string name="wifi_p2p_enabled_notification_title">Wi-Fi Direct is on</string> - <string name="wifi_p2p_enabled_notification_message">Touch for settings</string> - <!-- Name of the dialog that lets the user choose an accented character to insert --> <string name="select_character">Insert character</string> diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml index 571c4ad9e447..610bad888cbe 100644 --- a/core/res/res/values/styles.xml +++ b/core/res/res/values/styles.xml @@ -198,8 +198,10 @@ please see styles_device_defaults.xml. <!-- A special animation we can use for recent applications, for devices that can support it (do alpha transformations). --> <style name="Animation.RecentApplications"> - <item name="windowEnterAnimation">@anim/fade_in</item> - <item name="windowExitAnimation">@anim/fade_out</item> + <item name="windowEnterAnimation">@anim/recents_fade_in</item> + <item name="windowShowAnimation">@anim/recents_fade_in</item> + <item name="windowExitAnimation">@anim/recents_fade_out</item> + <item name="windowHideAnimation">@anim/recents_fade_out</item> </style> <!-- A special animation value used internally for popup windows. --> diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestRunner.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestRunner.java index 9819c54aad6d..9c1922ff71e7 100644 --- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestRunner.java +++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestRunner.java @@ -46,8 +46,7 @@ public class ConnectivityManagerTestRunner extends InstrumentationTestRunner { // create a new test suite suite.setName("ConnectivityManagerWifiOnlyFunctionalTests"); String[] methodNames = {"testConnectToWifi", "testConnectToWifWithKnownAP", - "testDisconnectWifi", "testDataConnectionOverAMWithWifi", - "testDataConnectionWithWifiToAMToWifi", "testWifiStateChange"}; + "testDisconnectWifi", "testWifiStateChange"}; Class<ConnectivityManagerMobileTest> testClass = ConnectivityManagerMobileTest.class; for (String method: methodNames) { suite.addTest(TestSuite.createTest(testClass, method)); diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk index b81f7744cf37..88f3f348e76b 100644 --- a/core/tests/coretests/Android.mk +++ b/core/tests/coretests/Android.mk @@ -22,7 +22,7 @@ LOCAL_SRC_FILES := \ $(call all-java-files-under, EnabledTestApp/src) LOCAL_DX_FLAGS := --core-library -LOCAL_STATIC_JAVA_LIBRARIES := core-tests android-common frameworks-core-util-lib mockwebserver guava +LOCAL_STATIC_JAVA_LIBRARIES := core-tests android-common frameworks-core-util-lib mockwebserver guava littlemock LOCAL_JAVA_LIBRARIES := android.test.runner LOCAL_PACKAGE_NAME := FrameworksCoreTests diff --git a/core/tests/coretests/src/android/net/http/HttpResponseCacheTest.java b/core/tests/coretests/src/android/net/http/HttpResponseCacheTest.java index 4d65588532ec..9015a6f5d7e4 100644 --- a/core/tests/coretests/src/android/net/http/HttpResponseCacheTest.java +++ b/core/tests/coretests/src/android/net/http/HttpResponseCacheTest.java @@ -16,6 +16,8 @@ package android.net.http; +import com.google.mockwebserver.MockResponse; +import com.google.mockwebserver.MockWebServer; import java.io.File; import java.net.CacheRequest; import java.net.CacheResponse; @@ -30,6 +32,7 @@ import junit.framework.TestCase; public final class HttpResponseCacheTest extends TestCase { private File cacheDir; + private MockWebServer server = new MockWebServer(); @Override public void setUp() throws Exception { super.setUp(); @@ -39,6 +42,7 @@ public final class HttpResponseCacheTest extends TestCase { @Override protected void tearDown() throws Exception { ResponseCache.setDefault(null); + server.shutdown(); super.tearDown(); } @@ -100,4 +104,32 @@ public final class HttpResponseCacheTest extends TestCase { cache.delete(); assertNull(ResponseCache.getDefault()); } + + /** + * Make sure that statistics tracking are wired all the way through the + * wrapper class. http://code.google.com/p/android/issues/detail?id=25418 + */ + public void testStatisticsTracking() throws Exception { + HttpResponseCache cache = HttpResponseCache.install(cacheDir, 10 * 1024 * 1024); + + server.enqueue(new MockResponse() + .addHeader("Cache-Control: max-age=60") + .setBody("A")); + server.play(); + + URLConnection c1 = server.getUrl("/").openConnection(); + assertEquals('A', c1.getInputStream().read()); + assertEquals(1, cache.getRequestCount()); + assertEquals(1, cache.getNetworkCount()); + assertEquals(0, cache.getHitCount()); + + URLConnection c2 = server.getUrl("/").openConnection(); + assertEquals('A', c2.getInputStream().read()); + + URLConnection c3 = server.getUrl("/").openConnection(); + assertEquals('A', c3.getInputStream().read()); + assertEquals(3, cache.getRequestCount()); + assertEquals(1, cache.getNetworkCount()); + assertEquals(2, cache.getHitCount()); + } } diff --git a/core/tests/coretests/src/android/widget/focus/RequestFocusTest.java b/core/tests/coretests/src/android/widget/focus/RequestFocusTest.java index baf587e39c1b..f2eba2335808 100644 --- a/core/tests/coretests/src/android/widget/focus/RequestFocusTest.java +++ b/core/tests/coretests/src/android/widget/focus/RequestFocusTest.java @@ -16,6 +16,9 @@ package android.widget.focus; +import static com.google.testing.littlemock.LittleMock.inOrder; +import static com.google.testing.littlemock.LittleMock.mock; + import android.os.Handler; import android.test.ActivityInstrumentationTestCase2; import android.test.UiThreadTest; @@ -28,9 +31,7 @@ import android.view.ViewTreeObserver.OnGlobalFocusChangeListener; import android.widget.Button; import com.android.frameworks.coretests.R; - -import java.util.ArrayList; -import java.util.List; +import com.google.testing.littlemock.LittleMock.InOrder; /** * {@link RequestFocusTest} is set up to exercise cases where the views that @@ -105,43 +106,47 @@ public class RequestFocusTest extends ActivityInstrumentationTestCase2<RequestFo * This tests checks the case in which the first focusable View clears focus. * In such a case the framework tries to give the focus to another View starting * from the top. Hence, the framework will try to give focus to the view that - * wants to clear its focus. From a client perspective, the view does not loose - * focus after the call, therefore no callback for focus change should be invoked. + * wants to clear its focus. * * @throws Exception If an error occurs. */ @UiThreadTest - public void testOnFocusChangeNotCalledIfFocusDoesNotMove() throws Exception { + public void testOnFocusChangeCallbackOrderWhenClearingFocusOfFirstFocusable() + throws Exception { // Get the first focusable. - Button button = mTopLeftButton; - - // Make sure that the button is the first focusable and focus it. - button.getRootView().requestFocus(View.FOCUS_DOWN); - assertTrue(button.hasFocus()); - - // Attach on focus change listener that should not be called. - button.setOnFocusChangeListener(new OnFocusChangeListener() { - @Override - public void onFocusChange(View v, boolean hasFocus) { - throw new IllegalStateException("Unexpeced call to" - + "OnFocusChangeListener#onFocusChange"); - } - }); - - // Attach on global focus change listener that should not be called. - button.getViewTreeObserver().addOnGlobalFocusChangeListener( - new OnGlobalFocusChangeListener() { - @Override - public void onGlobalFocusChanged(View oldFocus, View newFocus) { - throw new IllegalStateException("Unexpeced call to" - + "OnFocusChangeListener#onFocusChange"); - } - }); + Button clearingFocusButton = mTopLeftButton; + Button gainingFocusButton = mTopLeftButton; + + // Make sure that the clearing focus View is the first focusable. + View focusCandidate = clearingFocusButton.getRootView().getParent().focusSearch(null, + View.FOCUS_FORWARD); + assertSame("The clearing focus button is the first focusable.", + clearingFocusButton, focusCandidate); + assertSame("The gaining focus button is the first focusable.", + gainingFocusButton, focusCandidate); + + // Focus the clearing focus button. + clearingFocusButton.requestFocus(); + assertTrue(clearingFocusButton.hasFocus()); + + // Register the invocation order checker. + CombinedListeners mock = mock(CombinedListeners.class); + clearingFocusButton.setOnFocusChangeListener(mock); + gainingFocusButton.setOnFocusChangeListener(mock); + clearingFocusButton.getViewTreeObserver().addOnGlobalFocusChangeListener(mock); // Try to clear focus. - button.clearFocus(); + clearingFocusButton.clearFocus(); + + // Check that no callback was invoked since focus did not move. + InOrder inOrder = inOrder(mock); + inOrder.verify(mock).onFocusChange(clearingFocusButton, false); + inOrder.verify(mock).onGlobalFocusChanged(clearingFocusButton, gainingFocusButton); + inOrder.verify(mock).onFocusChange(gainingFocusButton, true); } + public interface CombinedListeners extends OnFocusChangeListener, OnGlobalFocusChangeListener {} + /** * This tests check whether the on focus change callbacks are invoked in * the proper order when a View loses focus and the framework gives it to @@ -150,12 +155,12 @@ public class RequestFocusTest extends ActivityInstrumentationTestCase2<RequestFo * @throws Exception */ @UiThreadTest - public void testOnFocusChangeCallbackOrder() throws Exception { - // Get the first focusable. + public void testOnFocusChangeCallbackOrderWhenClearingFocusOfNotFirstFocusable() + throws Exception { Button clearingFocusButton = mTopRightButton; Button gainingFocusButton = mTopLeftButton; - // Make sure that the clearing focus is not the first focusable. + // Make sure that the clearing focus View is not the first focusable. View focusCandidate = clearingFocusButton.getRootView().getParent().focusSearch(null, View.FOCUS_FORWARD); assertNotSame("The clearing focus button is not the first focusable.", @@ -168,77 +173,18 @@ public class RequestFocusTest extends ActivityInstrumentationTestCase2<RequestFo assertTrue(clearingFocusButton.hasFocus()); // Register the invocation order checker. - CallbackOrderChecker checker = new CallbackOrderChecker(clearingFocusButton, - gainingFocusButton); - clearingFocusButton.setOnFocusChangeListener(checker); - gainingFocusButton.setOnFocusChangeListener(checker); - clearingFocusButton.getViewTreeObserver().addOnGlobalFocusChangeListener(checker); + CombinedListeners mock = mock(CombinedListeners.class); + clearingFocusButton.setOnFocusChangeListener(mock); + gainingFocusButton.setOnFocusChangeListener(mock); + clearingFocusButton.getViewTreeObserver().addOnGlobalFocusChangeListener(mock); // Try to clear focus. clearingFocusButton.clearFocus(); // Check that no callback was invoked since focus did not move. - checker.verify(); - } - - /** - * This class check whether the focus change callback are invoked in order. - */ - private class CallbackOrderChecker implements OnFocusChangeListener, - OnGlobalFocusChangeListener { - - private class CallbackInvocation { - final String mMethodName; - final Object[] mArguments; - - CallbackInvocation(String methodName, Object[] arguments) { - mMethodName = methodName; - mArguments = arguments; - } - } - - private final View mClearingFocusView; - private final View mGainingFocusView; - - private final List<CallbackInvocation> mInvocations = new ArrayList<CallbackInvocation>(); - - public CallbackOrderChecker(View clearingFocusView, View gainingFocusView) { - mClearingFocusView = clearingFocusView; - mGainingFocusView = gainingFocusView; - } - - @Override - public void onFocusChange(View view, boolean hasFocus) { - CallbackInvocation invocation = new CallbackInvocation( - "OnFocusChangeListener#onFocusChange", new Object[] {view, hasFocus}); - mInvocations.add(invocation); - } - - @Override - public void onGlobalFocusChanged(View oldFocus, View newFocus) { - CallbackInvocation invocation = new CallbackInvocation( - "OnFocusChangeListener#onFocusChange", new Object[] {oldFocus, newFocus}); - mInvocations.add(invocation); - } - - public void verify() { - assertSame("All focus change callback should be invoked.", 3, mInvocations.size()); - assertInvioked("Callback for View clearing focus explected.", 0, - "OnFocusChangeListener#onFocusChange", - new Object[] {mClearingFocusView, false}); - assertInvioked("Callback for View global focus change explected.", 1, - "OnFocusChangeListener#onFocusChange", new Object[] {mClearingFocusView, - mGainingFocusView}); - assertInvioked("Callback for View gaining focus explected.", 2, - "OnFocusChangeListener#onFocusChange", new Object[] {mGainingFocusView, true}); - } - - private void assertInvioked(String message, int order, String methodName, - Object[] arguments) { - CallbackInvocation invocation = mInvocations.get(order); - assertEquals(message, methodName, invocation.mMethodName); - assertEquals(message, arguments[0], invocation.mArguments[0]); - assertEquals(message, arguments[1], invocation.mArguments[1]); - } + InOrder inOrder = inOrder(mock); + inOrder.verify(mock).onFocusChange(clearingFocusButton, false); + inOrder.verify(mock).onGlobalFocusChanged(clearingFocusButton, gainingFocusButton); + inOrder.verify(mock).onFocusChange(gainingFocusButton, true); } } diff --git a/data/etc/platform.xml b/data/etc/platform.xml index 6cd07a31ccc5..8be1db2bb1f6 100644 --- a/data/etc/platform.xml +++ b/data/etc/platform.xml @@ -158,6 +158,7 @@ <assign-permission name="android.permission.BACKUP" uid="shell" /> <assign-permission name="android.permission.FORCE_STOP_PACKAGES" uid="shell" /> <assign-permission name="android.permission.STOP_APP_SWITCHES" uid="shell" /> + <assign-permission name="android.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY" uid="shell" /> <assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="media" /> <assign-permission name="android.permission.ACCESS_DRM" uid="media" /> diff --git a/data/fonts/Android.mk b/data/fonts/Android.mk index 02d2f3d79217..ef38a60d14d9 100644 --- a/data/fonts/Android.mk +++ b/data/fonts/Android.mk @@ -51,6 +51,11 @@ ALL_MODULES.$(LOCAL_MODULE).INSTALLED := \ $(ALL_MODULES.$(LOCAL_MODULE).INSTALLED) $(font_symlink) ################################ +# On space-constrained devices, we include a subset of fonts: +ifeq ($(SMALLER_FONT_FOOTPRINT),true) +droidsans_fallback_src := DroidSansFallback.ttf +extra_droidsans_fonts := DroidSans.ttf DroidSans-Bold.ttf +else include $(CLEAR_VARS) LOCAL_MODULE := DroidSansEthiopic-Regular.ttf LOCAL_SRC_FILES := $(LOCAL_MODULE) @@ -59,15 +64,11 @@ LOCAL_MODULE_TAGS := optional LOCAL_MODULE_PATH := $(TARGET_OUT)/fonts include $(BUILD_PREBUILT) -################################ -ifeq ($(SMALLER_FONT_FOOTPRINT),true) -droidsans_fallback_src := DroidSansFallback.ttf -extra_droidsans_fonts := DroidSans.ttf DroidSans-Bold.ttf -else droidsans_fallback_src := DroidSansFallbackFull.ttf extra_droidsans_fonts := DroidSans.ttf DroidSans-Bold.ttf DroidSansEthiopic-Regular.ttf endif # SMALLER_FONT_FOOTPRINT +################################ include $(CLEAR_VARS) LOCAL_MODULE := DroidSansFallback.ttf LOCAL_SRC_FILES := $(droidsans_fallback_src) @@ -81,3 +82,46 @@ font_symlink_src := font_symlink := droidsans_fallback_src := extra_droidsans_fonts := + +################################ +# Build the rest font files as prebuilt. + +# $(1): The source file name in LOCAL_PATH. +# It also serves as the module name and the dest file name. +define build-one-font-module +$(eval include $(CLEAR_VARS))\ +$(eval LOCAL_MODULE := $(1))\ +$(eval LOCAL_SRC_FILES := $(1))\ +$(eval LOCAL_MODULE_CLASS := ETC)\ +$(eval LOCAL_MODULE_TAGS := optional)\ +$(eval LOCAL_MODULE_PATH := $(TARGET_OUT)/fonts)\ +$(eval include $(BUILD_PREBUILT)) +endef + +font_src_files := \ + Roboto-Regular.ttf \ + Roboto-Bold.ttf \ + Roboto-Italic.ttf \ + Roboto-BoldItalic.ttf \ + DroidSansArabic.ttf \ + DroidNaskh-Regular.ttf \ + DroidSansHebrew-Regular.ttf \ + DroidSansHebrew-Bold.ttf \ + DroidSansThai.ttf \ + DroidSerif-Regular.ttf \ + DroidSerif-Bold.ttf \ + DroidSerif-Italic.ttf \ + DroidSerif-BoldItalic.ttf \ + DroidSansMono.ttf \ + DroidSansArmenian.ttf \ + DroidSansGeorgian.ttf \ + AndroidEmoji.ttf \ + Clockopia.ttf \ + AndroidClock.ttf \ + AndroidClock_Highlight.ttf \ + AndroidClock_Solid.ttf \ + +$(foreach f, $(font_src_files), $(call build-one-font-module, $(f))) + +build-one-font-module := +font_src_files := diff --git a/data/fonts/DroidNaskh-Bold.ttf b/data/fonts/DroidNaskh-Bold.ttf Binary files differindex 6b7d4f0b39d3..692b79678170 100644 --- a/data/fonts/DroidNaskh-Bold.ttf +++ b/data/fonts/DroidNaskh-Bold.ttf diff --git a/data/fonts/DroidNaskh-Regular.ttf b/data/fonts/DroidNaskh-Regular.ttf Binary files differindex d11e1aebd04e..da9a45f150b9 100644 --- a/data/fonts/DroidNaskh-Regular.ttf +++ b/data/fonts/DroidNaskh-Regular.ttf diff --git a/data/fonts/DroidSansFallback.ttf b/data/fonts/DroidSansFallback.ttf Binary files differindex 2379b2d758a1..cfbc66ad0470 100644 --- a/data/fonts/DroidSansFallback.ttf +++ b/data/fonts/DroidSansFallback.ttf diff --git a/data/fonts/DroidSansFallbackFull.ttf b/data/fonts/DroidSansFallbackFull.ttf Binary files differindex 41b015d5a052..0cacabedcaed 100644 --- a/data/fonts/DroidSansFallbackFull.ttf +++ b/data/fonts/DroidSansFallbackFull.ttf diff --git a/data/fonts/fonts.mk b/data/fonts/fonts.mk index 6a9ed539bfc9..458f85b7d0a7 100644 --- a/data/fonts/fonts.mk +++ b/data/fonts/fonts.mk @@ -14,34 +14,30 @@ # Warning: this is actually a product definition, to be inherited from -# On space-constrained devices, we include a subset of fonts: -# First, core/required fonts PRODUCT_COPY_FILES := \ - frameworks/base/data/fonts/Roboto-Regular.ttf:system/fonts/Roboto-Regular.ttf \ - frameworks/base/data/fonts/Roboto-Bold.ttf:system/fonts/Roboto-Bold.ttf \ - frameworks/base/data/fonts/Roboto-Italic.ttf:system/fonts/Roboto-Italic.ttf \ - frameworks/base/data/fonts/Roboto-BoldItalic.ttf:system/fonts/Roboto-BoldItalic.ttf \ - frameworks/base/data/fonts/DroidSansArabic.ttf:system/fonts/DroidSansArabic.ttf \ - frameworks/base/data/fonts/DroidNaskh-Regular.ttf:system/fonts/DroidNaskh-Regular.ttf \ - frameworks/base/data/fonts/DroidSansHebrew-Regular.ttf:system/fonts/DroidSansHebrew-Regular.ttf \ - frameworks/base/data/fonts/DroidSansHebrew-Bold.ttf:system/fonts/DroidSansHebrew-Bold.ttf \ - frameworks/base/data/fonts/DroidSansThai.ttf:system/fonts/DroidSansThai.ttf \ - frameworks/base/data/fonts/DroidSerif-Regular.ttf:system/fonts/DroidSerif-Regular.ttf \ - frameworks/base/data/fonts/DroidSerif-Bold.ttf:system/fonts/DroidSerif-Bold.ttf \ - frameworks/base/data/fonts/DroidSerif-Italic.ttf:system/fonts/DroidSerif-Italic.ttf \ - frameworks/base/data/fonts/DroidSerif-BoldItalic.ttf:system/fonts/DroidSerif-BoldItalic.ttf \ - frameworks/base/data/fonts/DroidSansMono.ttf:system/fonts/DroidSansMono.ttf \ - frameworks/base/data/fonts/DroidSansArmenian.ttf:system/fonts/DroidSansArmenian.ttf \ - frameworks/base/data/fonts/DroidSansGeorgian.ttf:system/fonts/DroidSansGeorgian.ttf \ - frameworks/base/data/fonts/AndroidEmoji.ttf:system/fonts/AndroidEmoji.ttf \ - frameworks/base/data/fonts/Clockopia.ttf:system/fonts/Clockopia.ttf \ - frameworks/base/data/fonts/AndroidClock.ttf:system/fonts/AndroidClock.ttf \ - frameworks/base/data/fonts/AndroidClock_Highlight.ttf:system/fonts/AndroidClock_Highlight.ttf \ - frameworks/base/data/fonts/AndroidClock_Solid.ttf:system/fonts/AndroidClock_Solid.ttf \ frameworks/base/data/fonts/system_fonts.xml:system/etc/system_fonts.xml \ frameworks/base/data/fonts/fallback_fonts.xml:system/etc/fallback_fonts.xml -# Next, include additional fonts, depending on how much space we have. -# Details see module definitions in Android.mk. PRODUCT_PACKAGES := \ - DroidSansFallback.ttf + DroidSansFallback.ttf \ + Roboto-Regular.ttf \ + Roboto-Bold.ttf \ + Roboto-Italic.ttf \ + Roboto-BoldItalic.ttf \ + DroidSansArabic.ttf \ + DroidNaskh-Regular.ttf \ + DroidSansHebrew-Regular.ttf \ + DroidSansHebrew-Bold.ttf \ + DroidSansThai.ttf \ + DroidSerif-Regular.ttf \ + DroidSerif-Bold.ttf \ + DroidSerif-Italic.ttf \ + DroidSerif-BoldItalic.ttf \ + DroidSansMono.ttf \ + DroidSansArmenian.ttf \ + DroidSansGeorgian.ttf \ + AndroidEmoji.ttf \ + Clockopia.ttf \ + AndroidClock.ttf \ + AndroidClock_Highlight.ttf \ + AndroidClock_Solid.ttf \ diff --git a/docs/html/guide/developing/device.jd b/docs/html/guide/developing/device.jd index d390ec1474d1..d22dca1fee41 100644 --- a/docs/html/guide/developing/device.jd +++ b/docs/html/guide/developing/device.jd @@ -51,19 +51,13 @@ would on the emulator. Before you can start, there are just a few things to do:< <ol> <li>Declare your application as "debuggable" in your Android Manifest. - <p>In Eclipse, you can do this from the <b>Application</b> tab when viewing the Manifest - (on the right side, set <b>Debuggable</b> to <em>true</em>). Otherwise, in the -<code>AndroidManifest.xml</code> - file, add <code>android:debuggable="true"</code> to the <code><application></code> -element.</p> - </li> - <li>Set up your device to allow installation of non-Market applications. <p>On -the device, go to <strong>Settings > Applications</strong> and enable - -<strong>Unknown sources</strong> (on an Android 4.0 device, the setting is -located in <strong>Settings > Security</strong>).</p> - - </li> + <p>When using Eclipse, you can skip this step, because running your app directly from +the Eclipse IDE automatically enables debugging.</p> + <p>In the <code>AndroidManifest.xml</code> file, add <code>android:debuggable="true"</code> to +the <code><application></code> element.</p> + <p class="note"><strong>Note:</strong> If you manually enable debugging in the manifest + file, be sure to disable it before you build for release (your published application +should usually <em>not</em> be debuggable).</p></li> <li>Turn on "USB Debugging" on your device. <p>On the device, go to <strong>Settings > Applications > Development</strong> and enable <strong>USB debugging</strong> @@ -72,13 +66,10 @@ located in <strong>Settings > Developer options</strong>).</p> </li> <li>Set up your system to detect your device. <ul> - <li>If you're developing on Windows, you need to install a USB driver - for adb. If you're using an Android Developer Phone (ADP), Nexus One, or Nexus S, - see the <a href="{@docRoot}sdk/win-usb.html">Google Windows USB - Driver</a>. Otherwise, you can find a link to the appropriate OEM driver in the - <a href="{@docRoot}sdk/oem-usb.html">OEM USB Drivers</a> document.</li> + <li>If you're developing on Windows, you need to install a USB driver for adb. For an +installation guide and links to OEM drivers, see the <a href="{@docRoot}sdk/oem-usb.html">OEM USB +Drivers</a> document.</li> <li>If you're developing on Mac OS X, it just works. Skip this step.</li> - <li>If you're developing on Ubuntu Linux, you need to add a <code>udev</code> rules file that contains a USB configuration for each type of device you want to use for development. In the rules file, each device manufacturer @@ -114,7 +105,7 @@ rules</a>.</p> </li> </ol> -<p>You can verify that your device is connected by executing <code>adb +<p>When plugged in over USB, can verify that your device is connected by executing <code>adb devices</code> from your SDK {@code platform-tools/} directory. If connected, you'll see the device name listed as a "device."</p> diff --git a/docs/html/index.jd b/docs/html/index.jd index b9d67584aa74..431a7d26482c 100644 --- a/docs/html/index.jd +++ b/docs/html/index.jd @@ -154,7 +154,7 @@ href="{@docRoot}resources/dashboard/platform-versions.html">Learn more »</ + "href='https://plus.google.com/108967384991768947849'>+Android Developers</a>. " + "We'll use it to host Hangouts for developers, talk about the latest releases, " + "development and design tips, and much more.</p>" -+ "<div style='margin:.7em 0 0 -1.2em'><g:plus href='https://plus.google.com/108967384991768947849' " ++ "<div style='margin:.7em 0 0 0'><g:plus href='https://plus.google.com/108967384991768947849' " + "size=\"smallbadge\" width=\"275\"></g:plus></div>" }, diff --git a/docs/html/sdk/ndk/index.jd b/docs/html/sdk/ndk/index.jd index afbad57094d0..29f0749736fd 100644 --- a/docs/html/sdk/ndk/index.jd +++ b/docs/html/sdk/ndk/index.jd @@ -1,16 +1,16 @@ ndk=true -ndk.win_download=android-ndk-r7-windows.zip -ndk.win_bytes=81270552 -ndk.win_checksum=55483482cf2b75e8dd1a5d9a7caeb6e5 +ndk.win_download=android-ndk-r7b-windows.zip +ndk.win_bytes=80346206 +ndk.win_checksum=c42b0c9c14428397337421d5e4999380 -ndk.mac_download=android-ndk-r7-darwin-x86.tar.bz2 -ndk.mac_bytes=71262092 -ndk.mac_checksum=817ca5675a1dd44078098e43070f19b6 +ndk.mac_download=android-ndk-r7b-darwin-x86.tar.bz2 +ndk.mac_bytes=73817184 +ndk.mac_checksum=6daa82ca6b73bc0614c9997430079c7a -ndk.linux_download=android-ndk-r7-linux-x86.tar.bz2 -ndk.linux_bytes=64884365 -ndk.linux_checksum=bf15e6b47bf50824c4b96849bf003ca3 +ndk.linux_download=android-ndk-r7b-linux-x86.tar.bz2 +ndk.linux_bytes=64349733 +ndk.linux_checksum=0eb8af18796cdaa082df8f7c54ad7f9a page.title=Android NDK @@ -62,6 +62,116 @@ padding: .25em 1em; <div class="toggleable open"> <a href="#" onclick="return toggleDiv(this)"><img src= "{@docRoot}assets/images/triangle-opened.png" class="toggle-img" height="9px" width="9px"> + Android NDK, Revision 7b</a> <em>(February 2012)</em> + + <div class="toggleme"> + <p>This release of the NDK includes fixes for native Windows builds, Cygwin and many other + improvements:</p> + + <dl> + <dt>Important bug fixes:</dt> + + <dd> + <ul> + <li>Updated {@code sys/atomics.h} to avoid correctness issues + on some multi-core ARM-based devices. Rebuild your unmodified sources with this + version of the NDK and this problem should be completely eliminated. + For more details, read {@code docs/ANDROID-ATOMICS.html}.</li> + <li>Reverted to {@code binutils} 2.19 to fix debugging issues that + appeared in NDK r7 (which switched to {@code binutils} 2.20.1).</li> + <li>Fixed {@code ndk-build} on 32-bit Linux. A packaging error put a 64-bit version + of the {@code awk} executable under {@code prebuilt/linux-x86/bin} in NDK r7.</li> + <li>Fixed native Windows build ({@code ndk-build.cmd}). Other build modes were not + affected. The fixes include: + <ul> + <li>Removed an infinite loop / stack overflow bug that happened when trying + to call {@code ndk-build.cmd} from a directory that was <em>not</em> the top of + your project path (e.g., in any sub-directory of it).</li> + <li>Fixed a problem where the auto-generated dependency files were ignored. This + meant that updating a header didn't trigger recompilation of sources that included + it.</li> + <li>Fixed a problem where special characters in files or paths, other than spaces and + quotes, were not correctly handled.</li> + </ul> + </li> + <li>Fixed the standalone toolchain to generate proper binaries when using + {@code -lstdc++} (i.e., linking against the GNU {@code libstdc++} C++ runtime). You + should use {@code -lgnustl_shared} if you want to link against the shared library + version or {@code -lstdc++} for the static version. + + <p>See {@code docs/STANDALONE-TOOLCHAIN.html} for more details about this fix.</p> + </li> + <li>Fixed {@code gnustl_shared} on Cygwin. The linker complained that it couldn't find + {@code libsupc++.a} even though the file was at the right location.</li> + <li>Fixed Cygwin C++ link when not using any specific C++ runtime through + {@code APP_STL}.</li> + </ul> + </dd> + </dl> + + <dl> + <dt>Other changes:</dt> + + <dd> + <ul> + <li>When your application uses the GNU {@code libstdc++} runtime, the compiler will + no longer forcibly enable exceptions and RTTI. This change results in smaller code. + <p>If you need these features, you must do one of the following:</p> + <ul> + <li>Enable exceptions and/or RTTI explicitly in your modules or + {@code Application.mk}. (recommended)</li> + <li>Define {@code APP_GNUSTL_FORCE_CPP_FEATURES} to {@code 'exceptions'}, + {@code 'rtti'} or both in your {@code Application.mk}. See + {@code docs/APPLICATION-MK.html} for more details.</li> + </ul> + </li> + <li>{@code ndk-gdb} now works properly when your application has private services + running in independent processes. It debugs the main application process, instead of the + first process listed by {@code ps}, which is usually a service process.</li> + <li>Fixed a rare bug where NDK r7 would fail to honor the {@code LOCAL_ARM_MODE} value + and always compile certain source files (but not all) to 32-bit instructions.</li> + <li>{@code stlport}: Refresh the sources to match the Android platform version. This + update fixes a few minor bugs: + <ul> + <li>Fixed instantiation of an incomplete type</li> + <li>Fixed minor "==" versus "=" typo</li> + <li>Used {@code memmove} instead of {@code memcpy} in {@code string::assign}</li> + <li>Added better handling of {@code IsNANorINF}, {@code IsINF}, {@code IsNegNAN}, + etc.</li> + </ul> + <p>For complete details, see the commit log.</p> + </li> + <li>{@code stlport}: Removed 5 unnecessary static initializers from the library.</li> + <li>The GNU libstdc++ libraries for armeabi-v7a were mistakenly compiled for + armeabi instead. This change had no impact on correctness, but using the right + ABI should provide slightly better performance.</li> + <li>The {@code cpu-features} helper library was updated to report three optional + x86 CPU features ({@code SSSE3}, {@code MOVBE} and {@code POPCNT}). See + {@code docs/CPU-FEATURES.html} for more details.</li> + <li>{@code docs/NDK-BUILD.html} was updated to mention {@code NDK_APPLICATION_MK} instead + of {@code NDK_APP_APPLICATION_MK} to select a custom {@code Application.mk} file.</li> + <li>Cygwin: {@code ndk-build} no longer creates an empty "NUL" file in the current + directory when invoked.</li> + <li>Cygwin: Added better automatic dependency detection. In the previous version, it + didn't work properly in the following cases: + <ul> + <li>When the Cygwin drive prefix was not {@code /cygdrive}.</li> + <li>When using drive-less mounts, for example, when Cygwin would translate + {@code /home} to {@code \\server\subdir} instead of {@code C:\Some\Dir}.</li> + </ul> + </li> + <li>Cygwin: {@code ndk-build} does not try to use the native Windows tools under + {@code $NDK/prebuilt/windows/bin} with certain versions of Cygwin and/or GNU Make.</li> + </ul> + </dd> + </dl> + </div> +</div> + + +<div class="toggleable closed"> + <a href="#" onclick="return toggleDiv(this)"><img src= + "{@docRoot}assets/images/triangle-closed.png" class="toggle-img" height="9px" width="9px"> Android NDK, Revision 7</a> <em>(November 2011)</em> <div class="toggleme"> diff --git a/docs/html/sdk/oem-usb.jd b/docs/html/sdk/oem-usb.jd index b81be71dc079..f98257df0027 100644 --- a/docs/html/sdk/oem-usb.jd +++ b/docs/html/sdk/oem-usb.jd @@ -3,9 +3,21 @@ page.title=OEM USB Drivers <div id="qv-wrapper"> <div id="qv"> + <h2>In this document</h2> + <ol> + <li><a href="#InstallingDriver">Installing a USB Driver</a> + <ol> + <li><a href="#Win7">Windows 7</a></li> + <li><a href="#WinXp">Windows XP</a></li> + <li><a href="#WinVista">Windows Vista</a></li> + </ol> + </li> + <li><a href="#Drivers">OEM Drivers</a></li> + </ol> + <h2>See also</h2> <ol> - <li><a href="{@docRoot}guide/developing/device.html">Developing on a Device</a></li> + <li><a href="{@docRoot}guide/developing/device.html">Using Hardware Devices</a></li> <li><a href="{@docRoot}sdk/win-usb.html">Google USB Driver</a></li> </ol> </div> @@ -18,8 +30,185 @@ where you can download the appropriate USB driver for your device. However, this not exhaustive for all available Android-powered devices.</p> <p>If you're developing on Mac OS X or Linux, then you probably don't need to install a USB driver. -Refer to <a href="{@docRoot}guide/developing/device.html#setting-up">Setting up a Device</a> to -start development with a device.</p> +To start developing with your device, read <a +href="{@docRoot}guide/developing/device.html">Using Hardware Devices</a>.</p> + +<p class="note"><strong>Note:</strong> If your device is one of the Android Developer Phones +(purchased from the Android Market publisher site), a Nexus One, or a Nexus S, then you need +the <a href="{@docRoot}sdk/win-usb.html">Google USB Driver</a>, instead of an OEM driver. The Galaxy +Nexus driver, however, is distributed by <a +href="http://www.samsung.com/us/support/downloads/verizon-wireless/SCH-I515MSAVZW">Samsung</a> +(listed as model SCH-I515).</p> + + +<h2 id="InstallingDriver">Installing a USB Driver</h2> + +<p>First, find the appropriate driver for your device from the <a href="#Drivers">OEM drivers</a> +table below.</p> + +<p>Once you've downloaded your USB driver, follow the instructions below to install or upgrade the +driver, based on your version of Windows and whether you're installing for the first time +or upgrading an existing driver.</p> + +<p class="note"><strong>Tip:</strong> When you finish the USB driver installation, +see <a +href="{@docRoot}guide/developing/device.html">Using Hardware Devices</a> for +other important information about using an Android-powered device for +development.</p> + +<ol class="nolist"> + <li><a href="#Win7">Windows 7</a></li> + <li><a href="#WinXp">Windows XP</a></li> + <li><a href="#WinVista">Windows Vista</a></li> +</ol> + + +<p class="caution"><strong>Caution:</strong> +You may make changes to <code>android_winusb.inf</code> file found inside +<code>usb_driver\</code> (for example, to add support for other devices), +however, this will lead to security warnings when you install or upgrade the +driver. Making any other changes to the driver files may break the installation +process.</p> + + +<h3 id="Win7">Windows 7</h3> + + +<p>To install the Android USB driver on Windows 7 for the first time:</p> +<ol> + <li>Connect your Android-powered device to your computer's USB port.</li> + <li>Right-click on <em>Computer</em> from your desktop or Windows Explorer, + and select <strong>Manage</strong>.</li> + <li>Select <strong>Devices</strong> in the left pane.</li> + <li>Locate and expand <em>Other device</em> in the right pane.</li> + <li>Right-click the device name (such as <em>Nexus S</em>) and select <strong>Update + Driver Software</strong>. + This will launch the Hardware Update Wizard.</li> + <li>Select <strong>Browse my computer for driver software</strong> and click + <strong>Next</strong>.</li> + <li>Click <strong>Browse</strong> and locate the USB driver folder. (The Google USB +Driver is located in {@code <sdk>\extras\google\usb_driver\}.)</li> + <li>Click <strong>Next</strong> to install the driver.</li> +</ol> + +<p>Or, to <em>upgrade</em> an existing Android USB driver on Windows 7 with the new +driver:</p> + +<ol> + <li>Connect your Android-powered device to your computer's USB port.</li> + <li>Right-click on <em>Computer</em> from your desktop or Windows Explorer, + and select <strong>Manage</strong>.</li> + <li>Select <strong>Device Manager</strong> in the left pane of the Computer Management + window.</li> + <li>Locate and expand <em>Android Phone</em> in the right pane.</li> + <li>Right-click <em>Android Composite ADB Interface</em> and select <strong>Update + Driver</strong>. + This will launch the Hardware Update Wizard.</li> + <li>Select <strong>Install from a list or specific location</strong> and click + <strong>Next</strong>.</li> + <li>Select <strong>Search for the best driver in these locations</strong>; un-check +<strong>Search removable media</strong>; and check <strong>Include this location in the +search</strong>.</li> + <li>Click <strong>Browse</strong> and locate the USB driver folder. (The Google USB +Driver is located in {@code <sdk>\extras\google\usb_driver\}.)</li> + <li>Click <strong>Next</strong> to upgrade the driver.</li> +</ol> + + + + + +<h3 id="WinXp">Windows XP</h3> + +<p>To install the Android USB driver on Windows XP for the first time:</p> + +<ol> + <li>Connect your Android-powered device to your computer's USB port. Windows + will detect the device and launch the Hardware Update Wizard.</li> + <li>Select <strong>Install from a list or specific location</strong> and click + <strong>Next</strong>.</li> + <li>Select <strong>Search for the best driver in these locations</strong>; un-check +<strong>Search + removable media</strong>; and check <strong>Include +this location in the search</strong>.</li> + <li>Click <strong>Browse</strong> and locate the USB driver folder. (The Google USB +Driver is located in {@code <sdk>\extras\google\usb_driver\}.)</li> + <li>Click <strong>Next</strong> to install the driver.</li> +</ol> + +<p>Or, to <em>upgrade</em> an existing Android USB driver on Windows XP with the new +driver:</p> + +<ol> + <li>Connect your Android-powered device to your computer's USB port.</li> + <li>Right-click on <em>My Computer</em> from your desktop or Windows Explorer, + and select <strong>Manage</strong>.</li> + <li>Select <strong>Device Manager</strong> in the left pane.</li> + <li>Locate and expand <em>Android Phone</em> in the right pane.</li> + <li>Right-click <em>Android Composite ADB Interface</em> and select <strong>Update + Driver</strong>. + This will launch the Hardware Update Wizard.</li> + <li>Select <strong>Install from a list or specific location</strong> and click + <strong>Next</strong>.</li> + <li>Select <strong>Search for the best driver in these locations</strong>; un-check <strong>Search + removable media</strong>; and check <strong>Include +this location in the search</strong>.</li> + <li>Click <strong>Browse</strong> and locate the USB driver folder. (The Google USB +Driver is located in {@code <sdk>\extras\google\usb_driver\}.)</li> + <li>Click <strong>Next</strong> to upgrade the driver.</li> +</ol> + + + +<h3 id="WinVista">Windows Vista</h3> + +<p>To install the Android USB driver on Windows Vista for the first time:</p> + +<ol> + <li>Connect your Android-powered device to your computer's USB port. Windows + will detect the device and launch the Found New Hardware wizard.</li> + <li>Select <strong>Locate and install driver software</strong>.</li> + <li>Select <strong>Don't search online</strong>.</li> + <li>Select <strong>I don't have the disk. Show me other options</strong>.</li> + <li>Select <strong>Browse my computer for driver software</strong>.</li> + <li>Click <strong>Browse</strong> and locate the USB driver folder. (The Google USB +Driver is located in {@code <sdk>\extras\google\usb_driver\}.) As long as you specified the +exact location of the + installation package, you may leave <strong>Include subfolders</strong> checked or + unchecked—it doesn't matter.</li> + <li>Click <strong>Next</strong>. Vista may prompt you to confirm the privilege elevation + required for driver installation. Confirm it.</li> + <li>When Vista asks if you'd like to install the Google ADB Interface device, + click <strong>Install</strong> to install the driver.</li> +</ol> + +<p>Or, to <em>upgrade</em> an existing Android USB driver on Windows Vista with the new +driver:</p> + +<ol> + <li>Connect your Android-powered device to your computer's USB port.</li> + <li>Right-click on <em>Computer</em> from your desktop or Windows Explorer, + and select <strong>Manage</strong>.</li> + <li>Select <strong>Device Manager</strong> in the left pane.</li> + <li>Locate and expand <em>ADB Interface</em> in the right pane.</li> + <li>Right-click on <em>HTC Dream Composite ADB Interface</em>, and select <strong>Update + Driver Software</strong>.</li> + <li>When Vista starts updating the driver, a prompt will ask how you want to + search for the driver + software. Select <strong>Browse my computer for driver software</strong>.</li> + <li>Click <strong>Browse</strong> and locate the USB driver folder. (The Google USB +Driver is located in {@code <sdk>\extras\google\usb_driver\}.) As long as you specified the +exact location of the + installation package, you may leave <strong>Include subfolders</strong> checked or + unchecked—it doesn't matter.</li> + <li>Click <strong>Next</strong>. Vista might prompt you to confirm the privilege elevation + required for driver installation. Confirm it.</li> + <li>When Vista asks if you'd like to install the Google ADB Interface device, + click <strong>Install</strong> to upgrade the driver.</li> +</ol> + + +<h2 id="Drivers">OEM Drivers</h2> <p class="note"><strong>Note:</strong> If your device is one of the Android Developer Phones (purchased from the Android Market publisher site), a Nexus One, or a Nexus S, then you need @@ -28,10 +217,7 @@ Nexus driver, however, is distributed by <a href="http://www.samsung.com/us/support/downloads/verizon-wireless/SCH-I515MSAVZW">Samsung</a> (listed as model SCH-I515).</p> -<p>For instructions about how to install the driver on Windows, follow the guide for <a - href="{@docRoot}sdk/win-usb.html#InstallingDriver">Installing the USB Driver</a>.</p> -<p class="table-caption"><strong>Table 1.</strong> Links to OEM USB drivers</p> <table><tr> <th>OEM</th> <th>Driver URL</th></tr> @@ -92,7 +278,7 @@ href="http://www.huaweidevice.com/worldwide/downloadCenter.do?method=index">http </tr> <tr><td>KT Tech</td> <td><a -href="http://www.kttech.co.kr/cscenter/download05.asp">http://www.kttech.co.kr/cscenter/download05.asp</a> for EV-S100(Take)</td> +href="http://www.kttech.co.kr/cscenter/download05.asp">http://www.kttech.co.kr/cscenter/download05.asp</a> for EV-S100 (Take)</td> </tr> <tr> <td> diff --git a/docs/html/sdk/sdk_toc.cs b/docs/html/sdk/sdk_toc.cs index 0de477a25dfa..f7541f7167e5 100644 --- a/docs/html/sdk/sdk_toc.cs +++ b/docs/html/sdk/sdk_toc.cs @@ -195,7 +195,7 @@ class="new">new!</span> <span style="display:none" class="zh-TW"></span> </span> <ul> - <li><a href="<?cs var:toroot ?>sdk/ndk/index.html">Android NDK, r7</a> + <li><a href="<?cs var:toroot ?>sdk/ndk/index.html">Android NDK, r7b</a> <span class="new">new!</span> </li> <li><a href="<?cs var:toroot ?>sdk/ndk/overview.html">What is the NDK?</a></li> diff --git a/docs/html/sdk/win-usb.jd b/docs/html/sdk/win-usb.jd index 2d1435b8d4b5..2bd031ebb8b3 100644 --- a/docs/html/sdk/win-usb.jd +++ b/docs/html/sdk/win-usb.jd @@ -7,19 +7,12 @@ page.title=Google USB Driver <ol> <li><a href="#notes">Revisions</a></li> <li><a href="#WinUsbDriver">Downloading the Google USB Driver</a></li> - <li><a href="#InstallingDriver">Installing the USB Driver</a> - <ol> - <li><a href="#Win7">Windows 7</a></li> - <li><a href="#WinXp">Windows XP</a></li> - <li><a href="#WinVista">Windows Vista</a></li> - </ol> - </li> </ol> <h2>See also</h2> <ol> - <li><a href="{@docRoot}guide/developing/device.html">Developing on a Device</a></li> + <li><a href="{@docRoot}sdk/oem-usb.html#InstallingDriver">Installing a USB Driver</a></li> + <li><a href="{@docRoot}guide/developing/device.html">Using Hardware Devices</a></li> <li><a href="{@docRoot}sdk/adding-components.html">Adding SDK Components</a></li> - <li><a href="{@docRoot}sdk/oem-usb.html">OEM USB Drivers</a></li> </ol> </div> </div> @@ -43,9 +36,9 @@ href="http://www.samsung.com/us/support/downloads/verizon-wireless/SCH-I515MSAVZ (listed as model SCH-I515).</p> <p class="note"><strong>Note:</strong> -If you're developing on Mac OS X or Linux, then you do not need to install a USB driver. Refer to <a -href="{@docRoot}guide/developing/device.html#setting-up">Setting up a Device</a> to start -development with a device.</p> +If you're developing on Mac OS X or Linux, then you do not need to install a USB driver. To start +developing with your device, also read <a href="{@docRoot}guide/developing/device.html">Using +Hardware Devices</a>.</p> <p>The sections below provide instructions on how to download and install the Google USB Driver for Windows. </p> @@ -170,174 +163,10 @@ included with the <a href="{@docRoot}sdk/index.html">Android SDK</a>:</p> <ol> <li>Launch the SDK and AVD Manager by double-clicking <code>SDK Manager.exe</code>, at the root of your SDK directory.</li> - <li>Expand the <em>Third party Add-ons</em> and <em>Google Inc. add-ons</em>.</li> - <li>Check <strong>Google Usb Driver package</strong> and click <strong>Install selected</strong>.</li> + <li>Expand <em>Extras</em>.</li> + <li>Check <strong>Google USB Driver package</strong> and click <strong>Install</strong>.</li> <li>Proceed to install the package. When done, the driver files are downloaded into the <code><sdk>\extras\google\usb_driver\</code> directory.</li> </ol> - - -<h2 id="InstallingDriver">Installing the USB Driver</h2> - -<p>Once you've downloaded your USB driver, follow the instructions below to install or upgrade the -driver, based on your version of Windows and whether you're installing for the first time -or upgrading an existing driver.</p> - -<p class="note"><strong>Tip:</strong> When you finish the USB driver installation, -see <a -href="{@docRoot}guide/developing/device.html">Developing on a Device</a> for -other important information about using an Android-powered device for -development.</p> - -<ol class="nolist"> - <li><a href="#Win7">Windows 7</a></li> - <li><a href="#WinXp">Windows XP</a></li> - <li><a href="#WinVista">Windows Vista</a></li> -</ol> - - -<p class="caution"><strong>Caution:</strong> -You may make changes to <code>android_winusb.inf</code> file found inside -<code>usb_driver\</code> (for example, to add support for other devices), -however, this will lead to security warnings when you install or upgrade the -driver. Making any other changes to the driver files may break the installation -process.</p> - - -<h3 id="Win7">Windows 7</h3> - - -<p>To install the Android USB driver on Windows 7 for the first time:</p> -<ol> - <li>Connect your Android-powered device to your computer's USB port.</li> - <li>Right-click on <em>Computer</em> from your desktop or Windows Explorer, - and select <strong>Manage</strong>.</li> - <li>Select <strong>Devices</strong> in the left pane.</li> - <li>Locate and expand <em>Other device</em> in the right pane.</li> - <li>Right-click the device name (such as <em>Nexus S</em>) and select <strong>Update - Driver Software</strong>. - This will launch the Hardware Update Wizard.</li> - <li>Select <strong>Browse my computer for driver software</strong> and click - <strong>Next</strong>.</li> - <li>Click <strong>Browse</strong> and locate the USB driver folder. (The Google USB -Driver is located in {@code <sdk>\extras\google\usb_driver\}.)</li> - <li>Click <strong>Next</strong> to install the driver.</li> -</ol> - -<p>Or, to <em>upgrade</em> an existing Android USB driver on Windows 7 with the new -driver:</p> - -<ol> - <li>Connect your Android-powered device to your computer's USB port.</li> - <li>Right-click on <em>Computer</em> from your desktop or Windows Explorer, - and select <strong>Manage</strong>.</li> - <li>Select <strong>Device Manager</strong> in the left pane of the Computer Management - window.</li> - <li>Locate and expand <em>Android Phone</em> in the right pane.</li> - <li>Right-click <em>Android Composite ADB Interface</em> and select <strong>Update - Driver</strong>. - This will launch the Hardware Update Wizard.</li> - <li>Select <strong>Install from a list or specific location</strong> and click - <strong>Next</strong>.</li> - <li>Select <strong>Search for the best driver in these locations</strong>; un-check -<strong>Search removable media</strong>; and check <strong>Include this location in the -search</strong>.</li> - <li>Click <strong>Browse</strong> and locate the USB driver folder. (The Google USB -Driver is located in {@code <sdk>\extras\google\usb_driver\}.)</li> - <li>Click <strong>Next</strong> to upgrade the driver.</li> -</ol> - - - - - -<h3 id="WinXp">Windows XP</h3> - -<p>To install the Android USB driver on Windows XP for the first time:</p> - -<ol> - <li>Connect your Android-powered device to your computer's USB port. Windows - will detect the device and launch the Hardware Update Wizard.</li> - <li>Select <strong>Install from a list or specific location</strong> and click - <strong>Next</strong>.</li> - <li>Select <strong>Search for the best driver in these locations</strong>; un-check -<strong>Search - removable media</strong>; and check <strong>Include -this location in the search</strong>.</li> - <li>Click <strong>Browse</strong> and locate the USB driver folder. (The Google USB -Driver is located in {@code <sdk>\extras\google\usb_driver\}.)</li> - <li>Click <strong>Next</strong> to install the driver.</li> -</ol> - -<p>Or, to <em>upgrade</em> an existing Android USB driver on Windows XP with the new -driver:</p> - -<ol> - <li>Connect your Android-powered device to your computer's USB port.</li> - <li>Right-click on <em>My Computer</em> from your desktop or Windows Explorer, - and select <strong>Manage</strong>.</li> - <li>Select <strong>Device Manager</strong> in the left pane.</li> - <li>Locate and expand <em>Android Phone</em> in the right pane.</li> - <li>Right-click <em>Android Composite ADB Interface</em> and select <strong>Update - Driver</strong>. - This will launch the Hardware Update Wizard.</li> - <li>Select <strong>Install from a list or specific location</strong> and click - <strong>Next</strong>.</li> - <li>Select <strong>Search for the best driver in these locations</strong>; un-check <strong>Search - removable media</strong>; and check <strong>Include -this location in the search</strong>.</li> - <li>Click <strong>Browse</strong> and locate the USB driver folder. (The Google USB -Driver is located in {@code <sdk>\extras\google\usb_driver\}.)</li> - <li>Click <strong>Next</strong> to upgrade the driver.</li> -</ol> - - - -<h3 id="WinVista">Windows Vista</h3> - -<p>To install the Android USB driver on Windows Vista for the first time:</p> - -<ol> - <li>Connect your Android-powered device to your computer's USB port. Windows - will detect the device and launch the Found New Hardware wizard.</li> - <li>Select <strong>Locate and install driver software</strong>.</li> - <li>Select <strong>Don't search online</strong>.</li> - <li>Select <strong>I don't have the disk. Show me other options</strong>.</li> - <li>Select <strong>Browse my computer for driver software</strong>.</li> - <li>Click <strong>Browse</strong> and locate the USB driver folder. (The Google USB -Driver is located in {@code <sdk>\extras\google\usb_driver\}.) As long as you specified the -exact location of the - installation package, you may leave <strong>Include subfolders</strong> checked or - unchecked—it doesn't matter.</li> - <li>Click <strong>Next</strong>. Vista may prompt you to confirm the privilege elevation - required for driver installation. Confirm it.</li> - <li>When Vista asks if you'd like to install the Google ADB Interface device, - click <strong>Install</strong> to install the driver.</li> -</ol> - -<p>Or, to <em>upgrade</em> an existing Android USB driver on Windows Vista with the new -driver:</p> - -<ol> - <li>Connect your Android-powered device to your computer's USB port.</li> - <li>Right-click on <em>Computer</em> from your desktop or Windows Explorer, - and select <strong>Manage</strong>.</li> - <li>Select <strong>Device Manager</strong> in the left pane.</li> - <li>Locate and expand <em>ADB Interface</em> in the right pane.</li> - <li>Right-click on <em>HTC Dream Composite ADB Interface</em>, and select <strong>Update - Driver Software</strong>.</li> - <li>When Vista starts updating the driver, a prompt will ask how you want to - search for the driver - software. Select <strong>Browse my computer for driver software</strong>.</li> - <li>Click <strong>Browse</strong> and locate the USB driver folder. (The Google USB -Driver is located in {@code <sdk>\extras\google\usb_driver\}.) As long as you specified the -exact location of the - installation package, you may leave <strong>Include subfolders</strong> checked or - unchecked—it doesn't matter.</li> - <li>Click <strong>Next</strong>. Vista might prompt you to confirm the privilege elevation - required for driver installation. Confirm it.</li> - <li>When Vista asks if you'd like to install the Google ADB Interface device, - click <strong>Install</strong> to upgrade the driver.</li> -</ol> - +<p>For installation information, read <a href="{@docRoot}sdk/oem-usb.html#InstallingDriver">Installing a USB Driver</a>.</p> diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java index 380b3d86718f..6f939be0b0b2 100644 --- a/graphics/java/android/graphics/Bitmap.java +++ b/graphics/java/android/graphics/Bitmap.java @@ -408,16 +408,19 @@ public final class Bitmap implements Parcelable { } /** - * Creates a new bitmap, scaled from an existing bitmap. + * Creates a new bitmap, scaled from an existing bitmap, when possible. If the + * specified width and height are the same as the current width and height of + * the source btimap, the source bitmap is returned and now new bitmap is + * created. * * @param src The source bitmap. * @param dstWidth The new bitmap's desired width. * @param dstHeight The new bitmap's desired height. * @param filter true if the source should be filtered. - * @return the new scaled bitmap. + * @return The new scaled bitmap or the source bitmap if no scaling is required. */ - public static Bitmap createScaledBitmap(Bitmap src, int dstWidth, - int dstHeight, boolean filter) { + public static Bitmap createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, + boolean filter) { Matrix m; synchronized (Bitmap.class) { // small pool of just 1 matrix @@ -458,14 +461,15 @@ public final class Bitmap implements Parcelable { /** * Returns an immutable bitmap from the specified subset of the source * bitmap. The new bitmap may be the same object as source, or a copy may - * have been made. It is - * initialized with the same density as the original bitmap. + * have been made. It is initialized with the same density as the original + * bitmap. * * @param source The bitmap we are subsetting * @param x The x coordinate of the first pixel in source * @param y The y coordinate of the first pixel in source * @param width The number of pixels in each row * @param height The number of rows + * @return A copy of a subset of the source bitmap or the source bitmap itself. */ public static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height) { return createBitmap(source, x, y, width, height, null, false); @@ -473,8 +477,13 @@ public final class Bitmap implements Parcelable { /** * Returns an immutable bitmap from subset of the source bitmap, - * transformed by the optional matrix. It is + * transformed by the optional matrix. The new bitmap may be the + * same object as source, or a copy may have been made. It is * initialized with the same density as the original bitmap. + * + * If the source bitmap is immutable and the requested subset is the + * same as the source bitmap itself, then the source bitmap is + * returned and no new bitmap is created. * * @param source The bitmap we are subsetting * @param x The x coordinate of the first pixel in source diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java index 509b9726e326..37a270e9c10d 100644 --- a/graphics/java/android/renderscript/Allocation.java +++ b/graphics/java/android/renderscript/Allocation.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 The Android Open Source Project + * Copyright (C) 2008-2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -102,7 +102,7 @@ public class Allocation extends BaseObj { public static final int USAGE_SCRIPT = 0x0001; /** - * GRAPHICS_TEXTURE The allcation will be used as a texture + * GRAPHICS_TEXTURE The allocation will be used as a texture * source by one or more graphics programs. * */ @@ -124,34 +124,34 @@ public class Allocation extends BaseObj { public static final int USAGE_GRAPHICS_CONSTANTS = 0x0008; /** - * USAGE_GRAPHICS_RENDER_TARGET The allcation will be used as a + * USAGE_GRAPHICS_RENDER_TARGET The allocation will be used as a * target for offscreen rendering * */ public static final int USAGE_GRAPHICS_RENDER_TARGET = 0x0010; /** - * USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT The allcation will be - * used with a SurfaceTexture object. This usage will cause the - * allocation to be created read only. + * USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE The allocation + * will be used as a SurfaceTexture graphics consumer. This + * usage may only be used with USAGE_GRAPHICS_TEXTURE. * * @hide */ public static final int USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE = 0x0020; /** - * USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT The allcation will be - * used with a SurfaceTexture object. This usage will cause the - * allocation to be created read only. + * USAGE_IO_INPUT The allocation will be used as SurfaceTexture + * consumer. This usage will cause the allocation to be created + * read only. * * @hide */ - public static final int USAGE_IO_INPUT = 0x0040; + /** - * USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT The allcation will be - * used with a SurfaceTexture object. This usage will cause the - * allocation to be created read only. + * USAGE_IO_OUTPUT The allocation will be used as a + * SurfaceTexture producer. The dimensions and format of the + * SurfaceTexture will be forced to those of the allocation. * * @hide */ @@ -323,6 +323,37 @@ public class Allocation extends BaseObj { mRS.nAllocationSyncAll(getIDSafe(), srcLocation); } + /** + * Send a buffer to the output stream. The contents of the + * Allocation will be undefined after this operation. + * + * @hide + * + */ + public void ioSendOutput() { + if ((mUsage & USAGE_IO_OUTPUT) == 0) { + throw new RSIllegalArgumentException( + "Can only send buffer if IO_OUTPUT usage specified."); + } + mRS.validate(); + mRS.nAllocationIoSend(getID()); + } + + /** + * Receive the latest input into the Allocation. + * + * @hide + * + */ + public void ioGetInput() { + if ((mUsage & USAGE_IO_INPUT) == 0) { + throw new RSIllegalArgumentException( + "Can only send buffer if IO_OUTPUT usage specified."); + } + mRS.validate(); + mRS.nAllocationIoReceive(getID()); + } + public void copyFrom(BaseObj[] d) { mRS.validate(); validateIsObject(); @@ -887,17 +918,37 @@ public class Allocation extends BaseObj { updateCacheInfo(mType); } - /* + /** + * Resize a 2D allocation. The contents of the allocation are + * preserved. If new elements are allocated objects are created + * with null contents and the new region is otherwise undefined. + * + * If the new region is smaller the references of any objects + * outside the new region will be released. + * + * A new type will be created with the new dimension. + * + * @hide + * @param dimX The new size of the allocation. + * @param dimY The new size of the allocation. + */ public void resize(int dimX, int dimY) { - if ((mType.getZ() > 0) || mType.getFaces() || mType.getLOD()) { - throw new RSIllegalStateException("Resize only support for 2D allocations at this time."); + if ((mType.getZ() > 0) || mType.hasFaces() || mType.hasMipmaps()) { + throw new RSInvalidStateException( + "Resize only support for 2D allocations at this time."); } if (mType.getY() == 0) { - throw new RSIllegalStateException("Resize only support for 2D allocations at this time."); + throw new RSInvalidStateException( + "Resize only support for 2D allocations at this time."); } mRS.nAllocationResize2D(getID(), dimX, dimY); + mRS.finish(); // Necessary because resize is fifoed and update is async. + + int typeID = mRS.nAllocationGetType(getID()); + mType = new Type(typeID, mRS); + mType.updateFromNative(); + updateCacheInfo(mType); } - */ @@ -921,7 +972,31 @@ public class Allocation extends BaseObj { if (type.getID() == 0) { throw new RSInvalidStateException("Bad Type"); } - int id = rs.nAllocationCreateTyped(type.getID(), mips.mID, usage); + int id = rs.nAllocationCreateTyped(type.getID(), mips.mID, usage, 0); + if (id == 0) { + throw new RSRuntimeException("Allocation creation failed."); + } + return new Allocation(id, rs, type, usage); + } + + /** + * @hide + * This API is hidden and only intended to be used for + * transitional purposes. + * + * @param type renderscript type describing data layout + * @param mips specifies desired mipmap behaviour for the + * allocation + * @param usage bit field specifying how the allocation is + * utilized + */ + static public Allocation createTyped(RenderScript rs, Type type, MipmapControl mips, + int usage, int pointer) { + rs.validate(); + if (type.getID() == 0) { + throw new RSInvalidStateException("Bad Type"); + } + int id = rs.nAllocationCreateTyped(type.getID(), mips.mID, usage, pointer); if (id == 0) { throw new RSRuntimeException("Allocation creation failed."); } @@ -976,7 +1051,7 @@ public class Allocation extends BaseObj { b.setX(count); Type t = b.create(); - int id = rs.nAllocationCreateTyped(t.getID(), MipmapControl.MIPMAP_NONE.mID, usage); + int id = rs.nAllocationCreateTyped(t.getID(), MipmapControl.MIPMAP_NONE.mID, usage, 0); if (id == 0) { throw new RSRuntimeException("Allocation creation failed."); } @@ -1066,6 +1141,18 @@ public class Allocation extends BaseObj { } + /** + * @hide + */ + public void setSurfaceTexture(SurfaceTexture sur) { + if ((mUsage & USAGE_IO_OUTPUT) == 0) { + throw new RSInvalidStateException("Allocation is not USAGE_IO_OUTPUT."); + } + + mRS.validate(); + mRS.nAllocationSetSurfaceTexture(getID(), sur); + } + /** * Creates a non-mipmapped renderscript allocation to use as a diff --git a/graphics/java/android/renderscript/Element.java b/graphics/java/android/renderscript/Element.java index 22ef7bb08f47..3d4951f534ce 100644 --- a/graphics/java/android/renderscript/Element.java +++ b/graphics/java/android/renderscript/Element.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 The Android Open Source Project + * Copyright (C) 2008-2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -54,26 +54,59 @@ public class Element extends BaseObj { int[] mArraySizes; int[] mOffsetInBytes; + int[] mVisibleElementMap; + DataType mType; DataKind mKind; boolean mNormalized; int mVectorSize; + private void updateVisibleSubElements() { + if (mElements == null) { + return; + } + + int noPaddingFieldCount = 0; + int fieldCount = mElementNames.length; + // Find out how many elements are not padding + for (int ct = 0; ct < fieldCount; ct ++) { + if (mElementNames[ct].charAt(0) != '#') { + noPaddingFieldCount ++; + } + } + mVisibleElementMap = new int[noPaddingFieldCount]; + + // Make a map that points us at non-padding elements + for (int ct = 0, ctNoPadding = 0; ct < fieldCount; ct ++) { + if (mElementNames[ct].charAt(0) != '#') { + mVisibleElementMap[ctNoPadding ++] = ct; + } + } + } + /** * @hide * @return element size in bytes */ public int getSizeBytes() {return mSize;} + /** + * @hide + * @return element vector size + */ + public int getVectorSize() {return mVectorSize;} + /** * DataType represents the basic type information for a basic element. The - * naming convention follows. For numeric types its FLOAT, SIGNED, UNSIGNED - * followed by the _BITS where BITS is the size of the data. BOOLEAN is a - * true / false (1,0) represented in an 8 bit container. The UNSIGNED - * variants with multiple bit definitions are for packed graphical data - * formats and represents vectors with per vector member sizes which are - * treated as a single unit for packing and alignment purposes. + * naming convention follows. For numeric types it is FLOAT, + * SIGNED, or UNSIGNED followed by the _BITS where BITS is the + * size of the data. BOOLEAN is a true / false (1,0) + * represented in an 8 bit container. The UNSIGNED variants + * with multiple bit definitions are for packed graphical data + * formats and represent vectors with per vector member sizes + * which are treated as a single unit for packing and alignment + * purposes. * * MATRIX the three matrix types contain FLOAT_32 elements and are treated * as 32 bits for alignment purposes. @@ -81,6 +114,11 @@ public class Element extends BaseObj { * RS_* objects. 32 bit opaque handles. */ public enum DataType { + /** + * @hide + * new enum + */ + NONE (0, 0), //FLOAT_16 (1, 2), FLOAT_32 (2, 4), FLOAT_64 (3, 8), @@ -167,10 +205,10 @@ public class Element extends BaseObj { * @return number of sub-elements in this element */ public int getSubElementCount() { - if (mElements == null) { + if (mVisibleElementMap == null) { return 0; } - return mElements.length; + return mVisibleElementMap.length; } /** @@ -179,13 +217,13 @@ public class Element extends BaseObj { * @return sub-element in this element at given index */ public Element getSubElement(int index) { - if (mElements == null) { + if (mVisibleElementMap == null) { throw new RSIllegalArgumentException("Element contains no sub-elements"); } - if (index < 0 || index >= mElements.length) { + if (index < 0 || index >= mVisibleElementMap.length) { throw new RSIllegalArgumentException("Illegal sub-element index"); } - return mElements[index]; + return mElements[mVisibleElementMap[index]]; } /** @@ -194,13 +232,13 @@ public class Element extends BaseObj { * @return sub-element in this element at given index */ public String getSubElementName(int index) { - if (mElements == null) { + if (mVisibleElementMap == null) { throw new RSIllegalArgumentException("Element contains no sub-elements"); } - if (index < 0 || index >= mElements.length) { + if (index < 0 || index >= mVisibleElementMap.length) { throw new RSIllegalArgumentException("Illegal sub-element index"); } - return mElementNames[index]; + return mElementNames[mVisibleElementMap[index]]; } /** @@ -209,13 +247,13 @@ public class Element extends BaseObj { * @return array size of sub-element in this element at given index */ public int getSubElementArraySize(int index) { - if (mElements == null) { + if (mVisibleElementMap == null) { throw new RSIllegalArgumentException("Element contains no sub-elements"); } - if (index < 0 || index >= mElements.length) { + if (index < 0 || index >= mVisibleElementMap.length) { throw new RSIllegalArgumentException("Illegal sub-element index"); } - return mArraySizes[index]; + return mArraySizes[mVisibleElementMap[index]]; } /** @@ -224,13 +262,29 @@ public class Element extends BaseObj { * @return offset in bytes of sub-element in this element at given index */ public int getSubElementOffsetBytes(int index) { - if (mElements == null) { + if (mVisibleElementMap == null) { throw new RSIllegalArgumentException("Element contains no sub-elements"); } - if (index < 0 || index >= mElements.length) { + if (index < 0 || index >= mVisibleElementMap.length) { throw new RSIllegalArgumentException("Illegal sub-element index"); } - return mOffsetInBytes[index]; + return mOffsetInBytes[mVisibleElementMap[index]]; + } + + /** + * @hide + * @return element data type + */ + public DataType getDataType() { + return mType; + } + + /** + * @hide + * @return element data kind + */ + public DataKind getDataKind() { + return mKind; } /** @@ -681,14 +735,18 @@ public class Element extends BaseObj { Element(int id, RenderScript rs, Element[] e, String[] n, int[] as) { super(id, rs); mSize = 0; + mVectorSize = 1; mElements = e; mElementNames = n; mArraySizes = as; + mType = DataType.NONE; + mKind = DataKind.USER; mOffsetInBytes = new int[mElements.length]; for (int ct = 0; ct < mElements.length; ct++ ) { mOffsetInBytes[ct] = mSize; mSize += mElements[ct].mSize * mArraySizes[ct]; } + updateVisibleSubElements(); } Element(int id, RenderScript rs, DataType dt, DataKind dk, boolean norm, int size) { @@ -753,7 +811,7 @@ public class Element extends BaseObj { mSize += mElements[i].mSize * mArraySizes[i]; } } - + updateVisibleSubElements(); } /** @@ -774,10 +832,12 @@ public class Element extends BaseObj { /** * Create a custom vector element of the specified DataType and vector size. - * DataKind will be set to USER. + * DataKind will be set to USER. Only primitive types (FLOAT_32, FLOAT_64, + * SIGNED_8, SIGNED_16, SIGNED_32, SIGNED_64, UNSIGNED_8, UNSIGNED_16, + * UNSIGNED_32, UNSIGNED_64, BOOLEAN) are supported. * * @param rs The context associated with the new Element. - * @param dt The DataType for the new element. + * @param dt The DataType for the new Element. * @param size Vector size for the new Element. Range 2-4 inclusive * supported. * @@ -787,10 +847,31 @@ public class Element extends BaseObj { if (size < 2 || size > 4) { throw new RSIllegalArgumentException("Vector size out of range 2-4."); } - DataKind dk = DataKind.USER; - boolean norm = false; - int id = rs.nElementCreate(dt.mID, dk.mID, norm, size); - return new Element(id, rs, dt, dk, norm, size); + + switch (dt) { + // Support only primitive integer/float/boolean types as vectors. + case FLOAT_32: + case FLOAT_64: + case SIGNED_8: + case SIGNED_16: + case SIGNED_32: + case SIGNED_64: + case UNSIGNED_8: + case UNSIGNED_16: + case UNSIGNED_32: + case UNSIGNED_64: + case BOOLEAN: { + DataKind dk = DataKind.USER; + boolean norm = false; + int id = rs.nElementCreate(dt.mID, dk.mID, norm, size); + return new Element(id, rs, dt, dk, norm, size); + } + + default: { + throw new RSIllegalArgumentException("Cannot create vector of " + + "non-primitive type."); + } + } } /** @@ -875,10 +956,10 @@ public class Element extends BaseObj { // Ignore mKind because it is allowed to be different (user vs. pixel). // We also ignore mNormalized because it can be different. The mType - // field must be non-null since we require name equivalence for - // user-created Elements. + // field must not be NONE since we require name equivalence for + // all user-created Elements. return ((mSize == e.mSize) && - (mType != null) && + (mType != DataType.NONE) && (mType == e.mType) && (mVectorSize == e.mVectorSize)); } diff --git a/graphics/java/android/renderscript/Path.java b/graphics/java/android/renderscript/Path.java new file mode 100644 index 000000000000..83ae150abd13 --- /dev/null +++ b/graphics/java/android/renderscript/Path.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.renderscript; + +import java.util.Vector; +import android.util.Log; + +/** + * @hide + * + */ +public class Path extends BaseObj { + + public enum Primitive { + QUADRATIC_BEZIER(0), + CUBIC_BEZIER(1); + + int mID; + Primitive(int id) { + mID = id; + } + } + + Allocation mVertexBuffer; + Allocation mLoopBuffer; + Primitive mPrimitive; + float mQuality; + boolean mCoverageToAlpha; + + Path(int id, RenderScript rs, Primitive p, Allocation vtx, Allocation loop, float q) { + super(id, rs); + mVertexBuffer = vtx; + mLoopBuffer = loop; + mPrimitive = p; + mQuality = q; + } + + public Allocation getVertexAllocation() { + return mVertexBuffer; + } + + public Allocation getLoopAllocation() { + return mLoopBuffer; + } + + public Primitive getPrimitive() { + return mPrimitive; + } + + @Override + void updateFromNative() { + } + + + public static Path createStaticPath(RenderScript rs, Primitive p, float quality, Allocation vtx) { + int id = rs.nPathCreate(p.mID, false, vtx.getID(), 0, quality); + Path newPath = new Path(id, rs, p, null, null, quality); + return newPath; + } + + public static Path createStaticPath(RenderScript rs, Primitive p, float quality, Allocation vtx, Allocation loops) { + return null; + } + + public static Path createDynamicPath(RenderScript rs, Primitive p, float quality, Allocation vtx) { + return null; + } + + public static Path createDynamicPath(RenderScript rs, Primitive p, float quality, Allocation vtx, Allocation loops) { + return null; + } + + +} + + diff --git a/graphics/java/android/renderscript/Program.java b/graphics/java/android/renderscript/Program.java index a1b1ba3dac23..4d60ac860621 100644 --- a/graphics/java/android/renderscript/Program.java +++ b/graphics/java/android/renderscript/Program.java @@ -69,6 +69,7 @@ public class Program extends BaseObj { Element mOutputs[]; Type mConstants[]; TextureType mTextures[]; + String mTextureNames[]; int mTextureCount; String mShader; @@ -77,6 +78,50 @@ public class Program extends BaseObj { } /** + * @hide + */ + public int getConstantCount() { + return mConstants != null ? mConstants.length : 0; + } + + /** + * @hide + */ + public Type getConstant(int slot) { + if (slot < 0 || slot >= mConstants.length) { + throw new IllegalArgumentException("Slot ID out of range."); + } + return mConstants[slot]; + } + + /** + * @hide + */ + public int getTextureCount() { + return mTextureCount; + } + + /** + * @hide + */ + public TextureType getTextureType(int slot) { + if ((slot < 0) || (slot >= mTextureCount)) { + throw new IllegalArgumentException("Slot ID out of range."); + } + return mTextures[slot]; + } + + /** + * @hide + */ + public String getTextureName(int slot) { + if ((slot < 0) || (slot >= mTextureCount)) { + throw new IllegalArgumentException("Slot ID out of range."); + } + return mTextureNames[slot]; + } + + /** * Binds a constant buffer to be used as uniform inputs to the * program * @@ -146,6 +191,7 @@ public class Program extends BaseObj { Type mConstants[]; Type mTextures[]; TextureType mTextureTypes[]; + String mTextureNames[]; int mInputCount; int mOutputCount; int mConstantCount; @@ -163,6 +209,7 @@ public class Program extends BaseObj { mConstantCount = 0; mTextureCount = 0; mTextureTypes = new TextureType[MAX_TEXTURE]; + mTextureNames = new String[MAX_TEXTURE]; } /** @@ -266,10 +313,28 @@ public class Program extends BaseObj { * @return self */ public BaseProgramBuilder addTexture(TextureType texType) throws IllegalArgumentException { + addTexture(texType, "Tex" + mTextureCount); + return this; + } + + /** + * @hide + * Adds a texture input to the Program + * + * @param texType describes that the texture to append it (2D, + * Cubemap, etc.) + * @param texName what the texture should be called in the + * shader + * @return self + */ + public BaseProgramBuilder addTexture(TextureType texType, String texName) + throws IllegalArgumentException { if(mTextureCount >= MAX_TEXTURE) { throw new IllegalArgumentException("Max texture count exceeded."); } - mTextureTypes[mTextureCount ++] = texType; + mTextureTypes[mTextureCount] = texType; + mTextureNames[mTextureCount] = texName; + mTextureCount ++; return this; } @@ -283,6 +348,8 @@ public class Program extends BaseObj { p.mTextureCount = mTextureCount; p.mTextures = new TextureType[mTextureCount]; System.arraycopy(mTextureTypes, 0, p.mTextures, 0, mTextureCount); + p.mTextureNames = new String[mTextureCount]; + System.arraycopy(mTextureNames, 0, p.mTextureNames, 0, mTextureCount); } } diff --git a/graphics/java/android/renderscript/ProgramFragment.java b/graphics/java/android/renderscript/ProgramFragment.java index 21bace82f74f..ebc15e5070b5 100644 --- a/graphics/java/android/renderscript/ProgramFragment.java +++ b/graphics/java/android/renderscript/ProgramFragment.java @@ -59,6 +59,7 @@ public class ProgramFragment extends Program { public ProgramFragment create() { mRS.validate(); int[] tmp = new int[(mInputCount + mOutputCount + mConstantCount + mTextureCount) * 2]; + String[] texNames = new String[mTextureCount]; int idx = 0; for (int i=0; i < mInputCount; i++) { @@ -76,9 +77,10 @@ public class ProgramFragment extends Program { for (int i=0; i < mTextureCount; i++) { tmp[idx++] = ProgramParam.TEXTURE_TYPE.mID; tmp[idx++] = mTextureTypes[i].mID; + texNames[i] = mTextureNames[i]; } - int id = mRS.nProgramFragmentCreate(mShader, tmp); + int id = mRS.nProgramFragmentCreate(mShader, texNames, tmp); ProgramFragment pf = new ProgramFragment(id, mRS); initProgram(pf); return pf; diff --git a/graphics/java/android/renderscript/ProgramFragmentFixedFunction.java b/graphics/java/android/renderscript/ProgramFragmentFixedFunction.java index 0ab73c1b222b..cd31db3a919b 100644 --- a/graphics/java/android/renderscript/ProgramFragmentFixedFunction.java +++ b/graphics/java/android/renderscript/ProgramFragmentFixedFunction.java @@ -47,6 +47,7 @@ public class ProgramFragmentFixedFunction extends ProgramFragment { public ProgramFragmentFixedFunction create() { mRS.validate(); int[] tmp = new int[(mInputCount + mOutputCount + mConstantCount + mTextureCount) * 2]; + String[] texNames = new String[mTextureCount]; int idx = 0; for (int i=0; i < mInputCount; i++) { @@ -64,9 +65,10 @@ public class ProgramFragmentFixedFunction extends ProgramFragment { for (int i=0; i < mTextureCount; i++) { tmp[idx++] = ProgramParam.TEXTURE_TYPE.mID; tmp[idx++] = mTextureTypes[i].mID; + texNames[i] = mTextureNames[i]; } - int id = mRS.nProgramFragmentCreate(mShader, tmp); + int id = mRS.nProgramFragmentCreate(mShader, texNames, tmp); ProgramFragmentFixedFunction pf = new ProgramFragmentFixedFunction(id, mRS); initProgram(pf); return pf; diff --git a/graphics/java/android/renderscript/ProgramVertex.java b/graphics/java/android/renderscript/ProgramVertex.java index 56bb8365674d..a6cd15b731ea 100644 --- a/graphics/java/android/renderscript/ProgramVertex.java +++ b/graphics/java/android/renderscript/ProgramVertex.java @@ -55,6 +55,23 @@ public class ProgramVertex extends Program { } /** + * @hide + */ + public int getInputCount() { + return mInputs != null ? mInputs.length : 0; + } + + /** + * @hide + */ + public Element getInput(int slot) { + if (slot < 0 || slot >= mInputs.length) { + throw new IllegalArgumentException("Slot ID out of range."); + } + return mInputs[slot]; + } + + /** * Builder class for creating ProgramVertex objects. * The builder starts empty and the user must minimally provide * the GLSL shader code, and the varying inputs. Constant, or @@ -99,6 +116,7 @@ public class ProgramVertex extends Program { public ProgramVertex create() { mRS.validate(); int[] tmp = new int[(mInputCount + mOutputCount + mConstantCount + mTextureCount) * 2]; + String[] texNames = new String[mTextureCount]; int idx = 0; for (int i=0; i < mInputCount; i++) { @@ -116,9 +134,10 @@ public class ProgramVertex extends Program { for (int i=0; i < mTextureCount; i++) { tmp[idx++] = ProgramParam.TEXTURE_TYPE.mID; tmp[idx++] = mTextureTypes[i].mID; + texNames[i] = mTextureNames[i]; } - int id = mRS.nProgramVertexCreate(mShader, tmp); + int id = mRS.nProgramVertexCreate(mShader, texNames, tmp); ProgramVertex pv = new ProgramVertex(id, mRS); initProgram(pv); return pv; diff --git a/graphics/java/android/renderscript/ProgramVertexFixedFunction.java b/graphics/java/android/renderscript/ProgramVertexFixedFunction.java index 740d6a5a9566..9a43943da360 100644 --- a/graphics/java/android/renderscript/ProgramVertexFixedFunction.java +++ b/graphics/java/android/renderscript/ProgramVertexFixedFunction.java @@ -70,6 +70,7 @@ public class ProgramVertexFixedFunction extends ProgramVertex { public ProgramVertexFixedFunction create() { mRS.validate(); int[] tmp = new int[(mInputCount + mOutputCount + mConstantCount + mTextureCount) * 2]; + String[] texNames = new String[mTextureCount]; int idx = 0; for (int i=0; i < mInputCount; i++) { @@ -87,9 +88,10 @@ public class ProgramVertexFixedFunction extends ProgramVertex { for (int i=0; i < mTextureCount; i++) { tmp[idx++] = ProgramParam.TEXTURE_TYPE.mID; tmp[idx++] = mTextureTypes[i].mID; + texNames[i] = mTextureNames[i]; } - int id = mRS.nProgramVertexCreate(mShader, tmp); + int id = mRS.nProgramVertexCreate(mShader, texNames, tmp); ProgramVertexFixedFunction pv = new ProgramVertexFixedFunction(id, mRS); initProgram(pv); return pv; diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java index 3f3033b44a0f..95175135cf3a 100644 --- a/graphics/java/android/renderscript/RenderScript.java +++ b/graphics/java/android/renderscript/RenderScript.java @@ -231,10 +231,10 @@ public class RenderScript { rsnTypeGetNativeData(mContext, id, typeData); } - native int rsnAllocationCreateTyped(int con, int type, int mip, int usage); - synchronized int nAllocationCreateTyped(int type, int mip, int usage) { + native int rsnAllocationCreateTyped(int con, int type, int mip, int usage, int pointer); + synchronized int nAllocationCreateTyped(int type, int mip, int usage, int pointer) { validate(); - return rsnAllocationCreateTyped(mContext, type, mip, usage); + return rsnAllocationCreateTyped(mContext, type, mip, usage, pointer); } native int rsnAllocationCreateFromBitmap(int con, int type, int mip, Bitmap bmp, int usage); synchronized int nAllocationCreateFromBitmap(int type, int mip, Bitmap bmp, int usage) { @@ -274,6 +274,22 @@ public class RenderScript { validate(); return rsnAllocationGetSurfaceTextureID(mContext, alloc); } + native void rsnAllocationSetSurfaceTexture(int con, int alloc, SurfaceTexture sur); + synchronized void nAllocationSetSurfaceTexture(int alloc, SurfaceTexture sur) { + validate(); + rsnAllocationSetSurfaceTexture(mContext, alloc, sur); + } + native void rsnAllocationIoSend(int con, int alloc); + synchronized void nAllocationIoSend(int alloc) { + validate(); + rsnAllocationIoSend(mContext, alloc); + } + native void rsnAllocationIoReceive(int con, int alloc); + synchronized void nAllocationIoReceive(int alloc) { + validate(); + rsnAllocationIoReceive(mContext, alloc); + } + native void rsnAllocationGenerateMipmaps(int con, int alloc); synchronized void nAllocationGenerateMipmaps(int alloc) { @@ -553,15 +569,15 @@ public class RenderScript { validate(); rsnProgramBindSampler(mContext, vpf, slot, s); } - native int rsnProgramFragmentCreate(int con, String shader, int[] params); - synchronized int nProgramFragmentCreate(String shader, int[] params) { + native int rsnProgramFragmentCreate(int con, String shader, String[] texNames, int[] params); + synchronized int nProgramFragmentCreate(String shader, String[] texNames, int[] params) { validate(); - return rsnProgramFragmentCreate(mContext, shader, params); + return rsnProgramFragmentCreate(mContext, shader, texNames, params); } - native int rsnProgramVertexCreate(int con, String shader, int[] params); - synchronized int nProgramVertexCreate(String shader, int[] params) { + native int rsnProgramVertexCreate(int con, String shader, String[] texNames, int[] params); + synchronized int nProgramVertexCreate(String shader, String[] texNames, int[] params) { validate(); - return rsnProgramVertexCreate(mContext, shader, params); + return rsnProgramVertexCreate(mContext, shader, texNames, params); } native int rsnMeshCreate(int con, int[] vtx, int[] idx, int[] prim); @@ -590,6 +606,11 @@ public class RenderScript { rsnMeshGetIndices(mContext, id, idxIds, primitives, vtxIdCount); } + native int rsnPathCreate(int con, int prim, boolean isStatic, int vtx, int loop, float q); + synchronized int nPathCreate(int prim, boolean isStatic, int vtx, int loop, float q) { + validate(); + return rsnPathCreate(mContext, prim, isStatic, vtx, loop, q); + } int mDev; int mContext; diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp index a9f0f1fa1f5a..27ea8f6ecc8a 100644 --- a/graphics/jni/android_renderscript_RenderScript.cpp +++ b/graphics/jni/android_renderscript_RenderScript.cpp @@ -31,9 +31,9 @@ #include <core/SkTemplates.h> #include <images/SkImageDecoder.h> -#include <utils/Asset.h> -#include <utils/AssetManager.h> -#include <utils/ResourceTypes.h> +#include <androidfw/Asset.h> +#include <androidfw/AssetManager.h> +#include <androidfw/ResourceTypes.h> #include "jni.h" #include "JNIHelp.h" @@ -41,8 +41,8 @@ #include "android_runtime/android_view_Surface.h" #include "android_runtime/android_util_AssetManager.h" -#include <RenderScript.h> -#include <RenderScriptEnv.h> +#include <rs.h> +#include <rsEnv.h> #include <gui/SurfaceTexture.h> #include <gui/SurfaceTextureClient.h> #include <android_runtime/android_graphics_SurfaceTexture.h> @@ -54,13 +54,11 @@ using namespace android; class AutoJavaStringToUTF8 { public: - AutoJavaStringToUTF8(JNIEnv* env, jstring str) : fEnv(env), fJStr(str) - { + AutoJavaStringToUTF8(JNIEnv* env, jstring str) : fEnv(env), fJStr(str) { fCStr = env->GetStringUTFChars(str, NULL); fLength = env->GetStringUTFLength(str); } - ~AutoJavaStringToUTF8() - { + ~AutoJavaStringToUTF8() { fEnv->ReleaseStringUTFChars(fJStr, fCStr); } const char* c_str() const { return fCStr; } @@ -73,6 +71,42 @@ private: jsize fLength; }; +class AutoJavaStringArrayToUTF8 { +public: + AutoJavaStringArrayToUTF8(JNIEnv* env, jobjectArray strings, jsize stringsLength) + : mEnv(env), mStrings(strings), mStringsLength(stringsLength) { + mCStrings = NULL; + mSizeArray = NULL; + if (stringsLength > 0) { + mCStrings = (const char **)calloc(stringsLength, sizeof(char *)); + mSizeArray = (size_t*)calloc(stringsLength, sizeof(size_t)); + for (jsize ct = 0; ct < stringsLength; ct ++) { + jstring s = (jstring)mEnv->GetObjectArrayElement(mStrings, ct); + mCStrings[ct] = mEnv->GetStringUTFChars(s, NULL); + mSizeArray[ct] = mEnv->GetStringUTFLength(s); + } + } + } + ~AutoJavaStringArrayToUTF8() { + for (jsize ct=0; ct < mStringsLength; ct++) { + jstring s = (jstring)mEnv->GetObjectArrayElement(mStrings, ct); + mEnv->ReleaseStringUTFChars(s, mCStrings[ct]); + } + free(mCStrings); + free(mSizeArray); + } + const char **c_str() const { return mCStrings; } + size_t *c_str_len() const { return mSizeArray; } + jsize length() const { return mStringsLength; } + +private: + JNIEnv *mEnv; + jobjectArray mStrings; + const char **mCStrings; + size_t *mSizeArray; + jsize mStringsLength; +}; + // --------------------------------------------------------------------------- static jfieldID gContextId = 0; @@ -322,33 +356,27 @@ nElementCreate(JNIEnv *_env, jobject _this, RsContext con, jint type, jint kind, } static jint -nElementCreate2(JNIEnv *_env, jobject _this, RsContext con, jintArray _ids, jobjectArray _names, jintArray _arraySizes) +nElementCreate2(JNIEnv *_env, jobject _this, RsContext con, + jintArray _ids, jobjectArray _names, jintArray _arraySizes) { int fieldCount = _env->GetArrayLength(_ids); LOG_API("nElementCreate2, con(%p)", con); jint *ids = _env->GetIntArrayElements(_ids, NULL); jint *arraySizes = _env->GetIntArrayElements(_arraySizes, NULL); - const char ** nameArray = (const char **)calloc(fieldCount, sizeof(char *)); - size_t* sizeArray = (size_t*)calloc(fieldCount, sizeof(size_t)); - for (int ct=0; ct < fieldCount; ct++) { - jstring s = (jstring)_env->GetObjectArrayElement(_names, ct); - nameArray[ct] = _env->GetStringUTFChars(s, NULL); - sizeArray[ct] = _env->GetStringUTFLength(s); - } + AutoJavaStringArrayToUTF8 names(_env, _names, fieldCount); + + const char **nameArray = names.c_str(); + size_t *sizeArray = names.c_str_len(); + jint id = (jint)rsElementCreate2(con, (RsElement *)ids, fieldCount, nameArray, fieldCount * sizeof(size_t), sizeArray, (const uint32_t *)arraySizes, fieldCount); - for (int ct=0; ct < fieldCount; ct++) { - jstring s = (jstring)_env->GetObjectArrayElement(_names, ct); - _env->ReleaseStringUTFChars(s, nameArray[ct]); - } + _env->ReleaseIntArrayElements(_ids, ids, JNI_ABORT); _env->ReleaseIntArrayElements(_arraySizes, arraySizes, JNI_ABORT); - free(nameArray); - free(sizeArray); return (jint)id; } @@ -430,10 +458,10 @@ nTypeGetNativeData(JNIEnv *_env, jobject _this, RsContext con, jint id, jintArra // ----------------------------------- static jint -nAllocationCreateTyped(JNIEnv *_env, jobject _this, RsContext con, jint type, jint mips, jint usage) +nAllocationCreateTyped(JNIEnv *_env, jobject _this, RsContext con, jint type, jint mips, jint usage, jint pointer) { - LOG_API("nAllocationCreateTyped, con(%p), type(%p), mip(%i), usage(%i)", con, (RsElement)type, mips, usage); - return (jint) rsAllocationCreateTyped(con, (RsType)type, (RsAllocationMipmapControl)mips, (uint32_t)usage); + LOG_API("nAllocationCreateTyped, con(%p), type(%p), mip(%i), usage(%i), ptr(%p)", con, (RsElement)type, mips, usage, (void *)pointer); + return (jint) rsAllocationCreateTyped(con, (RsType)type, (RsAllocationMipmapControl)mips, (uint32_t)usage, (uint32_t)pointer); } static void @@ -451,6 +479,37 @@ nAllocationGetSurfaceTextureID(JNIEnv *_env, jobject _this, RsContext con, jint } static void +nAllocationSetSurfaceTexture(JNIEnv *_env, jobject _this, RsContext con, + RsAllocation alloc, jobject sur) +{ + LOG_API("nAllocationSetSurfaceTexture, con(%p), alloc(%p), surface(%p)", + con, alloc, (Surface *)sur); + + sp<ANativeWindow> window; + if (sur != 0) { + sp<SurfaceTexture> st = SurfaceTexture_getSurfaceTexture(_env, sur); + window = new SurfaceTextureClient(st); + } + + rsAllocationSetSurface(con, alloc, window.get()); +} + +static void +nAllocationIoSend(JNIEnv *_env, jobject _this, RsContext con, RsAllocation alloc) +{ + LOG_API("nAllocationIoSend, con(%p), alloc(%p)", con, alloc); + rsAllocationIoSend(con, alloc); +} + +static void +nAllocationIoReceive(JNIEnv *_env, jobject _this, RsContext con, RsAllocation alloc) +{ + LOG_API("nAllocationIoReceive, con(%p), alloc(%p)", con, alloc); + rsAllocationIoReceive(con, alloc); +} + + +static void nAllocationGenerateMipmaps(JNIEnv *_env, jobject _this, RsContext con, jint alloc) { LOG_API("nAllocationGenerateMipmaps, con(%p), a(%p)", con, (RsAllocation)alloc); @@ -1033,15 +1092,24 @@ nProgramBindSampler(JNIEnv *_env, jobject _this, RsContext con, jint vpf, jint s // --------------------------------------------------------------------------- static jint -nProgramFragmentCreate(JNIEnv *_env, jobject _this, RsContext con, jstring shader, jintArray params) +nProgramFragmentCreate(JNIEnv *_env, jobject _this, RsContext con, jstring shader, + jobjectArray texNames, jintArray params) { AutoJavaStringToUTF8 shaderUTF(_env, shader); jint *paramPtr = _env->GetIntArrayElements(params, NULL); jint paramLen = _env->GetArrayLength(params); + int texCount = _env->GetArrayLength(texNames); + AutoJavaStringArrayToUTF8 names(_env, texNames, texCount); + const char ** nameArray = names.c_str(); + size_t* sizeArray = names.c_str_len(); + LOG_API("nProgramFragmentCreate, con(%p), paramLen(%i)", con, paramLen); - jint ret = (jint)rsProgramFragmentCreate(con, shaderUTF.c_str(), shaderUTF.length(), (uint32_t *)paramPtr, paramLen); + jint ret = (jint)rsProgramFragmentCreate(con, shaderUTF.c_str(), shaderUTF.length(), + nameArray, texCount, sizeArray, + (uint32_t *)paramPtr, paramLen); + _env->ReleaseIntArrayElements(params, paramPtr, JNI_ABORT); return ret; } @@ -1050,7 +1118,8 @@ nProgramFragmentCreate(JNIEnv *_env, jobject _this, RsContext con, jstring shade // --------------------------------------------------------------------------- static jint -nProgramVertexCreate(JNIEnv *_env, jobject _this, RsContext con, jstring shader, jintArray params) +nProgramVertexCreate(JNIEnv *_env, jobject _this, RsContext con, jstring shader, + jobjectArray texNames, jintArray params) { AutoJavaStringToUTF8 shaderUTF(_env, shader); jint *paramPtr = _env->GetIntArrayElements(params, NULL); @@ -1058,7 +1127,15 @@ nProgramVertexCreate(JNIEnv *_env, jobject _this, RsContext con, jstring shader, LOG_API("nProgramVertexCreate, con(%p), paramLen(%i)", con, paramLen); - jint ret = (jint)rsProgramVertexCreate(con, shaderUTF.c_str(), shaderUTF.length(), (uint32_t *)paramPtr, paramLen); + int texCount = _env->GetArrayLength(texNames); + AutoJavaStringArrayToUTF8 names(_env, texNames, texCount); + const char ** nameArray = names.c_str(); + size_t* sizeArray = names.c_str_len(); + + jint ret = (jint)rsProgramVertexCreate(con, shaderUTF.c_str(), shaderUTF.length(), + nameArray, texCount, sizeArray, + (uint32_t *)paramPtr, paramLen); + _env->ReleaseIntArrayElements(params, paramPtr, JNI_ABORT); return ret; } @@ -1129,6 +1206,17 @@ nSamplerCreate(JNIEnv *_env, jobject _this, RsContext con, jint magFilter, jint // --------------------------------------------------------------------------- +//native int rsnPathCreate(int con, int prim, boolean isStatic, int vtx, int loop, float q); +static jint +nPathCreate(JNIEnv *_env, jobject _this, RsContext con, jint prim, jboolean isStatic, jint _vtx, jint _loop, jfloat q) { + LOG_API("nPathCreate, con(%p)", con); + + int id = (int)rsPathCreate(con, (RsPathPrimitive)prim, isStatic, + (RsAllocation)_vtx, + (RsAllocation)_loop, q); + return id; +} + static jint nMeshCreate(JNIEnv *_env, jobject _this, RsContext con, jintArray _vtx, jintArray _idx, jintArray _prim) { @@ -1257,7 +1345,7 @@ static JNINativeMethod methods[] = { {"rsnTypeCreate", "(IIIIIZZ)I", (void*)nTypeCreate }, {"rsnTypeGetNativeData", "(II[I)V", (void*)nTypeGetNativeData }, -{"rsnAllocationCreateTyped", "(IIII)I", (void*)nAllocationCreateTyped }, +{"rsnAllocationCreateTyped", "(IIIII)I", (void*)nAllocationCreateTyped }, {"rsnAllocationCreateFromBitmap", "(IIILandroid/graphics/Bitmap;I)I", (void*)nAllocationCreateFromBitmap }, {"rsnAllocationCubeCreateFromBitmap","(IIILandroid/graphics/Bitmap;I)I", (void*)nAllocationCubeCreateFromBitmap }, @@ -1266,6 +1354,9 @@ static JNINativeMethod methods[] = { {"rsnAllocationSyncAll", "(III)V", (void*)nAllocationSyncAll }, {"rsnAllocationGetSurfaceTextureID", "(II)I", (void*)nAllocationGetSurfaceTextureID }, +{"rsnAllocationSetSurfaceTexture", "(IILandroid/graphics/SurfaceTexture;)V", (void*)nAllocationSetSurfaceTexture }, +{"rsnAllocationIoSend", "(II)V", (void*)nAllocationIoSend }, +{"rsnAllocationIoReceive", "(II)V", (void*)nAllocationIoReceive }, {"rsnAllocationData1D", "(IIIII[II)V", (void*)nAllocationData1D_i }, {"rsnAllocationData1D", "(IIIII[SI)V", (void*)nAllocationData1D_s }, {"rsnAllocationData1D", "(IIIII[BI)V", (void*)nAllocationData1D_b }, @@ -1306,9 +1397,9 @@ static JNINativeMethod methods[] = { {"rsnProgramBindTexture", "(IIII)V", (void*)nProgramBindTexture }, {"rsnProgramBindSampler", "(IIII)V", (void*)nProgramBindSampler }, -{"rsnProgramFragmentCreate", "(ILjava/lang/String;[I)I", (void*)nProgramFragmentCreate }, +{"rsnProgramFragmentCreate", "(ILjava/lang/String;[Ljava/lang/String;[I)I", (void*)nProgramFragmentCreate }, {"rsnProgramRasterCreate", "(IZI)I", (void*)nProgramRasterCreate }, -{"rsnProgramVertexCreate", "(ILjava/lang/String;[I)I", (void*)nProgramVertexCreate }, +{"rsnProgramVertexCreate", "(ILjava/lang/String;[Ljava/lang/String;[I)I", (void*)nProgramVertexCreate }, {"rsnContextBindRootScript", "(II)V", (void*)nContextBindRootScript }, {"rsnContextBindProgramStore", "(II)V", (void*)nContextBindProgramStore }, @@ -1318,6 +1409,7 @@ static JNINativeMethod methods[] = { {"rsnSamplerCreate", "(IIIIIIF)I", (void*)nSamplerCreate }, +{"rsnPathCreate", "(IIZIIF)I", (void*)nPathCreate }, {"rsnMeshCreate", "(I[I[I[I)I", (void*)nMeshCreate }, {"rsnMeshGetVertexBufferCount", "(II)I", (void*)nMeshGetVertexBufferCount }, diff --git a/include/android_runtime/android_app_NativeActivity.h b/include/android_runtime/android_app_NativeActivity.h index 93fcf69a17a9..a59677a167ce 100644 --- a/include/android_runtime/android_app_NativeActivity.h +++ b/include/android_runtime/android_app_NativeActivity.h @@ -17,7 +17,7 @@ #ifndef _ANDROID_APP_NATIVEACTIVITY_H #define _ANDROID_APP_NATIVEACTIVITY_H -#include <ui/InputTransport.h> +#include <androidfw/InputTransport.h> #include <utils/Looper.h> #include <android/native_activity.h> diff --git a/include/android_runtime/android_content_res_Configuration.h b/include/android_runtime/android_content_res_Configuration.h index 2f5a98249cb7..34c4439bbde8 100644 --- a/include/android_runtime/android_content_res_Configuration.h +++ b/include/android_runtime/android_content_res_Configuration.h @@ -17,7 +17,7 @@ #ifndef _ANDROID_CONTENT_RES_CONFIGURATION_H #define _ANDROID_CONTENT_RES_CONFIGURATION_H -#include <utils/ResourceTypes.h> +#include <androidfw/ResourceTypes.h> #include <android/configuration.h> #include "jni.h" diff --git a/include/android_runtime/android_util_AssetManager.h b/include/android_runtime/android_util_AssetManager.h index b6dd9c9f5d8d..8dd933707a6a 100644 --- a/include/android_runtime/android_util_AssetManager.h +++ b/include/android_runtime/android_util_AssetManager.h @@ -17,7 +17,7 @@ #ifndef android_util_AssetManager_H #define android_util_AssetManager_H -#include <utils/AssetManager.h> +#include <androidfw/AssetManager.h> #include "jni.h" diff --git a/include/utils/Asset.h b/include/androidfw/Asset.h index 1fe0e063c886..1fe0e063c886 100644 --- a/include/utils/Asset.h +++ b/include/androidfw/Asset.h diff --git a/include/utils/AssetDir.h b/include/androidfw/AssetDir.h index abf8a3595dfb..abf8a3595dfb 100644 --- a/include/utils/AssetDir.h +++ b/include/androidfw/AssetDir.h diff --git a/include/utils/AssetManager.h b/include/androidfw/AssetManager.h index a8c7ddbd78a6..d95b45e98554 100644 --- a/include/utils/AssetManager.h +++ b/include/androidfw/AssetManager.h @@ -20,14 +20,15 @@ #ifndef __LIBS_ASSETMANAGER_H #define __LIBS_ASSETMANAGER_H -#include <utils/Asset.h> -#include <utils/AssetDir.h> +#include <androidfw/Asset.h> +#include <androidfw/AssetDir.h> +#include <androidfw/ZipFileRO.h> #include <utils/KeyedVector.h> -#include <utils/String8.h> -#include <utils/Vector.h> +#include <utils/SortedVector.h> #include <utils/String16.h> -#include <utils/ZipFileRO.h> +#include <utils/String8.h> #include <utils/threads.h> +#include <utils/Vector.h> /* * Native-app access is via the opaque typedef struct AAssetManager in the C namespace. diff --git a/include/utils/BackupHelpers.h b/include/androidfw/BackupHelpers.h index 1bb04a7123a3..1bb04a7123a3 100644 --- a/include/utils/BackupHelpers.h +++ b/include/androidfw/BackupHelpers.h diff --git a/include/ui/Input.h b/include/androidfw/Input.h index c2cbe1d6e871..f5db6e24e5d5 100644 --- a/include/ui/Input.h +++ b/include/androidfw/Input.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef _UI_INPUT_H -#define _UI_INPUT_H +#ifndef _ANDROIDFW_INPUT_H +#define _ANDROIDFW_INPUT_H /** * Native input event structures. @@ -894,4 +894,4 @@ extern String8 getInputDeviceConfigurationFilePathByName( } // namespace android -#endif // _UI_INPUT_H +#endif // _ANDROIDFW_INPUT_H diff --git a/include/ui/InputTransport.h b/include/androidfw/InputTransport.h index 1f738cdbdc7a..a846e6599a91 100644 --- a/include/ui/InputTransport.h +++ b/include/androidfw/InputTransport.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef _UI_INPUT_TRANSPORT_H -#define _UI_INPUT_TRANSPORT_H +#ifndef _ANDROIDFW_INPUT_TRANSPORT_H +#define _ANDROIDFW_INPUT_TRANSPORT_H /** * Native input transport. @@ -27,11 +27,12 @@ * The InputConsumer is used by the application to receive events from the input dispatcher. */ -#include <ui/Input.h> +#include <androidfw/Input.h> #include <utils/Errors.h> #include <utils/Timers.h> #include <utils/RefBase.h> #include <utils/String8.h> +#include <utils/Vector.h> namespace android { @@ -123,7 +124,7 @@ protected: virtual ~InputChannel(); public: - InputChannel(const String8& name, int32_t fd); + InputChannel(const String8& name, int fd); /* Creates a pair of input channels. * @@ -133,7 +134,7 @@ public: sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel); inline String8 getName() const { return mName; } - inline int32_t getFd() const { return mFd; } + inline int getFd() const { return mFd; } /* Sends a message to the other endpoint. * @@ -162,7 +163,7 @@ public: private: String8 mName; - int32_t mFd; + int mFd; }; /* @@ -332,4 +333,4 @@ private: } // namespace android -#endif // _UI_INPUT_TRANSPORT_H +#endif // _ANDROIDFW_INPUT_TRANSPORT_H diff --git a/include/ui/KeyCharacterMap.h b/include/androidfw/KeyCharacterMap.h index be14432ae59b..679dd2c04fdf 100644 --- a/include/ui/KeyCharacterMap.h +++ b/include/androidfw/KeyCharacterMap.h @@ -14,12 +14,12 @@ * limitations under the License. */ -#ifndef _UI_KEY_CHARACTER_MAP_H -#define _UI_KEY_CHARACTER_MAP_H +#ifndef _ANDROIDFW_KEY_CHARACTER_MAP_H +#define _ANDROIDFW_KEY_CHARACTER_MAP_H #include <stdint.h> -#include <ui/Input.h> +#include <androidfw/Input.h> #include <utils/Errors.h> #include <utils/KeyedVector.h> #include <utils/Tokenizer.h> @@ -196,4 +196,4 @@ private: } // namespace android -#endif // _UI_KEY_CHARACTER_MAP_H +#endif // _ANDROIDFW_KEY_CHARACTER_MAP_H diff --git a/include/ui/KeyLayoutMap.h b/include/androidfw/KeyLayoutMap.h index d82d0c8e0ef0..5a6f55035463 100644 --- a/include/ui/KeyLayoutMap.h +++ b/include/androidfw/KeyLayoutMap.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef _UI_KEY_LAYOUT_MAP_H -#define _UI_KEY_LAYOUT_MAP_H +#ifndef _ANDROIDFW_KEY_LAYOUT_MAP_H +#define _ANDROIDFW_KEY_LAYOUT_MAP_H #include <stdint.h> #include <utils/Errors.h> @@ -96,4 +96,4 @@ private: } // namespace android -#endif // _UI_KEY_LAYOUT_MAP_H +#endif // _ANDROIDFW_KEY_LAYOUT_MAP_H diff --git a/include/ui/Keyboard.h b/include/androidfw/Keyboard.h index 274f5264f463..ae65198044de 100644 --- a/include/ui/Keyboard.h +++ b/include/androidfw/Keyboard.h @@ -14,10 +14,10 @@ * limitations under the License. */ -#ifndef _UI_KEYBOARD_H -#define _UI_KEYBOARD_H +#ifndef _ANDROIDFW_KEYBOARD_H +#define _ANDROIDFW_KEYBOARD_H -#include <ui/Input.h> +#include <androidfw/Input.h> #include <utils/Errors.h> #include <utils/String8.h> #include <utils/PropertyMap.h> @@ -116,4 +116,4 @@ extern bool isMetaKey(int32_t keyCode); } // namespace android -#endif // _UI_KEYBOARD_H +#endif // _ANDROIDFW_KEYBOARD_H diff --git a/include/ui/KeycodeLabels.h b/include/androidfw/KeycodeLabels.h index c5bd0c544673..9e4dfcb4df15 100755 --- a/include/ui/KeycodeLabels.h +++ b/include/androidfw/KeycodeLabels.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef _UI_KEYCODE_LABELS_H -#define _UI_KEYCODE_LABELS_H +#ifndef _ANDROIDFW_KEYCODE_LABELS_H +#define _ANDROIDFW_KEYCODE_LABELS_H #include <android/keycodes.h> @@ -307,4 +307,4 @@ static const KeycodeLabel AXES[] = { { NULL, -1 } }; -#endif // _UI_KEYCODE_LABELS_H +#endif // _ANDROIDFW_KEYCODE_LABELS_H diff --git a/include/utils/ObbFile.h b/include/androidfw/ObbFile.h index 47559cdd0d61..47559cdd0d61 100644 --- a/include/utils/ObbFile.h +++ b/include/androidfw/ObbFile.h diff --git a/include/ui/PowerManager.h b/include/androidfw/PowerManager.h index dd80318e6349..59e993abfb9c 100644 --- a/include/ui/PowerManager.h +++ b/include/androidfw/PowerManager.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef _UI_POWER_MANAGER_H -#define _UI_POWER_MANAGER_H +#ifndef _ANDROIDFW_POWER_MANAGER_H +#define _ANDROIDFW_POWER_MANAGER_H namespace android { @@ -30,4 +30,4 @@ enum { } // namespace android -#endif // _UI_POWER_MANAGER_H +#endif // _ANDROIDFW_POWER_MANAGER_H diff --git a/include/utils/ResourceTypes.h b/include/androidfw/ResourceTypes.h index c496da6bac56..23bca3e2ad9f 100644 --- a/include/utils/ResourceTypes.h +++ b/include/androidfw/ResourceTypes.h @@ -20,7 +20,7 @@ #ifndef _LIBS_UTILS_RESOURCE_TYPES_H #define _LIBS_UTILS_RESOURCE_TYPES_H -#include <utils/Asset.h> +#include <androidfw/Asset.h> #include <utils/ByteOrder.h> #include <utils/Errors.h> #include <utils/String16.h> diff --git a/include/utils/StreamingZipInflater.h b/include/androidfw/StreamingZipInflater.h index 3ace5d5a83cf..3ace5d5a83cf 100644 --- a/include/utils/StreamingZipInflater.h +++ b/include/androidfw/StreamingZipInflater.h diff --git a/include/ui/VirtualKeyMap.h b/include/androidfw/VirtualKeyMap.h index 7813d9d03241..66340e3f7a96 100644 --- a/include/ui/VirtualKeyMap.h +++ b/include/androidfw/VirtualKeyMap.h @@ -14,12 +14,12 @@ * limitations under the License. */ -#ifndef _UI_VIRTUAL_KEY_MAP_H -#define _UI_VIRTUAL_KEY_MAP_H +#ifndef _ANDROIDFW_VIRTUAL_KEY_MAP_H +#define _ANDROIDFW_VIRTUAL_KEY_MAP_H #include <stdint.h> -#include <ui/Input.h> +#include <androidfw/Input.h> #include <utils/Errors.h> #include <utils/KeyedVector.h> #include <utils/Tokenizer.h> @@ -76,4 +76,4 @@ private: } // namespace android -#endif // _UI_KEY_CHARACTER_MAP_H +#endif // _ANDROIDFW_KEY_CHARACTER_MAP_H diff --git a/include/utils/ZipFileCRO.h b/include/androidfw/ZipFileCRO.h index 3e42a958bf5f..3e42a958bf5f 100644 --- a/include/utils/ZipFileCRO.h +++ b/include/androidfw/ZipFileCRO.h diff --git a/include/utils/ZipFileRO.h b/include/androidfw/ZipFileRO.h index 547e36a09864..547e36a09864 100644 --- a/include/utils/ZipFileRO.h +++ b/include/androidfw/ZipFileRO.h diff --git a/include/utils/ZipUtils.h b/include/androidfw/ZipUtils.h index 42c42b6c0f54..42c42b6c0f54 100644 --- a/include/utils/ZipUtils.h +++ b/include/androidfw/ZipUtils.h diff --git a/include/common_time/ICommonClock.h b/include/common_time/ICommonClock.h new file mode 100644 index 000000000000..d7073f1337d9 --- /dev/null +++ b/include/common_time/ICommonClock.h @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_ICOMMONCLOCK_H +#define ANDROID_ICOMMONCLOCK_H + +#include <stdint.h> +#include <linux/socket.h> + +#include <binder/IInterface.h> +#include <binder/IServiceManager.h> + +namespace android { + +class ICommonClockListener : public IInterface { + public: + DECLARE_META_INTERFACE(CommonClockListener); + + virtual void onTimelineChanged(uint64_t timelineID) = 0; +}; + +class BnCommonClockListener : public BnInterface<ICommonClockListener> { + public: + virtual status_t onTransact(uint32_t code, const Parcel& data, + Parcel* reply, uint32_t flags = 0); +}; + +class ICommonClock : public IInterface { + public: + DECLARE_META_INTERFACE(CommonClock); + + // Name of the ICommonClock service registered with the service manager. + static const String16 kServiceName; + + // a reserved invalid timeline ID + static const uint64_t kInvalidTimelineID; + + // a reserved invalid error estimate + static const int32_t kErrorEstimateUnknown; + + enum State { + // the device just came up and is trying to discover the master + STATE_INITIAL, + + // the device is a client of a master + STATE_CLIENT, + + // the device is acting as master + STATE_MASTER, + + // the device has lost contact with its master and needs to participate + // in the election of a new master + STATE_RONIN, + + // the device is waiting for announcement of the newly elected master + STATE_WAIT_FOR_ELECTION, + }; + + virtual status_t isCommonTimeValid(bool* valid, uint32_t* timelineID) = 0; + virtual status_t commonTimeToLocalTime(int64_t commonTime, + int64_t* localTime) = 0; + virtual status_t localTimeToCommonTime(int64_t localTime, + int64_t* commonTime) = 0; + virtual status_t getCommonTime(int64_t* commonTime) = 0; + virtual status_t getCommonFreq(uint64_t* freq) = 0; + virtual status_t getLocalTime(int64_t* localTime) = 0; + virtual status_t getLocalFreq(uint64_t* freq) = 0; + virtual status_t getEstimatedError(int32_t* estimate) = 0; + virtual status_t getTimelineID(uint64_t* id) = 0; + virtual status_t getState(State* state) = 0; + virtual status_t getMasterAddr(struct sockaddr_storage* addr) = 0; + + virtual status_t registerListener( + const sp<ICommonClockListener>& listener) = 0; + virtual status_t unregisterListener( + const sp<ICommonClockListener>& listener) = 0; + + // Simple helper to make it easier to connect to the CommonClock service. + static inline sp<ICommonClock> getInstance() { + sp<IBinder> binder = defaultServiceManager()->checkService( + ICommonClock::kServiceName); + sp<ICommonClock> clk = interface_cast<ICommonClock>(binder); + return clk; + } +}; + +class BnCommonClock : public BnInterface<ICommonClock> { + public: + virtual status_t onTransact(uint32_t code, const Parcel& data, + Parcel* reply, uint32_t flags = 0); +}; + +}; // namespace android + +#endif // ANDROID_ICOMMONCLOCK_H diff --git a/include/common_time/ICommonTimeConfig.h b/include/common_time/ICommonTimeConfig.h new file mode 100644 index 000000000000..497b666de6f8 --- /dev/null +++ b/include/common_time/ICommonTimeConfig.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_ICOMMONTIMECONFIG_H +#define ANDROID_ICOMMONTIMECONFIG_H + +#include <stdint.h> +#include <linux/socket.h> + +#include <binder/IInterface.h> +#include <binder/IServiceManager.h> + +namespace android { + +class String16; + +class ICommonTimeConfig : public IInterface { + public: + DECLARE_META_INTERFACE(CommonTimeConfig); + + // Name of the ICommonTimeConfig service registered with the service + // manager. + static const String16 kServiceName; + + virtual status_t getMasterElectionPriority(uint8_t *priority) = 0; + virtual status_t setMasterElectionPriority(uint8_t priority) = 0; + virtual status_t getMasterElectionEndpoint(struct sockaddr_storage *addr) = 0; + virtual status_t setMasterElectionEndpoint(const struct sockaddr_storage *addr) = 0; + virtual status_t getMasterElectionGroupId(uint64_t *id) = 0; + virtual status_t setMasterElectionGroupId(uint64_t id) = 0; + virtual status_t getInterfaceBinding(String16& ifaceName) = 0; + virtual status_t setInterfaceBinding(const String16& ifaceName) = 0; + virtual status_t getMasterAnnounceInterval(int *interval) = 0; + virtual status_t setMasterAnnounceInterval(int interval) = 0; + virtual status_t getClientSyncInterval(int *interval) = 0; + virtual status_t setClientSyncInterval(int interval) = 0; + virtual status_t getPanicThreshold(int *threshold) = 0; + virtual status_t setPanicThreshold(int threshold) = 0; + virtual status_t getAutoDisable(bool *autoDisable) = 0; + virtual status_t setAutoDisable(bool autoDisable) = 0; + virtual status_t forceNetworklessMasterMode() = 0; + + // Simple helper to make it easier to connect to the CommonTimeConfig service. + static inline sp<ICommonTimeConfig> getInstance() { + sp<IBinder> binder = defaultServiceManager()->checkService( + ICommonTimeConfig::kServiceName); + sp<ICommonTimeConfig> clk = interface_cast<ICommonTimeConfig>(binder); + return clk; + } +}; + +class BnCommonTimeConfig : public BnInterface<ICommonTimeConfig> { + public: + virtual status_t onTransact(uint32_t code, const Parcel& data, + Parcel* reply, uint32_t flags = 0); +}; + +}; // namespace android + +#endif // ANDROID_ICOMMONTIMECONFIG_H diff --git a/include/common_time/cc_helper.h b/include/common_time/cc_helper.h new file mode 100644 index 000000000000..8c4d5c063d52 --- /dev/null +++ b/include/common_time/cc_helper.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __CC_HELPER_H__ +#define __CC_HELPER_H__ + +#include <stdint.h> +#include <common_time/ICommonClock.h> +#include <utils/threads.h> + +namespace android { + +// CCHelper is a simple wrapper class to help with centralizing access to the +// Common Clock service and implementing lifetime managment, as well as to +// implement a simple policy of making a basic attempt to reconnect to the +// common clock service when things go wrong. +// +// On platforms which run the native common_time service in auto-disable mode, +// the service will go into networkless mode whenever it has no active clients. +// It tracks active clients using registered CommonClockListeners (the callback +// interface for onTimelineChanged) since this provides a convienent death +// handler notification for when the service's clients die unexpectedly. This +// means that users of the common time service should really always have a +// CommonClockListener, unless they know that the time service is not running in +// auto disabled mode, or that there is at least one other registered listener +// active in the system. The CCHelper makes this a little easier by sharing a +// ref counted ICommonClock interface across all clients and automatically +// registering and unregistering a listener whenever there are CCHelper +// instances active in the process. +class CCHelper { + public: + CCHelper(); + ~CCHelper(); + + status_t isCommonTimeValid(bool* valid, uint32_t* timelineID); + status_t commonTimeToLocalTime(int64_t commonTime, int64_t* localTime); + status_t localTimeToCommonTime(int64_t localTime, int64_t* commonTime); + status_t getCommonTime(int64_t* commonTime); + status_t getCommonFreq(uint64_t* freq); + status_t getLocalTime(int64_t* localTime); + status_t getLocalFreq(uint64_t* freq); + + private: + class CommonClockListener : public BnCommonClockListener { + public: + void onTimelineChanged(uint64_t timelineID); + }; + + static bool verifyClock_l(); + + static Mutex lock_; + static sp<ICommonClock> common_clock_; + static sp<ICommonClockListener> common_clock_listener_; + static uint32_t ref_count_; +}; + + +} // namespace android +#endif // __CC_HELPER_H__ diff --git a/include/common_time/local_clock.h b/include/common_time/local_clock.h new file mode 100644 index 000000000000..845d1c21614d --- /dev/null +++ b/include/common_time/local_clock.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef __LOCAL_CLOCK_H__ +#define __LOCAL_CLOCK_H__ + +#include <stdint.h> + +#include <hardware/local_time_hal.h> +#include <utils/Errors.h> +#include <utils/threads.h> + +namespace android { + +class LocalClock { + public: + LocalClock(); + + bool initCheck(); + + int64_t getLocalTime(); + uint64_t getLocalFreq(); + status_t setLocalSlew(int16_t rate); + int32_t getDebugLog(struct local_time_debug_event* records, + int max_records); + + private: + static Mutex dev_lock_; + static local_time_hw_device_t* dev_; +}; + +} // namespace android +#endif // __LOCAL_CLOCK_H__ diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h index 991a1817acdd..ae991601817a 100644 --- a/include/gui/BufferQueue.h +++ b/include/gui/BufferQueue.h @@ -60,6 +60,8 @@ public: BufferQueue(bool allowSynchronousMode = true); virtual ~BufferQueue(); + virtual int query(int what, int* value); + // setBufferCount updates the number of available buffer slots. After // calling this all buffer slots are both unallocated and owned by the // BufferQueue object (i.e. they are not owned by the client). diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h index 4318f0fa4841..dcab049ef06d 100644 --- a/include/gui/SurfaceTexture.h +++ b/include/gui/SurfaceTexture.h @@ -55,7 +55,7 @@ public: virtual ~SurfaceTexture(); - virtual int query(int what, int* value); + // updateTexImage sets the image contents of the target texture to that of // the most recently queued buffer. diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h index ca57f9edc9ae..437a89c0b09f 100644 --- a/include/media/AudioRecord.h +++ b/include/media/AudioRecord.h @@ -341,7 +341,7 @@ private: private: friend class AudioRecord; virtual bool threadLoop(); - virtual status_t readyToRun() { return NO_ERROR; } + virtual status_t readyToRun(); virtual void onFirstRef() {} AudioRecord& mReceiver; }; @@ -359,7 +359,9 @@ private: sp<IAudioRecord> mAudioRecord; sp<IMemory> mCblkMemory; sp<ClientRecordThread> mClientRecordThread; + status_t mReadyToRun; Mutex mLock; + Condition mCondition; uint32_t mFrameCount; diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h index da99620ea039..1916ac5fd781 100644 --- a/include/media/AudioSystem.h +++ b/include/media/AudioSystem.h @@ -131,7 +131,7 @@ public: NUM_CONFIG_EVENTS }; - // audio output descritor used to cache output configurations in client process to avoid frequent calls + // audio output descriptor used to cache output configurations in client process to avoid frequent calls // through IAudioFlinger class OutputDescriptor { public: diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h index 11db81ba52fb..9f2bd3a15cf4 100644 --- a/include/media/AudioTrack.h +++ b/include/media/AudioTrack.h @@ -58,8 +58,8 @@ public: EVENT_BUFFER_END = 5 // Playback head is at the end of the buffer. }; - /* Create Buffer on the stack and pass it to obtainBuffer() - * and releaseBuffer(). + /* Client should declare Buffer on the stack and pass address to obtainBuffer() + * and releaseBuffer(). See also callback_t for EVENT_MORE_DATA. */ class Buffer @@ -68,12 +68,16 @@ public: enum { MUTE = 0x00000001 }; - uint32_t flags; + uint32_t flags; // 0 or MUTE audio_format_t format; // but AUDIO_FORMAT_PCM_8_BIT -> AUDIO_FORMAT_PCM_16_BIT // accessed directly by WebKit ANP callback int channelCount; // will be removed in the future, do not use - size_t frameCount; - size_t size; + + size_t frameCount; // number of sample frames corresponding to size; + // on input it is the number of frames desired, + // on output is the number of frames actually filled + + size_t size; // input/output in byte units union { void* raw; short* i16; // signed 16-bit @@ -84,15 +88,15 @@ public: /* As a convenience, if a callback is supplied, a handler thread * is automatically created with the appropriate priority. This thread - * invokes the callback when a new buffer becomes available or an underrun condition occurs. + * invokes the callback when a new buffer becomes available or various conditions occur. * Parameters: * * event: type of event notified (see enum AudioTrack::event_type). * user: Pointer to context for use by the callback receiver. * info: Pointer to optional parameter according to event type: * - EVENT_MORE_DATA: pointer to AudioTrack::Buffer struct. The callback must not write - * more bytes than indicated by 'size' field and update 'size' if less bytes are - * written. + * more bytes than indicated by 'size' field and update 'size' if fewer bytes are + * written. * - EVENT_UNDERRUN: unused. * - EVENT_LOOP_END: pointer to an int indicating the number of loops remaining. * - EVENT_MARKER: pointer to an uint32_t containing the marker position in frames. @@ -225,7 +229,7 @@ public: */ uint32_t latency() const; - /* getters, see constructor */ + /* getters, see constructors and set() */ audio_stream_type_t streamType() const; audio_format_t format() const; @@ -299,7 +303,6 @@ public: * (loopEnd-loopStart) <= framecount() */ status_t setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount); - status_t getLoop(uint32_t *loopStart, uint32_t *loopEnd, int *loopCount) const; /* Sets marker position. When playback reaches the number of frames specified, a callback with * event type EVENT_MARKER is called. Calling setMarkerPosition with marker == 0 cancels marker @@ -401,13 +404,19 @@ public: status_t attachAuxEffect(int effectId); /* Obtains a buffer of "frameCount" frames. The buffer must be - * filled entirely. If the track is stopped, obtainBuffer() returns + * filled entirely, and then released with releaseBuffer(). + * If the track is stopped, obtainBuffer() returns * STOPPED instead of NO_ERROR as long as there are buffers available, * at which point NO_MORE_BUFFERS is returned. * Buffers will be returned until the pool (buffercount()) * is exhausted, at which point obtainBuffer() will either block * or return WOULD_BLOCK depending on the value of the "blocking" * parameter. + * + * Interpretation of waitCount: + * +n limits wait time to n * WAIT_PERIOD_MS, + * -1 causes an (almost) infinite wait time, + * 0 non-blocking. */ enum { @@ -416,12 +425,19 @@ public: }; status_t obtainBuffer(Buffer* audioBuffer, int32_t waitCount); + + /* Release a filled buffer of "frameCount" frames for AudioFlinger to process. */ void releaseBuffer(Buffer* audioBuffer); /* As a convenience we provide a write() interface to the audio buffer. - * This is implemented on top of lockBuffer/unlockBuffer. For best - * performance use callbacks. Return actual number of bytes written. - * + * This is implemented on top of obtainBuffer/releaseBuffer. For best + * performance use callbacks. Returns actual number of bytes written >= 0, + * or one of the following negative status codes: + * INVALID_OPERATION AudioTrack is configured for shared buffer mode + * BAD_VALUE size is invalid + * STOPPED AudioTrack was stopped during the write + * NO_MORE_BUFFERS when obtainBuffer() returns same + * or any other error code returned by IAudioTrack::start() or restoreTrack_l(). */ ssize_t write(const void* buffer, size_t size); @@ -430,7 +446,7 @@ public: */ status_t dump(int fd, const Vector<String16>& args) const; -private: +protected: /* copying audio tracks is not allowed */ AudioTrack(const AudioTrack& other); AudioTrack& operator = (const AudioTrack& other); @@ -448,6 +464,7 @@ private: AudioTrack& mReceiver; }; + // body of AudioTrackThread::threadLoop() bool processAudioBuffer(const sp<AudioTrackThread>& thread); status_t createTrack_l(audio_stream_type_t streamType, uint32_t sampleRate, @@ -484,7 +501,7 @@ private: bool mActive; // protected by mLock - callback_t mCbf; + callback_t mCbf; // callback handler for events, or NULL void* mUserData; uint32_t mNotificationFramesReq; // requested number of frames between each notification callback uint32_t mNotificationFramesAct; // actual number of frames between each notification callback @@ -501,10 +518,33 @@ private: int mAuxEffectId; mutable Mutex mLock; status_t mRestoreStatus; + bool mIsTimed; int mPreviousPriority; // before start() int mPreviousSchedulingGroup; }; +class TimedAudioTrack : public AudioTrack +{ +public: + TimedAudioTrack(); + + /* allocate a shared memory buffer that can be passed to queueTimedBuffer */ + status_t allocateTimedBuffer(size_t size, sp<IMemory>* buffer); + + /* queue a buffer obtained via allocateTimedBuffer for playback at the + given timestamp. PTS units a microseconds on the media time timeline. + The media time transform (set with setMediaTimeTransform) set by the + audio producer will handle converting from media time to local time + (perhaps going through the common time timeline in the case of + synchronized multiroom audio case) */ + status_t queueTimedBuffer(const sp<IMemory>& buffer, int64_t pts); + + /* define a transform between media time and either common time or + local time */ + enum TargetTimeline {LOCAL_TIME, COMMON_TIME}; + status_t setMediaTimeTransform(const LinearTransform& xform, + TargetTimeline target); +}; }; // namespace android diff --git a/include/media/EffectsFactoryApi.h b/include/media/EffectsFactoryApi.h index df83995aab19..65c26f4794be 100644 --- a/include/media/EffectsFactoryApi.h +++ b/include/media/EffectsFactoryApi.h @@ -87,7 +87,7 @@ int EffectQueryEffect(uint32_t index, effect_descriptor_t *pDescriptor); // Description: Creates an effect engine of the specified type and returns an // effect control interface on this engine. The function will allocate the // resources for an instance of the requested effect engine and return -// a handler on the effect control interface. +// a handle on the effect control interface. // // Input: // pEffectUuid: pointer to the effect uuid. @@ -115,17 +115,17 @@ int EffectCreate(const effect_uuid_t *pEffectUuid, int32_t sessionId, int32_t io // // Function: EffectRelease // -// Description: Releases the effect engine whose handler is given as argument. +// Description: Releases the effect engine whose handle is given as argument. // All resources allocated to this particular instance of the effect are // released. // // Input: -// handle: handler on the effect interface to be released. +// handle: handle on the effect interface to be released. // // Output: // returned value: 0 successful operation. // -ENODEV factory failed to initialize -// -EINVAL invalid interface handler +// -EINVAL invalid interface handle // //////////////////////////////////////////////////////////////////////////////// int EffectRelease(effect_handle_t handle); diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h index 433ce7cf52f1..7a2ada032fb3 100644 --- a/include/media/IAudioFlinger.h +++ b/include/media/IAudioFlinger.h @@ -55,6 +55,7 @@ public: uint32_t flags, const sp<IMemory>& sharedBuffer, audio_io_handle_t output, + bool isTimed, int *sessionId, status_t *status) = 0; diff --git a/include/media/IAudioRecord.h b/include/media/IAudioRecord.h index 46735def2f52..7869020e9e06 100644 --- a/include/media/IAudioRecord.h +++ b/include/media/IAudioRecord.h @@ -37,8 +37,9 @@ public: /* After it's created the track is not active. Call start() to * make it active. If set, the callback will start being called. + * tid identifies the client callback thread, or 0 if not needed. */ - virtual status_t start() = 0; + virtual status_t start(pid_t tid) = 0; /* Stop a track. If set, the callback will cease being called and * obtainBuffer will return an error. Buffers that are already released diff --git a/include/media/IAudioTrack.h b/include/media/IAudioTrack.h index b83e552dcd97..77f3e213c875 100644 --- a/include/media/IAudioTrack.h +++ b/include/media/IAudioTrack.h @@ -24,7 +24,7 @@ #include <utils/Errors.h> #include <binder/IInterface.h> #include <binder/IMemory.h> - +#include <utils/LinearTransform.h> namespace android { @@ -40,17 +40,18 @@ public: /* After it's created the track is not active. Call start() to * make it active. If set, the callback will start being called. + * tid identifies the client callback thread, or 0 if not needed. */ - virtual status_t start() = 0; + virtual status_t start(pid_t tid) = 0; /* Stop a track. If set, the callback will cease being called and * obtainBuffer will return an error. Buffers that are already released - * will be processed, unless flush() is called. + * will continue to be processed, unless/until flush() is called. */ virtual void stop() = 0; - /* Flush a stopped track. All pending buffers are discarded. - * This function has no effect if the track is not stopped. + /* Flush a stopped or paused track. All pending/released buffers are discarded. + * This function has no effect if the track is not stopped or paused. */ virtual void flush() = 0; @@ -61,7 +62,7 @@ public: /* Pause a track. If set, the callback will cease being called and * obtainBuffer will return an error. Buffers that are already released - * will be processed, unless flush() is called. + * will continue to be processed, unless/until flush() is called. */ virtual void pause() = 0; @@ -70,6 +71,23 @@ public: */ virtual status_t attachAuxEffect(int effectId) = 0; + + /* Allocate a shared memory buffer suitable for holding timed audio + samples */ + virtual status_t allocateTimedBuffer(size_t size, + sp<IMemory>* buffer) = 0; + + /* Queue a buffer obtained via allocateTimedBuffer for playback at the given + timestamp */ + virtual status_t queueTimedBuffer(const sp<IMemory>& buffer, + int64_t pts) = 0; + + /* Define the linear transform that will be applied to the timestamps + given to queueTimedBuffer (which are expressed in media time). + Target specifies whether this transform converts media time to local time + or Tungsten time. The values for target are defined in AudioTrack.h */ + virtual status_t setMediaTimeTransform(const LinearTransform& xform, + int target) = 0; }; // ---------------------------------------------------------------------------- diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h index 77c82b27ba1b..23a3e4905a63 100644 --- a/include/media/MediaPlayerInterface.h +++ b/include/media/MediaPlayerInterface.h @@ -46,6 +46,9 @@ enum player_type { // The shared library with the test player is passed passed as an // argument to the 'test:' url in the setDataSource call. TEST_PLAYER = 5, + + AAH_RX_PLAYER = 100, + AAH_TX_PLAYER = 101, }; diff --git a/include/media/MemoryLeakTrackUtil.h b/include/media/MemoryLeakTrackUtil.h index 290b7481712f..ac0f6b266b6d 100644 --- a/include/media/MemoryLeakTrackUtil.h +++ b/include/media/MemoryLeakTrackUtil.h @@ -19,7 +19,7 @@ namespace android { /* - * Dump the memory adddress of the calling process to the given fd. + * Dump the memory address of the calling process to the given fd. */ extern void dumpMemoryAddresses(int fd); diff --git a/include/media/stagefright/AudioSource.h b/include/media/stagefright/AudioSource.h index 79437bfcdb63..f5466e80ba6a 100644 --- a/include/media/stagefright/AudioSource.h +++ b/include/media/stagefright/AudioSource.h @@ -95,6 +95,7 @@ private: int32_t startFrame, int32_t rampDurationFrames, uint8_t *data, size_t bytes); + void queueInputBuffer_l(MediaBuffer *buffer, int64_t timeUs); void releaseQueuedFrames_l(); void waitOutstandingEncodingFrames_l(); status_t reset(); diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h index 23226c0f3505..af2db9379f31 100644 --- a/include/private/media/AudioTrackShared.h +++ b/include/private/media/AudioTrackShared.h @@ -62,16 +62,23 @@ struct audio_track_cblk_t // are in the same line of data cache. Mutex lock; // sizeof(int) Condition cv; // sizeof(int) + + // next 4 are offsets within "buffers" volatile uint32_t user; volatile uint32_t server; uint32_t userBase; uint32_t serverBase; + + // if there is a shared buffer, "buffers" is the value of pointer() for the shared + // buffer, otherwise "buffers" points immediately after the control block void* buffers; uint32_t frameCount; + // Cache line boundary + uint32_t loopStart; - uint32_t loopEnd; - int loopCount; + uint32_t loopEnd; // read-only for server, read/write for client + int loopCount; // read/write for client // Channel volumes are fixed point U4.12, so 0x1000 means 1.0. // Left channel is in [0:15], right channel is in [16:31]. @@ -82,29 +89,39 @@ private: public: uint32_t sampleRate; + // NOTE: audio_track_cblk_t::frameSize is not equal to AudioTrack::frameSize() for // 8 bit PCM data: in this case, mCblk->frameSize is based on a sample size of // 16 bit because data is converted to 16 bit before being stored in buffer + // read-only for client, server writes once at initialization and is then read-only uint8_t frameSize; // would normally be size_t, but 8 bits is plenty + + // never used uint8_t pad1; + + // used by client only uint16_t bufferTimeoutMs; // Maximum cumulated timeout before restarting audioflinger - uint16_t waitTimeMs; // Cumulated wait time + uint16_t waitTimeMs; // Cumulated wait time, used by client only private: + // client write-only, server read-only uint16_t mSendLevel; // Fixed point U4.12 so 0x1000 means 1.0 public: volatile int32_t flags; // Cache line boundary (32 bytes) + // Since the control block is always located in shared memory, this constructor + // is only used for placement new(). It is never used for regular new() or stack. audio_track_cblk_t(); - uint32_t stepUser(uint32_t frameCount); - bool stepServer(uint32_t frameCount); + uint32_t stepUser(uint32_t frameCount); // called by client only, where + // client includes regular AudioTrack and AudioFlinger::PlaybackThread::OutputTrack + bool stepServer(uint32_t frameCount); // called by server only void* buffer(uint32_t offset) const; uint32_t framesAvailable(); uint32_t framesAvailable_l(); - uint32_t framesReady(); + uint32_t framesReady(); // called by server only bool tryLock(); // No barriers on the following operations, so the ordering of loads/stores diff --git a/include/utils/KeyedVector.h b/include/utils/KeyedVector.h index 6bcdea4ff182..fcc3bcfa00a1 100644 --- a/include/utils/KeyedVector.h +++ b/include/utils/KeyedVector.h @@ -66,7 +66,7 @@ public: ssize_t indexOfKey(const KEY& key) const; /*! - * modifing the array + * modifying the array */ VALUE& editValueFor(const KEY& key); diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java index db6388ac14c8..0fe7bd88dad1 100644 --- a/keystore/java/android/security/KeyChain.java +++ b/keystore/java/android/security/KeyChain.java @@ -124,7 +124,7 @@ public final class KeyChain { public static final String EXTRA_SENDER = "sender"; /** - * Action to bring up the CertInstaller + * Action to bring up the CertInstaller. */ private static final String ACTION_INSTALL = "android.credentials.INSTALL"; @@ -167,6 +167,22 @@ public final class KeyChain { // Compatible with old android.security.Credentials.PKCS12 public static final String EXTRA_PKCS12 = "PKCS12"; + + /** + * @hide TODO This is temporary and will be removed + * Broadcast Action: Indicates the trusted storage has changed. Sent when + * one of this happens: + * + * <ul> + * <li>a new CA is added, + * <li>an existing CA is removed or disabled, + * <li>a disabled CA is enabled, + * <li>trusted storage is reset (all user certs are cleared), + * <li>when permission to access a private key is changed. + * </ul> + */ + public static final String ACTION_STORAGE_CHANGED = "android.security.STORAGE_CHANGED"; + /** * Returns an {@code Intent} that can be used for credential * installation. The intent may be used without any extras, in diff --git a/libs/common_time/Android.mk b/libs/common_time/Android.mk new file mode 100644 index 000000000000..526f17b44a5c --- /dev/null +++ b/libs/common_time/Android.mk @@ -0,0 +1,21 @@ +LOCAL_PATH:= $(call my-dir) +# +# libcommon_time_client +# (binder marshalers for ICommonClock as well as common clock and local clock +# helper code) +# + +include $(CLEAR_VARS) + +LOCAL_MODULE := libcommon_time_client +LOCAL_MODULE_TAGS := optional +LOCAL_SRC_FILES := cc_helper.cpp \ + local_clock.cpp \ + ICommonClock.cpp \ + ICommonTimeConfig.cpp \ + utils.cpp +LOCAL_SHARED_LIBRARIES := libbinder \ + libhardware \ + libutils + +include $(BUILD_SHARED_LIBRARY) diff --git a/libs/common_time/ICommonClock.cpp b/libs/common_time/ICommonClock.cpp new file mode 100644 index 000000000000..28b43acff16a --- /dev/null +++ b/libs/common_time/ICommonClock.cpp @@ -0,0 +1,432 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <linux/socket.h> + +#include <common_time/ICommonClock.h> +#include <binder/Parcel.h> + +#include "utils.h" + +namespace android { + +/***** ICommonClock *****/ + +enum { + IS_COMMON_TIME_VALID = IBinder::FIRST_CALL_TRANSACTION, + COMMON_TIME_TO_LOCAL_TIME, + LOCAL_TIME_TO_COMMON_TIME, + GET_COMMON_TIME, + GET_COMMON_FREQ, + GET_LOCAL_TIME, + GET_LOCAL_FREQ, + GET_ESTIMATED_ERROR, + GET_TIMELINE_ID, + GET_STATE, + GET_MASTER_ADDRESS, + REGISTER_LISTENER, + UNREGISTER_LISTENER, +}; + +const String16 ICommonClock::kServiceName("common_time.clock"); +const uint64_t ICommonClock::kInvalidTimelineID = 0; +const int32_t ICommonClock::kErrorEstimateUnknown = 0x7FFFFFFF; + +class BpCommonClock : public BpInterface<ICommonClock> +{ + public: + BpCommonClock(const sp<IBinder>& impl) + : BpInterface<ICommonClock>(impl) {} + + virtual status_t isCommonTimeValid(bool* valid, uint32_t* timelineID) { + Parcel data, reply; + data.writeInterfaceToken(ICommonClock::getInterfaceDescriptor()); + status_t status = remote()->transact(IS_COMMON_TIME_VALID, + data, + &reply); + if (status == OK) { + status = reply.readInt32(); + if (status == OK) { + *valid = reply.readInt32(); + *timelineID = reply.readInt32(); + } + } + return status; + } + + virtual status_t commonTimeToLocalTime(int64_t commonTime, + int64_t* localTime) { + Parcel data, reply; + data.writeInterfaceToken(ICommonClock::getInterfaceDescriptor()); + data.writeInt64(commonTime); + status_t status = remote()->transact(COMMON_TIME_TO_LOCAL_TIME, + data, &reply); + if (status == OK) { + status = reply.readInt32(); + if (status == OK) { + *localTime = reply.readInt64(); + } + } + return status; + } + + virtual status_t localTimeToCommonTime(int64_t localTime, + int64_t* commonTime) { + Parcel data, reply; + data.writeInterfaceToken(ICommonClock::getInterfaceDescriptor()); + data.writeInt64(localTime); + status_t status = remote()->transact(LOCAL_TIME_TO_COMMON_TIME, + data, &reply); + if (status == OK) { + status = reply.readInt32(); + if (status == OK) { + *commonTime = reply.readInt64(); + } + } + return status; + } + + virtual status_t getCommonTime(int64_t* commonTime) { + Parcel data, reply; + data.writeInterfaceToken(ICommonClock::getInterfaceDescriptor()); + status_t status = remote()->transact(GET_COMMON_TIME, data, &reply); + if (status == OK) { + status = reply.readInt32(); + if (status == OK) { + *commonTime = reply.readInt64(); + } + } + return status; + } + + virtual status_t getCommonFreq(uint64_t* freq) { + Parcel data, reply; + data.writeInterfaceToken(ICommonClock::getInterfaceDescriptor()); + status_t status = remote()->transact(GET_COMMON_FREQ, data, &reply); + if (status == OK) { + status = reply.readInt32(); + if (status == OK) { + *freq = reply.readInt64(); + } + } + return status; + } + + virtual status_t getLocalTime(int64_t* localTime) { + Parcel data, reply; + data.writeInterfaceToken(ICommonClock::getInterfaceDescriptor()); + status_t status = remote()->transact(GET_LOCAL_TIME, data, &reply); + if (status == OK) { + status = reply.readInt32(); + if (status == OK) { + *localTime = reply.readInt64(); + } + } + return status; + } + + virtual status_t getLocalFreq(uint64_t* freq) { + Parcel data, reply; + data.writeInterfaceToken(ICommonClock::getInterfaceDescriptor()); + status_t status = remote()->transact(GET_LOCAL_FREQ, data, &reply); + if (status == OK) { + status = reply.readInt32(); + if (status == OK) { + *freq = reply.readInt64(); + } + } + return status; + } + + virtual status_t getEstimatedError(int32_t* estimate) { + Parcel data, reply; + data.writeInterfaceToken(ICommonClock::getInterfaceDescriptor()); + status_t status = remote()->transact(GET_ESTIMATED_ERROR, data, &reply); + if (status == OK) { + status = reply.readInt32(); + if (status == OK) { + *estimate = reply.readInt32(); + } + } + return status; + } + + virtual status_t getTimelineID(uint64_t* id) { + Parcel data, reply; + data.writeInterfaceToken(ICommonClock::getInterfaceDescriptor()); + status_t status = remote()->transact(GET_TIMELINE_ID, data, &reply); + if (status == OK) { + status = reply.readInt32(); + if (status == OK) { + *id = static_cast<uint64_t>(reply.readInt64()); + } + } + return status; + } + + virtual status_t getState(State* state) { + Parcel data, reply; + data.writeInterfaceToken(ICommonClock::getInterfaceDescriptor()); + status_t status = remote()->transact(GET_STATE, data, &reply); + if (status == OK) { + status = reply.readInt32(); + if (status == OK) { + *state = static_cast<State>(reply.readInt32()); + } + } + return status; + } + + virtual status_t getMasterAddr(struct sockaddr_storage* addr) { + Parcel data, reply; + data.writeInterfaceToken(ICommonClock::getInterfaceDescriptor()); + status_t status = remote()->transact(GET_MASTER_ADDRESS, data, &reply); + if (status == OK) { + status = reply.readInt32(); + if (status == OK) + deserializeSockaddr(&reply, addr); + } + return status; + } + + virtual status_t registerListener( + const sp<ICommonClockListener>& listener) { + Parcel data, reply; + data.writeInterfaceToken(ICommonClock::getInterfaceDescriptor()); + data.writeStrongBinder(listener->asBinder()); + + status_t status = remote()->transact(REGISTER_LISTENER, data, &reply); + + if (status == OK) { + status = reply.readInt32(); + } + + return status; + } + + virtual status_t unregisterListener( + const sp<ICommonClockListener>& listener) { + Parcel data, reply; + data.writeInterfaceToken(ICommonClock::getInterfaceDescriptor()); + data.writeStrongBinder(listener->asBinder()); + status_t status = remote()->transact(UNREGISTER_LISTENER, data, &reply); + + if (status == OK) { + status = reply.readInt32(); + } + + return status; + } +}; + +IMPLEMENT_META_INTERFACE(CommonClock, "android.os.ICommonClock"); + +status_t BnCommonClock::onTransact(uint32_t code, + const Parcel& data, + Parcel* reply, + uint32_t flags) { + switch(code) { + case IS_COMMON_TIME_VALID: { + CHECK_INTERFACE(ICommonClock, data, reply); + bool valid; + uint32_t timelineID; + status_t status = isCommonTimeValid(&valid, &timelineID); + reply->writeInt32(status); + if (status == OK) { + reply->writeInt32(valid); + reply->writeInt32(timelineID); + } + return OK; + } break; + + case COMMON_TIME_TO_LOCAL_TIME: { + CHECK_INTERFACE(ICommonClock, data, reply); + int64_t commonTime = data.readInt64(); + int64_t localTime; + status_t status = commonTimeToLocalTime(commonTime, &localTime); + reply->writeInt32(status); + if (status == OK) { + reply->writeInt64(localTime); + } + return OK; + } break; + + case LOCAL_TIME_TO_COMMON_TIME: { + CHECK_INTERFACE(ICommonClock, data, reply); + int64_t localTime = data.readInt64(); + int64_t commonTime; + status_t status = localTimeToCommonTime(localTime, &commonTime); + reply->writeInt32(status); + if (status == OK) { + reply->writeInt64(commonTime); + } + return OK; + } break; + + case GET_COMMON_TIME: { + CHECK_INTERFACE(ICommonClock, data, reply); + int64_t commonTime; + status_t status = getCommonTime(&commonTime); + reply->writeInt32(status); + if (status == OK) { + reply->writeInt64(commonTime); + } + return OK; + } break; + + case GET_COMMON_FREQ: { + CHECK_INTERFACE(ICommonClock, data, reply); + uint64_t freq; + status_t status = getCommonFreq(&freq); + reply->writeInt32(status); + if (status == OK) { + reply->writeInt64(freq); + } + return OK; + } break; + + case GET_LOCAL_TIME: { + CHECK_INTERFACE(ICommonClock, data, reply); + int64_t localTime; + status_t status = getLocalTime(&localTime); + reply->writeInt32(status); + if (status == OK) { + reply->writeInt64(localTime); + } + return OK; + } break; + + case GET_LOCAL_FREQ: { + CHECK_INTERFACE(ICommonClock, data, reply); + uint64_t freq; + status_t status = getLocalFreq(&freq); + reply->writeInt32(status); + if (status == OK) { + reply->writeInt64(freq); + } + return OK; + } break; + + case GET_ESTIMATED_ERROR: { + CHECK_INTERFACE(ICommonClock, data, reply); + int32_t error; + status_t status = getEstimatedError(&error); + reply->writeInt32(status); + if (status == OK) { + reply->writeInt32(error); + } + return OK; + } break; + + case GET_TIMELINE_ID: { + CHECK_INTERFACE(ICommonClock, data, reply); + uint64_t id; + status_t status = getTimelineID(&id); + reply->writeInt32(status); + if (status == OK) { + reply->writeInt64(static_cast<int64_t>(id)); + } + return OK; + } break; + + case GET_STATE: { + CHECK_INTERFACE(ICommonClock, data, reply); + State state; + status_t status = getState(&state); + reply->writeInt32(status); + if (status == OK) { + reply->writeInt32(static_cast<int32_t>(state)); + } + return OK; + } break; + + case GET_MASTER_ADDRESS: { + CHECK_INTERFACE(ICommonClock, data, reply); + struct sockaddr_storage addr; + status_t status = getMasterAddr(&addr); + + if ((status == OK) && !canSerializeSockaddr(&addr)) { + status = UNKNOWN_ERROR; + } + + reply->writeInt32(status); + + if (status == OK) { + serializeSockaddr(reply, &addr); + } + + return OK; + } break; + + case REGISTER_LISTENER: { + CHECK_INTERFACE(ICommonClock, data, reply); + sp<ICommonClockListener> listener = + interface_cast<ICommonClockListener>(data.readStrongBinder()); + status_t status = registerListener(listener); + reply->writeInt32(status); + return OK; + } break; + + case UNREGISTER_LISTENER: { + CHECK_INTERFACE(ICommonClock, data, reply); + sp<ICommonClockListener> listener = + interface_cast<ICommonClockListener>(data.readStrongBinder()); + status_t status = unregisterListener(listener); + reply->writeInt32(status); + return OK; + } break; + } + return BBinder::onTransact(code, data, reply, flags); +} + +/***** ICommonClockListener *****/ + +enum { + ON_TIMELINE_CHANGED = IBinder::FIRST_CALL_TRANSACTION, +}; + +class BpCommonClockListener : public BpInterface<ICommonClockListener> +{ + public: + BpCommonClockListener(const sp<IBinder>& impl) + : BpInterface<ICommonClockListener>(impl) {} + + virtual void onTimelineChanged(uint64_t timelineID) { + Parcel data, reply; + data.writeInterfaceToken( + ICommonClockListener::getInterfaceDescriptor()); + data.writeInt64(timelineID); + remote()->transact(ON_TIMELINE_CHANGED, data, &reply); + } +}; + +IMPLEMENT_META_INTERFACE(CommonClockListener, + "android.os.ICommonClockListener"); + +status_t BnCommonClockListener::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { + switch(code) { + case ON_TIMELINE_CHANGED: { + CHECK_INTERFACE(ICommonClockListener, data, reply); + uint32_t timelineID = data.readInt64(); + onTimelineChanged(timelineID); + return NO_ERROR; + } break; + } + + return BBinder::onTransact(code, data, reply, flags); +} + +}; // namespace android diff --git a/libs/common_time/ICommonTimeConfig.cpp b/libs/common_time/ICommonTimeConfig.cpp new file mode 100644 index 000000000000..8eb37cb8064a --- /dev/null +++ b/libs/common_time/ICommonTimeConfig.cpp @@ -0,0 +1,508 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <linux/socket.h> + +#include <common_time/ICommonTimeConfig.h> +#include <binder/Parcel.h> + +#include "utils.h" + +namespace android { + +/***** ICommonTimeConfig *****/ + +enum { + GET_MASTER_ELECTION_PRIORITY = IBinder::FIRST_CALL_TRANSACTION, + SET_MASTER_ELECTION_PRIORITY, + GET_MASTER_ELECTION_ENDPOINT, + SET_MASTER_ELECTION_ENDPOINT, + GET_MASTER_ELECTION_GROUP_ID, + SET_MASTER_ELECTION_GROUP_ID, + GET_INTERFACE_BINDING, + SET_INTERFACE_BINDING, + GET_MASTER_ANNOUNCE_INTERVAL, + SET_MASTER_ANNOUNCE_INTERVAL, + GET_CLIENT_SYNC_INTERVAL, + SET_CLIENT_SYNC_INTERVAL, + GET_PANIC_THRESHOLD, + SET_PANIC_THRESHOLD, + GET_AUTO_DISABLE, + SET_AUTO_DISABLE, + FORCE_NETWORKLESS_MASTER_MODE, +}; + +const String16 ICommonTimeConfig::kServiceName("common_time.config"); + +class BpCommonTimeConfig : public BpInterface<ICommonTimeConfig> +{ + public: + BpCommonTimeConfig(const sp<IBinder>& impl) + : BpInterface<ICommonTimeConfig>(impl) {} + + virtual status_t getMasterElectionPriority(uint8_t *priority) { + Parcel data, reply; + data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor()); + status_t status = remote()->transact(GET_MASTER_ELECTION_PRIORITY, + data, + &reply); + if (status == OK) { + status = reply.readInt32(); + if (status == OK) { + *priority = static_cast<uint8_t>(reply.readInt32()); + } + } + + return status; + } + + virtual status_t setMasterElectionPriority(uint8_t priority) { + Parcel data, reply; + data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor()); + data.writeInt32(static_cast<int32_t>(priority)); + status_t status = remote()->transact(SET_MASTER_ELECTION_PRIORITY, + data, + &reply); + if (status == OK) { + status = reply.readInt32(); + } + + return status; + } + + virtual status_t getMasterElectionEndpoint(struct sockaddr_storage *addr) { + Parcel data, reply; + data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor()); + status_t status = remote()->transact(GET_MASTER_ELECTION_ENDPOINT, + data, + &reply); + if (status == OK) { + status = reply.readInt32(); + if (status == OK) { + deserializeSockaddr(&reply, addr); + } + } + + return status; + } + + virtual status_t setMasterElectionEndpoint( + const struct sockaddr_storage *addr) { + Parcel data, reply; + data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor()); + if (!canSerializeSockaddr(addr)) + return BAD_VALUE; + if (NULL == addr) { + data.writeInt32(0); + } else { + data.writeInt32(1); + serializeSockaddr(&data, addr); + } + status_t status = remote()->transact(SET_MASTER_ELECTION_ENDPOINT, + data, + &reply); + if (status == OK) { + status = reply.readInt32(); + } + + return status; + } + + virtual status_t getMasterElectionGroupId(uint64_t *id) { + Parcel data, reply; + data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor()); + status_t status = remote()->transact(GET_MASTER_ELECTION_GROUP_ID, + data, + &reply); + + if (status == OK) { + status = reply.readInt32(); + if (status == OK) { + *id = static_cast<uint64_t>(reply.readInt64()); + } + } + + return status; + } + + virtual status_t setMasterElectionGroupId(uint64_t id) { + Parcel data, reply; + data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor()); + data.writeInt64(id); + status_t status = remote()->transact(SET_MASTER_ELECTION_GROUP_ID, + data, + &reply); + + if (status == OK) { + status = reply.readInt32(); + } + + return status; + } + + virtual status_t getInterfaceBinding(String16& ifaceName) { + Parcel data, reply; + data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor()); + status_t status = remote()->transact(GET_INTERFACE_BINDING, + data, + &reply); + if (status == OK) { + status = reply.readInt32(); + if (status == OK) { + ifaceName = reply.readString16(); + } + } + + return status; + } + + virtual status_t setInterfaceBinding(const String16& ifaceName) { + Parcel data, reply; + data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor()); + data.writeString16(ifaceName); + status_t status = remote()->transact(SET_INTERFACE_BINDING, + data, + &reply); + if (status == OK) { + status = reply.readInt32(); + } + + return status; + } + + virtual status_t getMasterAnnounceInterval(int *interval) { + Parcel data, reply; + data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor()); + status_t status = remote()->transact(GET_MASTER_ANNOUNCE_INTERVAL, + data, + &reply); + if (status == OK) { + status = reply.readInt32(); + if (status == OK) { + *interval = reply.readInt32(); + } + } + + return status; + } + + virtual status_t setMasterAnnounceInterval(int interval) { + Parcel data, reply; + data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor()); + data.writeInt32(interval); + status_t status = remote()->transact(SET_MASTER_ANNOUNCE_INTERVAL, + data, + &reply); + if (status == OK) { + status = reply.readInt32(); + } + + return status; + } + + virtual status_t getClientSyncInterval(int *interval) { + Parcel data, reply; + data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor()); + status_t status = remote()->transact(GET_CLIENT_SYNC_INTERVAL, + data, + &reply); + if (status == OK) { + status = reply.readInt32(); + if (status == OK) { + *interval = reply.readInt32(); + } + } + + return status; + } + + virtual status_t setClientSyncInterval(int interval) { + Parcel data, reply; + data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor()); + data.writeInt32(interval); + status_t status = remote()->transact(SET_CLIENT_SYNC_INTERVAL, + data, + &reply); + if (status == OK) { + status = reply.readInt32(); + } + + return status; + } + + virtual status_t getPanicThreshold(int *threshold) { + Parcel data, reply; + data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor()); + status_t status = remote()->transact(GET_PANIC_THRESHOLD, + data, + &reply); + if (status == OK) { + status = reply.readInt32(); + if (status == OK) { + *threshold = reply.readInt32(); + } + } + + return status; + } + + virtual status_t setPanicThreshold(int threshold) { + Parcel data, reply; + data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor()); + data.writeInt32(threshold); + status_t status = remote()->transact(SET_PANIC_THRESHOLD, + data, + &reply); + if (status == OK) { + status = reply.readInt32(); + } + + return status; + } + + virtual status_t getAutoDisable(bool *autoDisable) { + Parcel data, reply; + data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor()); + status_t status = remote()->transact(GET_AUTO_DISABLE, + data, + &reply); + if (status == OK) { + status = reply.readInt32(); + if (status == OK) { + *autoDisable = (0 != reply.readInt32()); + } + } + + return status; + } + + virtual status_t setAutoDisable(bool autoDisable) { + Parcel data, reply; + data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor()); + data.writeInt32(autoDisable ? 1 : 0); + status_t status = remote()->transact(SET_AUTO_DISABLE, + data, + &reply); + + if (status == OK) { + status = reply.readInt32(); + } + + return status; + } + + virtual status_t forceNetworklessMasterMode() { + Parcel data, reply; + data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor()); + status_t status = remote()->transact(FORCE_NETWORKLESS_MASTER_MODE, + data, + &reply); + + if (status == OK) { + status = reply.readInt32(); + } + + return status; + } +}; + +IMPLEMENT_META_INTERFACE(CommonTimeConfig, "android.os.ICommonTimeConfig"); + +status_t BnCommonTimeConfig::onTransact(uint32_t code, + const Parcel& data, + Parcel* reply, + uint32_t flags) { + switch(code) { + case GET_MASTER_ELECTION_PRIORITY: { + CHECK_INTERFACE(ICommonTimeConfig, data, reply); + uint8_t priority; + status_t status = getMasterElectionPriority(&priority); + reply->writeInt32(status); + if (status == OK) { + reply->writeInt32(static_cast<int32_t>(priority)); + } + return OK; + } break; + + case SET_MASTER_ELECTION_PRIORITY: { + CHECK_INTERFACE(ICommonTimeConfig, data, reply); + uint8_t priority = static_cast<uint8_t>(data.readInt32()); + status_t status = setMasterElectionPriority(priority); + reply->writeInt32(status); + return OK; + } break; + + case GET_MASTER_ELECTION_ENDPOINT: { + CHECK_INTERFACE(ICommonTimeConfig, data, reply); + struct sockaddr_storage addr; + status_t status = getMasterElectionEndpoint(&addr); + + if ((status == OK) && !canSerializeSockaddr(&addr)) { + status = UNKNOWN_ERROR; + } + + reply->writeInt32(status); + + if (status == OK) { + serializeSockaddr(reply, &addr); + } + + return OK; + } break; + + case SET_MASTER_ELECTION_ENDPOINT: { + CHECK_INTERFACE(ICommonTimeConfig, data, reply); + struct sockaddr_storage addr; + int hasAddr = data.readInt32(); + + status_t status; + if (hasAddr) { + deserializeSockaddr(&data, &addr); + status = setMasterElectionEndpoint(&addr); + } else { + status = setMasterElectionEndpoint(&addr); + } + + reply->writeInt32(status); + return OK; + } break; + + case GET_MASTER_ELECTION_GROUP_ID: { + CHECK_INTERFACE(ICommonTimeConfig, data, reply); + uint64_t id; + status_t status = getMasterElectionGroupId(&id); + reply->writeInt32(status); + if (status == OK) { + reply->writeInt64(id); + } + return OK; + } break; + + case SET_MASTER_ELECTION_GROUP_ID: { + CHECK_INTERFACE(ICommonTimeConfig, data, reply); + uint64_t id = static_cast<uint64_t>(data.readInt64()); + status_t status = setMasterElectionGroupId(id); + reply->writeInt32(status); + return OK; + } break; + + case GET_INTERFACE_BINDING: { + CHECK_INTERFACE(ICommonTimeConfig, data, reply); + String16 ret; + status_t status = getInterfaceBinding(ret); + reply->writeInt32(status); + if (status == OK) { + reply->writeString16(ret); + } + return OK; + } break; + + case SET_INTERFACE_BINDING: { + CHECK_INTERFACE(ICommonTimeConfig, data, reply); + String16 ifaceName; + ifaceName = data.readString16(); + status_t status = setInterfaceBinding(ifaceName); + reply->writeInt32(status); + return OK; + } break; + + case GET_MASTER_ANNOUNCE_INTERVAL: { + CHECK_INTERFACE(ICommonTimeConfig, data, reply); + int interval; + status_t status = getMasterAnnounceInterval(&interval); + reply->writeInt32(status); + if (status == OK) { + reply->writeInt32(interval); + } + return OK; + } break; + + case SET_MASTER_ANNOUNCE_INTERVAL: { + CHECK_INTERFACE(ICommonTimeConfig, data, reply); + int interval = data.readInt32(); + status_t status = setMasterAnnounceInterval(interval); + reply->writeInt32(status); + return OK; + } break; + + case GET_CLIENT_SYNC_INTERVAL: { + CHECK_INTERFACE(ICommonTimeConfig, data, reply); + int interval; + status_t status = getClientSyncInterval(&interval); + reply->writeInt32(status); + if (status == OK) { + reply->writeInt32(interval); + } + return OK; + } break; + + case SET_CLIENT_SYNC_INTERVAL: { + CHECK_INTERFACE(ICommonTimeConfig, data, reply); + int interval = data.readInt32(); + status_t status = setClientSyncInterval(interval); + reply->writeInt32(status); + return OK; + } break; + + case GET_PANIC_THRESHOLD: { + CHECK_INTERFACE(ICommonTimeConfig, data, reply); + int threshold; + status_t status = getPanicThreshold(&threshold); + reply->writeInt32(status); + if (status == OK) { + reply->writeInt32(threshold); + } + return OK; + } break; + + case SET_PANIC_THRESHOLD: { + CHECK_INTERFACE(ICommonTimeConfig, data, reply); + int threshold = data.readInt32(); + status_t status = setPanicThreshold(threshold); + reply->writeInt32(status); + return OK; + } break; + + case GET_AUTO_DISABLE: { + CHECK_INTERFACE(ICommonTimeConfig, data, reply); + bool autoDisable; + status_t status = getAutoDisable(&autoDisable); + reply->writeInt32(status); + if (status == OK) { + reply->writeInt32(autoDisable ? 1 : 0); + } + return OK; + } break; + + case SET_AUTO_DISABLE: { + CHECK_INTERFACE(ICommonTimeConfig, data, reply); + bool autoDisable = (0 != data.readInt32()); + status_t status = setAutoDisable(autoDisable); + reply->writeInt32(status); + return OK; + } break; + + case FORCE_NETWORKLESS_MASTER_MODE: { + CHECK_INTERFACE(ICommonTimeConfig, data, reply); + status_t status = forceNetworklessMasterMode(); + reply->writeInt32(status); + return OK; + } break; + } + return BBinder::onTransact(code, data, reply, flags); +} + +}; // namespace android + diff --git a/libs/common_time/cc_helper.cpp b/libs/common_time/cc_helper.cpp new file mode 100644 index 000000000000..8d8556cb7f54 --- /dev/null +++ b/libs/common_time/cc_helper.cpp @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdint.h> + +#include <common_time/cc_helper.h> +#include <common_time/ICommonClock.h> +#include <utils/threads.h> + +namespace android { + +Mutex CCHelper::lock_; +sp<ICommonClock> CCHelper::common_clock_; +sp<ICommonClockListener> CCHelper::common_clock_listener_; +uint32_t CCHelper::ref_count_ = 0; + +bool CCHelper::verifyClock_l() { + bool ret = false; + + if (common_clock_ == NULL) { + common_clock_ = ICommonClock::getInstance(); + if (common_clock_ == NULL) + goto bailout; + } + + if (ref_count_ > 0) { + if (common_clock_listener_ == NULL) { + common_clock_listener_ = new CommonClockListener(); + if (common_clock_listener_ == NULL) + goto bailout; + + if (OK != common_clock_->registerListener(common_clock_listener_)) + goto bailout; + } + } + + ret = true; + +bailout: + if (!ret) { + common_clock_listener_ = NULL; + common_clock_ = NULL; + } + return ret; +} + +CCHelper::CCHelper() { + Mutex::Autolock lock(&lock_); + ref_count_++; + verifyClock_l(); +} + +CCHelper::~CCHelper() { + Mutex::Autolock lock(&lock_); + + assert(ref_count_ > 0); + ref_count_--; + + // If we were the last CCHelper instance in the system, and we had + // previously register a listener, unregister it now so that the common time + // service has the chance to go into auto-disabled mode. + if (!ref_count_ && + (common_clock_ != NULL) && + (common_clock_listener_ != NULL)) { + common_clock_->unregisterListener(common_clock_listener_); + common_clock_listener_ = NULL; + } +} + +void CCHelper::CommonClockListener::onTimelineChanged(uint64_t timelineID) { + // do nothing; listener is only really used as a token so the server can + // find out when clients die. +} + +// Helper methods which attempts to make calls to the common time binder +// service. If the first attempt fails with DEAD_OBJECT, the helpers will +// attempt to make a connection to the service again (assuming that the process +// hosting the service had crashed and the client proxy we are holding is dead) +// If the second attempt fails, or no connection can be made, the we let the +// error propagate up the stack and let the caller deal with the situation as +// best they can. +#define CCHELPER_METHOD(decl, call) \ + status_t CCHelper::decl { \ + Mutex::Autolock lock(&lock_); \ + \ + if (!verifyClock_l()) \ + return DEAD_OBJECT; \ + \ + status_t status = common_clock_->call; \ + if (DEAD_OBJECT == status) { \ + if (!verifyClock_l()) \ + return DEAD_OBJECT; \ + status = common_clock_->call; \ + } \ + \ + return status; \ + } + +#define VERIFY_CLOCK() + +CCHELPER_METHOD(isCommonTimeValid(bool* valid, uint32_t* timelineID), + isCommonTimeValid(valid, timelineID)) +CCHELPER_METHOD(commonTimeToLocalTime(int64_t commonTime, int64_t* localTime), + commonTimeToLocalTime(commonTime, localTime)) +CCHELPER_METHOD(localTimeToCommonTime(int64_t localTime, int64_t* commonTime), + localTimeToCommonTime(localTime, commonTime)) +CCHELPER_METHOD(getCommonTime(int64_t* commonTime), + getCommonTime(commonTime)) +CCHELPER_METHOD(getCommonFreq(uint64_t* freq), + getCommonFreq(freq)) +CCHELPER_METHOD(getLocalTime(int64_t* localTime), + getLocalTime(localTime)) +CCHELPER_METHOD(getLocalFreq(uint64_t* freq), + getLocalFreq(freq)) + +} // namespace android diff --git a/libs/common_time/local_clock.cpp b/libs/common_time/local_clock.cpp new file mode 100644 index 000000000000..a7c61fc76aa5 --- /dev/null +++ b/libs/common_time/local_clock.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "common_time" +#include <utils/Log.h> + +#include <assert.h> +#include <stdint.h> + +#include <common_time/local_clock.h> +#include <hardware/hardware.h> +#include <hardware/local_time_hal.h> +#include <utils/Errors.h> +#include <utils/threads.h> + +namespace android { + +Mutex LocalClock::dev_lock_; +local_time_hw_device_t* LocalClock::dev_ = NULL; + +LocalClock::LocalClock() { + int res; + const hw_module_t* mod; + + AutoMutex lock(&dev_lock_); + + if (dev_ != NULL) + return; + + res = hw_get_module_by_class(LOCAL_TIME_HARDWARE_MODULE_ID, NULL, &mod); + if (res) { + ALOGE("Failed to open local time HAL module (res = %d)", res); + } else { + res = local_time_hw_device_open(mod, &dev_); + if (res) { + ALOGE("Failed to open local time HAL device (res = %d)", res); + dev_ = NULL; + } + } +} + +bool LocalClock::initCheck() { + return (NULL != dev_); +} + +int64_t LocalClock::getLocalTime() { + assert(NULL != dev_); + assert(NULL != dev_->get_local_time); + + return dev_->get_local_time(dev_); +} + +uint64_t LocalClock::getLocalFreq() { + assert(NULL != dev_); + assert(NULL != dev_->get_local_freq); + + return dev_->get_local_freq(dev_); +} + +status_t LocalClock::setLocalSlew(int16_t rate) { + assert(NULL != dev_); + + if (!dev_->set_local_slew) + return INVALID_OPERATION; + + return static_cast<status_t>(dev_->set_local_slew(dev_, rate)); +} + +int32_t LocalClock::getDebugLog(struct local_time_debug_event* records, + int max_records) { + assert(NULL != dev_); + + if (!dev_->get_debug_log) + return INVALID_OPERATION; + + return dev_->get_debug_log(dev_, records, max_records); +} + +} // namespace android diff --git a/libs/common_time/utils.cpp b/libs/common_time/utils.cpp new file mode 100644 index 000000000000..65391711b0bd --- /dev/null +++ b/libs/common_time/utils.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <arpa/inet.h> +#include <linux/socket.h> + +#include <binder/Parcel.h> + +namespace android { + +bool canSerializeSockaddr(const struct sockaddr_storage* addr) { + switch (addr->ss_family) { + case AF_INET: + case AF_INET6: + return true; + default: + return false; + } +} + +void serializeSockaddr(Parcel* p, const struct sockaddr_storage* addr) { + switch (addr->ss_family) { + case AF_INET: { + const struct sockaddr_in* s = + reinterpret_cast<const struct sockaddr_in*>(addr); + p->writeInt32(AF_INET); + p->writeInt32(ntohl(s->sin_addr.s_addr)); + p->writeInt32(static_cast<int32_t>(ntohs(s->sin_port))); + } break; + + case AF_INET6: { + const struct sockaddr_in6* s = + reinterpret_cast<const struct sockaddr_in6*>(addr); + const int32_t* a = + reinterpret_cast<const int32_t*>(s->sin6_addr.s6_addr); + p->writeInt32(AF_INET6); + p->writeInt32(ntohl(a[0])); + p->writeInt32(ntohl(a[1])); + p->writeInt32(ntohl(a[2])); + p->writeInt32(ntohl(a[3])); + p->writeInt32(static_cast<int32_t>(ntohs(s->sin6_port))); + p->writeInt32(ntohl(s->sin6_flowinfo)); + p->writeInt32(ntohl(s->sin6_scope_id)); + } break; + } +} + +void deserializeSockaddr(const Parcel* p, struct sockaddr_storage* addr) { + memset(addr, 0, sizeof(addr)); + + addr->ss_family = p->readInt32(); + switch(addr->ss_family) { + case AF_INET: { + struct sockaddr_in* s = + reinterpret_cast<struct sockaddr_in*>(addr); + s->sin_addr.s_addr = htonl(p->readInt32()); + s->sin_port = htons(static_cast<uint16_t>(p->readInt32())); + } break; + + case AF_INET6: { + struct sockaddr_in6* s = + reinterpret_cast<struct sockaddr_in6*>(addr); + int32_t* a = reinterpret_cast<int32_t*>(s->sin6_addr.s6_addr); + + a[0] = htonl(p->readInt32()); + a[1] = htonl(p->readInt32()); + a[2] = htonl(p->readInt32()); + a[3] = htonl(p->readInt32()); + s->sin6_port = htons(static_cast<uint16_t>(p->readInt32())); + s->sin6_flowinfo = htonl(p->readInt32()); + s->sin6_scope_id = htonl(p->readInt32()); + } break; + } +} + +} // namespace android diff --git a/libs/common_time/utils.h b/libs/common_time/utils.h new file mode 100644 index 000000000000..ce79d0d74cec --- /dev/null +++ b/libs/common_time/utils.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_LIBCOMMONCLOCK_UTILS_H +#define ANDROID_LIBCOMMONCLOCK_UTILS_H + +#include <linux/socket.h> + +#include <binder/Parcel.h> +#include <utils/Errors.h> + +namespace android { + +extern bool canSerializeSockaddr(const struct sockaddr_storage* addr); +extern void serializeSockaddr(Parcel* p, const struct sockaddr_storage* addr); +extern status_t deserializeSockaddr(const Parcel* p, + struct sockaddr_storage* addr); + +}; // namespace android + +#endif // ANDROID_LIBCOMMONCLOCK_UTILS_H diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index c7e2c0f21fe4..0791de2269ef 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -166,6 +166,37 @@ status_t BufferQueue::setBufferCount(int bufferCount) { return OK; } +int BufferQueue::query(int what, int* outValue) +{ + Mutex::Autolock lock(mMutex); + + if (mAbandoned) { + ST_LOGE("query: SurfaceTexture has been abandoned!"); + return NO_INIT; + } + + int value; + switch (what) { + case NATIVE_WINDOW_WIDTH: + value = mDefaultWidth; + break; + case NATIVE_WINDOW_HEIGHT: + value = mDefaultHeight; + break; + case NATIVE_WINDOW_FORMAT: + value = mPixelFormat; + break; + case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS: + value = mSynchronousMode ? + (MIN_UNDEQUEUED_BUFFERS-1) : MIN_UNDEQUEUED_BUFFERS; + break; + default: + return BAD_VALUE; + } + outValue[0] = value; + return NO_ERROR; +} + status_t BufferQueue::requestBuffer(int slot, sp<GraphicBuffer>* buf) { ST_LOGV("requestBuffer: slot=%d", slot); Mutex::Autolock lock(mMutex); diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp index be1bcd1a8104..a7bfc613aa25 100644 --- a/libs/gui/SurfaceTexture.cpp +++ b/libs/gui/SurfaceTexture.cpp @@ -416,36 +416,7 @@ bool SurfaceTexture::isSynchronousMode() const { return mSynchronousMode; } -int SurfaceTexture::query(int what, int* outValue) -{ - Mutex::Autolock lock(mMutex); - if (mAbandoned) { - ST_LOGE("query: SurfaceTexture has been abandoned!"); - return NO_INIT; - } - - int value; - switch (what) { - case NATIVE_WINDOW_WIDTH: - value = mDefaultWidth; - break; - case NATIVE_WINDOW_HEIGHT: - value = mDefaultHeight; - break; - case NATIVE_WINDOW_FORMAT: - value = mPixelFormat; - break; - case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS: - value = mSynchronousMode ? - (MIN_UNDEQUEUED_BUFFERS-1) : MIN_UNDEQUEUED_BUFFERS; - break; - default: - return BAD_VALUE; - } - outValue[0] = value; - return NO_ERROR; -} void SurfaceTexture::abandon() { Mutex::Autolock lock(mMutex); diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp index 1a11fbcfad68..f9088aca3718 100644 --- a/libs/hwui/DisplayListRenderer.cpp +++ b/libs/hwui/DisplayListRenderer.cpp @@ -226,6 +226,11 @@ void DisplayList::output(OpenGLRenderer& renderer, uint32_t level) { while (!mReader.eof()) { int op = mReader.readInt(); + if (op & OP_MAY_BE_SKIPPED_MASK) { + int skip = mReader.readInt(); + ALOGD("%sSkip %d", (char*) indent, skip); + op &= ~OP_MAY_BE_SKIPPED_MASK; + } switch (op) { case DrawGLFunction: { @@ -316,8 +321,9 @@ void DisplayList::output(OpenGLRenderer& renderer, uint32_t level) { DisplayList* displayList = getDisplayList(); uint32_t width = getUInt(); uint32_t height = getUInt(); - ALOGD("%s%s %p, %dx%d, %d", (char*) indent, OP_NAMES[op], - displayList, width, height, level + 1); + int32_t flags = getInt(); + ALOGD("%s%s %p, %dx%d, 0x%x %d", (char*) indent, OP_NAMES[op], + displayList, width, height, flags, level + 1); renderer.outputDisplayList(displayList, level + 1); } break; @@ -551,7 +557,7 @@ void DisplayList::output(OpenGLRenderer& renderer, uint32_t level) { * in the output() function, since that function processes the same list of opcodes for the * purposes of logging display list info for a given view. */ -bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level) { +bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, uint32_t level) { bool needsInvalidate = false; TextContainer text; mReader.rewind(); @@ -572,6 +578,18 @@ bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level) int saveCount = renderer.getSaveCount() - 1; while (!mReader.eof()) { int op = mReader.readInt(); + if (op & OP_MAY_BE_SKIPPED_MASK) { + int32_t skip = mReader.readInt() * 4; + if (CC_LIKELY(flags & kReplayFlag_ClipChildren)) { + mReader.skip(skip); + DISPLAY_LIST_LOGD("%s%s skipping %d bytes", (char*) indent, + OP_NAMES[op & ~OP_MAY_BE_SKIPPED_MASK], skip); + continue; + } else { + op &= ~OP_MAY_BE_SKIPPED_MASK; + ALOGD("%s", OP_NAMES[op]); + } + } logBuffer.writeCommand(level, op); switch (op) { @@ -584,7 +602,7 @@ bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level) } break; case Save: { - int rendererNum = getInt(); + int32_t rendererNum = getInt(); DISPLAY_LIST_LOGD("%s%s %d", (char*) indent, OP_NAMES[op], rendererNum); renderer.save(rendererNum); } @@ -595,7 +613,7 @@ bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level) } break; case RestoreToCount: { - int restoreCount = saveCount + getInt(); + int32_t restoreCount = saveCount + getInt(); DISPLAY_LIST_LOGD("%s%s %d", (char*) indent, OP_NAMES[op], restoreCount); renderer.restoreToCount(restoreCount); } @@ -606,7 +624,7 @@ bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level) float f3 = getFloat(); float f4 = getFloat(); SkPaint* paint = getPaint(renderer); - int flags = getInt(); + int32_t flags = getInt(); DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p, 0x%x", (char*) indent, OP_NAMES[op], f1, f2, f3, f4, paint, flags); renderer.saveLayer(f1, f2, f3, f4, paint, flags); @@ -617,8 +635,8 @@ bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level) float f2 = getFloat(); float f3 = getFloat(); float f4 = getFloat(); - int alpha = getInt(); - int flags = getInt(); + int32_t alpha = getInt(); + int32_t flags = getInt(); DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d, 0x%x", (char*) indent, OP_NAMES[op], f1, f2, f3, f4, alpha, flags); renderer.saveLayerAlpha(f1, f2, f3, f4, alpha, flags); @@ -668,7 +686,7 @@ bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level) float f2 = getFloat(); float f3 = getFloat(); float f4 = getFloat(); - int regionOp = getInt(); + int32_t regionOp = getInt(); DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d", (char*) indent, OP_NAMES[op], f1, f2, f3, f4, regionOp); renderer.clipRect(f1, f2, f3, f4, (SkRegion::Op) regionOp); @@ -678,10 +696,11 @@ bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level) DisplayList* displayList = getDisplayList(); uint32_t width = getUInt(); uint32_t height = getUInt(); - DISPLAY_LIST_LOGD("%s%s %p, %dx%d, %d", (char*) indent, OP_NAMES[op], - displayList, width, height, level + 1); + int32_t flags = getInt(); + DISPLAY_LIST_LOGD("%s%s %p, %dx%d, 0x%x %d", (char*) indent, OP_NAMES[op], + displayList, width, height, flags, level + 1); needsInvalidate |= renderer.drawDisplayList(displayList, width, height, - dirty, level + 1); + dirty, flags, level + 1); } break; case DrawLayer: { @@ -730,7 +749,7 @@ bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level) } break; case DrawBitmapMesh: { - int verticesCount = 0; + int32_t verticesCount = 0; uint32_t colorsCount = 0; SkBitmap* bitmap = getBitmap(); @@ -738,7 +757,7 @@ bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level) uint32_t meshHeight = getInt(); float* vertices = getFloats(verticesCount); bool hasColors = getInt(); - int* colors = hasColors ? getInts(colorsCount) : NULL; + int32_t* colors = hasColors ? getInts(colorsCount) : NULL; SkPaint* paint = getPaint(renderer); DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]); @@ -771,8 +790,8 @@ bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level) } break; case DrawColor: { - int color = getInt(); - int xferMode = getInt(); + int32_t color = getInt(); + int32_t xferMode = getInt(); DISPLAY_LIST_LOGD("%s%s 0x%x %d", (char*) indent, OP_NAMES[op], color, xferMode); renderer.drawColor(color, (SkXfermode::Mode) xferMode); } @@ -829,7 +848,7 @@ bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level) float f4 = getFloat(); float f5 = getFloat(); float f6 = getFloat(); - int i1 = getInt(); + int32_t i1 = getInt(); SkPaint* paint = getPaint(renderer); DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %d, %p", (char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, i1, paint); @@ -844,7 +863,7 @@ bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level) } break; case DrawLines: { - int count = 0; + int32_t count = 0; float* points = getFloats(count); SkPaint* paint = getPaint(renderer); DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]); @@ -852,7 +871,7 @@ bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level) } break; case DrawPoints: { - int count = 0; + int32_t count = 0; float* points = getFloats(count); SkPaint* paint = getPaint(renderer); DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]); @@ -861,7 +880,7 @@ bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level) break; case DrawText: { getText(&text); - int count = getInt(); + int32_t count = getInt(); float x = getFloat(); float y = getFloat(); SkPaint* paint = getPaint(renderer); @@ -873,8 +892,8 @@ bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level) break; case DrawPosText: { getText(&text); - int count = getInt(); - int positionsCount = 0; + int32_t count = getInt(); + int32_t positionsCount = 0; float* positions = getFloats(positionsCount); SkPaint* paint = getPaint(renderer); DISPLAY_LIST_LOGD("%s%s %s, %d, %d, %p", (char*) indent, @@ -913,7 +932,7 @@ bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level) float radius = getFloat(); float dx = getFloat(); float dy = getFloat(); - int color = getInt(); + int32_t color = getInt(); DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, 0x%x", (char*) indent, OP_NAMES[op], radius, dx, dy, color); renderer.setupShadow(radius, dx, dy, color); @@ -925,8 +944,8 @@ bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level) } break; case SetupPaintFilter: { - int clearBits = getInt(); - int setBits = getInt(); + int32_t clearBits = getInt(); + int32_t setBits = getInt(); DISPLAY_LIST_LOGD("%s%s 0x%x, 0x%x", (char*) indent, OP_NAMES[op], clearBits, setBits); renderer.setupPaintFilter(clearBits, setBits); @@ -949,7 +968,8 @@ bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level) // Base structure /////////////////////////////////////////////////////////////////////////////// -DisplayListRenderer::DisplayListRenderer(): mWriter(MIN_WRITER_SIZE), mHasDrawOps(false) { +DisplayListRenderer::DisplayListRenderer(): mWriter(MIN_WRITER_SIZE), + mTranslateX(0.0f), mTranslateY(0.0f), mHasTranslate(false), mHasDrawOps(false) { } DisplayListRenderer::~DisplayListRenderer() { @@ -1019,6 +1039,7 @@ void DisplayListRenderer::prepareDirty(float left, float top, void DisplayListRenderer::finish() { insertRestoreToCount(); + insertTranlate(); OpenGLRenderer::finish(); } @@ -1043,15 +1064,18 @@ int DisplayListRenderer::save(int flags) { void DisplayListRenderer::restore() { if (mRestoreSaveCount < 0) { - addOp(DisplayList::Restore); - } else { - mRestoreSaveCount--; + restoreToCount(getSaveCount() - 1); + return; } + + mRestoreSaveCount--; + insertTranlate(); OpenGLRenderer::restore(); } void DisplayListRenderer::restoreToCount(int saveCount) { mRestoreSaveCount = saveCount; + insertTranlate(); OpenGLRenderer::restoreToCount(saveCount); } @@ -1074,8 +1098,10 @@ int DisplayListRenderer::saveLayerAlpha(float left, float top, float right, floa } void DisplayListRenderer::translate(float dx, float dy) { - addOp(DisplayList::Translate); - addPoint(dx, dy); + mHasTranslate = true; + mTranslateX += dx; + mTranslateY += dy; + insertRestoreToCount(); OpenGLRenderer::translate(dx, dy); } @@ -1118,12 +1144,15 @@ bool DisplayListRenderer::clipRect(float left, float top, float right, float bot } bool DisplayListRenderer::drawDisplayList(DisplayList* displayList, - uint32_t width, uint32_t height, Rect& dirty, uint32_t level) { + uint32_t width, uint32_t height, Rect& dirty, int32_t flags, uint32_t level) { // dirty is an out parameter and should not be recorded, // it matters only when replaying the display list - addOp(DisplayList::DrawDisplayList); + const bool reject = quickReject(0.0f, 0.0f, width, height); + uint32_t* location = addOp(DisplayList::DrawDisplayList, reject); addDisplayList(displayList); addSize(width, height); + addInt(flags); + addSkip(location); return false; } @@ -1134,30 +1163,38 @@ void DisplayListRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* pai addPaint(paint); } -void DisplayListRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, - SkPaint* paint) { - addOp(DisplayList::DrawBitmap); +void DisplayListRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint) { + const bool reject = quickReject(left, top, left + bitmap->width(), top + bitmap->height()); + uint32_t* location = addOp(DisplayList::DrawBitmap, reject); addBitmap(bitmap); addPoint(left, top); addPaint(paint); + addSkip(location); } -void DisplayListRenderer::drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, - SkPaint* paint) { - addOp(DisplayList::DrawBitmapMatrix); +void DisplayListRenderer::drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint) { + Rect r(0.0f, 0.0f, bitmap->width(), bitmap->height()); + const mat4 transform(*matrix); + transform.mapRect(r); + + const bool reject = quickReject(r.left, r.top, r.right, r.bottom); + uint32_t* location = addOp(DisplayList::DrawBitmapMatrix, reject); addBitmap(bitmap); addMatrix(matrix); addPaint(paint); + addSkip(location); } void DisplayListRenderer::drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop, float srcRight, float srcBottom, float dstLeft, float dstTop, float dstRight, float dstBottom, SkPaint* paint) { - addOp(DisplayList::DrawBitmapRect); + const bool reject = quickReject(dstLeft, dstTop, dstRight, dstBottom); + uint32_t* location = addOp(DisplayList::DrawBitmapRect, reject); addBitmap(bitmap); addBounds(srcLeft, srcTop, srcRight, srcBottom); addBounds(dstLeft, dstTop, dstRight, dstBottom); addPaint(paint); + addSkip(location); } void DisplayListRenderer::drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int meshHeight, @@ -1179,13 +1216,15 @@ void DisplayListRenderer::drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int me void DisplayListRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs, const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors, float left, float top, float right, float bottom, SkPaint* paint) { - addOp(DisplayList::DrawPatch); + const bool reject = quickReject(left, top, right, bottom); + uint32_t* location = addOp(DisplayList::DrawPatch, reject); addBitmap(bitmap); addInts(xDivs, width); addInts(yDivs, height); addUInts(colors, numColors); addBounds(left, top, right, bottom); addPaint(paint); + addSkip(location); } void DisplayListRenderer::drawColor(int color, SkXfermode::Mode mode) { @@ -1196,17 +1235,23 @@ void DisplayListRenderer::drawColor(int color, SkXfermode::Mode mode) { void DisplayListRenderer::drawRect(float left, float top, float right, float bottom, SkPaint* paint) { - addOp(DisplayList::DrawRect); + const bool reject = paint->getStyle() == SkPaint::kFill_Style && + quickReject(left, top, right, bottom); + uint32_t* location = addOp(DisplayList::DrawRect, reject); addBounds(left, top, right, bottom); addPaint(paint); + addSkip(location); } void DisplayListRenderer::drawRoundRect(float left, float top, float right, float bottom, float rx, float ry, SkPaint* paint) { - addOp(DisplayList::DrawRoundRect); + const bool reject = paint->getStyle() == SkPaint::kFill_Style && + quickReject(left, top, right, bottom); + uint32_t* location = addOp(DisplayList::DrawRoundRect, reject); addBounds(left, top, right, bottom); addPoint(rx, ry); addPaint(paint); + addSkip(location); } void DisplayListRenderer::drawCircle(float x, float y, float radius, SkPaint* paint) { @@ -1233,9 +1278,15 @@ void DisplayListRenderer::drawArc(float left, float top, float right, float bott } void DisplayListRenderer::drawPath(SkPath* path, SkPaint* paint) { - addOp(DisplayList::DrawPath); + float left, top, offset; + uint32_t width, height; + computePathBounds(path, paint, left, top, offset, width, height); + + const bool reject = quickReject(left - offset, top - offset, width, height); + uint32_t* location = addOp(DisplayList::DrawPath, reject); addPath(path); addPaint(paint); + addSkip(location); } void DisplayListRenderer::drawLines(float* points, int count, SkPaint* paint) { @@ -1252,11 +1303,8 @@ void DisplayListRenderer::drawPoints(float* points, int count, SkPaint* paint) { void DisplayListRenderer::drawText(const char* text, int bytesCount, int count, float x, float y, SkPaint* paint, float length) { - if (count <= 0) return; - addOp(DisplayList::DrawText); - addText(text, bytesCount); - addInt(count); - addPoint(x, y); + if (!text || count <= 0) return; + // TODO: We should probably make a copy of the paint instead of modifying // it; modifying the paint will change its generationID the first // time, which might impact caches. More investigation needed to @@ -1265,13 +1313,27 @@ void DisplayListRenderer::drawText(const char* text, int bytesCount, int count, // its own copy as it does right now. // Beware: this needs Glyph encoding (already done on the Paint constructor) paint->setAntiAlias(true); + if (length < 0.0f) length = paint->measureText(text, bytesCount); + + bool reject = false; + if (CC_LIKELY(paint->getTextAlign() == SkPaint::kLeft_Align)) { + SkPaint::FontMetrics metrics; + paint->getFontMetrics(&metrics, 0.0f); + reject = quickReject(x, y + metrics.fTop, x + length, y + metrics.fBottom); + } + + uint32_t* location = addOp(DisplayList::DrawText, reject); + addText(text, bytesCount); + addInt(count); + addPoint(x, y); addPaint(paint); - addFloat(length < 0.0f ? paint->measureText(text, bytesCount) : length); + addFloat(length); + addSkip(location); } void DisplayListRenderer::drawPosText(const char* text, int bytesCount, int count, const float* positions, SkPaint* paint) { - if (count <= 0) return; + if (!text || count <= 0) return; addOp(DisplayList::DrawPosText); addText(text, bytesCount); addInt(count); diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h index 46506e4e9a96..6dd47be991ac 100644 --- a/libs/hwui/DisplayListRenderer.h +++ b/libs/hwui/DisplayListRenderer.h @@ -42,6 +42,7 @@ namespace uirenderer { /////////////////////////////////////////////////////////////////////////////// #define MIN_WRITER_SIZE 4096 +#define OP_MAY_BE_SKIPPED_MASK 0xff000000 // Debug #if DEBUG_DISPLAY_LIST @@ -110,13 +111,18 @@ public: DrawGLFunction, }; + // See flags defined in DisplayList.java + enum ReplayFlag { + kReplayFlag_ClipChildren = 0x1 + }; + static const char* OP_NAMES[]; void initFromDisplayListRenderer(const DisplayListRenderer& recorder, bool reusing = false); ANDROID_API size_t getSize(); - bool replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level = 0); + bool replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, uint32_t level = 0); void output(OpenGLRenderer& renderer, uint32_t level = 0); @@ -167,11 +173,11 @@ private: return (SkiaColorFilter*) getInt(); } - inline int getIndex() { + inline int32_t getIndex() { return mReader.readInt(); } - inline int getInt() { + inline int32_t getInt() { return mReader.readInt(); } @@ -209,7 +215,7 @@ private: return (uint32_t*) mReader.skip(count * sizeof(uint32_t)); } - float* getFloats(int& count) { + float* getFloats(int32_t& count) { count = getInt(); return (float*) mReader.skip(count * sizeof(float)); } @@ -279,7 +285,7 @@ public: virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op); virtual bool drawDisplayList(DisplayList* displayList, uint32_t width, uint32_t height, - Rect& dirty, uint32_t level = 0); + Rect& dirty, int32_t flags, uint32_t level = 0); virtual void drawLayer(Layer* layer, float x, float y, SkPaint* paint); virtual void drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint); virtual void drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint); @@ -358,13 +364,45 @@ private: } } - inline void addOp(DisplayList::Op drawOp) { + void insertTranlate() { + if (mHasTranslate) { + if (mTranslateX != 0.0f || mTranslateY != 0.0f) { + mWriter.writeInt(DisplayList::Translate); + addPoint(mTranslateX, mTranslateY); + mTranslateX = mTranslateY = 0.0f; + } + mHasTranslate = false; + } + } + + inline void addOp(const DisplayList::Op drawOp) { insertRestoreToCount(); + insertTranlate(); mWriter.writeInt(drawOp); mHasDrawOps = mHasDrawOps || drawOp >= DisplayList::DrawDisplayList; } - inline void addInt(int value) { + uint32_t* addOp(const DisplayList::Op drawOp, const bool reject) { + insertRestoreToCount(); + insertTranlate(); + mHasDrawOps = mHasDrawOps || drawOp >= DisplayList::DrawDisplayList; + if (reject) { + mWriter.writeInt(OP_MAY_BE_SKIPPED_MASK | drawOp); + mWriter.writeInt(0); + uint32_t* location = reject ? mWriter.peek32(mWriter.size() - 4) : NULL; + return location; + } + mWriter.writeInt(drawOp); + return NULL; + } + + inline void addSkip(uint32_t* location) { + if (location) { + *location = (int32_t) (mWriter.peek32(mWriter.size() - 4) - location); + } + } + + inline void addInt(int32_t value) { mWriter.writeInt(value); } @@ -391,9 +429,9 @@ private: mWriter.writeScalar(value); } - void addFloats(const float* values, int count) { + void addFloats(const float* values, int32_t count) { mWriter.writeInt(count); - for (int i = 0; i < count; i++) { + for (int32_t i = 0; i < count; i++) { mWriter.writeScalar(values[i]); } } @@ -513,6 +551,11 @@ private: SkWriter32 mWriter; int mRestoreSaveCount; + + float mTranslateX; + float mTranslateY; + bool mHasTranslate; + bool mHasDrawOps; friend class DisplayList; diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index afae70fddb5d..55e2ca5d7f24 100644 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -1321,7 +1321,7 @@ void OpenGLRenderer::finishDrawTexture() { /////////////////////////////////////////////////////////////////////////////// bool OpenGLRenderer::drawDisplayList(DisplayList* displayList, uint32_t width, uint32_t height, - Rect& dirty, uint32_t level) { + Rect& dirty, int32_t flags, uint32_t level) { if (quickReject(0.0f, 0.0f, width, height)) { return false; } @@ -1329,7 +1329,7 @@ bool OpenGLRenderer::drawDisplayList(DisplayList* displayList, uint32_t width, u // All the usual checks and setup operations (quickReject, setupDraw, etc.) // will be performed by the display list itself if (displayList && displayList->isRenderable()) { - return displayList->replay(*this, dirty, level); + return displayList->replay(*this, dirty, flags, level); } return false; @@ -2189,8 +2189,7 @@ void OpenGLRenderer::drawText(const char* text, int bytesCount, int count, SkPaint::FontMetrics metrics; paint->getFontMetrics(&metrics, 0.0f); // If no length was specified, just perform the hit test on the Y axis - if (quickReject(x, y + metrics.fTop, - x + (length >= 0.0f ? length : INT_MAX / 2), y + metrics.fBottom)) { + if (quickReject(x, y + metrics.fTop, x + length, y + metrics.fBottom)) { return; } @@ -2298,6 +2297,7 @@ void OpenGLRenderer::drawPath(SkPath* path, SkPaint* paint) { mCaches.activeTexture(0); + // TODO: Perform early clip test before we rasterize the path const PathTexture* texture = mCaches.pathCache.get(path, paint); if (!texture) return; const AutoTexture autoCleanup(texture); diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index 3c2d09e81769..3f63c3fe11a1 100644 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -98,7 +98,7 @@ public: virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op); virtual bool drawDisplayList(DisplayList* displayList, uint32_t width, uint32_t height, - Rect& dirty, uint32_t level = 0); + Rect& dirty, int32_t flags, uint32_t level = 0); virtual void outputDisplayList(DisplayList* displayList, uint32_t level = 0); virtual void drawLayer(Layer* layer, float x, float y, SkPaint* paint); virtual void drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint); diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp index e893f7a95adb..e09c24381d9d 100644 --- a/libs/hwui/PathCache.cpp +++ b/libs/hwui/PathCache.cpp @@ -24,6 +24,23 @@ namespace android { namespace uirenderer { +// Defined in ShapeCache.h +void computePathBounds(const SkPath *path, const SkPaint* paint, + float& left, float& top, float& offset, uint32_t& width, uint32_t& height) { + const SkRect& bounds = path->getBounds(); + + const float pathWidth = fmax(bounds.width(), 1.0f); + const float pathHeight = fmax(bounds.height(), 1.0f); + + left = bounds.fLeft; + top = bounds.fTop; + + offset = (int) floorf(fmax(paint->getStrokeWidth(), 1.0f) * 1.5f + 0.5f); + + width = uint32_t(pathWidth + offset * 2.0 + 0.5); + height = uint32_t(pathHeight + offset * 2.0 + 0.5); +} + /////////////////////////////////////////////////////////////////////////////// // Path cache /////////////////////////////////////////////////////////////////////////////// @@ -69,6 +86,9 @@ PathTexture* PathCache::get(SkPath* path, SkPaint* paint) { PathCacheEntry entry(path, paint); PathTexture* texture = mCache.get(entry); + float left, top, offset; + uint32_t width, height; + if (!texture) { texture = addTexture(entry, path, paint); } else if (path->getGenerationID() != texture->generation) { diff --git a/libs/hwui/ShapeCache.h b/libs/hwui/ShapeCache.h index 30ce69081244..f180e942adc6 100644 --- a/libs/hwui/ShapeCache.h +++ b/libs/hwui/ShapeCache.h @@ -489,18 +489,16 @@ void ShapeCache<Entry>::removeTexture(PathTexture* texture) { } } +void computePathBounds(const SkPath *path, const SkPaint* paint, + float& left, float& top, float& offset, uint32_t& width, uint32_t& height); + template<class Entry> PathTexture* ShapeCache<Entry>::addTexture(const Entry& entry, const SkPath *path, const SkPaint* paint) { - const SkRect& bounds = path->getBounds(); - - const float pathWidth = fmax(bounds.width(), 1.0f); - const float pathHeight = fmax(bounds.height(), 1.0f); - - const float offset = (int) floorf(fmax(paint->getStrokeWidth(), 1.0f) * 1.5f + 0.5f); - const uint32_t width = uint32_t(pathWidth + offset * 2.0 + 0.5); - const uint32_t height = uint32_t(pathHeight + offset * 2.0 + 0.5); + float left, top, offset; + uint32_t width, height; + computePathBounds(path, paint, left, top, offset, width, height); if (width > mMaxTextureSize || height > mMaxTextureSize) { ALOGW("Shape %s too large to be rendered into a texture (%dx%d, max=%dx%d)", @@ -517,8 +515,8 @@ PathTexture* ShapeCache<Entry>::addTexture(const Entry& entry, const SkPath *pat } PathTexture* texture = new PathTexture; - texture->left = bounds.fLeft; - texture->top = bounds.fTop; + texture->left = left; + texture->top = top; texture->offset = offset; texture->width = width; texture->height = height; @@ -542,7 +540,7 @@ PathTexture* ShapeCache<Entry>::addTexture(const Entry& entry, const SkPath *pat SkSafeUnref(pathPaint.setXfermode(mode)); SkCanvas canvas(bitmap); - canvas.translate(-bounds.fLeft + offset, -bounds.fTop + offset); + canvas.translate(-left + offset, -top + offset); canvas.drawPath(*path, pathPaint); generateTexture(bitmap, texture); diff --git a/libs/rs/Android.mk b/libs/rs/Android.mk index 2166ce7dd01f..9c5d06b7333f 100644 --- a/libs/rs/Android.mk +++ b/libs/rs/Android.mk @@ -95,6 +95,7 @@ LOCAL_SRC_FILES:= \ rsMatrix4x4.cpp \ rsMesh.cpp \ rsMutex.cpp \ + rsPath.cpp \ rsProgram.cpp \ rsProgramFragment.cpp \ rsProgramStore.cpp \ @@ -117,6 +118,7 @@ LOCAL_SRC_FILES:= \ driver/rsdGL.cpp \ driver/rsdMesh.cpp \ driver/rsdMeshObj.cpp \ + driver/rsdPath.cpp \ driver/rsdProgram.cpp \ driver/rsdProgramRaster.cpp \ driver/rsdProgramStore.cpp \ @@ -201,6 +203,7 @@ LOCAL_SRC_FILES:= \ rsMatrix4x4.cpp \ rsMesh.cpp \ rsMutex.cpp \ + rsPath.cpp \ rsProgram.cpp \ rsProgramFragment.cpp \ rsProgramStore.cpp \ diff --git a/libs/rs/driver/rsdAllocation.cpp b/libs/rs/driver/rsdAllocation.cpp index fac40f2567cd..fb93d822e8a6 100644 --- a/libs/rs/driver/rsdAllocation.cpp +++ b/libs/rs/driver/rsdAllocation.cpp @@ -23,6 +23,11 @@ #include "rsAllocation.h" +#include "system/window.h" +#include "hardware/gralloc.h" +#include "ui/Rect.h" +#include "ui/GraphicBufferMapper.h" + #include <GLES/gl.h> #include <GLES2/gl2.h> #include <GLES/glext.h> @@ -219,10 +224,14 @@ bool rsdAllocationInit(const Context *rsc, Allocation *alloc, bool forceZero) { return false; } - void * ptr = malloc(alloc->mHal.state.type->getSizeBytes()); - if (!ptr) { - free(drv); - return false; + void * ptr = alloc->mHal.state.usrPtr; + if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_IO_OUTPUT) { + } else { + ptr = malloc(alloc->mHal.state.type->getSizeBytes()); + if (!ptr) { + free(drv); + return false; + } } drv->glTarget = GL_NONE; @@ -245,7 +254,7 @@ bool rsdAllocationInit(const Context *rsc, Allocation *alloc, bool forceZero) { alloc->mHal.drvState.mallocPtr = ptr; drv->mallocPtr = (uint8_t *)ptr; alloc->mHal.drv = drv; - if (forceZero) { + if (forceZero && ptr) { memset(ptr, 0, alloc->mHal.state.type->getSizeBytes()); } @@ -276,7 +285,7 @@ void rsdAllocationDestroy(const Context *rsc, Allocation *alloc) { drv->renderTargetID = 0; } - if (drv->mallocPtr) { + if (drv->mallocPtr && !alloc->mHal.state.usrPtr) { free(drv->mallocPtr); drv->mallocPtr = NULL; } @@ -383,9 +392,96 @@ int32_t rsdAllocationInitSurfaceTexture(const Context *rsc, const Allocation *al return drv->textureID; } +static bool IoGetBuffer(const Context *rsc, Allocation *alloc, ANativeWindow *nw) { + DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; + + int32_t r = nw->dequeueBuffer(nw, &drv->wndBuffer); + if (r) { + rsc->setError(RS_ERROR_DRIVER, "Error getting next IO output buffer."); + return false; + } + + // This lock is implicitly released by the queue buffer in IoSend + r = nw->lockBuffer(nw, drv->wndBuffer); + if (r) { + rsc->setError(RS_ERROR_DRIVER, "Error locking next IO output buffer."); + return false; + } + + // Must lock the whole surface + GraphicBufferMapper &mapper = GraphicBufferMapper::get(); + Rect bounds(drv->wndBuffer->width, drv->wndBuffer->height); + + void *dst = NULL; + mapper.lock(drv->wndBuffer->handle, + GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_OFTEN, + bounds, &dst); + alloc->mHal.drvState.mallocPtr = dst; + return true; +} + +void rsdAllocationSetSurfaceTexture(const Context *rsc, Allocation *alloc, ANativeWindow *nw) { + DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; + + //ALOGE("rsdAllocationSetSurfaceTexture %p %p", alloc, nw); + + // Cleanup old surface if there is one. + if (alloc->mHal.state.wndSurface) { + ANativeWindow *old = alloc->mHal.state.wndSurface; + GraphicBufferMapper &mapper = GraphicBufferMapper::get(); + mapper.unlock(drv->wndBuffer->handle); + old->queueBuffer(old, drv->wndBuffer); + } + + if (nw != NULL) { + int32_t r; + r = native_window_set_usage(nw, GRALLOC_USAGE_SW_READ_RARELY | + GRALLOC_USAGE_SW_WRITE_OFTEN); + if (r) { + rsc->setError(RS_ERROR_DRIVER, "Error setting IO output buffer usage."); + return; + } + + r = native_window_set_buffers_dimensions(nw, alloc->mHal.state.dimensionX, + alloc->mHal.state.dimensionY); + if (r) { + rsc->setError(RS_ERROR_DRIVER, "Error setting IO output buffer dimensions."); + return; + } + + r = native_window_set_buffer_count(nw, 3); + if (r) { + rsc->setError(RS_ERROR_DRIVER, "Error setting IO output buffer count."); + return; + } + + IoGetBuffer(rsc, alloc, nw); + } +} + +void rsdAllocationIoSend(const Context *rsc, Allocation *alloc) { + DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; + ANativeWindow *nw = alloc->mHal.state.wndSurface; + + GraphicBufferMapper &mapper = GraphicBufferMapper::get(); + mapper.unlock(drv->wndBuffer->handle); + int32_t r = nw->queueBuffer(nw, drv->wndBuffer); + if (r) { + rsc->setError(RS_ERROR_DRIVER, "Error sending IO output buffer."); + return; + } + + IoGetBuffer(rsc, alloc, nw); +} + +void rsdAllocationIoReceive(const Context *rsc, Allocation *alloc) { + ALOGE("not implemented"); +} + + void rsdAllocationData1D(const Context *rsc, const Allocation *alloc, uint32_t xoff, uint32_t lod, uint32_t count, - const void *data, uint32_t sizeBytes) { + const void *data, size_t sizeBytes) { DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; const uint32_t eSize = alloc->mHal.state.type->getElementSizeBytes(); @@ -404,7 +500,7 @@ void rsdAllocationData1D(const Context *rsc, const Allocation *alloc, void rsdAllocationData2D(const Context *rsc, const Allocation *alloc, uint32_t xoff, uint32_t yoff, uint32_t lod, RsAllocationCubemapFace face, - uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes) { + uint32_t w, uint32_t h, const void *data, size_t sizeBytes) { DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; uint32_t eSize = alloc->mHal.state.elementSizeBytes; diff --git a/libs/rs/driver/rsdAllocation.h b/libs/rs/driver/rsdAllocation.h index 230804b53ae8..e3a5126383d0 100644 --- a/libs/rs/driver/rsdAllocation.h +++ b/libs/rs/driver/rsdAllocation.h @@ -24,6 +24,7 @@ #include <GLES2/gl2.h> class RsdFrameBufferObj; +struct ANativeWindowBuffer; struct DrvAllocation { // Is this a legal structure to be used as a texture source. @@ -47,6 +48,7 @@ struct DrvAllocation { bool uploadDeferred; RsdFrameBufferObj * readBackFBO; + ANativeWindowBuffer *wndBuffer; }; GLenum rsdTypeToGLType(RsDataType t); @@ -69,6 +71,12 @@ void rsdAllocationMarkDirty(const android::renderscript::Context *rsc, const android::renderscript::Allocation *alloc); int32_t rsdAllocationInitSurfaceTexture(const android::renderscript::Context *rsc, const android::renderscript::Allocation *alloc); +void rsdAllocationSetSurfaceTexture(const android::renderscript::Context *rsc, + android::renderscript::Allocation *alloc, ANativeWindow *nw); +void rsdAllocationIoSend(const android::renderscript::Context *rsc, + android::renderscript::Allocation *alloc); +void rsdAllocationIoReceive(const android::renderscript::Context *rsc, + android::renderscript::Allocation *alloc); void rsdAllocationData1D(const android::renderscript::Context *rsc, const android::renderscript::Allocation *alloc, diff --git a/libs/rs/driver/rsdCore.cpp b/libs/rs/driver/rsdCore.cpp index 998702785abb..bf2b62a69cdb 100644 --- a/libs/rs/driver/rsdCore.cpp +++ b/libs/rs/driver/rsdCore.cpp @@ -18,6 +18,7 @@ #include "rsdAllocation.h" #include "rsdBcc.h" #include "rsdGL.h" +#include "rsdPath.h" #include "rsdProgramStore.h" #include "rsdProgramRaster.h" #include "rsdProgramVertex.h" @@ -73,6 +74,9 @@ static RsdHalFunctions FunctionTable = { rsdAllocationSyncAll, rsdAllocationMarkDirty, rsdAllocationInitSurfaceTexture, + rsdAllocationSetSurfaceTexture, + rsdAllocationIoSend, + rsdAllocationIoReceive, rsdAllocationData1D, rsdAllocationData2D, rsdAllocationData3D, @@ -115,6 +119,13 @@ static RsdHalFunctions FunctionTable = { }, { + rsdPathInitStatic, + rsdPathInitDynamic, + rsdPathDraw, + rsdPathDestroy + }, + + { rsdSamplerInit, rsdSamplerDestroy }, @@ -260,6 +271,9 @@ void SetPriority(const Context *rsc, int32_t priority) { for (uint32_t ct=0; ct < dc->mWorkers.mCount; ct++) { setpriority(PRIO_PROCESS, dc->mWorkers.mNativeThreadId[ct], priority); } + if (dc->mHasGraphics) { + rsdGLSetPriority(rsc, priority); + } } void Shutdown(Context *rsc) { diff --git a/libs/rs/driver/rsdCore.h b/libs/rs/driver/rsdCore.h index 126c87a2f04f..168bdf36e1cb 100644 --- a/libs/rs/driver/rsdCore.h +++ b/libs/rs/driver/rsdCore.h @@ -41,6 +41,7 @@ typedef struct ScriptTLSStructRec { typedef struct RsdHalRec { uint32_t version_major; uint32_t version_minor; + bool mHasGraphics; struct Workers { volatile int mRunningCount; diff --git a/libs/rs/driver/rsdGL.cpp b/libs/rs/driver/rsdGL.cpp index 368dd7107268..b136cc7d767c 100644 --- a/libs/rs/driver/rsdGL.cpp +++ b/libs/rs/driver/rsdGL.cpp @@ -361,6 +361,7 @@ bool rsdGLInit(const Context *rsc) { dc->gl.vertexArrayState = new RsdVertexArrayState(); dc->gl.vertexArrayState->init(dc->gl.gl.maxVertexAttribs); dc->gl.currentFrameBuffer = NULL; + dc->mHasGraphics = true; ALOGV("%p initGLThread end", rsc); rsc->setWatchdogGL(NULL, 0, NULL); @@ -421,6 +422,15 @@ void rsdGLSwap(const android::renderscript::Context *rsc) { RSD_CALL_GL(eglSwapBuffers, dc->gl.egl.display, dc->gl.egl.surface); } +void rsdGLSetPriority(const Context *rsc, int32_t priority) { + if (priority > 0) { + // Mark context as low priority. + ALOGV("low pri"); + } else { + ALOGV("normal pri"); + } +} + void rsdGLCheckError(const android::renderscript::Context *rsc, const char *msg, bool isFatal) { GLenum err = glGetError(); diff --git a/libs/rs/driver/rsdGL.h b/libs/rs/driver/rsdGL.h index 51893c305ec8..e015cb170246 100644 --- a/libs/rs/driver/rsdGL.h +++ b/libs/rs/driver/rsdGL.h @@ -82,6 +82,8 @@ bool rsdGLSetSurface(const android::renderscript::Context *rsc, void rsdGLSwap(const android::renderscript::Context *rsc); void rsdGLCheckError(const android::renderscript::Context *rsc, const char *msg, bool isFatal = false); +void rsdGLSetPriority(const android::renderscript::Context *rsc, + int32_t priority); #endif diff --git a/libs/rs/driver/rsdMesh.cpp b/libs/rs/driver/rsdMesh.cpp index eb62ddb6a845..50daf3eec693 100644 --- a/libs/rs/driver/rsdMesh.cpp +++ b/libs/rs/driver/rsdMesh.cpp @@ -35,7 +35,7 @@ bool rsdMeshInit(const Context *rsc, const Mesh *m) { } drv = new RsdMeshObj(rsc, m); m->mHal.drv = drv; - return drv->init(); + return drv->init(rsc); } void rsdMeshDraw(const Context *rsc, const Mesh *m, uint32_t primIndex, uint32_t start, uint32_t len) { diff --git a/libs/rs/driver/rsdMeshObj.cpp b/libs/rs/driver/rsdMeshObj.cpp index 99d79dceda79..893f046f8e0b 100644 --- a/libs/rs/driver/rsdMeshObj.cpp +++ b/libs/rs/driver/rsdMeshObj.cpp @@ -50,14 +50,9 @@ RsdMeshObj::~RsdMeshObj() { } bool RsdMeshObj::isValidGLComponent(const Element *elem, uint32_t fieldIdx) { - // Do not create attribs for padding - if (elem->getFieldName(fieldIdx)[0] == '#') { - return false; - } - // Only GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_FIXED, GL_FLOAT are accepted. // Filter rs types accordingly - RsDataType dt = elem->getField(fieldIdx)->getComponent().getType(); + RsDataType dt = elem->mHal.state.fields[fieldIdx]->mHal.state.dataType; if (dt != RS_TYPE_FLOAT_32 && dt != RS_TYPE_UNSIGNED_8 && dt != RS_TYPE_UNSIGNED_16 && dt != RS_TYPE_SIGNED_8 && dt != RS_TYPE_SIGNED_16) { @@ -65,7 +60,7 @@ bool RsdMeshObj::isValidGLComponent(const Element *elem, uint32_t fieldIdx) { } // Now make sure they are not arrays - uint32_t arraySize = elem->getFieldArraySize(fieldIdx); + uint32_t arraySize = elem->mHal.state.fieldArraySizes[fieldIdx]; if (arraySize != 1) { return false; } @@ -73,15 +68,15 @@ bool RsdMeshObj::isValidGLComponent(const Element *elem, uint32_t fieldIdx) { return true; } -bool RsdMeshObj::init() { +bool RsdMeshObj::init(const Context *rsc) { - updateGLPrimitives(); + updateGLPrimitives(rsc); // Count the number of gl attrs to initialize mAttribCount = 0; for (uint32_t ct=0; ct < mRSMesh->mHal.state.vertexBuffersCount; ct++) { const Element *elem = mRSMesh->mHal.state.vertexBuffers[ct]->getType()->getElement(); - for (uint32_t ct=0; ct < elem->getFieldCount(); ct++) { + for (uint32_t ct=0; ct < elem->mHal.state.fieldsCount; ct++) { if (isValidGLComponent(elem, ct)) { mAttribCount ++; } @@ -104,21 +99,21 @@ bool RsdMeshObj::init() { uint32_t userNum = 0; for (uint32_t ct=0; ct < mRSMesh->mHal.state.vertexBuffersCount; ct++) { const Element *elem = mRSMesh->mHal.state.vertexBuffers[ct]->getType()->getElement(); - uint32_t stride = elem->getSizeBytes(); - for (uint32_t fieldI=0; fieldI < elem->getFieldCount(); fieldI++) { - const Component &c = elem->getField(fieldI)->getComponent(); + uint32_t stride = elem->mHal.state.elementSizeBytes; + for (uint32_t fieldI=0; fieldI < elem->mHal.state.fieldsCount; fieldI++) { + const Element *f = elem->mHal.state.fields[fieldI]; if (!isValidGLComponent(elem, fieldI)) { continue; } - mAttribs[userNum].size = c.getVectorSize(); - mAttribs[userNum].offset = elem->getFieldOffsetBytes(fieldI); - mAttribs[userNum].type = rsdTypeToGLType(c.getType()); - mAttribs[userNum].normalized = c.getType() != RS_TYPE_FLOAT_32;//c.getIsNormalized(); + mAttribs[userNum].size = f->mHal.state.vectorSize; + mAttribs[userNum].offset = elem->mHal.state.fieldOffsetBytes[fieldI]; + mAttribs[userNum].type = rsdTypeToGLType(f->mHal.state.dataType); + mAttribs[userNum].normalized = f->mHal.state.dataType != RS_TYPE_FLOAT_32; mAttribs[userNum].stride = stride; String8 tmp(RS_SHADER_ATTR); - tmp.append(elem->getFieldName(fieldI)); + tmp.append(elem->mHal.state.fieldNames[fieldI]); mAttribs[userNum].name.setTo(tmp.string()); // Remember which allocation this attribute came from @@ -133,7 +128,7 @@ bool RsdMeshObj::init() { void RsdMeshObj::renderPrimitiveRange(const Context *rsc, uint32_t primIndex, uint32_t start, uint32_t len) const { if (len < 1 || primIndex >= mRSMesh->mHal.state.primitivesCount || mAttribCount == 0) { - ALOGE("Invalid mesh or parameters"); + rsc->setError(RS_ERROR_FATAL_DRIVER, "Invalid mesh or parameters"); return; } @@ -186,7 +181,7 @@ void RsdMeshObj::renderPrimitiveRange(const Context *rsc, uint32_t primIndex, rsdGLCheckError(rsc, "Mesh::renderPrimitiveRange"); } -void RsdMeshObj::updateGLPrimitives() { +void RsdMeshObj::updateGLPrimitives(const Context *rsc) { mGLPrimitives = new uint32_t[mRSMesh->mHal.state.primitivesCount]; for (uint32_t i = 0; i < mRSMesh->mHal.state.primitivesCount; i ++) { switch (mRSMesh->mHal.state.primitives[i]) { @@ -196,6 +191,7 @@ void RsdMeshObj::updateGLPrimitives() { case RS_PRIMITIVE_TRIANGLE: mGLPrimitives[i] = GL_TRIANGLES; break; case RS_PRIMITIVE_TRIANGLE_STRIP: mGLPrimitives[i] = GL_TRIANGLE_STRIP; break; case RS_PRIMITIVE_TRIANGLE_FAN: mGLPrimitives[i] = GL_TRIANGLE_FAN; break; + default: rsc->setError(RS_ERROR_FATAL_DRIVER, "Invalid mesh primitive"); break; } } } diff --git a/libs/rs/driver/rsdMeshObj.h b/libs/rs/driver/rsdMeshObj.h index 8b1271baeaf7..1370f0106bd0 100644 --- a/libs/rs/driver/rsdMeshObj.h +++ b/libs/rs/driver/rsdMeshObj.h @@ -37,15 +37,16 @@ public: const android::renderscript::Mesh *); ~RsdMeshObj(); - void renderPrimitiveRange(const android::renderscript::Context *, uint32_t primIndex, uint32_t start, uint32_t len) const; + void renderPrimitiveRange(const android::renderscript::Context *, + uint32_t primIndex, uint32_t start, uint32_t len) const; - bool init(); + bool init(const android::renderscript::Context *rsc); protected: const android::renderscript::Mesh *mRSMesh; uint32_t *mGLPrimitives; - void updateGLPrimitives(); + void updateGLPrimitives(const android::renderscript::Context *rsc); bool isValidGLComponent(const android::renderscript::Element *elem, uint32_t fieldIdx); // Attribues that allow us to map to GL diff --git a/libs/rs/driver/rsdPath.cpp b/libs/rs/driver/rsdPath.cpp new file mode 100644 index 000000000000..e04bc0258ed1 --- /dev/null +++ b/libs/rs/driver/rsdPath.cpp @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <GLES/gl.h> +#include <GLES2/gl2.h> +#include <GLES/glext.h> + +#include <rs_hal.h> +#include <rsContext.h> +#include <rsPath.h> + +#include "rsdCore.h" +#include "rsdPath.h" +#include "rsdAllocation.h" +#include "rsdGL.h" +#include "rsdVertexArray.h" +#include "rsdShaderCache.h" + +using namespace android; +using namespace android::renderscript; + +class DrvPath { +protected: + DrvPath(); +public: + virtual ~DrvPath(); + virtual void draw(Context *) = 0; +}; + +class DrvPathStatic : public DrvPath { +public: + typedef struct { + float x1, xc, x2; + float y1, yc, y2; + } segment_t; + + segment_t *mSegments; + uint32_t mSegmentCount; + + DrvPathStatic(const Allocation *vtx, const Allocation *loops); + virtual ~DrvPathStatic(); + + virtual void draw(Context *); +}; + +class DrvPathDynamic : public DrvPath { +public: + DrvPathDynamic(); + virtual ~DrvPathDynamic(); +}; + +static void cleanup(const Context *rsc, const Path *m) { + DrvPath *dp = (DrvPath *)m->mHal.drv; + if (dp) { + delete dp; + } +} + +bool rsdPathInitStatic(const Context *rsc, const Path *m, + const Allocation *vtx, const Allocation *loops) { + DrvPathStatic *drv = NULL; + cleanup(rsc, m); + + DrvPathStatic *dps = new DrvPathStatic(vtx, loops); + //LOGE("init path m %p, %p", m, dps); + m->mHal.drv = dps; + return dps != NULL; +} + +bool rsdPathInitDynamic(const Context *rsc, const Path *m) { + return false; +} + + +void rsdPathDraw(const Context *rsc, const Path *m) { + //LOGE("render m=%p", m); + + DrvPath *drv = (DrvPath *)m->mHal.drv; + if(drv) { + //LOGE("render 2 drv=%p", drv); + drv->draw((Context *)rsc); + } +} + +void rsdPathDestroy(const Context *rsc, const Path *m) { + cleanup(rsc, m); + m->mHal.drv = NULL; +} + + + + +DrvPath::DrvPath() { +} + +DrvPath::~DrvPath() { +} + +DrvPathStatic::DrvPathStatic(const Allocation *vtx, const Allocation *loops) { + mSegmentCount = vtx->getType()->getDimX() / 3; + mSegments = new segment_t[mSegmentCount]; + + const float *fin = (const float *)vtx->getPtr(); + for (uint32_t ct=0; ct < mSegmentCount; ct++) { + segment_t *s = &mSegments[ct]; + s->x1 = fin[0]; + s->y1 = fin[1]; + + s->xc = fin[2]; + s->yc = fin[3]; + + s->x2 = fin[4]; + s->y2 = fin[5]; + fin += 6; + } +} + +DrvPathStatic::~DrvPathStatic() { +} + +void DrvPathStatic::draw(Context *rsc) { + const static float color[24] = { + 1.f, 0.f, 0.f, 1.f, 0.5f, 0.f, 0.f, 1.f, + 1.f, 0.f, 0.f, 1.f, 0.5f, 0.f, 0.f, 1.f, + 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f}; + float vtx[12]; + + //LOGE("draw"); + if (!rsc->setupCheck()) { + return; + } + + RsdHal *dc = (RsdHal *)rsc->mHal.drv; + if (!dc->gl.shaderCache->setup(rsc)) { + return; + } + + RsdVertexArray::Attrib attribs[2]; + attribs[0].set(GL_FLOAT, 2, 8, false, (uint32_t)vtx, "ATTRIB_position"); + attribs[1].set(GL_FLOAT, 4, 16, false, (uint32_t)color, "ATTRIB_color"); + RsdVertexArray va(attribs, 2); + va.setup(rsc); + + //LOGE("mSegmentCount %i", mSegmentCount); + for (uint32_t ct=0; ct < mSegmentCount; ct++) { + segment_t *s = &mSegments[ct]; + + vtx[0] = s->x1; + vtx[1] = s->y1; + vtx[2] = s->xc; + vtx[3] = s->yc; + + vtx[4] = s->x2; + vtx[5] = s->y2; + vtx[6] = s->xc; + vtx[7] = s->yc; + + vtx[8] = s->x1; + vtx[9] = s->y1; + vtx[10] = s->x2; + vtx[11] = s->y2; + + RSD_CALL_GL(glDrawArrays, GL_LINES, 0, 6); + } + +} + +DrvPathDynamic::DrvPathDynamic() { +} + +DrvPathDynamic::~DrvPathDynamic() { +} diff --git a/libs/rs/driver/rsdPath.h b/libs/rs/driver/rsdPath.h new file mode 100644 index 000000000000..fa0097245e35 --- /dev/null +++ b/libs/rs/driver/rsdPath.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef RSD_PATH_H +#define RSD_PATH_H + +#include <rs_hal.h> + + +bool rsdPathInitStatic(const android::renderscript::Context *rsc, + const android::renderscript::Path *m, + const android::renderscript::Allocation *vertex, + const android::renderscript::Allocation *loops); +bool rsdPathInitDynamic(const android::renderscript::Context *rsc, + const android::renderscript::Path *m); +void rsdPathDraw(const android::renderscript::Context *rsc, + const android::renderscript::Path *m); +void rsdPathDestroy(const android::renderscript::Context *rsc, + const android::renderscript::Path *m); + + +#endif diff --git a/libs/rs/driver/rsdProgram.cpp b/libs/rs/driver/rsdProgram.cpp index 54484dfced3a..fa4cb0f4a70f 100644 --- a/libs/rs/driver/rsdProgram.cpp +++ b/libs/rs/driver/rsdProgram.cpp @@ -34,8 +34,11 @@ using namespace android; using namespace android::renderscript; bool rsdProgramVertexInit(const Context *rsc, const ProgramVertex *pv, - const char* shader, uint32_t shaderLen) { - RsdShader *drv = new RsdShader(pv, GL_VERTEX_SHADER, shader, shaderLen); + const char* shader, size_t shaderLen, + const char** textureNames, size_t textureNamesCount, + const size_t *textureNamesLength) { + RsdShader *drv = new RsdShader(pv, GL_VERTEX_SHADER, shader, shaderLen, + textureNames, textureNamesCount, textureNamesLength); pv->mHal.drv = drv; return drv->createShader(); @@ -78,8 +81,11 @@ void rsdProgramVertexDestroy(const Context *rsc, const ProgramVertex *pv) { } bool rsdProgramFragmentInit(const Context *rsc, const ProgramFragment *pf, - const char* shader, uint32_t shaderLen) { - RsdShader *drv = new RsdShader(pf, GL_FRAGMENT_SHADER, shader, shaderLen); + const char* shader, size_t shaderLen, + const char** textureNames, size_t textureNamesCount, + const size_t *textureNamesLength) { + RsdShader *drv = new RsdShader(pf, GL_FRAGMENT_SHADER, shader, shaderLen, + textureNames, textureNamesCount, textureNamesLength); pf->mHal.drv = drv; return drv->createShader(); diff --git a/libs/rs/driver/rsdProgramFragment.h b/libs/rs/driver/rsdProgramFragment.h index 366cb40d2962..b03a9fe65ac1 100644 --- a/libs/rs/driver/rsdProgramFragment.h +++ b/libs/rs/driver/rsdProgramFragment.h @@ -22,7 +22,9 @@ bool rsdProgramFragmentInit(const android::renderscript::Context *rsc, const android::renderscript::ProgramFragment *, - const char* shader, uint32_t shaderLen); + const char* shader, size_t shaderLen, + const char** textureNames, size_t textureNamesCount, + const size_t *textureNamesLength); void rsdProgramFragmentSetActive(const android::renderscript::Context *rsc, const android::renderscript::ProgramFragment *); void rsdProgramFragmentDestroy(const android::renderscript::Context *rsc, diff --git a/libs/rs/driver/rsdProgramRaster.cpp b/libs/rs/driver/rsdProgramRaster.cpp index b4937594ba4d..e5a029132d3b 100644 --- a/libs/rs/driver/rsdProgramRaster.cpp +++ b/libs/rs/driver/rsdProgramRaster.cpp @@ -45,6 +45,9 @@ void rsdProgramRasterSetActive(const Context *rsc, const ProgramRaster *pr) { case RS_CULL_NONE: RSD_CALL_GL(glDisable, GL_CULL_FACE); break; + default: + rsc->setError(RS_ERROR_FATAL_DRIVER, "Invalid cull type"); + break; } } diff --git a/libs/rs/driver/rsdProgramStore.cpp b/libs/rs/driver/rsdProgramStore.cpp index fca9ba9e11e8..c1295e8b1d86 100644 --- a/libs/rs/driver/rsdProgramStore.cpp +++ b/libs/rs/driver/rsdProgramStore.cpp @@ -111,7 +111,7 @@ bool rsdProgramStoreInit(const Context *rsc, const ProgramStore *ps) { drv->blendSrc = GL_SRC_ALPHA_SATURATE; break; default: - ALOGE("Unknown blend src mode."); + rsc->setError(RS_ERROR_FATAL_DRIVER, "Unknown blend src mode."); goto error; } @@ -141,7 +141,7 @@ bool rsdProgramStoreInit(const Context *rsc, const ProgramStore *ps) { drv->blendDst = GL_ONE_MINUS_DST_ALPHA; break; default: - ALOGE("Unknown blend dst mode."); + rsc->setError(RS_ERROR_FATAL_DRIVER, "Unknown blend dst mode."); goto error; } diff --git a/libs/rs/driver/rsdProgramVertex.h b/libs/rs/driver/rsdProgramVertex.h index e99857298165..f917a4123747 100644 --- a/libs/rs/driver/rsdProgramVertex.h +++ b/libs/rs/driver/rsdProgramVertex.h @@ -21,7 +21,9 @@ bool rsdProgramVertexInit(const android::renderscript::Context *rsc, const android::renderscript::ProgramVertex *, - const char* shader, uint32_t shaderLen); + const char* shader, size_t shaderLen, + const char** textureNames, size_t textureNamesCount, + const size_t *textureNamesLength); void rsdProgramVertexSetActive(const android::renderscript::Context *rsc, const android::renderscript::ProgramVertex *); void rsdProgramVertexDestroy(const android::renderscript::Context *rsc, diff --git a/libs/rs/driver/rsdRuntimeStubs.cpp b/libs/rs/driver/rsdRuntimeStubs.cpp index 14c297004f44..44bfb1c8fe9f 100644 --- a/libs/rs/driver/rsdRuntimeStubs.cpp +++ b/libs/rs/driver/rsdRuntimeStubs.cpp @@ -25,6 +25,7 @@ #include "rsdCore.h" #include "rsdRuntime.h" +#include "rsdPath.h" #include <time.h> @@ -89,6 +90,16 @@ static void SC_BindTexture(ProgramFragment *pf, uint32_t slot, Allocation *a) { rsrBindTexture(rsc, sc, pf, slot, a); } +static void SC_BindVertexConstant(ProgramVertex *pv, uint32_t slot, Allocation *a) { + GET_TLS(); + rsrBindConstant(rsc, sc, pv, slot, a); +} + +static void SC_BindFragmentConstant(ProgramFragment *pf, uint32_t slot, Allocation *a) { + GET_TLS(); + rsrBindConstant(rsc, sc, pf, slot, a); +} + static void SC_BindSampler(ProgramFragment *pf, uint32_t slot, Sampler *s) { GET_TLS(); rsrBindSampler(rsc, sc, pf, slot, s); @@ -204,6 +215,12 @@ static void SC_DrawRect(float x1, float y1, float x2, float y2, float z) { rsrDrawRect(rsc, sc, x1, y1, x2, y2, z); } +static void SC_DrawPath(Path *p) { + GET_TLS(); + //rsrDrawPath(rsc, sc, p); + rsdPathDraw(rsc, p); +} + static void SC_DrawMesh(Mesh *m) { GET_TLS(); rsrDrawMesh(rsc, sc, m); @@ -533,6 +550,10 @@ static RsdSymbolTable gSyms[] = { { "_Z13rsClearObjectP9rs_script", (void *)&SC_ClearObject, true }, { "_Z10rsIsObject9rs_script", (void *)&SC_IsObject, true }, + { "_Z11rsSetObjectP7rs_pathS_", (void *)&SC_SetObject, true }, + { "_Z13rsClearObjectP7rs_path", (void *)&SC_ClearObject, true }, + { "_Z10rsIsObject7rs_path", (void *)&SC_IsObject, true }, + { "_Z11rsSetObjectP7rs_meshS_", (void *)&SC_SetObject, true }, { "_Z13rsClearObjectP7rs_mesh", (void *)&SC_ClearObject, true }, { "_Z10rsIsObject7rs_mesh", (void *)&SC_IsObject, true }, @@ -580,6 +601,8 @@ static RsdSymbolTable gSyms[] = { { "_Z20rsgBindProgramRaster17rs_program_raster", (void *)&SC_BindProgramRaster, false }, { "_Z14rsgBindSampler19rs_program_fragmentj10rs_sampler", (void *)&SC_BindSampler, false }, { "_Z14rsgBindTexture19rs_program_fragmentj13rs_allocation", (void *)&SC_BindTexture, false }, + { "_Z15rsgBindConstant19rs_program_fragmentj13rs_allocation", (void *)&SC_BindFragmentConstant, false }, + { "_Z15rsgBindConstant17rs_program_vertexj13rs_allocation", (void *)&SC_BindVertexConstant, false }, { "_Z36rsgProgramVertexLoadProjectionMatrixPK12rs_matrix4x4", (void *)&SC_VpLoadProjectionMatrix, false }, { "_Z31rsgProgramVertexLoadModelMatrixPK12rs_matrix4x4", (void *)&SC_VpLoadModelMatrix, false }, @@ -603,6 +626,8 @@ static RsdSymbolTable gSyms[] = { { "_Z11rsgDrawMesh7rs_meshjjj", (void *)&SC_DrawMeshPrimitiveRange, false }, { "_Z25rsgMeshComputeBoundingBox7rs_meshPfS0_S0_S0_S0_S0_", (void *)&SC_MeshComputeBoundingBox, false }, + { "_Z11rsgDrawPath7rs_path", (void *)&SC_DrawPath, false }, + { "_Z13rsgClearColorffff", (void *)&SC_ClearColor, false }, { "_Z13rsgClearDepthf", (void *)&SC_ClearDepth, false }, diff --git a/libs/rs/driver/rsdShader.cpp b/libs/rs/driver/rsdShader.cpp index 056a33afca45..1e73b95b6cd6 100644 --- a/libs/rs/driver/rsdShader.cpp +++ b/libs/rs/driver/rsdShader.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 The Android Open Source Project + * Copyright (C) 2011-2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,14 +30,16 @@ using namespace android; using namespace android::renderscript; RsdShader::RsdShader(const Program *p, uint32_t type, - const char * shaderText, uint32_t shaderLength) { - + const char * shaderText, size_t shaderLength, + const char** textureNames, size_t textureNamesCount, + const size_t *textureNamesLength) { mUserShader.setTo(shaderText, shaderLength); mRSProgram = p; mType = type; initMemberVars(); initAttribAndUniformArray(); - init(); + init(textureNames, textureNamesCount, textureNamesLength); + createTexturesString(textureNames, textureNamesCount, textureNamesLength); } RsdShader::~RsdShader() { @@ -65,37 +67,38 @@ void RsdShader::initMemberVars() { mIsValid = false; } -void RsdShader::init() { +void RsdShader::init(const char** textureNames, size_t textureNamesCount, + const size_t *textureNamesLength) { uint32_t attribCount = 0; uint32_t uniformCount = 0; for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) { - initAddUserElement(mRSProgram->mHal.state.inputElements[ct], mAttribNames, NULL, &attribCount, RS_SHADER_ATTR); + initAddUserElement(mRSProgram->mHal.state.inputElements[ct], mAttribNames, + NULL, &attribCount, RS_SHADER_ATTR); } for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) { - initAddUserElement(mRSProgram->mHal.state.constantTypes[ct]->getElement(), mUniformNames, mUniformArraySizes, &uniformCount, RS_SHADER_UNI); + initAddUserElement(mRSProgram->mHal.state.constantTypes[ct]->getElement(), + mUniformNames, mUniformArraySizes, &uniformCount, RS_SHADER_UNI); } mTextureUniformIndexStart = uniformCount; - char buf[256]; for (uint32_t ct=0; ct < mRSProgram->mHal.state.texturesCount; ct++) { - snprintf(buf, sizeof(buf), "UNI_Tex%i", ct); - mUniformNames[uniformCount].setTo(buf); + mUniformNames[uniformCount].setTo("UNI_"); + mUniformNames[uniformCount].append(textureNames[ct], textureNamesLength[ct]); mUniformArraySizes[uniformCount] = 1; uniformCount++; } - } String8 RsdShader::getGLSLInputString() const { String8 s; for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) { const Element *e = mRSProgram->mHal.state.inputElements[ct]; - for (uint32_t field=0; field < e->getFieldCount(); field++) { - const Element *f = e->getField(field); + for (uint32_t field=0; field < e->mHal.state.fieldsCount; field++) { + const Element *f = e->mHal.state.fields[field]; // Cannot be complex - rsAssert(!f->getFieldCount()); - switch (f->getComponent().getVectorSize()) { + rsAssert(!f->mHal.state.fieldsCount); + switch (f->mHal.state.vectorSize) { case 1: s.append("attribute float ATTRIB_"); break; case 2: s.append("attribute vec2 ATTRIB_"); break; case 3: s.append("attribute vec3 ATTRIB_"); break; @@ -104,7 +107,7 @@ String8 RsdShader::getGLSLInputString() const { rsAssert(0); } - s.append(e->getFieldName(field)); + s.append(e->mHal.state.fieldNames[field]); s.append(";\n"); } } @@ -114,17 +117,13 @@ String8 RsdShader::getGLSLInputString() const { void RsdShader::appendAttributes() { for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) { const Element *e = mRSProgram->mHal.state.inputElements[ct]; - for (uint32_t field=0; field < e->getFieldCount(); field++) { - const Element *f = e->getField(field); - const char *fn = e->getFieldName(field); - - if (fn[0] == '#') { - continue; - } + for (uint32_t field=0; field < e->mHal.state.fieldsCount; field++) { + const Element *f = e->mHal.state.fields[field]; + const char *fn = e->mHal.state.fieldNames[field]; // Cannot be complex - rsAssert(!f->getFieldCount()); - switch (f->getComponent().getVectorSize()) { + rsAssert(!f->mHal.state.fieldsCount); + switch (f->mHal.state.vectorSize) { case 1: mShader.append("attribute float ATTRIB_"); break; case 2: mShader.append("attribute vec2 ATTRIB_"); break; case 3: mShader.append("attribute vec3 ATTRIB_"); break; @@ -139,22 +138,25 @@ void RsdShader::appendAttributes() { } } -void RsdShader::appendTextures() { - char buf[256]; - for (uint32_t ct=0; ct < mRSProgram->mHal.state.texturesCount; ct++) { +void RsdShader::createTexturesString(const char** textureNames, size_t textureNamesCount, + const size_t *textureNamesLength) { + mShaderTextures.setTo(""); + for (uint32_t ct = 0; ct < mRSProgram->mHal.state.texturesCount; ct ++) { if (mRSProgram->mHal.state.textureTargets[ct] == RS_TEXTURE_2D) { Allocation *a = mRSProgram->mHal.state.textures[ct]; if (a && a->mHal.state.surfaceTextureID) { - snprintf(buf, sizeof(buf), "uniform samplerExternalOES UNI_Tex%i;\n", ct); + mShaderTextures.append("uniform samplerExternalOES UNI_"); } else { - snprintf(buf, sizeof(buf), "uniform sampler2D UNI_Tex%i;\n", ct); + mShaderTextures.append("uniform sampler2D UNI_"); } mTextureTargets[ct] = GL_TEXTURE_2D; } else { - snprintf(buf, sizeof(buf), "uniform samplerCube UNI_Tex%i;\n", ct); + mShaderTextures.append("uniform samplerCube UNI_"); mTextureTargets[ct] = GL_TEXTURE_CUBE_MAP; } - mShader.append(buf); + + mShaderTextures.append(textureNames[ct], textureNamesLength[ct]); + mShaderTextures.append(";\n"); } } @@ -165,7 +167,7 @@ bool RsdShader::createShader() { } appendUserConstants(); appendAttributes(); - appendTextures(); + mShader.append(mShaderTextures); mShader.append(mUserShader); @@ -215,24 +217,20 @@ bool RsdShader::loadShader(const Context *rsc) { void RsdShader::appendUserConstants() { for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) { const Element *e = mRSProgram->mHal.state.constantTypes[ct]->getElement(); - for (uint32_t field=0; field < e->getFieldCount(); field++) { - const Element *f = e->getField(field); - const char *fn = e->getFieldName(field); - - if (fn[0] == '#') { - continue; - } + for (uint32_t field=0; field < e->mHal.state.fieldsCount; field++) { + const Element *f = e->mHal.state.fields[field]; + const char *fn = e->mHal.state.fieldNames[field]; // Cannot be complex - rsAssert(!f->getFieldCount()); - if (f->getType() == RS_TYPE_MATRIX_4X4) { + rsAssert(!f->mHal.state.fieldsCount); + if (f->mHal.state.dataType == RS_TYPE_MATRIX_4X4) { mShader.append("uniform mat4 UNI_"); - } else if (f->getType() == RS_TYPE_MATRIX_3X3) { + } else if (f->mHal.state.dataType == RS_TYPE_MATRIX_3X3) { mShader.append("uniform mat3 UNI_"); - } else if (f->getType() == RS_TYPE_MATRIX_2X2) { + } else if (f->mHal.state.dataType == RS_TYPE_MATRIX_2X2) { mShader.append("uniform mat2 UNI_"); } else { - switch (f->getComponent().getVectorSize()) { + switch (f->mHal.state.vectorSize) { case 1: mShader.append("uniform float UNI_"); break; case 2: mShader.append("uniform vec2 UNI_"); break; case 3: mShader.append("uniform vec3 UNI_"); break; @@ -243,8 +241,8 @@ void RsdShader::appendUserConstants() { } mShader.append(fn); - if (e->getFieldArraySize(field) > 1) { - mShader.appendFormat("[%d]", e->getFieldArraySize(field)); + if (e->mHal.state.fieldArraySizes[field] > 1) { + mShader.appendFormat("[%d]", e->mHal.state.fieldArraySizes[field]); } mShader.append(";\n"); } @@ -252,8 +250,8 @@ void RsdShader::appendUserConstants() { } void RsdShader::logUniform(const Element *field, const float *fd, uint32_t arraySize ) { - RsDataType dataType = field->getType(); - uint32_t elementSize = field->getSizeBytes() / sizeof(float); + RsDataType dataType = field->mHal.state.dataType; + uint32_t elementSize = field->mHal.state.elementSizeBytes / sizeof(float); for (uint32_t i = 0; i < arraySize; i ++) { if (arraySize > 1) { ALOGV("Array Element [%u]", i); @@ -274,7 +272,7 @@ void RsdShader::logUniform(const Element *field, const float *fd, uint32_t array ALOGV("{%f, %f", fd[0], fd[2]); ALOGV(" %f, %f}", fd[1], fd[3]); } else { - switch (field->getComponent().getVectorSize()) { + switch (field->mHal.state.vectorSize) { case 1: ALOGV("Uniform 1 = %f", fd[0]); break; @@ -299,7 +297,7 @@ void RsdShader::logUniform(const Element *field, const float *fd, uint32_t array void RsdShader::setUniform(const Context *rsc, const Element *field, const float *fd, int32_t slot, uint32_t arraySize ) { - RsDataType dataType = field->getType(); + RsDataType dataType = field->mHal.state.dataType; if (dataType == RS_TYPE_MATRIX_4X4) { RSD_CALL_GL(glUniformMatrix4fv, slot, arraySize, GL_FALSE, fd); } else if (dataType == RS_TYPE_MATRIX_3X3) { @@ -307,7 +305,7 @@ void RsdShader::setUniform(const Context *rsc, const Element *field, const float } else if (dataType == RS_TYPE_MATRIX_2X2) { RSD_CALL_GL(glUniformMatrix2fv, slot, arraySize, GL_FALSE, fd); } else { - switch (field->getComponent().getVectorSize()) { + switch (field->mHal.state.vectorSize) { case 1: RSD_CALL_GL(glUniform1fv, slot, arraySize, fd); break; @@ -426,7 +424,8 @@ void RsdShader::setupTextures(const Context *rsc, RsdShaderCache *sc) { DrvAllocation *drvTex = (DrvAllocation *)mRSProgram->mHal.state.textures[ct]->mHal.drv; if (drvTex->glTarget != GL_TEXTURE_2D && drvTex->glTarget != GL_TEXTURE_CUBE_MAP) { - ALOGE("Attempting to bind unknown texture to shader id %u, texture unit %u", (uint)this, ct); + ALOGE("Attempting to bind unknown texture to shader id %u, texture unit %u", + (uint)this, ct); rsc->setError(RS_ERROR_BAD_SHADER, "Non-texture allocation bound to a shader"); } RSD_CALL_GL(glBindTexture, drvTex->glTarget, drvTex->textureID); @@ -462,15 +461,11 @@ void RsdShader::setupUserConstants(const Context *rsc, RsdShaderCache *sc, bool const uint8_t *data = static_cast<const uint8_t *>(alloc->getPtr()); const Element *e = mRSProgram->mHal.state.constantTypes[ct]->getElement(); - for (uint32_t field=0; field < e->getFieldCount(); field++) { - const Element *f = e->getField(field); - const char *fieldName = e->getFieldName(field); - // If this field is padding, skip it - if (fieldName[0] == '#') { - continue; - } + for (uint32_t field=0; field < e->mHal.state.fieldsCount; field++) { + const Element *f = e->mHal.state.fields[field]; + const char *fieldName = e->mHal.state.fieldNames[field]; - uint32_t offset = e->getFieldOffsetBytes(field); + uint32_t offset = e->mHal.state.fieldOffsetBytes[field]; const float *fd = reinterpret_cast<const float *>(&data[offset]); int32_t slot = -1; @@ -509,22 +504,13 @@ void RsdShader::initAttribAndUniformArray() { mAttribCount = 0; for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) { const Element *elem = mRSProgram->mHal.state.inputElements[ct]; - for (uint32_t field=0; field < elem->getFieldCount(); field++) { - if (elem->getFieldName(field)[0] != '#') { - mAttribCount ++; - } - } + mAttribCount += elem->mHal.state.fieldsCount; } mUniformCount = 0; for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) { const Element *elem = mRSProgram->mHal.state.constantTypes[ct]->getElement(); - - for (uint32_t field=0; field < elem->getFieldCount(); field++) { - if (elem->getFieldName(field)[0] != '#') { - mUniformCount ++; - } - } + mUniformCount += elem->mHal.state.fieldsCount; } mUniformCount += mRSProgram->mHal.state.texturesCount; @@ -544,17 +530,17 @@ void RsdShader::initAttribAndUniformArray() { void RsdShader::initAddUserElement(const Element *e, String8 *names, uint32_t *arrayLengths, uint32_t *count, const char *prefix) { - rsAssert(e->getFieldCount()); - for (uint32_t ct=0; ct < e->getFieldCount(); ct++) { - const Element *ce = e->getField(ct); - if (ce->getFieldCount()) { + rsAssert(e->mHal.state.fieldsCount); + for (uint32_t ct=0; ct < e->mHal.state.fieldsCount; ct++) { + const Element *ce = e->mHal.state.fields[ct]; + if (ce->mHal.state.fieldsCount) { initAddUserElement(ce, names, arrayLengths, count, prefix); - } else if (e->getFieldName(ct)[0] != '#') { + } else { String8 tmp(prefix); - tmp.append(e->getFieldName(ct)); + tmp.append(e->mHal.state.fieldNames[ct]); names[*count].setTo(tmp.string()); if (arrayLengths) { - arrayLengths[*count] = e->getFieldArraySize(ct); + arrayLengths[*count] = e->mHal.state.fieldArraySizes[ct]; } (*count)++; } diff --git a/libs/rs/driver/rsdShader.h b/libs/rs/driver/rsdShader.h index 3f0d6eae909e..e32145fad548 100644 --- a/libs/rs/driver/rsdShader.h +++ b/libs/rs/driver/rsdShader.h @@ -39,7 +39,9 @@ class RsdShader { public: RsdShader(const android::renderscript::Program *p, uint32_t type, - const char * shaderText, uint32_t shaderLength); + const char * shaderText, uint32_t shaderLength, + const char** textureNames, size_t textureNamesCount, + const size_t *textureNamesLength); virtual ~RsdShader(); bool createShader(); @@ -67,19 +69,27 @@ protected: // Applies to vertex and fragment shaders only void appendUserConstants(); - void setupUserConstants(const android::renderscript::Context *rsc, RsdShaderCache *sc, bool isFragment); - void initAddUserElement(const android::renderscript::Element *e, android::String8 *names, uint32_t *arrayLengths, uint32_t *count, const char *prefix); + void setupUserConstants(const android::renderscript::Context *rsc, + RsdShaderCache *sc, bool isFragment); + void initAddUserElement(const android::renderscript::Element *e, + android::String8 *names, uint32_t *arrayLengths, + uint32_t *count, const char *prefix); void setupTextures(const android::renderscript::Context *rsc, RsdShaderCache *sc); - void setupSampler(const android::renderscript::Context *rsc, const android::renderscript::Sampler *s, const android::renderscript::Allocation *tex); + void setupSampler(const android::renderscript::Context *rsc, + const android::renderscript::Sampler *s, + const android::renderscript::Allocation *tex); void appendAttributes(); void appendTextures(); + void createTexturesString(const char** textureNames, size_t textureNamesCount, + const size_t *textureNamesLength); void initAttribAndUniformArray(); mutable bool mDirty; android::String8 mShader; android::String8 mUserShader; + android::String8 mShaderTextures; uint32_t mShaderID; uint32_t mType; @@ -93,10 +103,14 @@ protected: int32_t mTextureUniformIndexStart; - void logUniform(const android::renderscript::Element *field, const float *fd, uint32_t arraySize ); - void setUniform(const android::renderscript::Context *rsc, const android::renderscript::Element *field, const float *fd, int32_t slot, uint32_t arraySize ); + void logUniform(const android::renderscript::Element *field, + const float *fd, uint32_t arraySize); + void setUniform(const android::renderscript::Context *rsc, + const android::renderscript::Element *field, + const float *fd, int32_t slot, uint32_t arraySize ); void initMemberVars(); - void init(); + void init(const char** textureNames, size_t textureNamesCount, + const size_t *textureNamesLength); }; #endif //ANDROID_RSD_SHADER_H diff --git a/libs/rs/driver/rsdShaderCache.h b/libs/rs/driver/rsdShaderCache.h index d64780bdde2c..0beecaed4e41 100644 --- a/libs/rs/driver/rsdShaderCache.h +++ b/libs/rs/driver/rsdShaderCache.h @@ -98,7 +98,8 @@ protected: struct ProgramEntry { ProgramEntry(uint32_t numVtxAttr, uint32_t numVtxUnis, uint32_t numFragUnis) : vtx(0), frag(0), program(0), vtxAttrCount(0), - vtxAttrs(0), vtxUniforms(0), fragUniforms(0) { + vtxAttrs(0), vtxUniforms(0), fragUniforms(0), + fragUniformIsSTO(0) { vtxAttrCount = numVtxAttr; if (numVtxAttr) { vtxAttrs = new AttrData[numVtxAttr]; diff --git a/libs/rs/RenderScript.h b/libs/rs/rs.h index 6d5426882bda..fbcaf4a2e413 100644 --- a/libs/rs/RenderScript.h +++ b/libs/rs/rs.h @@ -24,7 +24,7 @@ extern "C" { #endif -#include "RenderScriptDefines.h" +#include "rsDefines.h" // // A3D loading and object update code. diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec index 09a29863f30b..cf4a3918771c 100644 --- a/libs/rs/rs.spec +++ b/libs/rs/rs.spec @@ -42,6 +42,7 @@ AllocationCreateTyped { param RsType vtype param RsAllocationMipmapControl mips param uint32_t usages + param uint32_t ptr ret RsAllocation } @@ -68,168 +69,183 @@ AllocationGetSurfaceTextureID { ret int32_t } +AllocationSetSurface { + param RsAllocation alloc + param RsNativeWindow sur + sync + } + +AllocationIoSend { + param RsAllocation alloc + } + +AllocationIoReceive { + param RsAllocation alloc + } + + ContextFinish { - sync - } + sync + } ContextBindRootScript { - param RsScript sampler - } + param RsScript sampler + } ContextBindProgramStore { - param RsProgramStore pgm - } + param RsProgramStore pgm + } ContextBindProgramFragment { - param RsProgramFragment pgm - } + param RsProgramFragment pgm + } ContextBindProgramVertex { - param RsProgramVertex pgm - } + param RsProgramVertex pgm + } ContextBindProgramRaster { - param RsProgramRaster pgm - } + param RsProgramRaster pgm + } ContextBindFont { - param RsFont pgm - } + param RsFont pgm + } ContextPause { - } + } ContextResume { - } + } ContextSetSurface { - param uint32_t width - param uint32_t height - param RsNativeWindow sur + param uint32_t width + param uint32_t height + param RsNativeWindow sur sync - } + } ContextDump { - param int32_t bits + param int32_t bits } ContextSetPriority { - param int32_t priority - } + param int32_t priority + } ContextDestroyWorker { sync } AssignName { - param RsObjectBase obj - param const char *name - } + param RsObjectBase obj + param const char *name + } ObjDestroy { - param RsAsyncVoidPtr objPtr - } + param RsAsyncVoidPtr objPtr + } ElementCreate { direct - param RsDataType mType - param RsDataKind mKind - param bool mNormalized - param uint32_t mVectorSize - ret RsElement - } + param RsDataType mType + param RsDataKind mKind + param bool mNormalized + param uint32_t mVectorSize + ret RsElement + } ElementCreate2 { direct - param const RsElement * elements - param const char ** names - param const uint32_t * arraySize - ret RsElement - } + param const RsElement * elements + param const char ** names + param const uint32_t * arraySize + ret RsElement + } AllocationCopyToBitmap { - param RsAllocation alloc - param void * data - } + param RsAllocation alloc + param void * data + } Allocation1DData { - param RsAllocation va - param uint32_t xoff - param uint32_t lod - param uint32_t count - param const void *data - } + param RsAllocation va + param uint32_t xoff + param uint32_t lod + param uint32_t count + param const void *data + } Allocation1DElementData { - param RsAllocation va - param uint32_t x - param uint32_t lod - param const void *data - param size_t comp_offset - } + param RsAllocation va + param uint32_t x + param uint32_t lod + param const void *data + param size_t comp_offset + } Allocation2DData { - param RsAllocation va - param uint32_t xoff - param uint32_t yoff - param uint32_t lod - param RsAllocationCubemapFace face - param uint32_t w - param uint32_t h - param const void *data - } + param RsAllocation va + param uint32_t xoff + param uint32_t yoff + param uint32_t lod + param RsAllocationCubemapFace face + param uint32_t w + param uint32_t h + param const void *data + } Allocation2DElementData { - param RsAllocation va - param uint32_t x - param uint32_t y - param uint32_t lod - param RsAllocationCubemapFace face - param const void *data - param size_t element_offset - } + param RsAllocation va + param uint32_t x + param uint32_t y + param uint32_t lod + param RsAllocationCubemapFace face + param const void *data + param size_t element_offset + } AllocationGenerateMipmaps { - param RsAllocation va + param RsAllocation va } AllocationRead { - param RsAllocation va - param void * data - } + param RsAllocation va + param void * data + } AllocationSyncAll { - param RsAllocation va - param RsAllocationUsageType src + param RsAllocation va + param RsAllocationUsageType src } AllocationResize1D { - param RsAllocation va - param uint32_t dimX - } + param RsAllocation va + param uint32_t dimX + } AllocationResize2D { - param RsAllocation va - param uint32_t dimX - param uint32_t dimY - } + param RsAllocation va + param uint32_t dimX + param uint32_t dimY + } AllocationCopy2DRange { - param RsAllocation dest - param uint32_t destXoff - param uint32_t destYoff - param uint32_t destMip - param uint32_t destFace - param uint32_t width - param uint32_t height - param RsAllocation src - param uint32_t srcXoff - param uint32_t srcYoff - param uint32_t srcMip - param uint32_t srcFace - } + param RsAllocation dest + param uint32_t destXoff + param uint32_t destYoff + param uint32_t destMip + param uint32_t destFace + param uint32_t width + param uint32_t height + param RsAllocation src + param uint32_t srcXoff + param uint32_t srcYoff + param uint32_t srcMip + param uint32_t srcFace + } SamplerCreate { direct @@ -243,26 +259,26 @@ SamplerCreate { } ScriptBindAllocation { - param RsScript vtm - param RsAllocation va - param uint32_t slot - } + param RsScript vtm + param RsAllocation va + param uint32_t slot + } ScriptSetTimeZone { - param RsScript s - param const char * timeZone - } + param RsScript s + param const char * timeZone + } ScriptInvoke { - param RsScript s - param uint32_t slot - } + param RsScript s + param uint32_t slot + } ScriptInvokeV { - param RsScript s - param uint32_t slot - param const void * data - } + param RsScript s + param uint32_t slot + param const void * data + } ScriptForEach { param RsScript s @@ -273,122 +289,133 @@ ScriptForEach { } ScriptSetVarI { - param RsScript s - param uint32_t slot - param int value - } + param RsScript s + param uint32_t slot + param int value + } ScriptSetVarObj { - param RsScript s - param uint32_t slot - param RsObjectBase value - } + param RsScript s + param uint32_t slot + param RsObjectBase value + } ScriptSetVarJ { - param RsScript s - param uint32_t slot - param int64_t value - } + param RsScript s + param uint32_t slot + param int64_t value + } ScriptSetVarF { - param RsScript s - param uint32_t slot - param float value - } + param RsScript s + param uint32_t slot + param float value + } ScriptSetVarD { - param RsScript s - param uint32_t slot - param double value - } + param RsScript s + param uint32_t slot + param double value + } ScriptSetVarV { - param RsScript s - param uint32_t slot - param const void * data - } + param RsScript s + param uint32_t slot + param const void * data + } ScriptCCreate { param const char * resName param const char * cacheDir - param const char * text - ret RsScript - } + param const char * text + ret RsScript + } ProgramStoreCreate { - direct - param bool colorMaskR - param bool colorMaskG - param bool colorMaskB - param bool colorMaskA + direct + param bool colorMaskR + param bool colorMaskG + param bool colorMaskB + param bool colorMaskA param bool depthMask param bool ditherEnable - param RsBlendSrcFunc srcFunc - param RsBlendDstFunc destFunc + param RsBlendSrcFunc srcFunc + param RsBlendDstFunc destFunc param RsDepthFunc depthFunc - ret RsProgramStore - } + ret RsProgramStore + } ProgramRasterCreate { - direct - param bool pointSprite - param RsCullMode cull - ret RsProgramRaster + direct + param bool pointSprite + param RsCullMode cull + ret RsProgramRaster } ProgramBindConstants { - param RsProgram vp - param uint32_t slot - param RsAllocation constants - } + param RsProgram vp + param uint32_t slot + param RsAllocation constants + } ProgramBindTexture { - param RsProgramFragment pf - param uint32_t slot - param RsAllocation a - } + param RsProgramFragment pf + param uint32_t slot + param RsAllocation a + } ProgramBindSampler { - param RsProgramFragment pf - param uint32_t slot - param RsSampler s - } + param RsProgramFragment pf + param uint32_t slot + param RsSampler s + } ProgramFragmentCreate { - direct - param const char * shaderText - param const uint32_t * params - ret RsProgramFragment - } + direct + param const char * shaderText + param const char ** textureNames + param const uint32_t * params + ret RsProgramFragment + } ProgramVertexCreate { - direct - param const char * shaderText - param const uint32_t * params - ret RsProgramVertex - } + direct + param const char * shaderText + param const char ** textureNames + param const uint32_t * params + ret RsProgramVertex + } FontCreateFromFile { - param const char *name - param float fontSize - param uint32_t dpi - ret RsFont - } + param const char *name + param float fontSize + param uint32_t dpi + ret RsFont + } FontCreateFromMemory { - param const char *name - param float fontSize - param uint32_t dpi - param const void *data - ret RsFont - } + param const char *name + param float fontSize + param uint32_t dpi + param const void *data + ret RsFont + } MeshCreate { - param RsAllocation *vtx - param RsAllocation *idx - param uint32_t *primType - ret RsMesh - } + param RsAllocation *vtx + param RsAllocation *idx + param uint32_t *primType + ret RsMesh + } + +PathCreate { + param RsPathPrimitive pp + param bool isStatic + param RsAllocation vertex + param RsAllocation loops + param float quality + ret RsPath + } diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp index 5f45abff2b9c..83c88fdffacf 100644 --- a/libs/rs/rsAllocation.cpp +++ b/libs/rs/rsAllocation.cpp @@ -17,32 +17,35 @@ #include "rsContext.h" #include "rs_hal.h" +#include "system/window.h" using namespace android; using namespace android::renderscript; Allocation::Allocation(Context *rsc, const Type *type, uint32_t usages, - RsAllocationMipmapControl mc) + RsAllocationMipmapControl mc, void * ptr) : ObjectBase(rsc) { memset(&mHal, 0, sizeof(mHal)); mHal.state.mipmapControl = RS_ALLOCATION_MIPMAP_NONE; mHal.state.usageFlags = usages; mHal.state.mipmapControl = mc; + mHal.state.usrPtr = ptr; setType(type); updateCache(); } Allocation * Allocation::createAllocation(Context *rsc, const Type *type, uint32_t usages, - RsAllocationMipmapControl mc) { - Allocation *a = new Allocation(rsc, type, usages, mc); + RsAllocationMipmapControl mc, void * ptr) { + Allocation *a = new Allocation(rsc, type, usages, mc, ptr); if (!rsc->mHal.funcs.allocation.init(rsc, a, type->getElement()->getHasReferences())) { rsc->setError(RS_ERROR_FATAL_DRIVER, "Allocation::Allocation, alloc failure"); delete a; return NULL; } + return a; } @@ -419,6 +422,28 @@ int32_t Allocation::getSurfaceTextureID(const Context *rsc) { return id; } +void Allocation::setSurface(const Context *rsc, RsNativeWindow sur) { + ANativeWindow *nw = (ANativeWindow *)sur; + ANativeWindow *old = mHal.state.wndSurface; + if (nw) { + nw->incStrong(NULL); + } + rsc->mHal.funcs.allocation.setSurfaceTexture(rsc, this, nw); + mHal.state.wndSurface = nw; + if (old) { + old->decStrong(NULL); + } +} + +void Allocation::ioSend(const Context *rsc) { + rsc->mHal.funcs.allocation.ioSend(rsc, this); +} + +void Allocation::ioReceive(const Context *rsc) { + rsc->mHal.funcs.allocation.ioReceive(rsc, this); +} + + ///////////////// // @@ -577,8 +602,8 @@ static void AllocationGenerateScriptMips(RsContext con, RsAllocation va) { RsAllocation rsi_AllocationCreateTyped(Context *rsc, RsType vtype, RsAllocationMipmapControl mips, - uint32_t usages) { - Allocation * alloc = Allocation::createAllocation(rsc, static_cast<Type *>(vtype), usages, mips); + uint32_t usages, uint32_t ptr) { + Allocation * alloc = Allocation::createAllocation(rsc, static_cast<Type *>(vtype), usages, mips, (void *)ptr); if (!alloc) { return NULL; } @@ -591,7 +616,7 @@ RsAllocation rsi_AllocationCreateFromBitmap(Context *rsc, RsType vtype, const void *data, size_t data_length, uint32_t usages) { Type *t = static_cast<Type *>(vtype); - RsAllocation vTexAlloc = rsi_AllocationCreateTyped(rsc, vtype, mips, usages); + RsAllocation vTexAlloc = rsi_AllocationCreateTyped(rsc, vtype, mips, usages, 0); Allocation *texAlloc = static_cast<Allocation *>(vTexAlloc); if (texAlloc == NULL) { ALOGE("Memory allocation failure"); @@ -615,7 +640,7 @@ RsAllocation rsi_AllocationCubeCreateFromBitmap(Context *rsc, RsType vtype, // Cubemap allocation's faces should be Width by Width each. // Source data should have 6 * Width by Width pixels // Error checking is done in the java layer - RsAllocation vTexAlloc = rsi_AllocationCreateTyped(rsc, vtype, mips, usages); + RsAllocation vTexAlloc = rsi_AllocationCreateTyped(rsc, vtype, mips, usages, 0); Allocation *texAlloc = static_cast<Allocation *>(vTexAlloc); if (texAlloc == NULL) { ALOGE("Memory allocation failure"); @@ -669,6 +694,21 @@ int32_t rsi_AllocationGetSurfaceTextureID(Context *rsc, RsAllocation valloc) { return alloc->getSurfaceTextureID(rsc); } +void rsi_AllocationSetSurface(Context *rsc, RsAllocation valloc, RsNativeWindow sur) { + Allocation *alloc = static_cast<Allocation *>(valloc); + alloc->setSurface(rsc, sur); +} + +void rsi_AllocationIoSend(Context *rsc, RsAllocation valloc) { + Allocation *alloc = static_cast<Allocation *>(valloc); + alloc->ioSend(rsc); +} + +void rsi_AllocationIoReceive(Context *rsc, RsAllocation valloc) { + Allocation *alloc = static_cast<Allocation *>(valloc); + alloc->ioReceive(rsc); +} + } } diff --git a/libs/rs/rsAllocation.h b/libs/rs/rsAllocation.h index a26d8355bc2f..58a6fcacf6ac 100644 --- a/libs/rs/rsAllocation.h +++ b/libs/rs/rsAllocation.h @@ -19,6 +19,8 @@ #include "rsType.h" +struct ANativeWindow; + // --------------------------------------------------------------------------- namespace android { namespace renderscript { @@ -57,6 +59,7 @@ public: bool hasReferences; void * usrPtr; int32_t surfaceTextureID; + ANativeWindow *wndSurface; }; State state; @@ -68,7 +71,8 @@ public: Hal mHal; static Allocation * createAllocation(Context *rsc, const Type *, uint32_t usages, - RsAllocationMipmapControl mc = RS_ALLOCATION_MIPMAP_NONE); + RsAllocationMipmapControl mc = RS_ALLOCATION_MIPMAP_NONE, + void *ptr = 0); virtual ~Allocation(); void updateCache(); @@ -126,6 +130,9 @@ public: } int32_t getSurfaceTextureID(const Context *rsc); + void setSurface(const Context *rsc, RsNativeWindow sur); + void ioSend(const Context *rsc); + void ioReceive(const Context *rsc); protected: Vector<const Program *> mToDirtyList; @@ -137,7 +144,7 @@ protected: private: void freeChildrenUnlocked(); - Allocation(Context *rsc, const Type *, uint32_t usages, RsAllocationMipmapControl mc); + Allocation(Context *rsc, const Type *, uint32_t usages, RsAllocationMipmapControl mc, void *ptr); uint32_t getPackedSize() const; static void writePackedData(const Type *type, uint8_t *dst, const uint8_t *src, bool dstPadded); diff --git a/libs/rs/rsComponent.cpp b/libs/rs/rsComponent.cpp index 21b98f6193a2..9c2c2005f38d 100644 --- a/libs/rs/rsComponent.cpp +++ b/libs/rs/rsComponent.cpp @@ -62,6 +62,7 @@ void Component::set(RsDataType dt, RsDataKind dk, bool norm, uint32_t vecSize) { rsAssert(mNormalized == true); break; default: + rsAssert(mKind != RS_KIND_INVALID); break; } @@ -167,6 +168,9 @@ void Component::set(RsDataType dt, RsDataKind dk, bool norm, uint32_t vecSize) { case RS_TYPE_BOOLEAN: mTypeBits = 8; break; + default: + rsAssert(mType != RS_TYPE_INVALID); + break; } mBitsUnpadded = mTypeBits * mVectorSize; diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp index 1a34bd588aa6..95ac76e84fd9 100644 --- a/libs/rs/rsContext.cpp +++ b/libs/rs/rsContext.cpp @@ -263,6 +263,10 @@ void * Context::threadProc(void *vrsc) { rsc->timerSet(RS_TIMER_IDLE); #ifndef ANDROID_RS_SERIALIZE + if (!rsc->mRootScript.get() || !rsc->mHasSurface || rsc->mPaused) { + targetRate = 0; + } + if (vsyncRate != targetRate) { displayEvent.setVsyncRate(targetRate); vsyncRate = targetRate; @@ -361,6 +365,7 @@ void Context::setPriority(int32_t p) { #else setpriority(PRIO_PROCESS, mNativeThreadId, p); #endif + mHal.funcs.setPriority(this, mThreadPriority); } Context::Context() { diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h index a844a20cfc6e..05c799e4a5cc 100644 --- a/libs/rs/rsContext.h +++ b/libs/rs/rsContext.h @@ -32,6 +32,7 @@ #include "rsAdapter.h" #include "rsSampler.h" #include "rsFont.h" +#include "rsPath.h" #include "rsProgramFragment.h" #include "rsProgramStore.h" #include "rsProgramRaster.h" diff --git a/libs/rs/RenderScriptDefines.h b/libs/rs/rsDefines.h index 5b0a3daaf045..990ef266f7ec 100644 --- a/libs/rs/RenderScriptDefines.h +++ b/libs/rs/rsDefines.h @@ -41,6 +41,7 @@ typedef void * RsFont; typedef void * RsSampler; typedef void * RsScript; typedef void * RsMesh; +typedef void * RsPath; typedef void * RsType; typedef void * RsObjectBase; @@ -155,6 +156,8 @@ enum RsDataType { RS_TYPE_PROGRAM_VERTEX, RS_TYPE_PROGRAM_RASTER, RS_TYPE_PROGRAM_STORE, + + RS_TYPE_INVALID = 10000, }; enum RsDataKind { @@ -166,6 +169,8 @@ enum RsDataKind { RS_KIND_PIXEL_RGB, RS_KIND_PIXEL_RGBA, RS_KIND_PIXEL_DEPTH, + + RS_KIND_INVALID = 100, }; enum RsSamplerParam { @@ -184,6 +189,8 @@ enum RsSamplerValue { RS_SAMPLER_WRAP, RS_SAMPLER_CLAMP, RS_SAMPLER_LINEAR_MIP_NEAREST, + + RS_SAMPLER_INVALID = 100, }; enum RsTextureTarget { @@ -224,7 +231,8 @@ enum RsBlendSrcFunc { RS_BLEND_SRC_ONE_MINUS_SRC_ALPHA, // 5 RS_BLEND_SRC_DST_ALPHA, // 6 RS_BLEND_SRC_ONE_MINUS_DST_ALPHA, // 7 - RS_BLEND_SRC_SRC_ALPHA_SATURATE // 8 + RS_BLEND_SRC_SRC_ALPHA_SATURATE, // 8 + RS_BLEND_SRC_INVALID = 100, }; enum RsBlendDstFunc { @@ -235,7 +243,9 @@ enum RsBlendDstFunc { RS_BLEND_DST_SRC_ALPHA, // 4 RS_BLEND_DST_ONE_MINUS_SRC_ALPHA, // 5 RS_BLEND_DST_DST_ALPHA, // 6 - RS_BLEND_DST_ONE_MINUS_DST_ALPHA // 7 + RS_BLEND_DST_ONE_MINUS_DST_ALPHA, // 7 + + RS_BLEND_DST_INVALID = 100, }; enum RsTexEnvMode { @@ -258,7 +268,14 @@ enum RsPrimitive { RS_PRIMITIVE_LINE_STRIP, RS_PRIMITIVE_TRIANGLE, RS_PRIMITIVE_TRIANGLE_STRIP, - RS_PRIMITIVE_TRIANGLE_FAN + RS_PRIMITIVE_TRIANGLE_FAN, + + RS_PRIMITIVE_INVALID = 100, +}; + +enum RsPathPrimitive { + RS_PATH_PRIMITIVE_QUADRATIC_BEZIER, + RS_PATH_PRIMITIVE_CUBIC_BEZIER }; enum RsError { @@ -312,7 +329,8 @@ enum RsA3DClassID { enum RsCullMode { RS_CULL_BACK, RS_CULL_FRONT, - RS_CULL_NONE + RS_CULL_NONE, + RS_CULL_INVALID = 100, }; typedef struct { diff --git a/libs/rs/rsElement.cpp b/libs/rs/rsElement.cpp index dff958532538..fb2892ce0f97 100644 --- a/libs/rs/rsElement.cpp +++ b/libs/rs/rsElement.cpp @@ -27,6 +27,7 @@ Element::Element(Context *rsc) : ObjectBase(rsc) { mFields = NULL; mFieldCount = 0; mHasReference = false; + memset(&mHal, 0, sizeof(mHal)); } Element::~Element() { @@ -47,6 +48,12 @@ void Element::clear() { mFields = NULL; mFieldCount = 0; mHasReference = false; + + delete [] mHal.state.fields; + delete [] mHal.state.fieldArraySizes; + delete [] mHal.state.fieldNames; + delete [] mHal.state.fieldNameLengths; + delete [] mHal.state.fieldOffsetBytes; } size_t Element::getSizeBits() const { @@ -157,16 +164,36 @@ Element *Element::createFromStream(Context *rsc, IStream *stream) { } void Element::compute() { + mHal.state.dataType = mComponent.getType(); + mHal.state.dataKind = mComponent.getKind(); + mHal.state.vectorSize = mComponent.getVectorSize(); + if (mFieldCount == 0) { mBits = mComponent.getBits(); mBitsUnpadded = mComponent.getBitsUnpadded(); mHasReference = mComponent.isReference(); + + mHal.state.elementSizeBytes = getSizeBytes(); return; } + uint32_t noPaddingFieldCount = 0; + for (uint32_t ct = 0; ct < mFieldCount; ct ++) { + if (mFields[ct].name.string()[0] != '#') { + noPaddingFieldCount ++; + } + } + + mHal.state.fields = new const Element*[noPaddingFieldCount]; + mHal.state.fieldArraySizes = new uint32_t[noPaddingFieldCount]; + mHal.state.fieldNames = new const char*[noPaddingFieldCount]; + mHal.state.fieldNameLengths = new uint32_t[noPaddingFieldCount]; + mHal.state.fieldOffsetBytes = new uint32_t[noPaddingFieldCount]; + mHal.state.fieldsCount = noPaddingFieldCount; + size_t bits = 0; size_t bitsUnpadded = 0; - for (size_t ct=0; ct < mFieldCount; ct++) { + for (size_t ct = 0, ctNoPadding = 0; ct < mFieldCount; ct++) { mFields[ct].offsetBits = bits; mFields[ct].offsetBitsUnpadded = bitsUnpadded; bits += mFields[ct].e->getSizeBits() * mFields[ct].arraySize; @@ -175,8 +202,21 @@ void Element::compute() { if (mFields[ct].e->mHasReference) { mHasReference = true; } + + if (mFields[ct].name.string()[0] == '#') { + continue; + } + + mHal.state.fields[ctNoPadding] = mFields[ct].e.get(); + mHal.state.fieldArraySizes[ctNoPadding] = mFields[ct].arraySize; + mHal.state.fieldNames[ctNoPadding] = mFields[ct].name.string(); + mHal.state.fieldNameLengths[ctNoPadding] = mFields[ct].name.length() + 1; // to include 0 + mHal.state.fieldOffsetBytes[ctNoPadding] = mFields[ct].offsetBits >> 3; + + ctNoPadding ++; } + mHal.state.elementSizeBytes = getSizeBytes(); } ObjectBaseRef<const Element> Element::createRef(Context *rsc, RsDataType dt, RsDataKind dk, diff --git a/libs/rs/rsElement.h b/libs/rs/rsElement.h index 04010faafac8..4b6b46016e3f 100644 --- a/libs/rs/rsElement.h +++ b/libs/rs/rsElement.h @@ -24,10 +24,38 @@ // --------------------------------------------------------------------------- namespace android { namespace renderscript { - +/***************************************************************************** + * CAUTION + * + * Any layout changes for this class may require a corresponding change to be + * made to frameworks/compile/libbcc/lib/ScriptCRT/rs_core.c, which contains + * a partial copy of the information below. + * + *****************************************************************************/ // An element is a group of Components that occupies one cell in a structure. class Element : public ObjectBase { public: + struct Hal { + mutable void *drv; + + struct State { + RsDataType dataType; + RsDataKind dataKind; + uint32_t vectorSize; + uint32_t elementSizeBytes; + + // Subelements + const Element **fields; + uint32_t *fieldArraySizes; + const char **fieldNames; + uint32_t *fieldNameLengths; + uint32_t *fieldOffsetBytes; + uint32_t fieldsCount; + }; + State state; + }; + Hal mHal; + class Builder { public: Builder(); diff --git a/libs/rs/RenderScriptEnv.h b/libs/rs/rsEnv.h index b82eaf1d6c59..b82eaf1d6c59 100644 --- a/libs/rs/RenderScriptEnv.h +++ b/libs/rs/rsEnv.h diff --git a/libs/rs/rsFileA3D.h b/libs/rs/rsFileA3D.h index 056b5af4c1d5..baf81de5083a 100644 --- a/libs/rs/rsFileA3D.h +++ b/libs/rs/rsFileA3D.h @@ -17,11 +17,11 @@ #ifndef ANDROID_RS_FILE_A3D_H #define ANDROID_RS_FILE_A3D_H -#include "RenderScript.h" +#include "rs.h" #include "rsMesh.h" +#include <androidfw/Asset.h> #include <utils/String8.h> -#include <utils/Asset.h> #include "rsStream.h" #include <stdio.h> diff --git a/libs/rs/rsFont.cpp b/libs/rs/rsFont.cpp index 4f21b3b0140d..c4276cfe8261 100644 --- a/libs/rs/rsFont.cpp +++ b/libs/rs/rsFont.cpp @@ -490,8 +490,14 @@ void FontState::initRenderState() { shaderString.append(" gl_FragColor = col;\n"); shaderString.append("}\n"); - ObjectBaseRef<const Element> colorElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 4); - ObjectBaseRef<const Element> gammaElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 1); + const char *textureNames[] = { "Tex0" }; + const size_t textureNamesLengths[] = { 4 }; + size_t numTextures = sizeof(textureNamesLengths)/sizeof(*textureNamesLengths); + + ObjectBaseRef<const Element> colorElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, + RS_KIND_USER, false, 4); + ObjectBaseRef<const Element> gammaElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, + RS_KIND_USER, false, 1); Element::Builder builder; builder.add(colorElem.get(), "Color", 1); builder.add(gammaElem.get(), "Gamma", 1); @@ -506,14 +512,17 @@ void FontState::initRenderState() { tmp[3] = RS_TEXTURE_2D; mFontShaderFConstant.set(Allocation::createAllocation(mRSC, inputType.get(), - RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS)); - ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(), - shaderString.length(), tmp, 4); + RS_ALLOCATION_USAGE_SCRIPT | + RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS)); + ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(), shaderString.length(), + textureNames, numTextures, textureNamesLengths, + tmp, 4); mFontShaderF.set(pf); mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0); mFontSampler.set(Sampler::getSampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST, - RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP).get()); + RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP, + RS_SAMPLER_CLAMP).get()); mFontShaderF->bindSampler(mRSC, 0, mFontSampler.get()); mFontProgramStore.set(ProgramStore::getProgramStore(mRSC, true, true, true, true, @@ -525,10 +534,12 @@ void FontState::initRenderState() { } void FontState::initTextTexture() { - ObjectBaseRef<const Element> alphaElem = Element::createRef(mRSC, RS_TYPE_UNSIGNED_8, RS_KIND_PIXEL_A, true, 1); + ObjectBaseRef<const Element> alphaElem = Element::createRef(mRSC, RS_TYPE_UNSIGNED_8, + RS_KIND_PIXEL_A, true, 1); // We will allocate a texture to initially hold 32 character bitmaps - ObjectBaseRef<Type> texType = Type::getTypeRef(mRSC, alphaElem.get(), 1024, 256, 0, false, false); + ObjectBaseRef<Type> texType = Type::getTypeRef(mRSC, alphaElem.get(), + 1024, 256, 0, false, false); Allocation *cacheAlloc = Allocation::createAllocation(mRSC, texType.get(), RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE); diff --git a/libs/rs/rsFont.h b/libs/rs/rsFont.h index 4ca794dcee1c..88c479534096 100644 --- a/libs/rs/rsFont.h +++ b/libs/rs/rsFont.h @@ -17,7 +17,7 @@ #ifndef ANDROID_RS_FONT_H #define ANDROID_RS_FONT_H -#include "RenderScript.h" +#include "rs.h" #include "rsStream.h" #include <utils/String8.h> #include <utils/Vector.h> diff --git a/libs/rs/rsMesh.h b/libs/rs/rsMesh.h index 0fc73fba5c95..8eea4279e3f7 100644 --- a/libs/rs/rsMesh.h +++ b/libs/rs/rsMesh.h @@ -18,25 +18,23 @@ #define ANDROID_RS_MESH_H -#include "RenderScript.h" +#include "rs.h" // --------------------------------------------------------------------------- namespace android { namespace renderscript { - +/***************************************************************************** + * CAUTION + * + * Any layout changes for this class may require a corresponding change to be + * made to frameworks/compile/libbcc/lib/ScriptCRT/rs_core.c, which contains + * a partial copy of the information below. + * + *****************************************************************************/ // An element is a group of Components that occupies one cell in a structure. class Mesh : public ObjectBase { public: - Mesh(Context *); - Mesh(Context *, uint32_t vertexBuffersCount, uint32_t primitivesCount); - ~Mesh(); - - virtual void serialize(OStream *stream) const; - virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_MESH; } - static Mesh *createFromStream(Context *rsc, IStream *stream); - void init(); - struct Hal { mutable void *drv; @@ -57,6 +55,15 @@ public: }; Hal mHal; + Mesh(Context *); + Mesh(Context *, uint32_t vertexBuffersCount, uint32_t primitivesCount); + ~Mesh(); + + virtual void serialize(OStream *stream) const; + virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_MESH; } + static Mesh *createFromStream(Context *rsc, IStream *stream); + void init(); + void setVertexBuffer(Allocation *vb, uint32_t index) { mVertexBuffers[index].set(vb); mHal.state.vertexBuffers[index] = vb; diff --git a/libs/rs/rsPath.cpp b/libs/rs/rsPath.cpp new file mode 100644 index 000000000000..c4f49789bfdc --- /dev/null +++ b/libs/rs/rsPath.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "rsContext.h" + +using namespace android; +using namespace android::renderscript; + + +Path::Path(Context *rsc) : ObjectBase(rsc) { +} + +Path::Path(Context *rsc, RsPathPrimitive pp, bool isStatic, + Allocation *vtx, Allocation *loops, float quality) +: ObjectBase(rsc) { + + memset(&mHal, 0, sizeof(mHal)); + mHal.state.quality = quality; + mHal.state.primitive = pp; + + //LOGE("i1"); + rsc->mHal.funcs.path.initStatic(rsc, this, vtx, loops); + + //LOGE("i2"); +} + +Path::Path(Context *rsc, uint32_t vertexBuffersCount, uint32_t primitivesCount) +: ObjectBase(rsc) { + +} + +Path::~Path() { + +} + + +void Path::rasterize(const BezierSegment_t *s, uint32_t num, Allocation *alloc) { + + for (uint32_t i=0; i < num; i++) { + + } + +} + +void Path::render(Context *rsc) { +} + +void Path::serialize(OStream *stream) const { + +} + +RsA3DClassID Path::getClassId() const { + return RS_A3D_CLASS_ID_UNKNOWN; +} + +namespace android { +namespace renderscript { + +RsPath rsi_PathCreate(Context *rsc, RsPathPrimitive pp, bool isStatic, + RsAllocation vtx, RsAllocation loops, float quality) { + return new Path(rsc, pp, isStatic, (Allocation *)vtx, (Allocation *)loops, quality); +} + +} +} diff --git a/libs/rs/rsPath.h b/libs/rs/rsPath.h new file mode 100644 index 000000000000..7c055037d5ab --- /dev/null +++ b/libs/rs/rsPath.h @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_RS_PATH_H +#define ANDROID_RS_PATH_H + + +#include "rs.h" + +// --------------------------------------------------------------------------- +namespace android { +namespace renderscript { + +class Path : public ObjectBase { +public: + struct { + mutable void * drv; + + struct State { + RsPathPrimitive primitive; + float quality; + }; + State state; + } mHal; + + Path(Context *); + Path(Context *, uint32_t vertexBuffersCount, uint32_t primitivesCount); + Path(Context *, RsPathPrimitive pp, bool isStatic, Allocation *vtx, Allocation *loop, float q); + + ~Path(); + + void render(Context *); + virtual void serialize(OStream *stream) const; + virtual RsA3DClassID getClassId() const; + +private: + + + typedef struct { + float x[4]; + float y[4]; + } BezierSegment_t; + + bool subdivideCheck(const BezierSegment_t *s, float u1, float u2); + + void rasterize(const BezierSegment_t *s, uint32_t num, Allocation *alloc); + + +}; + +} +} +#endif //ANDROID_RS_PATH_H + + + diff --git a/libs/rs/rsProgram.cpp b/libs/rs/rsProgram.cpp index 8061515e24fa..7114f29d0509 100644 --- a/libs/rs/rsProgram.cpp +++ b/libs/rs/rsProgram.cpp @@ -20,8 +20,8 @@ using namespace android; using namespace android::renderscript; -Program::Program(Context *rsc, const char * shaderText, uint32_t shaderLength, - const uint32_t * params, uint32_t paramLength) +Program::Program(Context *rsc, const char * shaderText, size_t shaderLength, + const uint32_t * params, size_t paramLength) : ProgramBase(rsc) { initMemberVars(); diff --git a/libs/rs/rsProgram.h b/libs/rs/rsProgram.h index 06fc3eca71ab..d03293066803 100644 --- a/libs/rs/rsProgram.h +++ b/libs/rs/rsProgram.h @@ -58,8 +58,8 @@ public: }; Hal mHal; - Program(Context *, const char * shaderText, uint32_t shaderLength, - const uint32_t * params, uint32_t paramLength); + Program(Context *, const char * shaderText, size_t shaderLength, + const uint32_t * params, size_t paramLength); virtual ~Program(); virtual bool freeChildren(); diff --git a/libs/rs/rsProgramFragment.cpp b/libs/rs/rsProgramFragment.cpp index 4e73ca63e90b..bebde1e0cb53 100644 --- a/libs/rs/rsProgramFragment.cpp +++ b/libs/rs/rsProgramFragment.cpp @@ -20,16 +20,18 @@ using namespace android; using namespace android::renderscript; -ProgramFragment::ProgramFragment(Context *rsc, const char * shaderText, - uint32_t shaderLength, const uint32_t * params, - uint32_t paramLength) +ProgramFragment::ProgramFragment(Context *rsc, const char * shaderText, size_t shaderLength, + const char** textureNames, size_t textureNamesCount, const size_t *textureNamesLength, + + const uint32_t * params, size_t paramLength) : Program(rsc, shaderText, shaderLength, params, paramLength) { mConstantColor[0] = 1.f; mConstantColor[1] = 1.f; mConstantColor[2] = 1.f; mConstantColor[3] = 1.f; - mRSC->mHal.funcs.fragment.init(mRSC, this, mUserShader.string(), mUserShader.length()); + mRSC->mHal.funcs.fragment.init(mRSC, this, mUserShader.string(), mUserShader.length(), + textureNames, textureNamesCount, textureNamesLength); } ProgramFragment::~ProgramFragment() { @@ -110,8 +112,8 @@ void ProgramFragmentState::init(Context *rsc) { Allocation *constAlloc = Allocation::createAllocation(rsc, inputType.get(), RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS); - ProgramFragment *pf = new ProgramFragment(rsc, shaderString.string(), - shaderString.length(), tmp, 2); + ProgramFragment *pf = new ProgramFragment(rsc, shaderString.string(), shaderString.length(), + NULL, 0, NULL, tmp, 2); pf->bindAllocation(rsc, constAlloc, 0); pf->setConstantColor(rsc, 1.0f, 1.0f, 1.0f, 1.0f); @@ -127,9 +129,14 @@ namespace android { namespace renderscript { RsProgramFragment rsi_ProgramFragmentCreate(Context *rsc, const char * shaderText, - size_t shaderLength, const uint32_t * params, - size_t paramLength) { - ProgramFragment *pf = new ProgramFragment(rsc, shaderText, shaderLength, params, paramLength); + size_t shaderLength, + const char** textureNames, + size_t textureNamesCount, + const size_t *textureNamesLength, + const uint32_t * params, size_t paramLength) { + ProgramFragment *pf = new ProgramFragment(rsc, shaderText, shaderLength, + textureNames, textureNamesCount, textureNamesLength, + params, paramLength); pf->incUserRef(); //ALOGE("rsi_ProgramFragmentCreate %p", pf); return pf; diff --git a/libs/rs/rsProgramFragment.h b/libs/rs/rsProgramFragment.h index d6e20cd192b9..4eb28e7db171 100644 --- a/libs/rs/rsProgramFragment.h +++ b/libs/rs/rsProgramFragment.h @@ -27,9 +27,9 @@ class ProgramFragmentState; class ProgramFragment : public Program { public: - ProgramFragment(Context *rsc, const char * shaderText, - uint32_t shaderLength, const uint32_t * params, - uint32_t paramLength); + ProgramFragment(Context *rsc, const char * shaderText, size_t shaderLength, + const char** textureNames, size_t textureNamesCount, const size_t *textureNamesLength, + const uint32_t * params, size_t paramLength); virtual ~ProgramFragment(); virtual void setup(Context *, ProgramFragmentState *); diff --git a/libs/rs/rsProgramVertex.cpp b/libs/rs/rsProgramVertex.cpp index 871caacd6f66..c8a53eab2012 100644 --- a/libs/rs/rsProgramVertex.cpp +++ b/libs/rs/rsProgramVertex.cpp @@ -21,11 +21,13 @@ using namespace android; using namespace android::renderscript; -ProgramVertex::ProgramVertex(Context *rsc, const char * shaderText, - uint32_t shaderLength, const uint32_t * params, - uint32_t paramLength) +ProgramVertex::ProgramVertex(Context *rsc, const char * shaderText, size_t shaderLength, + const char** textureNames, size_t textureNamesCount, const size_t *textureNamesLength, + + const uint32_t * params, size_t paramLength) : Program(rsc, shaderText, shaderLength, params, paramLength) { - mRSC->mHal.funcs.vertex.init(mRSC, this, mUserShader.string(), mUserShader.length()); + mRSC->mHal.funcs.vertex.init(mRSC, this, mUserShader.string(), mUserShader.length(), + textureNames, textureNamesCount, textureNamesLength); } ProgramVertex::~ProgramVertex() { @@ -191,8 +193,8 @@ void ProgramVertexState::init(Context *rsc) { tmp[2] = RS_PROGRAM_PARAM_INPUT; tmp[3] = (uint32_t)attrElem.get(); - ProgramVertex *pv = new ProgramVertex(rsc, shaderString.string(), - shaderString.length(), tmp, 4); + ProgramVertex *pv = new ProgramVertex(rsc, shaderString.string(), shaderString.length(), + NULL, 0, NULL, tmp, 4); Allocation *alloc = Allocation::createAllocation(rsc, inputType.get(), RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS); pv->bindAllocation(rsc, alloc, 0); @@ -229,10 +231,13 @@ void ProgramVertexState::deinit(Context *rsc) { namespace android { namespace renderscript { -RsProgramVertex rsi_ProgramVertexCreate(Context *rsc, const char * shaderText, - size_t shaderLength, const uint32_t * params, - size_t paramLength) { - ProgramVertex *pv = new ProgramVertex(rsc, shaderText, shaderLength, params, paramLength); +RsProgramVertex rsi_ProgramVertexCreate(Context *rsc, const char * shaderText, size_t shaderLength, + const char** textureNames, size_t textureNamesCount, + const size_t *textureNamesLength, + const uint32_t * params, size_t paramLength) { + ProgramVertex *pv = new ProgramVertex(rsc, shaderText, shaderLength, + textureNames, textureNamesCount, textureNamesLength, + params, paramLength); pv->incUserRef(); return pv; } diff --git a/libs/rs/rsProgramVertex.h b/libs/rs/rsProgramVertex.h index 5cfdd8be355d..67c2a88840f6 100644 --- a/libs/rs/rsProgramVertex.h +++ b/libs/rs/rsProgramVertex.h @@ -27,8 +27,9 @@ class ProgramVertexState; class ProgramVertex : public Program { public: - ProgramVertex(Context *,const char * shaderText, uint32_t shaderLength, - const uint32_t * params, uint32_t paramLength); + ProgramVertex(Context *,const char * shaderText, size_t shaderLength, + const char** textureNames, size_t textureNamesCount, const size_t *textureNamesLength, + const uint32_t * params, size_t paramLength); virtual ~ProgramVertex(); virtual void setup(Context *rsc, ProgramVertexState *state); diff --git a/libs/rs/rsRuntime.h b/libs/rs/rsRuntime.h index cb962a815dc3..3bded620e0d3 100644 --- a/libs/rs/rsRuntime.h +++ b/libs/rs/rsRuntime.h @@ -30,6 +30,8 @@ namespace renderscript { ////////////////////////////////////////////////////////////////////////////// void rsrBindTexture(Context *, Script *, ProgramFragment *, uint32_t slot, Allocation *); +void rsrBindConstant(Context *, Script *, ProgramFragment *, uint32_t slot, Allocation *); +void rsrBindConstant(Context *, Script *, ProgramVertex*, uint32_t slot, Allocation *); void rsrBindSampler(Context *, Script *, ProgramFragment *, uint32_t slot, Sampler *); void rsrBindProgramStore(Context *, Script *, ProgramStore *); void rsrBindProgramFragment(Context *, Script *, ProgramFragment *); @@ -68,6 +70,7 @@ void rsrDrawQuad(Context *, Script *, void rsrDrawSpriteScreenspace(Context *, Script *, float x, float y, float z, float w, float h); void rsrDrawRect(Context *, Script *, float x1, float y1, float x2, float y2, float z); +void rsrDrawPath(Context *, Script *, Path *); void rsrDrawMesh(Context *, Script *, Mesh *); void rsrDrawMeshPrimitive(Context *, Script *, Mesh *, uint32_t primIndex); void rsrDrawMeshPrimitiveRange(Context *, Script *, Mesh *, diff --git a/libs/rs/rsSampler.h b/libs/rs/rsSampler.h index 654cd9ce1a06..013e4ca32370 100644 --- a/libs/rs/rsSampler.h +++ b/libs/rs/rsSampler.h @@ -18,7 +18,7 @@ #define ANDROID_RS_SAMPLER_H #include "rsAllocation.h" -#include "RenderScript.h" +#include "rs.h" // --------------------------------------------------------------------------- namespace android { diff --git a/libs/rs/rsScriptC.h b/libs/rs/rsScriptC.h index c65a5bf7a06b..fc4df5132c23 100644 --- a/libs/rs/rsScriptC.h +++ b/libs/rs/rsScriptC.h @@ -19,7 +19,7 @@ #include "rsScript.h" -#include "RenderScriptEnv.h" +#include "rsEnv.h" #ifndef ANDROID_RS_SERIALIZE #include "bcinfo/BitcodeTranslator.h" diff --git a/libs/rs/rsScriptC_LibGL.cpp b/libs/rs/rsScriptC_LibGL.cpp index 79647922d5c1..97469d370553 100644 --- a/libs/rs/rsScriptC_LibGL.cpp +++ b/libs/rs/rsScriptC_LibGL.cpp @@ -50,6 +50,18 @@ void rsrBindTexture(Context *rsc, Script *sc, ProgramFragment *pf, uint32_t slot pf->bindTexture(rsc, slot, a); } +void rsrBindConstant(Context *rsc, Script *sc, ProgramFragment *pf, uint32_t slot, Allocation *a) { + CHECK_OBJ_OR_NULL(a); + CHECK_OBJ(pf); + pf->bindAllocation(rsc, a, slot); +} + +void rsrBindConstant(Context *rsc, Script *sc, ProgramVertex *pv, uint32_t slot, Allocation *a) { + CHECK_OBJ_OR_NULL(a); + CHECK_OBJ(pv); + pv->bindAllocation(rsc, a, slot); +} + void rsrBindSampler(Context *rsc, Script *sc, ProgramFragment *pf, uint32_t slot, Sampler *s) { CHECK_OBJ_OR_NULL(vs); CHECK_OBJ(vpf); @@ -200,6 +212,14 @@ void rsrDrawRect(Context *rsc, Script *sc, float x1, float y1, float x2, float y rsrDrawQuad(rsc, sc, x1, y2, z, x2, y2, z, x2, y1, z, x1, y1, z); } +void rsrDrawPath(Context *rsc, Script *sc, Path *sm) { + CHECK_OBJ(sm); + if (!rsc->setupCheck()) { + return; + } + sm->render(rsc); +} + void rsrDrawMesh(Context *rsc, Script *sc, Mesh *sm) { CHECK_OBJ(sm); if (!rsc->setupCheck()) { diff --git a/libs/rs/rsThreadIO.cpp b/libs/rs/rsThreadIO.cpp index 4f3057317ab9..7182f53a9517 100644 --- a/libs/rs/rsThreadIO.cpp +++ b/libs/rs/rsThreadIO.cpp @@ -31,6 +31,8 @@ using namespace android::renderscript; ThreadIO::ThreadIO() { mRunning = true; + mPureFifo = false; + mMaxInlineSize = 1024; } ThreadIO::~ThreadIO() { @@ -65,6 +67,16 @@ void ThreadIO::clientShutdown() { mToClient.shutdown(); } +void ThreadIO::coreWrite(const void *data, size_t len) { + //ALOGV("core write %p %i", data, (int)len); + mToCore.writeAsync(data, len, true); +} + +void ThreadIO::coreRead(void *data, size_t len) { + //ALOGV("core read %p %i", data, (int)len); + mToCore.read(data, len); +} + void ThreadIO::coreSetReturn(const void *data, size_t dataLen) { uint32_t buf; if (data == NULL) { @@ -91,6 +103,7 @@ void ThreadIO::setTimeoutCallback(void (*cb)(void *), void *dat, uint64_t timeou bool ThreadIO::playCoreCommands(Context *con, int waitFd) { bool ret = false; + const bool isLocal = !isPureFifo(); uint8_t buf[2 * 1024]; const CoreCmdHeader *cmd = (const CoreCmdHeader *)&buf[0]; @@ -120,14 +133,19 @@ bool ThreadIO::playCoreCommands(Context *con, int waitFd) { } if (p[0].revents) { - size_t r = mToCore.read(&buf[0], sizeof(CoreCmdHeader)); - mToCore.read(&buf[sizeof(CoreCmdHeader)], cmd->bytes); - - if (r != sizeof(CoreCmdHeader)) { - // exception or timeout occurred. - break; + size_t r = 0; + if (isLocal) { + r = mToCore.read(&buf[0], sizeof(CoreCmdHeader)); + mToCore.read(&buf[sizeof(CoreCmdHeader)], cmd->bytes); + if (r != sizeof(CoreCmdHeader)) { + // exception or timeout occurred. + break; + } + } else { + r = mToCore.read((void *)&cmd->cmdID, sizeof(cmd->cmdID)); } + ret = true; if (con->props.mLogTimes) { con->timerSet(Context::RS_TIMER_INTERNAL); @@ -138,7 +156,12 @@ bool ThreadIO::playCoreCommands(Context *con, int waitFd) { rsAssert(cmd->cmdID < (sizeof(gPlaybackFuncs) / sizeof(void *))); ALOGE("playCoreCommands error con %p, cmd %i", con, cmd->cmdID); } - gPlaybackFuncs[cmd->cmdID](con, data, cmd->bytes); + + if (isLocal) { + gPlaybackFuncs[cmd->cmdID](con, data, cmd->bytes); + } else { + gPlaybackRemoteFuncs[cmd->cmdID](con, this); + } if (con->props.mLogTimes) { con->timerSet(Context::RS_TIMER_IDLE); diff --git a/libs/rs/rsThreadIO.h b/libs/rs/rsThreadIO.h index 62e3e33efb60..cb7d4abca5c5 100644 --- a/libs/rs/rsThreadIO.h +++ b/libs/rs/rsThreadIO.h @@ -34,6 +34,13 @@ public: void init(); void shutdown(); + size_t getMaxInlineSize() { + return mMaxInlineSize; + } + bool isPureFifo() { + return mPureFifo; + } + // Plays back commands from the client. // Returns true if any commands were processed. bool playCoreCommands(Context *con, int waitFd); @@ -42,8 +49,16 @@ public: void * coreHeader(uint32_t, size_t dataLen); void coreCommit(); + void coreSetReturn(const void *data, size_t dataLen); void coreGetReturn(void *data, size_t dataLen); + void coreWrite(const void *data, size_t len); + void coreRead(void *data, size_t len); + + void asyncSetReturn(const void *data, size_t dataLen); + void asyncGetReturn(void *data, size_t dataLen); + void asyncWrite(const void *data, size_t len); + void asyncRead(void *data, size_t len); RsMessageToClientType getClientHeader(size_t *receiveLen, uint32_t *usrID); @@ -65,6 +80,8 @@ protected: ClientCmdHeader mLastClientHeader; bool mRunning; + bool mPureFifo; + size_t mMaxInlineSize; FifoSocket mToClient; FifoSocket mToCore; diff --git a/libs/rs/rsType.cpp b/libs/rs/rsType.cpp index 79664700b908..70ab7b7ca297 100644 --- a/libs/rs/rsType.cpp +++ b/libs/rs/rsType.cpp @@ -46,12 +46,8 @@ void Type::clear() { delete [] mLODs; mLODs = NULL; } - mDimX = 0; - mDimY = 0; - mDimZ = 0; - mDimLOD = 0; - mFaces = false; mElement.clear(); + memset(&mHal, 0, sizeof(mHal)); } TypeState::TypeState() { @@ -62,16 +58,16 @@ TypeState::~TypeState() { } size_t Type::getOffsetForFace(uint32_t face) const { - rsAssert(mFaces); + rsAssert(mHal.state.faces); return 0; } void Type::compute() { uint32_t oldLODCount = mLODCount; - if (mDimLOD) { - uint32_t l2x = rsFindHighBit(mDimX) + 1; - uint32_t l2y = rsFindHighBit(mDimY) + 1; - uint32_t l2z = rsFindHighBit(mDimZ) + 1; + if (mHal.state.dimLOD) { + uint32_t l2x = rsFindHighBit(mHal.state.dimX) + 1; + uint32_t l2y = rsFindHighBit(mHal.state.dimY) + 1; + uint32_t l2z = rsFindHighBit(mHal.state.dimZ) + 1; mLODCount = rsMax(l2x, l2y); mLODCount = rsMax(mLODCount, l2z); @@ -85,9 +81,9 @@ void Type::compute() { mLODs = new LOD[mLODCount]; } - uint32_t tx = mDimX; - uint32_t ty = mDimY; - uint32_t tz = mDimZ; + uint32_t tx = mHal.state.dimX; + uint32_t ty = mHal.state.dimY; + uint32_t tz = mHal.state.dimZ; size_t offset = 0; for (uint32_t lod=0; lod < mLODCount; lod++) { mLODs[lod].mX = tx; @@ -103,10 +99,11 @@ void Type::compute() { // At this point the offset is the size of a mipmap chain; mMipChainSizeBytes = offset; - if (mFaces) { + if (mHal.state.faces) { offset *= 6; } mTotalSizeBytes = offset; + mHal.state.element = mElement.get(); } uint32_t Type::getLODOffset(uint32_t lod, uint32_t x) const { @@ -127,7 +124,8 @@ uint32_t Type::getLODOffset(uint32_t lod, uint32_t x, uint32_t y, uint32_t z) co return offset; } -uint32_t Type::getLODFaceOffset(uint32_t lod, RsAllocationCubemapFace face, uint32_t x, uint32_t y) const { +uint32_t Type::getLODFaceOffset(uint32_t lod, RsAllocationCubemapFace face, + uint32_t x, uint32_t y) const { uint32_t offset = mLODs[lod].mOffset; offset += (x + y * mLODs[lod].mX) * mElement->getSizeBytes(); @@ -141,7 +139,12 @@ uint32_t Type::getLODFaceOffset(uint32_t lod, RsAllocationCubemapFace face, uint void Type::dumpLOGV(const char *prefix) const { char buf[1024]; ObjectBase::dumpLOGV(prefix); - ALOGV("%s Type: x=%zu y=%zu z=%zu mip=%i face=%i", prefix, mDimX, mDimY, mDimZ, mDimLOD, mFaces); + ALOGV("%s Type: x=%u y=%u z=%u mip=%i face=%i", prefix, + mHal.state.dimX, + mHal.state.dimY, + mHal.state.dimZ, + mHal.state.dimLOD, + mHal.state.faces); snprintf(buf, sizeof(buf), "%s element: ", prefix); mElement->dumpLOGV(buf); } @@ -155,12 +158,12 @@ void Type::serialize(OStream *stream) const { mElement->serialize(stream); - stream->addU32(mDimX); - stream->addU32(mDimY); - stream->addU32(mDimZ); + stream->addU32(mHal.state.dimX); + stream->addU32(mHal.state.dimY); + stream->addU32(mHal.state.dimZ); - stream->addU8((uint8_t)(mDimLOD ? 1 : 0)); - stream->addU8((uint8_t)(mFaces ? 1 : 0)); + stream->addU8((uint8_t)(mHal.state.dimLOD ? 1 : 0)); + stream->addU8((uint8_t)(mHal.state.faces ? 1 : 0)); } Type *Type::createFromStream(Context *rsc, IStream *stream) { @@ -232,11 +235,11 @@ ObjectBaseRef<Type> Type::getTypeRef(Context *rsc, const Element *e, Type *nt = new Type(rsc); returnRef.set(nt); nt->mElement.set(e); - nt->mDimX = dimX; - nt->mDimY = dimY; - nt->mDimZ = dimZ; - nt->mDimLOD = dimLOD; - nt->mFaces = dimFaces; + nt->mHal.state.dimX = dimX; + nt->mHal.state.dimY = dimY; + nt->mHal.state.dimZ = dimZ; + nt->mHal.state.dimLOD = dimLOD; + nt->mHal.state.faces = dimFaces; nt->compute(); ObjectBase::asyncLock(); @@ -248,14 +251,14 @@ ObjectBaseRef<Type> Type::getTypeRef(Context *rsc, const Element *e, ObjectBaseRef<Type> Type::cloneAndResize1D(Context *rsc, uint32_t dimX) const { return getTypeRef(rsc, mElement.get(), dimX, - mDimY, mDimZ, mDimLOD, mFaces); + mHal.state.dimY, mHal.state.dimZ, mHal.state.dimLOD, mHal.state.faces); } ObjectBaseRef<Type> Type::cloneAndResize2D(Context *rsc, uint32_t dimX, uint32_t dimY) const { return getTypeRef(rsc, mElement.get(), dimX, dimY, - mDimZ, mDimLOD, mFaces); + mHal.state.dimZ, mHal.state.dimLOD, mHal.state.faces); } @@ -276,8 +279,8 @@ RsType rsi_TypeCreate(Context *rsc, RsElement _e, uint32_t dimX, void rsaTypeGetNativeData(RsContext con, RsType type, uint32_t *typeData, uint32_t typeDataSize) { rsAssert(typeDataSize == 6); - // Pack the data in the follofing way mDimX; mDimY; mDimZ; - // mDimLOD; mDimFaces; mElement; into typeData + // Pack the data in the follofing way mHal.state.dimX; mHal.state.dimY; mHal.state.dimZ; + // mHal.state.dimLOD; mHal.state.faces; mElement; into typeData Type *t = static_cast<Type *>(type); (*typeData++) = t->getDimX(); diff --git a/libs/rs/rsType.h b/libs/rs/rsType.h index bc0d9ffdbe46..3878156a2191 100644 --- a/libs/rs/rsType.h +++ b/libs/rs/rsType.h @@ -22,10 +22,35 @@ // --------------------------------------------------------------------------- namespace android { namespace renderscript { - +/***************************************************************************** + * CAUTION + * + * Any layout changes for this class may require a corresponding change to be + * made to frameworks/compile/libbcc/lib/ScriptCRT/rs_core.c, which contains + * a partial copy of the information below. + * + *****************************************************************************/ class Type : public ObjectBase { public: + struct Hal { + mutable void *drv; + + struct State { + const Element * element; + + // Size of the structure in the various dimensions. A missing Dimension is + // specified as a 0 and not a 1. + uint32_t dimX; + uint32_t dimY; + uint32_t dimZ; + bool dimLOD; + bool faces; + }; + State state; + }; + Hal mHal; + Type * createTex2D(const Element *, size_t w, size_t h, bool mip); size_t getOffsetForFace(uint32_t face) const; @@ -34,22 +59,25 @@ public: size_t getElementSizeBytes() const {return mElement->getSizeBytes();} const Element * getElement() const {return mElement.get();} - uint32_t getDimX() const {return mDimX;} - uint32_t getDimY() const {return mDimY;} - uint32_t getDimZ() const {return mDimZ;} - uint32_t getDimLOD() const {return mDimLOD;} - bool getDimFaces() const {return mFaces;} + uint32_t getDimX() const {return mHal.state.dimX;} + uint32_t getDimY() const {return mHal.state.dimY;} + uint32_t getDimZ() const {return mHal.state.dimZ;} + uint32_t getDimLOD() const {return mHal.state.dimLOD;} + bool getDimFaces() const {return mHal.state.faces;} uint32_t getLODDimX(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mX;} uint32_t getLODDimY(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mY;} uint32_t getLODDimZ(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mZ;} - uint32_t getLODOffset(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mOffset;} + uint32_t getLODOffset(uint32_t lod) const { + rsAssert(lod < mLODCount); return mLODs[lod].mOffset; + } uint32_t getLODOffset(uint32_t lod, uint32_t x) const; uint32_t getLODOffset(uint32_t lod, uint32_t x, uint32_t y) const; uint32_t getLODOffset(uint32_t lod, uint32_t x, uint32_t y, uint32_t z) const; - uint32_t getLODFaceOffset(uint32_t lod, RsAllocationCubemapFace face, uint32_t x, uint32_t y) const; + uint32_t getLODFaceOffset(uint32_t lod, RsAllocationCubemapFace face, + uint32_t x, uint32_t y) const; uint32_t getLODCount() const {return mLODCount;} bool getIsNp2() const; @@ -95,14 +123,6 @@ protected: ObjectBaseRef<const Element> mElement; - // Size of the structure in the various dimensions. A missing Dimension is - // specified as a 0 and not a 1. - size_t mDimX; - size_t mDimY; - size_t mDimZ; - bool mDimLOD; - bool mFaces; - // count of mipmap levels, 0 indicates no mipmapping size_t mMipChainSizeBytes; diff --git a/libs/rs/rsUtils.h b/libs/rs/rsUtils.h index db6f59204d12..a9a992a773ec 100644 --- a/libs/rs/rsUtils.h +++ b/libs/rs/rsUtils.h @@ -34,7 +34,7 @@ #include <math.h> -#include "RenderScript.h" +#include "rs.h" namespace android { namespace renderscript { diff --git a/libs/rs/rs_hal.h b/libs/rs/rs_hal.h index 0afc94b99e9b..e4bf17f3be2a 100644 --- a/libs/rs/rs_hal.h +++ b/libs/rs/rs_hal.h @@ -17,7 +17,9 @@ #ifndef RS_HAL_H #define RS_HAL_H -#include <RenderScriptDefines.h> +#include <rsDefines.h> + +struct ANativeWindow; namespace android { namespace renderscript { @@ -29,6 +31,7 @@ class Type; class Allocation; class Script; class ScriptC; +class Path; class Program; class ProgramStore; class ProgramRaster; @@ -114,19 +117,23 @@ typedef struct { bool zeroNew); void (*syncAll)(const Context *rsc, const Allocation *alloc, RsAllocationUsageType src); void (*markDirty)(const Context *rsc, const Allocation *alloc); + int32_t (*initSurfaceTexture)(const Context *rsc, const Allocation *alloc); + void (*setSurfaceTexture)(const Context *rsc, Allocation *alloc, ANativeWindow *sur); + void (*ioSend)(const Context *rsc, Allocation *alloc); + void (*ioReceive)(const Context *rsc, Allocation *alloc); void (*data1D)(const Context *rsc, const Allocation *alloc, uint32_t xoff, uint32_t lod, uint32_t count, - const void *data, uint32_t sizeBytes); + const void *data, size_t sizeBytes); void (*data2D)(const Context *rsc, const Allocation *alloc, uint32_t xoff, uint32_t yoff, uint32_t lod, RsAllocationCubemapFace face, uint32_t w, uint32_t h, - const void *data, uint32_t sizeBytes); + const void *data, size_t sizeBytes); void (*data3D)(const Context *rsc, const Allocation *alloc, uint32_t xoff, uint32_t yoff, uint32_t zoff, uint32_t lod, RsAllocationCubemapFace face, - uint32_t w, uint32_t h, uint32_t d, const void *data, uint32_t sizeBytes); + uint32_t w, uint32_t h, uint32_t d, const void *data, size_t sizeBytes); // Allocation to allocation copies void (*allocData1D)(const Context *rsc, @@ -150,9 +157,9 @@ typedef struct { uint32_t srcLod, RsAllocationCubemapFace srcFace); void (*elementData1D)(const Context *rsc, const Allocation *alloc, uint32_t x, - const void *data, uint32_t elementOff, uint32_t sizeBytes); + const void *data, uint32_t elementOff, size_t sizeBytes); void (*elementData2D)(const Context *rsc, const Allocation *alloc, uint32_t x, uint32_t y, - const void *data, uint32_t elementOff, uint32_t sizeBytes); + const void *data, uint32_t elementOff, size_t sizeBytes); } allocation; @@ -171,14 +178,18 @@ typedef struct { struct { bool (*init)(const Context *rsc, const ProgramVertex *pv, - const char* shader, uint32_t shaderLen); + const char* shader, size_t shaderLen, + const char** textureNames, size_t textureNamesCount, + const size_t *textureNamesLength); void (*setActive)(const Context *rsc, const ProgramVertex *pv); void (*destroy)(const Context *rsc, const ProgramVertex *pv); } vertex; struct { bool (*init)(const Context *rsc, const ProgramFragment *pf, - const char* shader, uint32_t shaderLen); + const char* shader, size_t shaderLen, + const char** textureNames, size_t textureNamesCount, + const size_t *textureNamesLength); void (*setActive)(const Context *rsc, const ProgramFragment *pf); void (*destroy)(const Context *rsc, const ProgramFragment *pf); } fragment; @@ -190,6 +201,13 @@ typedef struct { } mesh; struct { + bool (*initStatic)(const Context *rsc, const Path *m, const Allocation *vtx, const Allocation *loops); + bool (*initDynamic)(const Context *rsc, const Path *m); + void (*draw)(const Context *rsc, const Path *m); + void (*destroy)(const Context *rsc, const Path *m); + } path; + + struct { bool (*init)(const Context *rsc, const Sampler *m); void (*destroy)(const Context *rsc, const Sampler *m); } sampler; diff --git a/libs/rs/rsg_generator.c b/libs/rs/rsg_generator.c index 385c8b58935b..99c305e0702c 100644 --- a/libs/rs/rsg_generator.c +++ b/libs/rs/rsg_generator.c @@ -238,7 +238,7 @@ void printApiCpp(FILE *f) { //fprintf(f, " ALOGE(\"add command %s\\n\");\n", api->name); if (hasInlineDataPointers(api)) { fprintf(f, " RS_CMD_%s *cmd = NULL;\n", api->name); - fprintf(f, " if (dataSize < 1024) {;\n"); + fprintf(f, " if (dataSize < io->getMaxInlineSize()) {;\n"); fprintf(f, " cmd = static_cast<RS_CMD_%s *>(io->coreHeader(RS_CMD_ID_%s, dataSize + size));\n", api->name, api->name); fprintf(f, " } else {\n"); fprintf(f, " cmd = static_cast<RS_CMD_%s *>(io->coreHeader(RS_CMD_ID_%s, size));\n", api->name, api->name); @@ -252,7 +252,7 @@ void printApiCpp(FILE *f) { const VarType *vt = &api->params[ct2]; needFlush += vt->ptrLevel; if (vt->ptrLevel && hasInlineDataPointers(api)) { - fprintf(f, " if (dataSize < 1024) {\n"); + fprintf(f, " if (dataSize < io->getMaxInlineSize()) {\n"); fprintf(f, " memcpy(payload, %s, %s_length);\n", vt->name, vt->name); fprintf(f, " cmd->%s = (", vt->name); printVarType(f, vt); @@ -272,7 +272,7 @@ void printApiCpp(FILE *f) { fprintf(f, " io->coreCommit();\n"); if (hasInlineDataPointers(api)) { - fprintf(f, " if (dataSize >= 1024) {\n"); + fprintf(f, " if (dataSize >= io->getMaxInlineSize()) {\n"); fprintf(f, " io->coreGetReturn(NULL, 0);\n"); fprintf(f, " }\n"); } else if (api->ret.typeName[0]) { @@ -288,81 +288,71 @@ void printApiCpp(FILE *f) { fprintf(f, "};\n\n"); + // Generate a remote sender function + const char * str = "core"; + if (api->direct) { + str = "async"; + } + fprintf(f, "static "); printFuncDecl(f, api, "RF_", 0, 0); fprintf(f, "\n{\n"); - fprintf(f, " Fifo *f = NULL;\n"); - fprintf(f, " RS_CMD_%s cmd;\n", api->name); - fprintf(f, " const uint32_t cmdSize = sizeof(cmd);\n"); + fprintf(f, " ThreadIO *io = &((Context *)rsc)->mIO;\n"); fprintf(f, " const uint32_t cmdID = RS_CMD_ID_%s;\n", api->name); - fprintf(f, " f->writeAsync(&cmdID, sizeof(cmdID));\n"); - fprintf(f, " intptr_t offset = cmdSize;\n"); - fprintf(f, " uint32_t dataSize = 0;\n"); + fprintf(f, " io->%sWrite(&cmdID, sizeof(cmdID));\n\n", str); + for (ct2=0; ct2 < api->paramCount; ct2++) { const VarType *vt = &api->params[ct2]; - if (vt->isConst && vt->ptrLevel) { - switch(vt->ptrLevel) { - case 1: - fprintf(f, " dataSize += %s_length;\n", vt->name); - break; - case 2: - fprintf(f, " for (size_t ct = 0; ct < (%s_length_length / sizeof(%s_length)); ct++) {\n", vt->name, vt->name); - fprintf(f, " dataSize += %s_length[ct];\n", vt->name); - fprintf(f, " }\n"); - break; - default: - printf("pointer level not handled!!"); - } + if (vt->ptrLevel == 0) { + fprintf(f, " io->%sWrite(& %s, sizeof(%s));\n", str, vt->name, vt->name); } } fprintf(f, "\n"); for (ct2=0; ct2 < api->paramCount; ct2++) { const VarType *vt = &api->params[ct2]; - switch(vt->ptrLevel) { - case 0: - fprintf(f, " cmd.%s = %s;\n", vt->name, vt->name); - break; - case 1: - fprintf(f, " cmd.%s = (", vt->name); - printVarType(f, vt); - fprintf(f, ")offset;\n"); - fprintf(f, " offset += %s_length;\n", vt->name); - break; - case 2: - fprintf(f, " cmd.%s = (", vt->name); - printVarType(f, vt); - fprintf(f, ")offset;\n"); + if ((vt->ptrLevel == 1) && (vt->isConst)) { + fprintf(f, " io->%sWrite(%s, %s_length);\n", str, vt->name, vt->name); + } + } + fprintf(f, "\n"); + + for (ct2=0; ct2 < api->paramCount; ct2++) { + const VarType *vt = &api->params[ct2]; + if ((vt->ptrLevel == 2) && (vt->isConst)) { fprintf(f, " for (size_t ct = 0; ct < (%s_length_length / sizeof(%s_length)); ct++) {\n", vt->name, vt->name); - fprintf(f, " offset += %s_length[ct];\n", vt->name); + fprintf(f, " io->%sWrite(%s[ct], %s_length[ct]);\n", str, vt->name, vt->name); fprintf(f, " }\n"); - break; - default: - fprintf(stderr, "pointer level not handled!!"); } } fprintf(f, "\n"); - fprintf(f, " f->writeAsync(&cmd, cmdSize);\n"); for (ct2=0; ct2 < api->paramCount; ct2++) { const VarType *vt = &api->params[ct2]; - if (vt->ptrLevel == 1) { - fprintf(f, " f->writeAsync(%s, %s_length);\n", vt->name, vt->name); + if ((vt->ptrLevel == 1) && (!vt->isConst)) { + fprintf(f, " io->%sGetReturn(%s, %s_length);\n", str, vt->name, vt->name); } - if (vt->ptrLevel == 2) { + } + fprintf(f, "\n"); + + for (ct2=0; ct2 < api->paramCount; ct2++) { + const VarType *vt = &api->params[ct2]; + if ((vt->ptrLevel == 2) && (!vt->isConst)) { fprintf(f, " for (size_t ct = 0; ct < (%s_length_length / sizeof(%s_length)); ct++) {\n", vt->name, vt->name); - fprintf(f, " f->writeAsync(%s, %s_length[ct]);\n", vt->name, vt->name); - fprintf(f, " offset += %s_length[ct];\n", vt->name); + fprintf(f, " io->%sGetReturn(%s[ct], %s_length[ct]);\n", str, vt->name, vt->name); fprintf(f, " }\n"); } } + fprintf(f, "\n"); if (api->ret.typeName[0]) { fprintf(f, " "); printVarType(f, &api->ret); fprintf(f, " retValue;\n"); - fprintf(f, " f->writeWaitReturn(&retValue, sizeof(retValue));\n"); + fprintf(f, " io->%sGetReturn(&retValue, sizeof(retValue));\n", str); fprintf(f, " return retValue;\n"); + } else /*if (api->sync)*/ { + fprintf(f, " io->%sGetReturn(NULL, 0);\n", str); } fprintf(f, "}\n\n"); } @@ -418,7 +408,6 @@ void printPlaybackCpp(FILE *f) { fprintf(f, "#include \"rsDevice.h\"\n"); fprintf(f, "#include \"rsContext.h\"\n"); fprintf(f, "#include \"rsThreadIO.h\"\n"); - //fprintf(f, "#include \"rsgApiStructs.h\"\n"); fprintf(f, "#include \"rsgApiFuncDecl.h\"\n"); fprintf(f, "\n"); fprintf(f, "namespace android {\n"); @@ -434,8 +423,6 @@ void printPlaybackCpp(FILE *f) { } fprintf(f, "void rsp_%s(Context *con, const void *vp, size_t cmdSizeBytes) {\n", api->name); - - //fprintf(f, " ALOGE(\"play command %s\\n\");\n", api->name); fprintf(f, " const RS_CMD_%s *cmd = static_cast<const RS_CMD_%s *>(vp);\n", api->name, api->name); if (hasInlineDataPointers(api)) { @@ -488,30 +475,40 @@ void printPlaybackCpp(FILE *f) { const ApiEntry * api = &apis[ct]; int needFlush = 0; - fprintf(f, "void rspr_%s(Context *con, Fifo *f, uint8_t *scratch, size_t scratchSize) {\n", api->name); - - //fprintf(f, " ALOGE(\"play command %s\\n\");\n", api->name); + fprintf(f, "void rspr_%s(Context *con, ThreadIO *io) {\n", api->name); fprintf(f, " RS_CMD_%s cmd;\n", api->name); - fprintf(f, " f->read(&cmd, sizeof(cmd));\n"); for (ct2=0; ct2 < api->paramCount; ct2++) { const VarType *vt = &api->params[ct2]; - needFlush += vt->ptrLevel; + if (vt->ptrLevel == 0) { + fprintf(f, " io->coreRead(&cmd.%s, sizeof(cmd.%s));\n", vt->name, vt->name); + } + } + fprintf(f, "\n"); + + for (ct2=0; ct2 < api->paramCount; ct2++) { + const VarType *vt = &api->params[ct2]; if (vt->ptrLevel == 1) { fprintf(f, " cmd.%s = (", vt->name); printVarType(f, vt); - fprintf(f, ")scratch;\n"); - fprintf(f, " f->read(scratch, cmd.%s_length);\n", vt->name); - fprintf(f, " scratch += cmd.%s_length;\n", vt->name); + fprintf(f, ")malloc(cmd.%s_length);\n", vt->name); + + if (vt->isConst) { + fprintf(f, " if (cmd.%s_length) io->coreRead((void *)cmd.%s, cmd.%s_length);\n", vt->name, vt->name, vt->name); + } } + } + fprintf(f, "\n"); + + for (ct2=0; ct2 < api->paramCount; ct2++) { + const VarType *vt = &api->params[ct2]; if (vt->ptrLevel == 2) { - fprintf(f, " size_t sum_%s = 0;\n", vt->name); fprintf(f, " for (size_t ct = 0; ct < (cmd.%s_length_length / sizeof(cmd.%s_length)); ct++) {\n", vt->name, vt->name); - fprintf(f, " ((size_t *)scratch)[ct] = cmd.%s_length[ct];\n", vt->name); - fprintf(f, " sum_%s += cmd.%s_length[ct];\n", vt->name, vt->name); + fprintf(f, " cmd.%s = (", vt->name); + printVarType(f, vt); + fprintf(f, ")malloc(cmd.%s_length[ct]);\n", vt->name); + fprintf(f, " io->coreRead(& cmd.%s, cmd.%s_length[ct]);\n", vt->name, vt->name); fprintf(f, " }\n"); - fprintf(f, " f->read(scratch, sum_%s);\n", vt->name); - fprintf(f, " scratch += sum_%s;\n", vt->name); } } fprintf(f, "\n"); @@ -535,10 +532,42 @@ void printPlaybackCpp(FILE *f) { } fprintf(f, ");\n"); + for (ct2=0; ct2 < api->paramCount; ct2++) { + const VarType *vt = &api->params[ct2]; + if ((vt->ptrLevel == 1) && (!vt->isConst)) { + fprintf(f, " io->coreSetReturn((void *)cmd.%s, cmd.%s_length);\n", vt->name, vt->name); + } + } + + for (ct2=0; ct2 < api->paramCount; ct2++) { + const VarType *vt = &api->params[ct2]; + if ((vt->ptrLevel == 2) && (!vt->isConst)) { + fprintf(f, " for (size_t ct = 0; ct < (cmd.%s_length_length / sizeof(cmd.%s_length)); ct++) {\n", vt->name, vt->name); + fprintf(f, " io->coreSetReturn((void *)cmd.%s[ct], cmd.%s_length[ct]);\n", vt->name, vt->name); + fprintf(f, " }\n"); + } + } + fprintf(f, "\n"); + if (api->ret.typeName[0]) { - fprintf(f, " f->readReturn(&ret, sizeof(ret));\n"); - } else if (needFlush) { - fprintf(f, " f->readReturn(NULL, 0);\n"); + fprintf(f, " io->coreSetReturn(&ret, sizeof(ret));\n"); + } else /*if (needFlush)*/ { + fprintf(f, " io->coreSetReturn(NULL, 0);\n"); + } + + for (ct2=0; ct2 < api->paramCount; ct2++) { + const VarType *vt = &api->params[ct2]; + if (vt->ptrLevel == 1) { + fprintf(f, " free((void *)cmd.%s);\n", vt->name); + } + } + for (ct2=0; ct2 < api->paramCount; ct2++) { + const VarType *vt = &api->params[ct2]; + if (vt->ptrLevel == 2) { + fprintf(f, " for (size_t ct = 0; ct < (cmd.%s_length_length / sizeof(cmd.%s_length)); ct++) {\n", vt->name, vt->name); + fprintf(f, " free((void *)cmd.%s);\n", vt->name); + fprintf(f, " }\n"); + } } fprintf(f, "};\n\n"); @@ -608,7 +637,7 @@ int main(int argc, char **argv) { fprintf(f, " uint32_t size;\n"); fprintf(f, "} RsPlaybackRemoteHeader;\n\n"); fprintf(f, "typedef void (*RsPlaybackLocalFunc)(Context *, const void *, size_t sizeBytes);\n"); - fprintf(f, "typedef void (*RsPlaybackRemoteFunc)(Context *, Fifo *, uint8_t *scratch, size_t scratchSize);\n"); + fprintf(f, "typedef void (*RsPlaybackRemoteFunc)(Context *, ThreadIO *);\n"); fprintf(f, "extern RsPlaybackLocalFunc gPlaybackFuncs[%i];\n", apiCount + 1); fprintf(f, "extern RsPlaybackRemoteFunc gPlaybackRemoteFuncs[%i];\n", apiCount + 1); diff --git a/libs/rs/scriptc/rs_allocation.rsh b/libs/rs/scriptc/rs_allocation.rsh index 9ec03bf840ca..a2f69d9942d0 100644 --- a/libs/rs/scriptc/rs_allocation.rsh +++ b/libs/rs/scriptc/rs_allocation.rsh @@ -168,5 +168,135 @@ extern const void * __attribute__((overloadable)) extern const void * __attribute__((overloadable)) rsGetElementAt(rs_allocation, uint32_t x, uint32_t y, uint32_t z); +/** + * @param a allocation to get data from + * @return element describing allocation layout + */ +extern rs_element __attribute__((overloadable)) + rsAllocationGetElement(rs_allocation a); + +/** + * @param m mesh to get data from + * @return number of allocations in the mesh that contain vertex + * data + */ +extern uint32_t __attribute__((overloadable)) + rsMeshGetVertexAllocationCount(rs_mesh m); + +/** + * @param m mesh to get data from + * @return number of primitive groups in the mesh. This would + * include simple primitives as well as allocations + * containing index data + */ +extern uint32_t __attribute__((overloadable)) + rsMeshGetPrimitiveCount(rs_mesh m); + +/** + * @param m mesh to get data from + * @param index index of the vertex allocation + * @return allocation containing vertex data + */ +extern rs_allocation __attribute__((overloadable)) + rsMeshGetVertexAllocation(rs_mesh m, uint32_t index); + +/** + * @param m mesh to get data from + * @param index index of the index allocation + * @return allocation containing index data + */ +extern rs_allocation __attribute__((overloadable)) + rsMeshGetIndexAllocation(rs_mesh m, uint32_t index); + +/** + * @param m mesh to get data from + * @param index index of the primitive + * @return primitive describing how the mesh is rendered + */ +extern rs_primitive __attribute__((overloadable)) + rsMeshGetPrimitive(rs_mesh m, uint32_t index); + +/** + * @param e element to get data from + * @return number of sub-elements in this element + */ +extern uint32_t __attribute__((overloadable)) + rsElementGetSubElementCount(rs_element e); + +/** + * @param e element to get data from + * @param index index of the sub-element to return + * @return sub-element in this element at given index + */ +extern rs_element __attribute__((overloadable)) + rsElementGetSubElement(rs_element, uint32_t index); + +/** + * @param e element to get data from + * @param index index of the sub-element to return + * @return length of the sub-element name including the null + * terminator (size of buffer needed to write the name) + */ +extern uint32_t __attribute__((overloadable)) + rsElementGetSubElementNameLength(rs_element e, uint32_t index); + +/** + * @param e element to get data from + * @param index index of the sub-element + * @param name array to store the name into + * @param nameLength length of the provided name array + * @return number of characters actually written, excluding the + * null terminator + */ +extern uint32_t __attribute__((overloadable)) + rsElementGetSubElementName(rs_element e, uint32_t index, char *name, uint32_t nameLength); + +/** + * @param e element to get data from + * @param index index of the sub-element + * @return array size of sub-element in this element at given + * index + */ +extern uint32_t __attribute__((overloadable)) + rsElementGetSubElementArraySize(rs_element e, uint32_t index); + +/** + * @param e element to get data from + * @param index index of the sub-element + * @return offset in bytes of sub-element in this element at + * given index + */ +extern uint32_t __attribute__((overloadable)) + rsElementGetSubElementOffsetBytes(rs_element e, uint32_t index); + +/** + * @param e element to get data from + * @return total size of the element in bytes + */ +extern uint32_t __attribute__((overloadable)) + rsElementGetSizeBytes(rs_element e); + +/** + * @param e element to get data from + * @return element's data type + */ +extern rs_data_type __attribute__((overloadable)) + rsElementGetDataType(rs_element e); + +/** + * @param e element to get data from + * @return element's data size + */ +extern rs_data_kind __attribute__((overloadable)) + rsElementGetDataKind(rs_element e); + +/** + * @param e element to get data from + * @return length of the element vector (for float2, float3, + * etc.) + */ +extern uint32_t __attribute__((overloadable)) + rsElementGetVectorSize(rs_element e); + #endif diff --git a/libs/rs/scriptc/rs_graphics.rsh b/libs/rs/scriptc/rs_graphics.rsh index 25819537e26b..7fdebdcd0468 100644 --- a/libs/rs/scriptc/rs_graphics.rsh +++ b/libs/rs/scriptc/rs_graphics.rsh @@ -22,6 +22,66 @@ */ #ifndef __RS_GRAPHICS_RSH__ #define __RS_GRAPHICS_RSH__ + +// These are API 15 once it get official +typedef enum { + RS_DEPTH_FUNC_ALWAYS, + RS_DEPTH_FUNC_LESS, + RS_DEPTH_FUNC_LEQUAL, + RS_DEPTH_FUNC_GREATER, + RS_DEPTH_FUNC_GEQUAL, + RS_DEPTH_FUNC_EQUAL, + RS_DEPTH_FUNC_NOTEQUAL, + + RS_DEPTH_FUNC_INVALID = 100, +} rs_depth_func; + +typedef enum { + RS_BLEND_SRC_ZERO, // 0 + RS_BLEND_SRC_ONE, // 1 + RS_BLEND_SRC_DST_COLOR, // 2 + RS_BLEND_SRC_ONE_MINUS_DST_COLOR, // 3 + RS_BLEND_SRC_SRC_ALPHA, // 4 + RS_BLEND_SRC_ONE_MINUS_SRC_ALPHA, // 5 + RS_BLEND_SRC_DST_ALPHA, // 6 + RS_BLEND_SRC_ONE_MINUS_DST_ALPHA, // 7 + RS_BLEND_SRC_SRC_ALPHA_SATURATE, // 8 + + RS_BLEND_SRC_INVALID = 100, +} rs_blend_src_func; + +typedef enum { + RS_BLEND_DST_ZERO, // 0 + RS_BLEND_DST_ONE, // 1 + RS_BLEND_DST_SRC_COLOR, // 2 + RS_BLEND_DST_ONE_MINUS_SRC_COLOR, // 3 + RS_BLEND_DST_SRC_ALPHA, // 4 + RS_BLEND_DST_ONE_MINUS_SRC_ALPHA, // 5 + RS_BLEND_DST_DST_ALPHA, // 6 + RS_BLEND_DST_ONE_MINUS_DST_ALPHA, // 7 + + RS_BLEND_DST_INVALID = 100, +} rs_blend_dst_func; + +typedef enum { + RS_CULL_BACK, + RS_CULL_FRONT, + RS_CULL_NONE, + + RS_CULL_INVALID = 100, +} rs_cull_mode; + +typedef enum { + RS_SAMPLER_NEAREST, + RS_SAMPLER_LINEAR, + RS_SAMPLER_LINEAR_MIP_LINEAR, + RS_SAMPLER_WRAP, + RS_SAMPLER_CLAMP, + RS_SAMPLER_LINEAR_MIP_NEAREST, + + RS_SAMPLER_INVALID = 100, +} rs_sampler_value; + #if (defined(RS_VERSION) && (RS_VERSION >= 14)) /** * Set the color target used for all subsequent rendering calls @@ -82,6 +142,88 @@ extern void __attribute__((overloadable)) extern void __attribute__((overloadable)) rsgBindProgramStore(rs_program_store ps); + +/** + * @hide + * Get program store depth function + * + * @param ps + */ +extern rs_depth_func __attribute__((overloadable)) + rsgProgramStoreGetDepthFunc(rs_program_store ps); + +/** + * @hide + * Get program store depth mask + * + * @param ps + */ +extern bool __attribute__((overloadable)) + rsgProgramStoreGetDepthMask(rs_program_store ps); +/** + * @hide + * Get program store red component color mask + * + * @param ps + */ +extern bool __attribute__((overloadable)) + rsgProgramStoreGetColorMaskR(rs_program_store ps); + +/** + * @hide + * Get program store green component color mask + * + * @param ps + */ +extern bool __attribute__((overloadable)) + rsgProgramStoreGetColorMaskG(rs_program_store ps); + +/** + * @hide + * Get program store blur component color mask + * + * @param ps + */ +extern bool __attribute__((overloadable)) + rsgProgramStoreGetColorMaskB(rs_program_store ps); + +/** + * @hide + * Get program store alpha component color mask + * + * @param ps + */ +extern bool __attribute__((overloadable)) + rsgProgramStoreGetColorMaskA(rs_program_store ps); + +/** + * @hide + * Get program store blend source function + * + * @param ps + */ +extern rs_blend_src_func __attribute__((overloadable)) + rsgProgramStoreGetBlendSrcFunc(rs_program_store ps); + +/** + * @hide + * Get program store blend destination function + * + * @param ps + */ +extern rs_blend_dst_func __attribute__((overloadable)) + rsgProgramStoreGetBlendDstFunc(rs_program_store ps); + +/** + * @hide + * Get program store dither state + * + * @param ps + */ +extern bool __attribute__((overloadable)) + rsgProgramStoreGetDitherEnabled(rs_program_store ps); + + /** * Bind a new ProgramVertex to the rendering context. * @@ -99,6 +241,24 @@ extern void __attribute__((overloadable)) rsgBindProgramRaster(rs_program_raster pr); /** + * @hide + * Get program raster point sprite state + * + * @param pr + */ +extern bool __attribute__((overloadable)) + rsgProgramRasterGetPointSpriteEnabled(rs_program_raster pr); + +/** + * @hide + * Get program raster cull mode + * + * @param pr + */ +extern rs_cull_mode __attribute__((overloadable)) + rsgProgramRasterGetCullMode(rs_program_raster pr); + +/** * Bind a new Sampler object to a ProgramFragment. The sampler will * operate on the texture bound at the matching slot. * @@ -108,6 +268,51 @@ extern void __attribute__((overloadable)) rsgBindSampler(rs_program_fragment, uint slot, rs_sampler); /** + * @hide + * Get sampler minification value + * + * @param pr + */ +extern rs_sampler_value __attribute__((overloadable)) + rsgSamplerGetMinification(rs_sampler s); + +/** + * @hide + * Get sampler magnification value + * + * @param pr + */ +extern rs_sampler_value __attribute__((overloadable)) + rsgSamplerGetMagnification(rs_sampler s); + +/** + * @hide + * Get sampler wrap S value + * + * @param pr + */ +extern rs_sampler_value __attribute__((overloadable)) + rsgSamplerGetWrapS(rs_sampler s); + +/** + * @hide + * Get sampler wrap T value + * + * @param pr + */ +extern rs_sampler_value __attribute__((overloadable)) + rsgSamplerGetWrapT(rs_sampler s); + +/** + * @hide + * Get sampler anisotropy + * + * @param pr + */ +extern float __attribute__((overloadable)) + rsgSamplerGetAnisotropy(rs_sampler s); + +/** * Bind a new Allocation object to a ProgramFragment. The * Allocation must be a valid texture for the Program. The sampling * of the texture will be controled by the Sampler bound at the @@ -164,6 +369,28 @@ extern void __attribute__((overloadable)) rsgProgramFragmentConstantColor(rs_program_fragment pf, float r, float g, float b, float a); /** + * Bind a new Allocation object to a ProgramFragment. The + * Allocation must be a valid constant input for the Program. + * + * @param ps program object + * @param slot index of the constant buffer on the program + * @param c constants to bind + */ +extern void __attribute__((overloadable)) + rsgBindConstant(rs_program_fragment ps, uint slot, rs_allocation c); + +/** + * Bind a new Allocation object to a ProgramVertex. The + * Allocation must be a valid constant input for the Program. + * + * @param pv program object + * @param slot index of the constant buffer on the program + * @param c constants to bind + */ +extern void __attribute__((overloadable)) + rsgBindConstant(rs_program_vertex pv, uint slot, rs_allocation c); + +/** * Get the width of the current rendering surface. * * @return uint @@ -288,6 +515,9 @@ extern void __attribute__((overloadable)) extern void __attribute__((overloadable)) rsgDrawSpriteScreenspace(float x, float y, float z, float w, float h); +extern void __attribute__((overloadable)) + rsgDrawPath(rs_path p); + /** * Draw a mesh using the current context state. The whole mesh is * rendered. diff --git a/libs/rs/scriptc/rs_object.rsh b/libs/rs/scriptc/rs_object.rsh index a43121937ea8..1fc3f83b49d6 100644 --- a/libs/rs/scriptc/rs_object.rsh +++ b/libs/rs/scriptc/rs_object.rsh @@ -56,6 +56,11 @@ extern void __attribute__((overloadable)) * \overload */ extern void __attribute__((overloadable)) + rsSetObject(rs_path *dst, rs_path src); +/** + * \overload + */ +extern void __attribute__((overloadable)) rsSetObject(rs_mesh *dst, rs_mesh src); /** * \overload @@ -114,6 +119,11 @@ extern void __attribute__((overloadable)) * \overload */ extern void __attribute__((overloadable)) + rsClearObject(rs_path *dst); +/** + * \overload + */ +extern void __attribute__((overloadable)) rsClearObject(rs_mesh *dst); /** * \overload @@ -175,6 +185,11 @@ extern bool __attribute__((overloadable)) * \overload */ extern bool __attribute__((overloadable)) + rsIsObject(rs_path); +/** + * \overload + */ +extern bool __attribute__((overloadable)) rsIsObject(rs_mesh); /** * \overload diff --git a/libs/rs/scriptc/rs_types.rsh b/libs/rs/scriptc/rs_types.rsh index 84bca9c8a7e5..5345a48ef895 100644 --- a/libs/rs/scriptc/rs_types.rsh +++ b/libs/rs/scriptc/rs_types.rsh @@ -138,6 +138,12 @@ typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_sc */ typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_mesh; /** + * \brief Opaque handle to a Renderscript Path object. + * + * See: android.renderscript.Path + */ +typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_path; +/** * \brief Opaque handle to a Renderscript ProgramFragment object. * * See: android.renderscript.ProgramFragment @@ -396,4 +402,96 @@ typedef enum { #endif //defined(RS_VERSION) && (RS_VERSION >= 14) +/** + * Describes the way mesh vertex data is interpreted when rendering + * + **/ +typedef enum { + RS_PRIMITIVE_POINT, + RS_PRIMITIVE_LINE, + RS_PRIMITIVE_LINE_STRIP, + RS_PRIMITIVE_TRIANGLE, + RS_PRIMITIVE_TRIANGLE_STRIP, + RS_PRIMITIVE_TRIANGLE_FAN, + + RS_PRIMITIVE_INVALID = 100, +} rs_primitive; + +/** + * \brief Enumeration for possible element data types + * + * DataType represents the basic type information for a basic element. The + * naming convention follows. For numeric types it is FLOAT, + * SIGNED, or UNSIGNED followed by the _BITS where BITS is the + * size of the data. BOOLEAN is a true / false (1,0) + * represented in an 8 bit container. The UNSIGNED variants + * with multiple bit definitions are for packed graphical data + * formats and represent vectors with per vector member sizes + * which are treated as a single unit for packing and alignment + * purposes. + * + * MATRIX the three matrix types contain FLOAT_32 elements and are treated + * as 32 bits for alignment purposes. + * + * RS_* objects. 32 bit opaque handles. + */ +typedef enum { + RS_TYPE_NONE, + //RS_TYPE_FLOAT_16, + RS_TYPE_FLOAT_32 = 2, + RS_TYPE_FLOAT_64, + RS_TYPE_SIGNED_8, + RS_TYPE_SIGNED_16, + RS_TYPE_SIGNED_32, + RS_TYPE_SIGNED_64, + RS_TYPE_UNSIGNED_8, + RS_TYPE_UNSIGNED_16, + RS_TYPE_UNSIGNED_32, + RS_TYPE_UNSIGNED_64, + + RS_TYPE_BOOLEAN, + + RS_TYPE_UNSIGNED_5_6_5, + RS_TYPE_UNSIGNED_5_5_5_1, + RS_TYPE_UNSIGNED_4_4_4_4, + + RS_TYPE_MATRIX_4X4, + RS_TYPE_MATRIX_3X3, + RS_TYPE_MATRIX_2X2, + + RS_TYPE_ELEMENT = 1000, + RS_TYPE_TYPE, + RS_TYPE_ALLOCATION, + RS_TYPE_SAMPLER, + RS_TYPE_SCRIPT, + RS_TYPE_MESH, + RS_TYPE_PROGRAM_FRAGMENT, + RS_TYPE_PROGRAM_VERTEX, + RS_TYPE_PROGRAM_RASTER, + RS_TYPE_PROGRAM_STORE, + + RS_TYPE_INVALID = 10000, +} rs_data_type; + +/** + * \brief Enumeration for possible element data kind + * + * The special interpretation of the data if required. This is primarly + * useful for graphical data. USER indicates no special interpretation is + * expected. PIXEL is used in conjunction with the standard data types for + * representing texture formats. + */ +typedef enum { + RS_KIND_USER, + + RS_KIND_PIXEL_L = 7, + RS_KIND_PIXEL_A, + RS_KIND_PIXEL_LA, + RS_KIND_PIXEL_RGB, + RS_KIND_PIXEL_RGBA, + RS_KIND_PIXEL_DEPTH, + + RS_KIND_INVALID = 100, +} rs_data_kind; + #endif diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp index 263c8d919889..ca09caf6a255 100644 --- a/libs/ui/Input.cpp +++ b/libs/ui/Input.cpp @@ -24,7 +24,7 @@ #include <unistd.h> #include <ctype.h> -#include <ui/Input.h> +#include <androidfw/Input.h> #include <math.h> #include <limits.h> diff --git a/libs/ui/InputTransport.cpp b/libs/ui/InputTransport.cpp index ecb3fb5c9870..1ebd75cda17f 100644 --- a/libs/ui/InputTransport.cpp +++ b/libs/ui/InputTransport.cpp @@ -20,7 +20,7 @@ #include <cutils/log.h> #include <errno.h> #include <fcntl.h> -#include <ui/InputTransport.h> +#include <androidfw/InputTransport.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> diff --git a/libs/ui/KeyCharacterMap.cpp b/libs/ui/KeyCharacterMap.cpp index 485234c2abbc..6984084370ab 100644 --- a/libs/ui/KeyCharacterMap.cpp +++ b/libs/ui/KeyCharacterMap.cpp @@ -19,8 +19,8 @@ #include <stdlib.h> #include <string.h> #include <android/keycodes.h> -#include <ui/Keyboard.h> -#include <ui/KeyCharacterMap.h> +#include <androidfw/Keyboard.h> +#include <androidfw/KeyCharacterMap.h> #include <utils/Log.h> #include <utils/Errors.h> #include <utils/Tokenizer.h> diff --git a/libs/ui/KeyLayoutMap.cpp b/libs/ui/KeyLayoutMap.cpp index 44a94207c1c2..15d81ee2ed74 100644 --- a/libs/ui/KeyLayoutMap.cpp +++ b/libs/ui/KeyLayoutMap.cpp @@ -18,8 +18,8 @@ #include <stdlib.h> #include <android/keycodes.h> -#include <ui/Keyboard.h> -#include <ui/KeyLayoutMap.h> +#include <androidfw/Keyboard.h> +#include <androidfw/KeyLayoutMap.h> #include <utils/Log.h> #include <utils/Errors.h> #include <utils/Tokenizer.h> diff --git a/libs/ui/Keyboard.cpp b/libs/ui/Keyboard.cpp index e4611f71cbd1..e97a5eb6c2c0 100644 --- a/libs/ui/Keyboard.cpp +++ b/libs/ui/Keyboard.cpp @@ -20,10 +20,10 @@ #include <unistd.h> #include <limits.h> -#include <ui/Keyboard.h> -#include <ui/KeycodeLabels.h> -#include <ui/KeyLayoutMap.h> -#include <ui/KeyCharacterMap.h> +#include <androidfw/Keyboard.h> +#include <androidfw/KeycodeLabels.h> +#include <androidfw/KeyLayoutMap.h> +#include <androidfw/KeyCharacterMap.h> #include <utils/Errors.h> #include <utils/Log.h> #include <cutils/properties.h> diff --git a/libs/ui/VirtualKeyMap.cpp b/libs/ui/VirtualKeyMap.cpp index 62d5b593b27c..2ba1673d35b7 100644 --- a/libs/ui/VirtualKeyMap.cpp +++ b/libs/ui/VirtualKeyMap.cpp @@ -18,7 +18,7 @@ #include <stdlib.h> #include <string.h> -#include <ui/VirtualKeyMap.h> +#include <androidfw/VirtualKeyMap.h> #include <utils/Log.h> #include <utils/Errors.h> #include <utils/Tokenizer.h> diff --git a/libs/ui/tests/InputChannel_test.cpp b/libs/ui/tests/InputChannel_test.cpp index ee422fe7d8c2..0e5d19d01009 100644 --- a/libs/ui/tests/InputChannel_test.cpp +++ b/libs/ui/tests/InputChannel_test.cpp @@ -14,9 +14,10 @@ * limitations under the License. */ -#include <ui/InputTransport.h> +#include <androidfw/InputTransport.h> #include <utils/Timers.h> #include <utils/StopWatch.h> +#include <utils/StrongPointer.h> #include <gtest/gtest.h> #include <unistd.h> #include <time.h> diff --git a/libs/ui/tests/InputEvent_test.cpp b/libs/ui/tests/InputEvent_test.cpp index e21c464a1974..ac5549cdd6dd 100644 --- a/libs/ui/tests/InputEvent_test.cpp +++ b/libs/ui/tests/InputEvent_test.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include <ui/Input.h> +#include <androidfw/Input.h> #include <gtest/gtest.h> #include <binder/Parcel.h> diff --git a/libs/ui/tests/InputPublisherAndConsumer_test.cpp b/libs/ui/tests/InputPublisherAndConsumer_test.cpp index 33030531322e..bb4524742307 100644 --- a/libs/ui/tests/InputPublisherAndConsumer_test.cpp +++ b/libs/ui/tests/InputPublisherAndConsumer_test.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include <ui/InputTransport.h> +#include <androidfw/InputTransport.h> #include <utils/Timers.h> #include <utils/StopWatch.h> #include <gtest/gtest.h> diff --git a/libs/utils/Asset.cpp b/libs/utils/Asset.cpp index 50e701aa8d89..cb7628d1d5b1 100644 --- a/libs/utils/Asset.cpp +++ b/libs/utils/Asset.cpp @@ -21,23 +21,23 @@ #define LOG_TAG "asset" //#define NDEBUG 0 -#include <utils/Asset.h> +#include <androidfw/Asset.h> +#include <androidfw/StreamingZipInflater.h> +#include <androidfw/ZipFileRO.h> +#include <androidfw/ZipUtils.h> #include <utils/Atomic.h> #include <utils/FileMap.h> -#include <utils/StreamingZipInflater.h> -#include <utils/ZipUtils.h> -#include <utils/ZipFileRO.h> #include <utils/Log.h> #include <utils/threads.h> -#include <string.h> -#include <memory.h> -#include <fcntl.h> -#include <errno.h> #include <assert.h> -#include <unistd.h> +#include <errno.h> +#include <fcntl.h> +#include <memory.h> +#include <string.h> #include <sys/stat.h> #include <sys/types.h> +#include <unistd.h> using namespace android; diff --git a/libs/utils/AssetDir.cpp b/libs/utils/AssetDir.cpp index c5f664eccf9a..475f521c117b 100644 --- a/libs/utils/AssetDir.cpp +++ b/libs/utils/AssetDir.cpp @@ -19,7 +19,7 @@ // implementation is in the header file or in friend functions in // AssetManager. // -#include <utils/AssetDir.h> +#include <androidfw/AssetDir.h> using namespace android; diff --git a/libs/utils/AssetManager.cpp b/libs/utils/AssetManager.cpp index 47a2b9953fcc..4829addecf59 100644 --- a/libs/utils/AssetManager.cpp +++ b/libs/utils/AssetManager.cpp @@ -21,23 +21,23 @@ #define LOG_TAG "asset" //#define LOG_NDEBUG 0 -#include <utils/AssetManager.h> -#include <utils/AssetDir.h> -#include <utils/Asset.h> +#include <androidfw/Asset.h> +#include <androidfw/AssetDir.h> +#include <androidfw/AssetManager.h> +#include <androidfw/ResourceTypes.h> +#include <androidfw/ZipFileRO.h> #include <utils/Atomic.h> +#include <utils/Log.h> #include <utils/String8.h> -#include <utils/ResourceTypes.h> #include <utils/String8.h> -#include <utils/ZipFileRO.h> -#include <utils/Log.h> -#include <utils/Timers.h> #include <utils/threads.h> +#include <utils/Timers.h> +#include <assert.h> #include <dirent.h> #include <errno.h> -#include <assert.h> -#include <strings.h> #include <fcntl.h> +#include <strings.h> #include <sys/stat.h> #include <unistd.h> diff --git a/libs/utils/BackupData.cpp b/libs/utils/BackupData.cpp index f956306136a1..7b1bcba2d130 100644 --- a/libs/utils/BackupData.cpp +++ b/libs/utils/BackupData.cpp @@ -16,7 +16,7 @@ #define LOG_TAG "backup_data" -#include <utils/BackupHelpers.h> +#include <androidfw/BackupHelpers.h> #include <utils/ByteOrder.h> #include <stdio.h> diff --git a/libs/utils/BackupHelpers.cpp b/libs/utils/BackupHelpers.cpp index f77a8917c7f9..7a817a78995a 100644 --- a/libs/utils/BackupHelpers.cpp +++ b/libs/utils/BackupHelpers.cpp @@ -16,7 +16,7 @@ #define LOG_TAG "file_backup_helper" -#include <utils/BackupHelpers.h> +#include <androidfw/BackupHelpers.h> #include <utils/KeyedVector.h> #include <utils/ByteOrder.h> @@ -546,7 +546,7 @@ int write_tarfile(const String8& packageName, const String8& domain, // read/write up to this much at a time. const size_t BUFSIZE = 32 * 1024; - char* buf = new char[BUFSIZE]; + char* buf = (char *)calloc(1,BUFSIZE); char* paxHeader = buf + 512; // use a different chunk of it as separate scratch char* paxData = buf + 1024; @@ -556,9 +556,6 @@ int write_tarfile(const String8& packageName, const String8& domain, goto cleanup; } - // Good to go -- first construct the standard tar header at the start of the buffer - memset(buf, 0, BUFSIZE); - // Magic fields for the ustar file format strcat(buf + 257, "ustar"); strcat(buf + 263, "00"); diff --git a/libs/utils/ObbFile.cpp b/libs/utils/ObbFile.cpp index ddf59914b87d..21e06c8db5cd 100644 --- a/libs/utils/ObbFile.cpp +++ b/libs/utils/ObbFile.cpp @@ -23,9 +23,9 @@ #define LOG_TAG "ObbFile" +#include <androidfw/ObbFile.h> #include <utils/Compat.h> #include <utils/Log.h> -#include <utils/ObbFile.h> //#define DEBUG 1 diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp index 3fa562ec6074..07f3b1624f5b 100644 --- a/libs/utils/ResourceTypes.cpp +++ b/libs/utils/ResourceTypes.cpp @@ -17,14 +17,14 @@ #define LOG_TAG "ResourceType" //#define LOG_NDEBUG 0 +#include <androidfw/ResourceTypes.h> #include <utils/Atomic.h> #include <utils/ByteOrder.h> #include <utils/Debug.h> -#include <utils/ResourceTypes.h> +#include <utils/Log.h> #include <utils/String16.h> #include <utils/String8.h> #include <utils/TextOutput.h> -#include <utils/Log.h> #include <stdlib.h> #include <string.h> @@ -379,8 +379,7 @@ status_t ResStringPool::setTo(const void* data, size_t size, bool copyData) size_t charSize; if (mHeader->flags&ResStringPool_header::UTF8_FLAG) { charSize = sizeof(uint8_t); - mCache = (char16_t**)malloc(sizeof(char16_t**)*mHeader->stringCount); - memset(mCache, 0, sizeof(char16_t**)*mHeader->stringCount); + mCache = (char16_t**)calloc(mHeader->stringCount, sizeof(char16_t**)); } else { charSize = sizeof(char16_t); } @@ -3252,16 +3251,14 @@ ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag, // Bag not found, we need to compute it! if (!grp->bags) { - grp->bags = (bag_set***)malloc(sizeof(bag_set*)*grp->typeCount); + grp->bags = (bag_set***)calloc(grp->typeCount, sizeof(bag_set*)); if (!grp->bags) return NO_MEMORY; - memset(grp->bags, 0, sizeof(bag_set*)*grp->typeCount); } bag_set** typeSet = grp->bags[t]; if (!typeSet) { - typeSet = (bag_set**)malloc(sizeof(bag_set*)*NENTRY); + typeSet = (bag_set**)calloc(NENTRY, sizeof(bag_set*)); if (!typeSet) return NO_MEMORY; - memset(typeSet, 0, sizeof(bag_set*)*NENTRY); grp->bags[t] = typeSet; } diff --git a/libs/utils/StreamingZipInflater.cpp b/libs/utils/StreamingZipInflater.cpp index 8512170ae900..d3fb98d57fac 100644 --- a/libs/utils/StreamingZipInflater.cpp +++ b/libs/utils/StreamingZipInflater.cpp @@ -18,8 +18,8 @@ #define LOG_TAG "szipinf" #include <utils/Log.h> +#include <androidfw/StreamingZipInflater.h> #include <utils/FileMap.h> -#include <utils/StreamingZipInflater.h> #include <string.h> #include <stddef.h> #include <assert.h> diff --git a/libs/utils/ZipFileCRO.cpp b/libs/utils/ZipFileCRO.cpp index 55dfd9f873b8..c8df8453df73 100644 --- a/libs/utils/ZipFileCRO.cpp +++ b/libs/utils/ZipFileCRO.cpp @@ -14,8 +14,8 @@ * limitations under the License. */ -#include <utils/ZipFileCRO.h> -#include <utils/ZipFileRO.h> +#include <androidfw/ZipFileCRO.h> +#include <androidfw/ZipFileRO.h> using namespace android; diff --git a/libs/utils/ZipFileRO.cpp b/libs/utils/ZipFileRO.cpp index 1498aac07e1e..4b7f1e73faa2 100644 --- a/libs/utils/ZipFileRO.cpp +++ b/libs/utils/ZipFileRO.cpp @@ -19,7 +19,7 @@ // #define LOG_TAG "zipro" //#define LOG_NDEBUG 0 -#include <utils/ZipFileRO.h> +#include <androidfw/ZipFileRO.h> #include <utils/Log.h> #include <utils/misc.h> #include <utils/threads.h> diff --git a/libs/utils/ZipUtils.cpp b/libs/utils/ZipUtils.cpp index 2dbdc1d3800a..db3479d3363d 100644 --- a/libs/utils/ZipUtils.cpp +++ b/libs/utils/ZipUtils.cpp @@ -20,8 +20,8 @@ #define LOG_TAG "ziputil" -#include <utils/ZipUtils.h> -#include <utils/ZipFileRO.h> +#include <androidfw/ZipUtils.h> +#include <androidfw/ZipFileRO.h> #include <utils/Log.h> #include <stdlib.h> diff --git a/libs/utils/tests/ObbFile_test.cpp b/libs/utils/tests/ObbFile_test.cpp index 46b30c2a6de0..09d4d7d985a9 100644 --- a/libs/utils/tests/ObbFile_test.cpp +++ b/libs/utils/tests/ObbFile_test.cpp @@ -15,8 +15,8 @@ */ #define LOG_TAG "ObbFile_test" +#include <androidfw/ObbFile.h> #include <utils/Log.h> -#include <utils/ObbFile.h> #include <utils/RefBase.h> #include <utils/String8.h> diff --git a/libs/utils/tests/ZipFileRO_test.cpp b/libs/utils/tests/ZipFileRO_test.cpp index 7a1d0bd958a3..344f97416b65 100644 --- a/libs/utils/tests/ZipFileRO_test.cpp +++ b/libs/utils/tests/ZipFileRO_test.cpp @@ -15,8 +15,8 @@ */ #define LOG_TAG "ZipFileRO_test" +#include <androidfw/ZipFileRO.h> #include <utils/Log.h> -#include <utils/ZipFileRO.h> #include <gtest/gtest.h> diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index eae03beae6fc..1c7f57750d02 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -591,7 +591,7 @@ public class AudioService extends IAudioService.Stub { // Post a persist volume msg sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, - SENDMSG_REPLACE, + SENDMSG_QUEUE, PERSIST_LAST_AUDIBLE, device, s, @@ -606,7 +606,7 @@ public class AudioService extends IAudioService.Stub { // to persist). Do not change volume if stream is muted. sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, - SENDMSG_NOOP, + SENDMSG_QUEUE, device, 0, streamState, @@ -746,7 +746,7 @@ public class AudioService extends IAudioService.Stub { // Post a persist volume msg sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, - SENDMSG_REPLACE, + SENDMSG_QUEUE, PERSIST_LAST_AUDIBLE, device, streamState, @@ -758,7 +758,7 @@ public class AudioService extends IAudioService.Stub { // to persist). sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, - SENDMSG_NOOP, + SENDMSG_QUEUE, device, 0, streamState, @@ -2208,7 +2208,7 @@ public class AudioService extends IAudioService.Stub { } sendMsg(mAudioHandler, MSG_SET_ALL_VOLUMES, - SENDMSG_NOOP, + SENDMSG_QUEUE, 0, 0, VolumeStreamState.this, 0); @@ -2252,7 +2252,7 @@ public class AudioService extends IAudioService.Stub { } sendMsg(mAudioHandler, MSG_SET_ALL_VOLUMES, - SENDMSG_NOOP, + SENDMSG_QUEUE, 0, 0, VolumeStreamState.this, 0); @@ -2350,7 +2350,7 @@ public class AudioService extends IAudioService.Stub { // Post a persist volume msg sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, - SENDMSG_REPLACE, + SENDMSG_QUEUE, PERSIST_CURRENT|PERSIST_LAST_AUDIBLE, device, streamState, diff --git a/media/java/android/media/audiofx/Visualizer.java b/media/java/android/media/audiofx/Visualizer.java index bcf7b89b48a5..91d0addde5f8 100755 --- a/media/java/android/media/audiofx/Visualizer.java +++ b/media/java/android/media/audiofx/Visualizer.java @@ -84,6 +84,7 @@ public class Visualizer { // to keep in sync with frameworks/base/media/jni/audioeffect/android_media_Visualizer.cpp private static final int NATIVE_EVENT_PCM_CAPTURE = 0; private static final int NATIVE_EVENT_FFT_CAPTURE = 1; + private static final int NATIVE_EVENT_SERVER_DIED = 2; // Error codes: /** @@ -147,6 +148,10 @@ public class Visualizer { * PCM and FFT capture listener registered by client */ private OnDataCaptureListener mCaptureListener = null; + /** + * Server Died listener registered by client + */ + private OnServerDiedListener mServerDiedListener = null; // accessed by native methods private int mNativeVisualizer; @@ -396,6 +401,9 @@ public class Visualizer { public interface OnDataCaptureListener { /** * Method called when a new waveform capture is available. + * <p>Data in the waveform buffer is valid only within the scope of the callback. + * Applications which needs access to the waveform data after returning from the callback + * should make a copy of the data instead of holding a reference. * @param visualizer Visualizer object on which the listener is registered. * @param waveform array of bytes containing the waveform representation. * @param samplingRate sampling rate of the audio visualized. @@ -404,6 +412,9 @@ public class Visualizer { /** * Method called when a new frequency capture is available. + * <p>Data in the fft buffer is valid only within the scope of the callback. + * Applications which needs access to the fft data after returning from the callback + * should make a copy of the data instead of holding a reference. * @param visualizer Visualizer object on which the listener is registered. * @param fft array of bytes containing the frequency representation. * @param samplingRate sampling rate of the audio visualized. @@ -452,6 +463,43 @@ public class Visualizer { } /** + * @hide + * + * The OnServerDiedListener interface defines a method called by the Visualizer to indicate that + * the connection to the native media server has been broken and that the Visualizer object will + * need to be released and re-created. + * The client application can implement this interface and register the listener with the + * {@link #setServerDiedListener(OnServerDiedListener)} method. + */ + public interface OnServerDiedListener { + /** + * @hide + * + * Method called when the native media server has died. + * <p>If the native media server encounters a fatal error and needs to restart, the binder + * connection from the {@link #Visualizer} to the media server will be broken. Data capture + * callbacks will stop happening, and client initiated calls to the {@link #Visualizer} + * instance will fail with the error code {@link #DEAD_OBJECT}. To restore functionality, + * clients should {@link #release()} their old visualizer and create a new instance. + */ + void onServerDied(); + } + + /** + * @hide + * + * Registers an OnServerDiedListener interface. + * <p>Call this method with a null listener to stop receiving server death notifications. + * @return {@link #SUCCESS} in case of success, + */ + public int setServerDiedListener(OnServerDiedListener listener) { + synchronized (mListenerLock) { + mServerDiedListener = listener; + } + return SUCCESS; + } + + /** * Helper class to handle the forwarding of native events to the appropriate listeners */ private class NativeEventHandler extends Handler @@ -463,11 +511,7 @@ public class Visualizer { mVisualizer = v; } - @Override - public void handleMessage(Message msg) { - if (mVisualizer == null) { - return; - } + private void handleCaptureMessage(Message msg) { OnDataCaptureListener l = null; synchronized (mListenerLock) { l = mVisualizer.mCaptureListener; @@ -476,6 +520,7 @@ public class Visualizer { if (l != null) { byte[] data = (byte[])msg.obj; int samplingRate = msg.arg1; + switch(msg.what) { case NATIVE_EVENT_PCM_CAPTURE: l.onWaveFormDataCapture(mVisualizer, data, samplingRate); @@ -484,11 +529,41 @@ public class Visualizer { l.onFftDataCapture(mVisualizer, data, samplingRate); break; default: - Log.e(TAG,"Unknown native event: "+msg.what); + Log.e(TAG,"Unknown native event in handleCaptureMessge: "+msg.what); break; } } } + + private void handleServerDiedMessage(Message msg) { + OnServerDiedListener l = null; + synchronized (mListenerLock) { + l = mVisualizer.mServerDiedListener; + } + + if (l != null) + l.onServerDied(); + } + + @Override + public void handleMessage(Message msg) { + if (mVisualizer == null) { + return; + } + + switch(msg.what) { + case NATIVE_EVENT_PCM_CAPTURE: + case NATIVE_EVENT_FFT_CAPTURE: + handleCaptureMessage(msg); + break; + case NATIVE_EVENT_SERVER_DIED: + handleServerDiedMessage(msg); + break; + default: + Log.e(TAG,"Unknown native event: "+msg.what); + break; + } + } } //--------------------------------------------------------- diff --git a/media/jni/audioeffect/android_media_Visualizer.cpp b/media/jni/audioeffect/android_media_Visualizer.cpp index ecd4d076aaed..f015afbaf209 100644 --- a/media/jni/audioeffect/android_media_Visualizer.cpp +++ b/media/jni/audioeffect/android_media_Visualizer.cpp @@ -23,6 +23,7 @@ #include <nativehelper/jni.h> #include <nativehelper/JNIHelp.h> #include <android_runtime/AndroidRuntime.h> +#include <utils/threads.h> #include "media/Visualizer.h" using namespace android; @@ -38,6 +39,7 @@ using namespace android; #define NATIVE_EVENT_PCM_CAPTURE 0 #define NATIVE_EVENT_FFT_CAPTURE 1 +#define NATIVE_EVENT_SERVER_DIED 2 // ---------------------------------------------------------------------------- static const char* const kClassPathName = "android/media/audiofx/Visualizer"; @@ -54,6 +56,43 @@ static fields_t fields; struct visualizer_callback_cookie { jclass visualizer_class; // Visualizer class jobject visualizer_ref; // Visualizer object instance + + // Lazily allocated arrays used to hold callback data provided to java + // applications. These arrays are allocated during the first callback and + // reallocated when the size of the callback data changes. Allocating on + // demand and saving the arrays means that applications cannot safely hold a + // reference to the provided data (they need to make a copy if they want to + // hold onto outside of the callback scope), but it avoids GC thrash caused + // by constantly allocating and releasing arrays to hold callback data. + Mutex callback_data_lock; + jbyteArray waveform_data; + jbyteArray fft_data; + + visualizer_callback_cookie() { + waveform_data = NULL; + fft_data = NULL; + } + + ~visualizer_callback_cookie() { + cleanupBuffers(); + } + + void cleanupBuffers() { + AutoMutex lock(&callback_data_lock); + if (waveform_data || fft_data) { + JNIEnv *env = AndroidRuntime::getJNIEnv(); + + if (waveform_data) { + env->DeleteGlobalRef(waveform_data); + waveform_data = NULL; + } + + if (fft_data) { + env->DeleteGlobalRef(fft_data); + fft_data = NULL; + } + } + } }; // ---------------------------------------------------------------------------- @@ -66,7 +105,6 @@ class visualizerJniStorage { ~visualizerJniStorage() { } - }; @@ -93,6 +131,26 @@ static jint translateError(int code) { // ---------------------------------------------------------------------------- +static void ensureArraySize(JNIEnv *env, jbyteArray *array, uint32_t size) { + if (NULL != *array) { + uint32_t len = env->GetArrayLength(*array); + if (len == size) + return; + + env->DeleteGlobalRef(*array); + *array = NULL; + } + + jbyteArray localRef = env->NewByteArray(size); + if (NULL != localRef) { + // Promote to global ref. + *array = (jbyteArray)env->NewGlobalRef(localRef); + + // Release our (now pointless) local ref. + env->DeleteLocalRef(localRef); + } +} + static void captureCallback(void* user, uint32_t waveformSize, uint8_t *waveform, @@ -106,6 +164,7 @@ static void captureCallback(void* user, visualizer_callback_cookie *callbackInfo = (visualizer_callback_cookie *)user; JNIEnv *env = AndroidRuntime::getJNIEnv(); + AutoMutex lock(&callbackInfo->callback_data_lock); ALOGV("captureCallback: callbackInfo %p, visualizer_ref %p visualizer_class %p", callbackInfo, @@ -118,7 +177,11 @@ static void captureCallback(void* user, } if (waveformSize != 0 && waveform != NULL) { - jbyteArray jArray = env->NewByteArray(waveformSize); + jbyteArray jArray; + + ensureArraySize(env, &callbackInfo->waveform_data, waveformSize); + jArray = callbackInfo->waveform_data; + if (jArray != NULL) { jbyte *nArray = env->GetByteArrayElements(jArray, NULL); memcpy(nArray, waveform, waveformSize); @@ -131,12 +194,15 @@ static void captureCallback(void* user, samplingrate, 0, jArray); - env->DeleteLocalRef(jArray); } } if (fftSize != 0 && fft != NULL) { - jbyteArray jArray = env->NewByteArray(fftSize); + jbyteArray jArray; + + ensureArraySize(env, &callbackInfo->fft_data, fftSize); + jArray = callbackInfo->fft_data; + if (jArray != NULL) { jbyte *nArray = env->GetByteArrayElements(jArray, NULL); memcpy(nArray, fft, fftSize); @@ -149,7 +215,6 @@ static void captureCallback(void* user, samplingrate, 0, jArray); - env->DeleteLocalRef(jArray); } } @@ -220,6 +285,23 @@ android_media_visualizer_native_init(JNIEnv *env) } +static void android_media_visualizer_effect_callback(int32_t event, + void *user, + void *info) { + if ((event == AudioEffect::EVENT_ERROR) && + (*((status_t*)info) == DEAD_OBJECT)) { + visualizerJniStorage* lpJniStorage = (visualizerJniStorage*)user; + visualizer_callback_cookie* callbackInfo = &lpJniStorage->mCallbackData; + JNIEnv *env = AndroidRuntime::getJNIEnv(); + + env->CallStaticVoidMethod( + callbackInfo->visualizer_class, + fields.midPostNativeEvent, + callbackInfo->visualizer_ref, + NATIVE_EVENT_SERVER_DIED, + 0, 0, 0); + } +} static jint android_media_visualizer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this, @@ -255,8 +337,8 @@ android_media_visualizer_native_setup(JNIEnv *env, jobject thiz, jobject weak_th // create the native Visualizer object lpVisualizer = new Visualizer(0, - NULL, - NULL, + android_media_visualizer_effect_callback, + lpJniStorage, sessionId); if (lpVisualizer == NULL) { ALOGE("Error creating Visualizer"); @@ -345,7 +427,17 @@ android_media_visualizer_native_setEnabled(JNIEnv *env, jobject thiz, jboolean e return VISUALIZER_ERROR_NO_INIT; } - return translateError(lpVisualizer->setEnabled(enabled)); + jint retVal = translateError(lpVisualizer->setEnabled(enabled)); + + if (!enabled) { + visualizerJniStorage* lpJniStorage = (visualizerJniStorage *)env->GetIntField( + thiz, fields.fidJniData); + + if (NULL != lpJniStorage) + lpJniStorage->mCallbackData.cleanupBuffers(); + } + + return retVal; } static jboolean diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp index df4fbb55bc7e..ceb87db12aee 100644 --- a/media/jni/soundpool/SoundPool.cpp +++ b/media/jni/soundpool/SoundPool.cpp @@ -623,7 +623,7 @@ void SoundChannel::play(const sp<Sample>& sample, int nextChannelID, float leftV newTrack->setVolume(leftVolume, rightVolume); newTrack->setLoop(0, frameCount, loop); - // From now on, AudioTrack callbacks recevieved with previous toggle value will be ignored. + // From now on, AudioTrack callbacks received with previous toggle value will be ignored. mToggle = toggle; mAudioTrack = newTrack; mPos = 0; diff --git a/media/libaah_rtp/Android.mk b/media/libaah_rtp/Android.mk new file mode 100644 index 000000000000..54fd9ec10ebd --- /dev/null +++ b/media/libaah_rtp/Android.mk @@ -0,0 +1,40 @@ +LOCAL_PATH:= $(call my-dir) +# +# libaah_rtp +# + +include $(CLEAR_VARS) + +LOCAL_MODULE := libaah_rtp +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES := \ + aah_decoder_pump.cpp \ + aah_rx_player.cpp \ + aah_rx_player_core.cpp \ + aah_rx_player_ring_buffer.cpp \ + aah_rx_player_substream.cpp \ + aah_tx_packet.cpp \ + aah_tx_player.cpp \ + aah_tx_sender.cpp \ + pipe_event.cpp + +LOCAL_C_INCLUDES := \ + frameworks/base/include \ + frameworks/base/include/media/stagefright/openmax \ + frameworks/base/media \ + frameworks/base/media/libstagefright + +LOCAL_SHARED_LIBRARIES := \ + libcommon_time_client \ + libbinder \ + libmedia \ + libstagefright \ + libstagefright_foundation \ + libutils + +LOCAL_LDLIBS := \ + -lpthread + +include $(BUILD_SHARED_LIBRARY) + diff --git a/media/libaah_rtp/aah_decoder_pump.cpp b/media/libaah_rtp/aah_decoder_pump.cpp new file mode 100644 index 000000000000..72fe43baf5d9 --- /dev/null +++ b/media/libaah_rtp/aah_decoder_pump.cpp @@ -0,0 +1,520 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "LibAAH_RTP" +//#define LOG_NDEBUG 0 +#include <utils/Log.h> + +#include <poll.h> +#include <pthread.h> + +#include <common_time/cc_helper.h> +#include <media/AudioSystem.h> +#include <media/AudioTrack.h> +#include <media/stagefright/foundation/ADebug.h> +#include <media/stagefright/MetaData.h> +#include <media/stagefright/OMXClient.h> +#include <media/stagefright/OMXCodec.h> +#include <media/stagefright/Utils.h> +#include <utils/Timers.h> +#include <utils/threads.h> + +#include "aah_decoder_pump.h" + +namespace android { + +static const long long kLongDecodeErrorThreshold = 1000000ll; +static const uint32_t kMaxLongErrorsBeforeFatal = 3; +static const uint32_t kMaxErrorsBeforeFatal = 60; + +AAH_DecoderPump::AAH_DecoderPump(OMXClient& omx) + : omx_(omx) + , thread_status_(OK) + , renderer_(NULL) + , last_queued_pts_valid_(false) + , last_queued_pts_(0) + , last_ts_transform_valid_(false) + , last_volume_(0xFF) { + thread_ = new ThreadWrapper(this); +} + +AAH_DecoderPump::~AAH_DecoderPump() { + shutdown(); +} + +status_t AAH_DecoderPump::initCheck() { + if (thread_ == NULL) { + ALOGE("Failed to allocate thread"); + return NO_MEMORY; + } + + return OK; +} + +status_t AAH_DecoderPump::queueForDecode(MediaBuffer* buf) { + if (NULL == buf) { + return BAD_VALUE; + } + + if (OK != thread_status_) { + return thread_status_; + } + + { // Explicit scope for AutoMutex pattern. + AutoMutex lock(&thread_lock_); + in_queue_.push_back(buf); + } + + thread_cond_.signal(); + + return OK; +} + +void AAH_DecoderPump::queueToRenderer(MediaBuffer* decoded_sample) { + Mutex::Autolock lock(&render_lock_); + sp<MetaData> meta; + int64_t ts; + status_t res; + + // Fetch the metadata and make sure the sample has a timestamp. We + // cannot render samples which are missing PTSs. + meta = decoded_sample->meta_data(); + if ((meta == NULL) || (!meta->findInt64(kKeyTime, &ts))) { + ALOGV("Decoded sample missing timestamp, cannot render."); + CHECK(false); + } else { + // If we currently are not holding on to a renderer, go ahead and + // make one now. + if (NULL == renderer_) { + renderer_ = new TimedAudioTrack(); + if (NULL != renderer_) { + int frameCount; + AudioTrack::getMinFrameCount(&frameCount, + AUDIO_STREAM_DEFAULT, + static_cast<int>(format_sample_rate_)); + int ch_format = (format_channels_ == 1) + ? AUDIO_CHANNEL_OUT_MONO + : AUDIO_CHANNEL_OUT_STEREO; + + res = renderer_->set(AUDIO_STREAM_DEFAULT, + format_sample_rate_, + AUDIO_FORMAT_PCM_16_BIT, + ch_format, + frameCount); + if (res != OK) { + ALOGE("Failed to setup audio renderer. (res = %d)", res); + delete renderer_; + renderer_ = NULL; + } else { + CHECK(last_ts_transform_valid_); + + res = renderer_->setMediaTimeTransform( + last_ts_transform_, TimedAudioTrack::COMMON_TIME); + if (res != NO_ERROR) { + ALOGE("Failed to set media time transform on AudioTrack" + " (res = %d)", res); + delete renderer_; + renderer_ = NULL; + } else { + float volume = static_cast<float>(last_volume_) + / 255.0f; + if (renderer_->setVolume(volume, volume) != OK) { + ALOGW("%s: setVolume failed", __FUNCTION__); + } + + renderer_->start(); + } + } + } else { + ALOGE("Failed to allocate AudioTrack to use as a renderer."); + } + } + + if (NULL != renderer_) { + uint8_t* decoded_data = + reinterpret_cast<uint8_t*>(decoded_sample->data()); + uint32_t decoded_amt = decoded_sample->range_length(); + decoded_data += decoded_sample->range_offset(); + + sp<IMemory> pcm_payload; + res = renderer_->allocateTimedBuffer(decoded_amt, &pcm_payload); + if (res != OK) { + ALOGE("Failed to allocate %d byte audio track buffer." + " (res = %d)", decoded_amt, res); + } else { + memcpy(pcm_payload->pointer(), decoded_data, decoded_amt); + + res = renderer_->queueTimedBuffer(pcm_payload, ts); + if (res != OK) { + ALOGE("Failed to queue %d byte audio track buffer with media" + " PTS %lld. (res = %d)", decoded_amt, ts, res); + } else { + last_queued_pts_valid_ = true; + last_queued_pts_ = ts; + } + } + + } else { + ALOGE("No renderer, dropping audio payload."); + } + } +} + +void AAH_DecoderPump::stopAndCleanupRenderer() { + if (NULL == renderer_) { + return; + } + + renderer_->stop(); + delete renderer_; + renderer_ = NULL; +} + +void AAH_DecoderPump::setRenderTSTransform(const LinearTransform& trans) { + Mutex::Autolock lock(&render_lock_); + + if (last_ts_transform_valid_ && !memcmp(&trans, + &last_ts_transform_, + sizeof(trans))) { + return; + } + + last_ts_transform_ = trans; + last_ts_transform_valid_ = true; + + if (NULL != renderer_) { + status_t res = renderer_->setMediaTimeTransform( + last_ts_transform_, TimedAudioTrack::COMMON_TIME); + if (res != NO_ERROR) { + ALOGE("Failed to set media time transform on AudioTrack" + " (res = %d)", res); + } + } +} + +void AAH_DecoderPump::setRenderVolume(uint8_t volume) { + Mutex::Autolock lock(&render_lock_); + + if (volume == last_volume_) { + return; + } + + last_volume_ = volume; + if (renderer_ != NULL) { + float volume = static_cast<float>(last_volume_) / 255.0f; + if (renderer_->setVolume(volume, volume) != OK) { + ALOGW("%s: setVolume failed", __FUNCTION__); + } + } +} + +// isAboutToUnderflow is something of a hack used to figure out when it might be +// time to give up on trying to fill in a gap in the RTP sequence and simply +// move on with a discontinuity. If we had perfect knowledge of when we were +// going to underflow, it would not be a hack, but unfortunately we do not. +// Right now, we just take the PTS of the last sample queued, and check to see +// if its presentation time is within kAboutToUnderflowThreshold from now. If +// it is, then we say that we are about to underflow. This decision is based on +// two (possibly invalid) assumptions. +// +// 1) The transmitter is leading the clock by more than +// kAboutToUnderflowThreshold. +// 2) The delta between the PTS of the last sample queued and the next sample +// is less than the transmitter's clock lead amount. +// +// Right now, the default transmitter lead time is 1 second, which is a pretty +// large number and greater than the 50mSec that kAboutToUnderflowThreshold is +// currently set to. This should satisfy assumption #1 for now, but changes to +// the transmitter clock lead time could effect this. +// +// For non-sparse streams with a homogeneous sample rate (the vast majority of +// streams in the world), the delta between any two adjacent PTSs will always be +// the homogeneous sample period. It is very uncommon to see a sample period +// greater than the 1 second clock lead we are currently using, and you +// certainly will not see it in an MP3 file which should satisfy assumption #2. +// Sparse audio streams (where no audio is transmitted for long periods of +// silence) and extremely low framerate video stream (like an MPEG-2 slideshow +// or the video stream for a pay TV audio channel) are examples of streams which +// might violate assumption #2. +bool AAH_DecoderPump::isAboutToUnderflow(int64_t threshold) { + Mutex::Autolock lock(&render_lock_); + + // If we have never queued anything to the decoder, we really don't know if + // we are going to underflow or not. + if (!last_queued_pts_valid_ || !last_ts_transform_valid_) { + return false; + } + + // Don't have access to Common Time? If so, then things are Very Bad + // elsewhere in the system; it pretty much does not matter what we do here. + // Since we cannot really tell if we are about to underflow or not, its + // probably best to assume that we are not and proceed accordingly. + int64_t tt_now; + if (OK != cc_helper_.getCommonTime(&tt_now)) { + return false; + } + + // Transform from media time to common time. + int64_t last_queued_pts_tt; + if (!last_ts_transform_.doForwardTransform(last_queued_pts_, + &last_queued_pts_tt)) { + return false; + } + + // Check to see if we are underflowing. + return ((tt_now + threshold - last_queued_pts_tt) > 0); +} + +void* AAH_DecoderPump::workThread() { + // No need to lock when accessing decoder_ from the thread. The + // implementation of init and shutdown ensure that other threads never touch + // decoder_ while the work thread is running. + CHECK(decoder_ != NULL); + CHECK(format_ != NULL); + + // Start the decoder and note its result code. If something goes horribly + // wrong, callers of queueForDecode and getOutput will be able to detect + // that the thread encountered a fatal error and shut down by examining + // thread_status_. + thread_status_ = decoder_->start(format_.get()); + if (OK != thread_status_) { + ALOGE("AAH_DecoderPump's work thread failed to start decoder (res = %d)", + thread_status_); + return NULL; + } + + DurationTimer decode_timer; + uint32_t consecutive_long_errors = 0; + uint32_t consecutive_errors = 0; + + while (!thread_->exitPending()) { + status_t res; + MediaBuffer* bufOut = NULL; + + decode_timer.start(); + res = decoder_->read(&bufOut); + decode_timer.stop(); + + if (res == INFO_FORMAT_CHANGED) { + // Format has changed. Destroy our current renderer so that a new + // one can be created during queueToRenderer with the proper format. + // + // TODO : In order to transition seamlessly, we should change this + // to put the old renderer in a queue to play out completely before + // we destroy it. We can still create a new renderer, the timed + // nature of the renderer should ensure a seamless splice. + stopAndCleanupRenderer(); + res = OK; + } + + // Try to be a little nuanced in our handling of actual decode errors. + // Errors could happen because of minor stream corruption or because of + // transient resource limitations. In these cases, we would rather drop + // a little bit of output and ride out the unpleasantness then throw up + // our hands and abort everything. + // + // OTOH - When things are really bad (like we have a non-transient + // resource or bookkeeping issue, or the stream being fed to us is just + // complete and total garbage) we really want to terminate playback and + // raise an error condition all the way up to the application level so + // they can deal with it. + // + // Unfortunately, the error codes returned by the decoder can be a + // little non-specific. For example, if an OMXCodec times out + // attempting to obtain an output buffer, the error we get back is a + // generic -1. Try to distinguish between this resource timeout error + // and ES corruption error by timing how long the decode operation + // takes. Maintain accounting for both errors and "long errors". If we + // get more than a certain number consecutive errors of either type, + // consider it fatal and shutdown (which will cause the error to + // propagate all of the way up to the application level). The threshold + // for "long errors" is deliberately much lower than that of normal + // decode errors, both because of how long they take to happen and + // because they generally indicate resource limitation errors which are + // unlikely to go away in pathologically bad cases (in contrast to + // stream corruption errors which might happen 20 times in a row and + // then be suddenly OK again) + if (res != OK) { + consecutive_errors++; + if (decode_timer.durationUsecs() >= kLongDecodeErrorThreshold) + consecutive_long_errors++; + + CHECK(NULL == bufOut); + + ALOGW("%s: Failed to decode data (res = %d)", + __PRETTY_FUNCTION__, res); + + if ((consecutive_errors >= kMaxErrorsBeforeFatal) || + (consecutive_long_errors >= kMaxLongErrorsBeforeFatal)) { + ALOGE("%s: Maximum decode error threshold has been reached." + " There have been %d consecutive decode errors, and %d" + " consecutive decode operations which resulted in errors" + " and took more than %lld uSec to process. The last" + " decode operation took %lld uSec.", + __PRETTY_FUNCTION__, + consecutive_errors, consecutive_long_errors, + kLongDecodeErrorThreshold, decode_timer.durationUsecs()); + thread_status_ = res; + break; + } + + continue; + } + + if (NULL == bufOut) { + ALOGW("%s: Successful decode, but no buffer produced", + __PRETTY_FUNCTION__); + continue; + } + + // Successful decode (with actual output produced). Clear the error + // counters. + consecutive_errors = 0; + consecutive_long_errors = 0; + + queueToRenderer(bufOut); + bufOut->release(); + } + + decoder_->stop(); + stopAndCleanupRenderer(); + + return NULL; +} + +status_t AAH_DecoderPump::init(const sp<MetaData>& params) { + Mutex::Autolock lock(&init_lock_); + + if (decoder_ != NULL) { + // already inited + return OK; + } + + if (params == NULL) { + return BAD_VALUE; + } + + if (!params->findInt32(kKeyChannelCount, &format_channels_)) { + return BAD_VALUE; + } + + if (!params->findInt32(kKeySampleRate, &format_sample_rate_)) { + return BAD_VALUE; + } + + CHECK(OK == thread_status_); + CHECK(decoder_ == NULL); + + status_t ret_val = UNKNOWN_ERROR; + + // Cache the format and attempt to create the decoder. + format_ = params; + decoder_ = OMXCodec::Create( + omx_.interface(), // IOMX Handle + format_, // Metadata for substream (indicates codec) + false, // Make a decoder, not an encoder + sp<MediaSource>(this)); // We will be the source for this codec. + + if (decoder_ == NULL) { + ALOGE("Failed to allocate decoder in %s", __PRETTY_FUNCTION__); + goto bailout; + } + + // Fire up the pump thread. It will take care of starting and stopping the + // decoder. + ret_val = thread_->run("aah_decode_pump", ANDROID_PRIORITY_AUDIO); + if (OK != ret_val) { + ALOGE("Failed to start work thread in %s (res = %d)", + __PRETTY_FUNCTION__, ret_val); + goto bailout; + } + +bailout: + if (OK != ret_val) { + decoder_ = NULL; + format_ = NULL; + } + + return OK; +} + +status_t AAH_DecoderPump::shutdown() { + Mutex::Autolock lock(&init_lock_); + return shutdown_l(); +} + +status_t AAH_DecoderPump::shutdown_l() { + thread_->requestExit(); + thread_cond_.signal(); + thread_->requestExitAndWait(); + + for (MBQueue::iterator iter = in_queue_.begin(); + iter != in_queue_.end(); + ++iter) { + (*iter)->release(); + } + in_queue_.clear(); + + last_queued_pts_valid_ = false; + last_ts_transform_valid_ = false; + last_volume_ = 0xFF; + thread_status_ = OK; + + decoder_ = NULL; + format_ = NULL; + + return OK; +} + +status_t AAH_DecoderPump::read(MediaBuffer **buffer, + const ReadOptions *options) { + if (!buffer) { + return BAD_VALUE; + } + + *buffer = NULL; + + // While its not time to shut down, and we have no data to process, wait. + AutoMutex lock(&thread_lock_); + while (!thread_->exitPending() && in_queue_.empty()) + thread_cond_.wait(thread_lock_); + + // At this point, if its not time to shutdown then we must have something to + // process. Go ahead and pop the front of the queue for processing. + if (!thread_->exitPending()) { + CHECK(!in_queue_.empty()); + + *buffer = *(in_queue_.begin()); + in_queue_.erase(in_queue_.begin()); + } + + // If we managed to get a buffer, then everything must be OK. If not, then + // we must be shutting down. + return (NULL == *buffer) ? INVALID_OPERATION : OK; +} + +AAH_DecoderPump::ThreadWrapper::ThreadWrapper(AAH_DecoderPump* owner) + : Thread(false /* canCallJava*/ ) + , owner_(owner) { +} + +bool AAH_DecoderPump::ThreadWrapper::threadLoop() { + CHECK(NULL != owner_); + owner_->workThread(); + return false; +} + +} // namespace android diff --git a/media/libaah_rtp/aah_decoder_pump.h b/media/libaah_rtp/aah_decoder_pump.h new file mode 100644 index 000000000000..f5a6529396be --- /dev/null +++ b/media/libaah_rtp/aah_decoder_pump.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __DECODER_PUMP_H__ +#define __DECODER_PUMP_H__ + +#include <pthread.h> + +#include <common_time/cc_helper.h> +#include <media/stagefright/MediaSource.h> +#include <utils/LinearTransform.h> +#include <utils/List.h> +#include <utils/threads.h> + +namespace android { + +class MetaData; +class OMXClient; +class TimedAudioTrack; + +class AAH_DecoderPump : public MediaSource { + public: + explicit AAH_DecoderPump(OMXClient& omx); + status_t initCheck(); + + status_t queueForDecode(MediaBuffer* buf); + + status_t init(const sp<MetaData>& params); + status_t shutdown(); + + void setRenderTSTransform(const LinearTransform& trans); + void setRenderVolume(uint8_t volume); + bool isAboutToUnderflow(int64_t threshold); + bool getStatus() const { return thread_status_; } + + // MediaSource methods + virtual status_t start(MetaData *params) { return OK; } + virtual sp<MetaData> getFormat() { return format_; } + virtual status_t stop() { return OK; } + virtual status_t read(MediaBuffer **buffer, + const ReadOptions *options); + + protected: + virtual ~AAH_DecoderPump(); + + private: + class ThreadWrapper : public Thread { + public: + friend class AAH_DecoderPump; + explicit ThreadWrapper(AAH_DecoderPump* owner); + + private: + virtual bool threadLoop(); + AAH_DecoderPump* owner_; + + DISALLOW_EVIL_CONSTRUCTORS(ThreadWrapper); + }; + + void* workThread(); + virtual status_t shutdown_l(); + void queueToRenderer(MediaBuffer* decoded_sample); + void stopAndCleanupRenderer(); + + sp<MetaData> format_; + int32_t format_channels_; + int32_t format_sample_rate_; + + sp<MediaSource> decoder_; + OMXClient& omx_; + Mutex init_lock_; + + sp<ThreadWrapper> thread_; + Condition thread_cond_; + Mutex thread_lock_; + status_t thread_status_; + + Mutex render_lock_; + TimedAudioTrack* renderer_; + bool last_queued_pts_valid_; + int64_t last_queued_pts_; + bool last_ts_transform_valid_; + LinearTransform last_ts_transform_; + uint8_t last_volume_; + CCHelper cc_helper_; + + // protected by the thread_lock_ + typedef List<MediaBuffer*> MBQueue; + MBQueue in_queue_; + + DISALLOW_EVIL_CONSTRUCTORS(AAH_DecoderPump); +}; + +} // namespace android +#endif // __DECODER_PUMP_H__ diff --git a/media/libaah_rtp/aah_rx_player.cpp b/media/libaah_rtp/aah_rx_player.cpp new file mode 100644 index 000000000000..9dd79fd2dd83 --- /dev/null +++ b/media/libaah_rtp/aah_rx_player.cpp @@ -0,0 +1,288 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "LibAAH_RTP" +//#define LOG_NDEBUG 0 + +#include <binder/IServiceManager.h> +#include <media/MediaPlayerInterface.h> +#include <utils/Log.h> + +#include "aah_rx_player.h" + +namespace android { + +const uint32_t AAH_RXPlayer::kRTPRingBufferSize = 1 << 10; + +sp<MediaPlayerBase> createAAH_RXPlayer() { + sp<MediaPlayerBase> ret = new AAH_RXPlayer(); + return ret; +} + +AAH_RXPlayer::AAH_RXPlayer() + : ring_buffer_(kRTPRingBufferSize) + , substreams_(NULL) { + thread_wrapper_ = new ThreadWrapper(*this); + + is_playing_ = false; + multicast_joined_ = false; + transmitter_known_ = false; + current_epoch_known_ = false; + data_source_set_ = false; + sock_fd_ = -1; + + substreams_.setCapacity(4); + + memset(&listen_addr_, 0, sizeof(listen_addr_)); + memset(&transmitter_addr_, 0, sizeof(transmitter_addr_)); + + fetchAudioFlinger(); +} + +AAH_RXPlayer::~AAH_RXPlayer() { + reset_l(); + CHECK(substreams_.size() == 0); + omx_.disconnect(); +} + +status_t AAH_RXPlayer::initCheck() { + if (thread_wrapper_ == NULL) { + ALOGE("Failed to allocate thread wrapper!"); + return NO_MEMORY; + } + + if (!ring_buffer_.initCheck()) { + ALOGE("Failed to allocate reassembly ring buffer!"); + return NO_MEMORY; + } + + // Check for the presense of the common time service by attempting to query + // for CommonTime's frequency. If we get an error back, we cannot talk to + // the service at all and should abort now. + status_t res; + uint64_t freq; + res = cc_helper_.getCommonFreq(&freq); + if (OK != res) { + ALOGE("Failed to connect to common time service!"); + return res; + } + + return omx_.connect(); +} + +status_t AAH_RXPlayer::setDataSource( + const char *url, + const KeyedVector<String8, String8> *headers) { + AutoMutex api_lock(&api_lock_); + uint32_t a, b, c, d; + uint16_t port; + + if (data_source_set_) { + return INVALID_OPERATION; + } + + if (NULL == url) { + return BAD_VALUE; + } + + if (5 != sscanf(url, "%*[^:/]://%u.%u.%u.%u:%hu", &a, &b, &c, &d, &port)) { + ALOGE("Failed to parse URL \"%s\"", url); + return BAD_VALUE; + } + + if ((a > 255) || (b > 255) || (c > 255) || (d > 255) || (port == 0)) { + ALOGE("Bad multicast address \"%s\"", url); + return BAD_VALUE; + } + + ALOGI("setDataSource :: %u.%u.%u.%u:%hu", a, b, c, d, port); + + a = (a << 24) | (b << 16) | (c << 8) | d; + + memset(&listen_addr_, 0, sizeof(listen_addr_)); + listen_addr_.sin_family = AF_INET; + listen_addr_.sin_port = htons(port); + listen_addr_.sin_addr.s_addr = htonl(a); + data_source_set_ = true; + + return OK; +} + +status_t AAH_RXPlayer::setDataSource(int fd, int64_t offset, int64_t length) { + return INVALID_OPERATION; +} + +status_t AAH_RXPlayer::setVideoSurface(const sp<Surface>& surface) { + return OK; +} + +status_t AAH_RXPlayer::setVideoSurfaceTexture( + const sp<ISurfaceTexture>& surfaceTexture) { + return OK; +} + +status_t AAH_RXPlayer::prepare() { + return OK; +} + +status_t AAH_RXPlayer::prepareAsync() { + sendEvent(MEDIA_PREPARED); + return OK; +} + +status_t AAH_RXPlayer::start() { + AutoMutex api_lock(&api_lock_); + + if (is_playing_) { + return OK; + } + + status_t res = startWorkThread(); + is_playing_ = (res == OK); + return res; +} + +status_t AAH_RXPlayer::stop() { + return pause(); +} + +status_t AAH_RXPlayer::pause() { + AutoMutex api_lock(&api_lock_); + stopWorkThread(); + CHECK(sock_fd_ < 0); + is_playing_ = false; + return OK; +} + +bool AAH_RXPlayer::isPlaying() { + AutoMutex api_lock(&api_lock_); + return is_playing_; +} + +status_t AAH_RXPlayer::seekTo(int msec) { + sendEvent(MEDIA_SEEK_COMPLETE); + return OK; +} + +status_t AAH_RXPlayer::getCurrentPosition(int *msec) { + if (NULL != msec) { + *msec = 0; + } + return OK; +} + +status_t AAH_RXPlayer::getDuration(int *msec) { + if (NULL != msec) { + *msec = 1; + } + return OK; +} + +status_t AAH_RXPlayer::reset() { + AutoMutex api_lock(&api_lock_); + reset_l(); + return OK; +} + +void AAH_RXPlayer::reset_l() { + stopWorkThread(); + CHECK(sock_fd_ < 0); + CHECK(!multicast_joined_); + is_playing_ = false; + data_source_set_ = false; + transmitter_known_ = false; + memset(&listen_addr_, 0, sizeof(listen_addr_)); +} + +status_t AAH_RXPlayer::setLooping(int loop) { + return OK; +} + +player_type AAH_RXPlayer::playerType() { + return AAH_RX_PLAYER; +} + +status_t AAH_RXPlayer::setParameter(int key, const Parcel &request) { + return ERROR_UNSUPPORTED; +} + +status_t AAH_RXPlayer::getParameter(int key, Parcel *reply) { + return ERROR_UNSUPPORTED; +} + +status_t AAH_RXPlayer::invoke(const Parcel& request, Parcel *reply) { + if (!reply) { + return BAD_VALUE; + } + + int32_t magic; + status_t err = request.readInt32(&magic); + if (err != OK) { + reply->writeInt32(err); + return OK; + } + + if (magic != 0x12345) { + reply->writeInt32(BAD_VALUE); + return OK; + } + + int32_t methodID; + err = request.readInt32(&methodID); + if (err != OK) { + reply->writeInt32(err); + return OK; + } + + switch (methodID) { + // Get Volume + case INVOKE_GET_MASTER_VOLUME: { + if (audio_flinger_ != NULL) { + reply->writeInt32(OK); + reply->writeFloat(audio_flinger_->masterVolume()); + } else { + reply->writeInt32(UNKNOWN_ERROR); + } + } break; + + // Set Volume + case INVOKE_SET_MASTER_VOLUME: { + float targetVol = request.readFloat(); + reply->writeInt32(audio_flinger_->setMasterVolume(targetVol)); + } break; + + default: return BAD_VALUE; + } + + return OK; +} + +void AAH_RXPlayer::fetchAudioFlinger() { + if (audio_flinger_ == NULL) { + sp<IServiceManager> sm = defaultServiceManager(); + sp<IBinder> binder; + binder = sm->getService(String16("media.audio_flinger")); + + if (binder == NULL) { + ALOGW("AAH_RXPlayer failed to fetch handle to audio flinger." + " Master volume control will not be possible."); + } + + audio_flinger_ = interface_cast<IAudioFlinger>(binder); + } +} + +} // namespace android diff --git a/media/libaah_rtp/aah_rx_player.h b/media/libaah_rtp/aah_rx_player.h new file mode 100644 index 000000000000..7a1b6e3a7efa --- /dev/null +++ b/media/libaah_rtp/aah_rx_player.h @@ -0,0 +1,313 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __AAH_RX_PLAYER_H__ +#define __AAH_RX_PLAYER_H__ + +#include <common_time/cc_helper.h> +#include <media/MediaPlayerInterface.h> +#include <media/stagefright/foundation/ADebug.h> +#include <media/stagefright/MediaBuffer.h> +#include <media/stagefright/MediaSource.h> +#include <media/stagefright/MetaData.h> +#include <media/stagefright/OMXClient.h> +#include <netinet/in.h> +#include <utils/KeyedVector.h> +#include <utils/LinearTransform.h> +#include <utils/threads.h> + +#include "aah_decoder_pump.h" +#include "pipe_event.h" + +namespace android { + +class AAH_RXPlayer : public MediaPlayerInterface { + public: + AAH_RXPlayer(); + + virtual status_t initCheck(); + virtual status_t setDataSource(const char *url, + const KeyedVector<String8, String8>* + headers); + virtual status_t setDataSource(int fd, int64_t offset, int64_t length); + virtual status_t setVideoSurface(const sp<Surface>& surface); + virtual status_t setVideoSurfaceTexture(const sp<ISurfaceTexture>& + surfaceTexture); + virtual status_t prepare(); + virtual status_t prepareAsync(); + virtual status_t start(); + virtual status_t stop(); + virtual status_t pause(); + virtual bool isPlaying(); + virtual status_t seekTo(int msec); + virtual status_t getCurrentPosition(int *msec); + virtual status_t getDuration(int *msec); + virtual status_t reset(); + virtual status_t setLooping(int loop); + virtual player_type playerType(); + virtual status_t setParameter(int key, const Parcel &request); + virtual status_t getParameter(int key, Parcel *reply); + virtual status_t invoke(const Parcel& request, Parcel *reply); + + protected: + virtual ~AAH_RXPlayer(); + + private: + class ThreadWrapper : public Thread { + public: + friend class AAH_RXPlayer; + explicit ThreadWrapper(AAH_RXPlayer& player) + : Thread(false /* canCallJava */ ) + , player_(player) { } + + virtual bool threadLoop() { return player_.threadLoop(); } + + private: + AAH_RXPlayer& player_; + + DISALLOW_EVIL_CONSTRUCTORS(ThreadWrapper); + }; + +#pragma pack(push, 1) + // PacketBuffers are structures used by the RX ring buffer. The ring buffer + // is a ring of pointers to PacketBuffer structures which act as variable + // length byte arrays and hold the contents of received UDP packets. Rather + // than make this a structure which hold a length and a pointer to another + // allocated structure (which would require two allocations), this struct + // uses a structure overlay pattern where allocation for the byte array + // consists of allocating (arrayLen + sizeof(ssize_t)) bytes of data from + // whatever pool/heap the packet buffer pulls from, and then overlaying the + // packed PacketBuffer structure on top of the allocation. The one-byte + // array at the end of the structure serves as an offset to the the data + // portion of the allocation; packet buffers are never allocated on the + // stack or using the new operator. Instead, the static allocate-byte-array + // and destroy methods handle the allocate and overlay pattern. They also + // allow for a potential future optimization where instead of just + // allocating blocks from the process global heap and overlaying, the + // allocator is replaced with a different implementation (private heap, + // free-list, circular buffer, etc) which reduces potential heap + // fragmentation issues which might arise from the frequent allocation and + // destruction of the received UDP traffic. + struct PacketBuffer { + ssize_t length_; + uint8_t data_[1]; + + // TODO : consider changing this to be some form of ring buffer or free + // pool system instead of just using the heap in order to avoid heap + // fragmentation. + static PacketBuffer* allocate(ssize_t length); + static void destroy(PacketBuffer* pb); + + private: + // Force people to use allocate/destroy instead of new/delete. + PacketBuffer() { } + ~PacketBuffer() { } + }; + + struct RetransRequest { + uint32_t magic_; + uint32_t mcast_ip_; + uint16_t mcast_port_; + uint16_t start_seq_; + uint16_t end_seq_; + }; +#pragma pack(pop) + + enum GapStatus { + kGS_NoGap = 0, + kGS_NormalGap, + kGS_FastStartGap, + }; + + struct SeqNoGap { + uint16_t start_seq_; + uint16_t end_seq_; + }; + + class RXRingBuffer { + public: + explicit RXRingBuffer(uint32_t capacity); + ~RXRingBuffer(); + + bool initCheck() const { return (ring_ != NULL); } + void reset(); + + // Push a packet buffer with a given sequence number into the ring + // buffer. pushBuffer will always consume the buffer pushed to it, + // either destroying it because it was a duplicate or overflow, or + // holding on to it in the ring. Callers should not hold any references + // to PacketBuffers after they have been pushed to the ring. Returns + // false in the case of a serious error (such as ring overflow). + // Callers should consider resetting the pipeline entirely in the event + // of a serious error. + bool pushBuffer(PacketBuffer* buf, uint16_t seq); + + // Fetch the next buffer in the RTP sequence. Returns NULL if there is + // no buffer to fetch. If a non-NULL PacketBuffer is returned, + // is_discon will be set to indicate whether or not this PacketBuffer is + // discontiuous with any previously returned packet buffers. Packet + // buffers returned by fetchBuffer are the caller's responsibility; they + // must be certain to destroy the buffers when they are done. + PacketBuffer* fetchBuffer(bool* is_discon); + + // Returns true and fills out the gap structure if the read pointer of + // the ring buffer is currently pointing to a gap which would stall a + // fetchBuffer operation. Returns false if the read pointer is not + // pointing to a gap in the sequence currently. + GapStatus fetchCurrentGap(SeqNoGap* gap); + + // Causes the read pointer to skip over any portion of a gap indicated + // by nak. If nak is NULL, any gap currently blocking the read pointer + // will be completely skipped. If any portion of a gap is skipped, the + // next successful read from fetch buffer will indicate a discontinuity. + void processNAK(const SeqNoGap* nak = NULL); + + // Compute the number of milliseconds until the inactivity timer for + // this RTP stream. Returns -1 if there is no active timeout, or 0 if + // the system has already timed out. + int computeInactivityTimeout(); + + private: + Mutex lock_; + PacketBuffer** ring_; + uint32_t capacity_; + uint32_t rd_; + uint32_t wr_; + + uint16_t rd_seq_; + bool rd_seq_known_; + bool waiting_for_fast_start_; + bool fetched_first_packet_; + + uint64_t rtp_activity_timeout_; + bool rtp_activity_timeout_valid_; + + DISALLOW_EVIL_CONSTRUCTORS(RXRingBuffer); + }; + + class Substream : public virtual RefBase { + public: + Substream(uint32_t ssrc, OMXClient& omx); + + void cleanupBufferInProgress(); + void shutdown(); + void processPayloadStart(uint8_t* buf, + uint32_t amt, + int32_t ts_lower); + void processPayloadCont (uint8_t* buf, + uint32_t amt); + void processTSTransform(const LinearTransform& trans); + + bool isAboutToUnderflow(); + uint32_t getSSRC() const { return ssrc_; } + uint16_t getProgramID() const { return (ssrc_ >> 5) & 0x1F; } + status_t getStatus() const { return status_; } + + protected: + virtual ~Substream() { + shutdown(); + } + + private: + void cleanupDecoder(); + bool shouldAbort(const char* log_tag); + void processCompletedBuffer(); + bool setupSubstreamType(uint8_t substream_type, + uint8_t codec_type); + + uint32_t ssrc_; + bool waiting_for_rap_; + status_t status_; + + bool substream_details_known_; + uint8_t substream_type_; + uint8_t codec_type_; + sp<MetaData> substream_meta_; + + MediaBuffer* buffer_in_progress_; + uint32_t expected_buffer_size_; + uint32_t buffer_filled_; + + sp<AAH_DecoderPump> decoder_; + + static int64_t kAboutToUnderflowThreshold; + + DISALLOW_EVIL_CONSTRUCTORS(Substream); + }; + + typedef DefaultKeyedVector< uint32_t, sp<Substream> > SubstreamVec; + + status_t startWorkThread(); + void stopWorkThread(); + virtual bool threadLoop(); + bool setupSocket(); + void cleanupSocket(); + void resetPipeline(); + void reset_l(); + bool processRX(PacketBuffer* pb); + void processRingBuffer(); + void processCommandPacket(PacketBuffer* pb); + bool processGaps(); + int computeNextGapRetransmitTimeout(); + void fetchAudioFlinger(); + + PipeEvent wakeup_work_thread_evt_; + sp<ThreadWrapper> thread_wrapper_; + Mutex api_lock_; + bool is_playing_; + bool data_source_set_; + + struct sockaddr_in listen_addr_; + int sock_fd_; + bool multicast_joined_; + + struct sockaddr_in transmitter_addr_; + bool transmitter_known_; + + uint32_t current_epoch_; + bool current_epoch_known_; + + SeqNoGap current_gap_; + GapStatus current_gap_status_; + uint64_t next_retrans_req_time_; + + RXRingBuffer ring_buffer_; + SubstreamVec substreams_; + OMXClient omx_; + CCHelper cc_helper_; + + // Connection to audio flinger used to hack a path to setMasterVolume. + sp<IAudioFlinger> audio_flinger_; + + static const uint32_t kRTPRingBufferSize; + static const uint32_t kRetransRequestMagic; + static const uint32_t kFastStartRequestMagic; + static const uint32_t kRetransNAKMagic; + static const uint32_t kGapRerequestTimeoutUSec; + static const uint32_t kFastStartTimeoutUSec; + static const uint32_t kRTPActivityTimeoutUSec; + + static const uint32_t INVOKE_GET_MASTER_VOLUME = 3; + static const uint32_t INVOKE_SET_MASTER_VOLUME = 4; + + static uint64_t monotonicUSecNow(); + + DISALLOW_EVIL_CONSTRUCTORS(AAH_RXPlayer); +}; + +} // namespace android + +#endif // __AAH_RX_PLAYER_H__ diff --git a/media/libaah_rtp/aah_rx_player_core.cpp b/media/libaah_rtp/aah_rx_player_core.cpp new file mode 100644 index 000000000000..d2b33866cdeb --- /dev/null +++ b/media/libaah_rtp/aah_rx_player_core.cpp @@ -0,0 +1,807 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "LibAAH_RTP" +//#define LOG_NDEBUG 0 +#include <utils/Log.h> + +#include <fcntl.h> +#include <poll.h> +#include <sys/socket.h> +#include <time.h> +#include <utils/misc.h> + +#include <media/stagefright/Utils.h> + +#include "aah_rx_player.h" +#include "aah_tx_packet.h" + +namespace android { + +const uint32_t AAH_RXPlayer::kRetransRequestMagic = + FOURCC('T','r','e','q'); +const uint32_t AAH_RXPlayer::kRetransNAKMagic = + FOURCC('T','n','a','k'); +const uint32_t AAH_RXPlayer::kFastStartRequestMagic = + FOURCC('T','f','s','t'); +const uint32_t AAH_RXPlayer::kGapRerequestTimeoutUSec = 75000; +const uint32_t AAH_RXPlayer::kFastStartTimeoutUSec = 800000; +const uint32_t AAH_RXPlayer::kRTPActivityTimeoutUSec = 10000000; + +static inline int16_t fetchInt16(uint8_t* data) { + return static_cast<int16_t>(U16_AT(data)); +} + +static inline int32_t fetchInt32(uint8_t* data) { + return static_cast<int32_t>(U32_AT(data)); +} + +static inline int64_t fetchInt64(uint8_t* data) { + return static_cast<int64_t>(U64_AT(data)); +} + +uint64_t AAH_RXPlayer::monotonicUSecNow() { + struct timespec now; + int res = clock_gettime(CLOCK_MONOTONIC, &now); + CHECK(res >= 0); + + uint64_t ret = static_cast<uint64_t>(now.tv_sec) * 1000000; + ret += now.tv_nsec / 1000; + + return ret; +} + +status_t AAH_RXPlayer::startWorkThread() { + status_t res; + stopWorkThread(); + res = thread_wrapper_->run("TRX_Player", PRIORITY_AUDIO); + + if (res != OK) { + ALOGE("Failed to start work thread (res = %d)", res); + } + + return res; +} + +void AAH_RXPlayer::stopWorkThread() { + thread_wrapper_->requestExit(); // set the exit pending flag + wakeup_work_thread_evt_.setEvent(); + + status_t res; + res = thread_wrapper_->requestExitAndWait(); // block until thread exit. + if (res != OK) { + ALOGE("Failed to stop work thread (res = %d)", res); + } + + wakeup_work_thread_evt_.clearPendingEvents(); +} + +void AAH_RXPlayer::cleanupSocket() { + if (sock_fd_ >= 0) { + if (multicast_joined_) { + int res; + struct ip_mreq mreq; + mreq.imr_multiaddr = listen_addr_.sin_addr; + mreq.imr_interface.s_addr = htonl(INADDR_ANY); + res = setsockopt(sock_fd_, + IPPROTO_IP, + IP_DROP_MEMBERSHIP, + &mreq, sizeof(mreq)); + if (res < 0) { + ALOGW("Failed to leave multicast group. (%d, %d)", res, errno); + } + multicast_joined_ = false; + } + + close(sock_fd_); + sock_fd_ = -1; + } + + resetPipeline(); +} + +void AAH_RXPlayer::resetPipeline() { + ring_buffer_.reset(); + + // Explicitly shudown all of the active substreams, then call clear out the + // collection. Failure to clear out a substream can result in its decoder + // holding a reference to itself and therefor not going away when the + // collection is cleared. + for (size_t i = 0; i < substreams_.size(); ++i) + substreams_.valueAt(i)->shutdown(); + + substreams_.clear(); + + current_gap_status_ = kGS_NoGap; +} + +bool AAH_RXPlayer::setupSocket() { + long flags; + int res, buf_size; + socklen_t opt_size; + + cleanupSocket(); + CHECK(sock_fd_ < 0); + + // Make the socket + sock_fd_ = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (sock_fd_ < 0) { + ALOGE("Failed to create listen socket (errno %d)", errno); + goto bailout; + } + + // Set non-blocking operation + flags = fcntl(sock_fd_, F_GETFL); + res = fcntl(sock_fd_, F_SETFL, flags | O_NONBLOCK); + if (res < 0) { + ALOGE("Failed to set socket (%d) to non-blocking mode (errno %d)", + sock_fd_, errno); + goto bailout; + } + + // Bind to our port + struct sockaddr_in bind_addr; + memset(&bind_addr, 0, sizeof(bind_addr)); + bind_addr.sin_family = AF_INET; + bind_addr.sin_addr.s_addr = INADDR_ANY; + bind_addr.sin_port = listen_addr_.sin_port; + res = bind(sock_fd_, + reinterpret_cast<const sockaddr*>(&bind_addr), + sizeof(bind_addr)); + if (res < 0) { + uint32_t a = ntohl(bind_addr.sin_addr.s_addr); + uint16_t p = ntohs(bind_addr.sin_port); + ALOGE("Failed to bind socket (%d) to %d.%d.%d.%d:%hd. (errno %d)", + sock_fd_, + (a >> 24) & 0xFF, + (a >> 16) & 0xFF, + (a >> 8) & 0xFF, + (a ) & 0xFF, + p, + errno); + + goto bailout; + } + + buf_size = 1 << 16; // 64k + res = setsockopt(sock_fd_, + SOL_SOCKET, SO_RCVBUF, + &buf_size, sizeof(buf_size)); + if (res < 0) { + ALOGW("Failed to increase socket buffer size to %d. (errno %d)", + buf_size, errno); + } + + buf_size = 0; + opt_size = sizeof(buf_size); + res = getsockopt(sock_fd_, + SOL_SOCKET, SO_RCVBUF, + &buf_size, &opt_size); + if (res < 0) { + ALOGW("Failed to fetch socket buffer size. (errno %d)", errno); + } else { + ALOGI("RX socket buffer size is now %d bytes", buf_size); + } + + if (listen_addr_.sin_addr.s_addr) { + // Join the multicast group and we should be good to go. + struct ip_mreq mreq; + mreq.imr_multiaddr = listen_addr_.sin_addr; + mreq.imr_interface.s_addr = htonl(INADDR_ANY); + res = setsockopt(sock_fd_, + IPPROTO_IP, + IP_ADD_MEMBERSHIP, + &mreq, sizeof(mreq)); + if (res < 0) { + ALOGE("Failed to join multicast group. (errno %d)", errno); + goto bailout; + } + multicast_joined_ = true; + } + + return true; + +bailout: + cleanupSocket(); + return false; +} + +bool AAH_RXPlayer::threadLoop() { + struct pollfd poll_fds[2]; + bool process_more_right_now = false; + + if (!setupSocket()) { + sendEvent(MEDIA_ERROR); + goto bailout; + } + + while (!thread_wrapper_->exitPending()) { + // Step 1: Wait until there is something to do. + int gap_timeout = computeNextGapRetransmitTimeout(); + int ring_timeout = ring_buffer_.computeInactivityTimeout(); + int timeout = -1; + + if (!ring_timeout) { + ALOGW("RTP inactivity timeout reached, resetting pipeline."); + resetPipeline(); + timeout = gap_timeout; + } else { + if (gap_timeout < 0) { + timeout = ring_timeout; + } else if (ring_timeout < 0) { + timeout = gap_timeout; + } else { + timeout = (gap_timeout < ring_timeout) ? gap_timeout + : ring_timeout; + } + } + + if ((0 != timeout) && (!process_more_right_now)) { + // Set up the events to wait on. Start with the wakeup pipe. + memset(&poll_fds, 0, sizeof(poll_fds)); + poll_fds[0].fd = wakeup_work_thread_evt_.getWakeupHandle(); + poll_fds[0].events = POLLIN; + + // Add the RX socket. + poll_fds[1].fd = sock_fd_; + poll_fds[1].events = POLLIN; + + // Wait for something interesing to happen. + int poll_res = poll(poll_fds, NELEM(poll_fds), timeout); + if (poll_res < 0) { + ALOGE("Fatal error (%d,%d) while waiting on events", + poll_res, errno); + sendEvent(MEDIA_ERROR); + goto bailout; + } + } + + if (thread_wrapper_->exitPending()) { + break; + } + + wakeup_work_thread_evt_.clearPendingEvents(); + process_more_right_now = false; + + // Step 2: Do we have data waiting in the socket? If so, drain the + // socket moving valid RTP information into the ring buffer to be + // processed. + if (poll_fds[1].revents) { + struct sockaddr_in from; + socklen_t from_len; + + ssize_t res = 0; + while (!thread_wrapper_->exitPending()) { + // Check the size of any pending packet. + res = recv(sock_fd_, NULL, 0, MSG_PEEK | MSG_TRUNC); + + // Error? + if (res < 0) { + // If the error is anything other than would block, + // something has gone very wrong. + if ((errno != EAGAIN) && (errno != EWOULDBLOCK)) { + ALOGE("Fatal socket error during recvfrom (%d, %d)", + (int)res, errno); + goto bailout; + } + + // Socket is out of data, just break out of processing and + // wait for more. + break; + } + + // Allocate a payload. + PacketBuffer* pb = PacketBuffer::allocate(res); + if (NULL == pb) { + ALOGE("Fatal error, failed to allocate packet buffer of" + " length %u", static_cast<uint32_t>(res)); + goto bailout; + } + + // Fetch the data. + from_len = sizeof(from); + res = recvfrom(sock_fd_, pb->data_, pb->length_, 0, + reinterpret_cast<struct sockaddr*>(&from), + &from_len); + if (res != pb->length_) { + ALOGE("Fatal error, fetched packet length (%d) does not" + " match peeked packet length (%u). This should never" + " happen. (errno = %d)", + static_cast<int>(res), + static_cast<uint32_t>(pb->length_), + errno); + } + + bool drop_packet = false; + if (transmitter_known_) { + if (from.sin_addr.s_addr != + transmitter_addr_.sin_addr.s_addr) { + uint32_t a = ntohl(from.sin_addr.s_addr); + uint16_t p = ntohs(from.sin_port); + ALOGV("Dropping packet from unknown transmitter" + " %u.%u.%u.%u:%hu", + ((a >> 24) & 0xFF), + ((a >> 16) & 0xFF), + ((a >> 8) & 0xFF), + ( a & 0xFF), + p); + + drop_packet = true; + } else { + transmitter_addr_.sin_port = from.sin_port; + } + } else { + memcpy(&transmitter_addr_, &from, sizeof(from)); + transmitter_known_ = true; + } + + if (!drop_packet) { + bool serious_error = !processRX(pb); + + if (serious_error) { + // Something went "seriously wrong". Currently, the + // only trigger for this should be a ring buffer + // overflow. The current failsafe behavior for when + // something goes seriously wrong is to just reset the + // pipeline. The system should behave as if this + // AAH_RXPlayer was just set up for the first time. + ALOGE("Something just went seriously wrong with the" + " pipeline. Resetting."); + resetPipeline(); + } + } else { + PacketBuffer::destroy(pb); + } + } + } + + // Step 3: Process any data we mave have accumulated in the ring buffer + // so far. + if (!thread_wrapper_->exitPending()) { + processRingBuffer(); + } + + // Step 4: At this point in time, the ring buffer should either be + // empty, or stalled in front of a gap caused by some dropped packets. + // Check on the current gap situation and deal with it in an appropriate + // fashion. If processGaps returns true, it means that it has given up + // on a gap and that we should try to process some more data + // immediately. + if (!thread_wrapper_->exitPending()) { + process_more_right_now = processGaps(); + } + + // Step 5: Check for fatal errors. If any of our substreams has + // encountered a fatal, unrecoverable, error, then propagate the error + // up to user level and shut down. + for (size_t i = 0; i < substreams_.size(); ++i) { + status_t status; + CHECK(substreams_.valueAt(i) != NULL); + + status = substreams_.valueAt(i)->getStatus(); + if (OK != status) { + ALOGE("Substream index %d has encountered an unrecoverable" + " error (%d). Signalling application level and shutting" + " down.", i, status); + sendEvent(MEDIA_ERROR); + goto bailout; + } + } + } + +bailout: + cleanupSocket(); + return false; +} + +bool AAH_RXPlayer::processRX(PacketBuffer* pb) { + CHECK(NULL != pb); + + uint8_t* data = pb->data_; + ssize_t amt = pb->length_; + uint32_t nak_magic; + uint16_t seq_no; + uint32_t epoch; + + // Every packet either starts with an RTP header which is at least 12 bytes + // long or is a retry NAK which is 14 bytes long. If there are fewer than + // 12 bytes here, this cannot be a proper RTP packet. + if (amt < 12) { + ALOGV("Dropping packet, too short to contain RTP header (%u bytes)", + static_cast<uint32_t>(amt)); + goto drop_packet; + } + + // Check to see if this is the special case of a NAK packet. + nak_magic = ntohl(*(reinterpret_cast<uint32_t*>(data))); + if (nak_magic == kRetransNAKMagic) { + // Looks like a NAK packet; make sure its long enough. + + if (amt < static_cast<ssize_t>(sizeof(RetransRequest))) { + ALOGV("Dropping packet, too short to contain NAK payload (%u bytes)", + static_cast<uint32_t>(amt)); + goto drop_packet; + } + + SeqNoGap gap; + RetransRequest* rtr = reinterpret_cast<RetransRequest*>(data); + gap.start_seq_ = ntohs(rtr->start_seq_); + gap.end_seq_ = ntohs(rtr->end_seq_); + + ALOGV("Process NAK for gap at [%hu, %hu]", gap.start_seq_, gap.end_seq_); + ring_buffer_.processNAK(&gap); + + return true; + } + + // According to the TRTP spec, version should be 2, padding should be 0, + // extension should be 0 and CSRCCnt should be 0. If any of these tests + // fail, we chuck the packet. + if (data[0] != 0x80) { + ALOGV("Dropping packet, bad V/P/X/CSRCCnt field (0x%02x)", + data[0]); + goto drop_packet; + } + + // Check the payload type. For TRTP, it should always be 100. + if ((data[1] & 0x7F) != 100) { + ALOGV("Dropping packet, bad payload type. (%u)", + data[1] & 0x7F); + goto drop_packet; + } + + // Check whether the transmitter has begun a new epoch. + epoch = (U32_AT(data + 8) >> 10) & 0x3FFFFF; + if (current_epoch_known_) { + if (epoch != current_epoch_) { + ALOGV("%s: new epoch %u", __PRETTY_FUNCTION__, epoch); + current_epoch_ = epoch; + resetPipeline(); + } + } else { + current_epoch_ = epoch; + current_epoch_known_ = true; + } + + // Extract the sequence number and hand the packet off to the ring buffer + // for dropped packet detection and later processing. + seq_no = U16_AT(data + 2); + return ring_buffer_.pushBuffer(pb, seq_no); + +drop_packet: + PacketBuffer::destroy(pb); + return true; +} + +void AAH_RXPlayer::processRingBuffer() { + PacketBuffer* pb; + bool is_discon; + sp<Substream> substream; + LinearTransform trans; + bool foundTrans = false; + + while (NULL != (pb = ring_buffer_.fetchBuffer(&is_discon))) { + if (is_discon) { + // Abort all partially assembled payloads. + for (size_t i = 0; i < substreams_.size(); ++i) { + CHECK(substreams_.valueAt(i) != NULL); + substreams_.valueAt(i)->cleanupBufferInProgress(); + } + } + + uint8_t* data = pb->data_; + ssize_t amt = pb->length_; + + // Should not have any non-RTP packets in the ring buffer. RTP packets + // must be at least 12 bytes long. + CHECK(amt >= 12); + + // Extract the marker bit and the SSRC field. + bool marker = (data[1] & 0x80) != 0; + uint32_t ssrc = U32_AT(data + 8); + + // Is this the start of a new TRTP payload? If so, the marker bit + // should be set and there are some things we should be checking for. + if (marker) { + // TRTP headers need to have at least a byte for version, a byte for + // payload type and flags, and 4 bytes for length. + if (amt < 18) { + ALOGV("Dropping packet, too short to contain TRTP header" + " (%u bytes)", static_cast<uint32_t>(amt)); + goto process_next_packet; + } + + // Check the TRTP version and extract the payload type/flags. + uint8_t trtp_version = data[12]; + uint8_t payload_type = (data[13] >> 4) & 0xF; + uint8_t trtp_flags = data[13] & 0xF; + + if (1 != trtp_version) { + ALOGV("Dropping packet, bad trtp version %hhu", trtp_version); + goto process_next_packet; + } + + // Is there a timestamp transformation present on this packet? If + // so, extract it and pass it to the appropriate substreams. + if (trtp_flags & 0x02) { + ssize_t offset = 18 + ((trtp_flags & 0x01) ? 4 : 0); + if (amt < (offset + 24)) { + ALOGV("Dropping packet, too short to contain TRTP Timestamp" + " Transformation (%u bytes)", + static_cast<uint32_t>(amt)); + goto process_next_packet; + } + + trans.a_zero = fetchInt64(data + offset); + trans.b_zero = fetchInt64(data + offset + 16); + trans.a_to_b_numer = static_cast<int32_t>( + fetchInt32 (data + offset + 8)); + trans.a_to_b_denom = U32_AT(data + offset + 12); + foundTrans = true; + + uint32_t program_id = (ssrc >> 5) & 0x1F; + for (size_t i = 0; i < substreams_.size(); ++i) { + sp<Substream> iter = substreams_.valueAt(i); + CHECK(iter != NULL); + + if (iter->getProgramID() == program_id) { + iter->processTSTransform(trans); + } + } + } + + // Is this a command packet? If so, its not necessarily associate + // with one particular substream. Just give it to the command + // packet handler and then move on. + if (4 == payload_type) { + processCommandPacket(pb); + goto process_next_packet; + } + } + + // If we got to here, then we are a normal packet. Find (or allocate) + // the substream we belong to and send the packet off to be processed. + substream = substreams_.valueFor(ssrc); + if (substream == NULL) { + substream = new Substream(ssrc, omx_); + if (substream == NULL) { + ALOGE("Failed to allocate substream for SSRC 0x%08x", ssrc); + goto process_next_packet; + } + substreams_.add(ssrc, substream); + + if (foundTrans) { + substream->processTSTransform(trans); + } + } + + CHECK(substream != NULL); + + if (marker) { + // Start of a new TRTP payload for this substream. Extract the + // lower 32 bits of the timestamp and hand the buffer to the + // substream for processing. + uint32_t ts_lower = U32_AT(data + 4); + substream->processPayloadStart(data + 12, amt - 12, ts_lower); + } else { + // Continuation of an existing TRTP payload. Just hand it off to + // the substream for processing. + substream->processPayloadCont(data + 12, amt - 12); + } + +process_next_packet: + PacketBuffer::destroy(pb); + } // end of main processing while loop. +} + +void AAH_RXPlayer::processCommandPacket(PacketBuffer* pb) { + CHECK(NULL != pb); + + uint8_t* data = pb->data_; + ssize_t amt = pb->length_; + + // verify that this packet meets the minimum length of a command packet + if (amt < 20) { + return; + } + + uint8_t trtp_version = data[12]; + uint8_t trtp_flags = data[13] & 0xF; + + if (1 != trtp_version) { + ALOGV("Dropping packet, bad trtp version %hhu", trtp_version); + return; + } + + // calculate the start of the command payload + ssize_t offset = 18; + if (trtp_flags & 0x01) { + // timestamp is present (4 bytes) + offset += 4; + } + if (trtp_flags & 0x02) { + // transform is present (24 bytes) + offset += 24; + } + + // the packet must contain 2 bytes of command payload beyond the TRTP header + if (amt < offset + 2) { + return; + } + + uint16_t command_id = U16_AT(data + offset); + + switch (command_id) { + case TRTPControlPacket::kCommandNop: + break; + + case TRTPControlPacket::kCommandEOS: + case TRTPControlPacket::kCommandFlush: { + uint16_t program_id = (U32_AT(data + 8) >> 5) & 0x1F; + ALOGI("*** %s flushing program_id=%d", + __PRETTY_FUNCTION__, program_id); + + Vector<uint32_t> substreams_to_remove; + for (size_t i = 0; i < substreams_.size(); ++i) { + sp<Substream> iter = substreams_.valueAt(i); + if (iter->getProgramID() == program_id) { + iter->shutdown(); + substreams_to_remove.add(iter->getSSRC()); + } + } + + for (size_t i = 0; i < substreams_to_remove.size(); ++i) { + substreams_.removeItem(substreams_to_remove[i]); + } + } break; + } +} + +bool AAH_RXPlayer::processGaps() { + // Deal with the current gap situation. Specifically... + // + // 1) If a new gap has shown up, send a retransmit request to the + // transmitter. + // 2) If a gap we were working on has had a packet in the middle or at + // the end filled in, send another retransmit request for the begining + // portion of the gap. TRTP was designed for LANs where packet + // re-ordering is very unlikely; so see the middle or end of a gap + // filled in before the begining is an almost certain indication that + // a retransmission packet was also dropped. + // 3) If we have been working on a gap for a while and it still has not + // been filled in, send another retransmit request. + // 4) If the are no more gaps in the ring, clear the current_gap_status_ + // flag to indicate that all is well again. + + // Start by fetching the active gap status. + SeqNoGap gap; + bool send_retransmit_request = false; + bool ret_val = false; + GapStatus gap_status; + if (kGS_NoGap != (gap_status = ring_buffer_.fetchCurrentGap(&gap))) { + // Note: checking for a change in the end sequence number should cover + // moving on to an entirely new gap for case #1 as well as resending the + // begining of a gap range for case #2. + send_retransmit_request = (kGS_NoGap == current_gap_status_) || + (current_gap_.end_seq_ != gap.end_seq_); + + // If this is the same gap we have been working on, and it has timed + // out, then check to see if our substreams are about to underflow. If + // so, instead of sending another retransmit request, just give up on + // this gap and move on. + if (!send_retransmit_request && + (kGS_NoGap != current_gap_status_) && + (0 == computeNextGapRetransmitTimeout())) { + + // If out current gap is the fast-start gap, don't bother to skip it + // because substreams look like the are about to underflow. + if ((kGS_FastStartGap != gap_status) || + (current_gap_.end_seq_ != gap.end_seq_)) { + for (size_t i = 0; i < substreams_.size(); ++i) { + if (substreams_.valueAt(i)->isAboutToUnderflow()) { + ALOGV("About to underflow, giving up on gap [%hu, %hu]", + gap.start_seq_, gap.end_seq_); + ring_buffer_.processNAK(); + current_gap_status_ = kGS_NoGap; + return true; + } + } + } + + // Looks like no one is about to underflow. Just go ahead and send + // the request. + send_retransmit_request = true; + } + } else { + current_gap_status_ = kGS_NoGap; + } + + if (send_retransmit_request) { + // If we have been working on a fast start, and it is still not filled + // in, even after the extended retransmit time out, give up and skip it. + // The system should fall back into its normal slow-start behavior. + if ((kGS_FastStartGap == current_gap_status_) && + (current_gap_.end_seq_ == gap.end_seq_)) { + ALOGV("Fast start is taking forever; giving up."); + ring_buffer_.processNAK(); + current_gap_status_ = kGS_NoGap; + return true; + } + + // Send the request. + RetransRequest req; + uint32_t magic = (kGS_FastStartGap == gap_status) + ? kFastStartRequestMagic + : kRetransRequestMagic; + req.magic_ = htonl(magic); + req.mcast_ip_ = listen_addr_.sin_addr.s_addr; + req.mcast_port_ = listen_addr_.sin_port; + req.start_seq_ = htons(gap.start_seq_); + req.end_seq_ = htons(gap.end_seq_); + + { + uint32_t a = ntohl(transmitter_addr_.sin_addr.s_addr); + uint16_t p = ntohs(transmitter_addr_.sin_port); + ALOGV("Sending to transmitter %u.%u.%u.%u:%hu", + ((a >> 24) & 0xFF), + ((a >> 16) & 0xFF), + ((a >> 8) & 0xFF), + ( a & 0xFF), + p); + } + + int res = sendto(sock_fd_, &req, sizeof(req), 0, + reinterpret_cast<struct sockaddr*>(&transmitter_addr_), + sizeof(transmitter_addr_)); + if (res < 0) { + ALOGE("Error when sending retransmit request (%d)", errno); + } else { + ALOGV("%s request for range [%hu, %hu] sent", + (kGS_FastStartGap == gap_status) ? "Fast Start" : "Retransmit", + gap.start_seq_, gap.end_seq_); + } + + // Update the current gap info. + current_gap_ = gap; + current_gap_status_ = gap_status; + next_retrans_req_time_ = monotonicUSecNow() + + ((kGS_FastStartGap == current_gap_status_) + ? kFastStartTimeoutUSec + : kGapRerequestTimeoutUSec); + } + + return false; +} + +// Compute when its time to send the next gap retransmission in milliseconds. +// Returns < 0 for an infinite timeout (no gap) and 0 if its time to retransmit +// right now. +int AAH_RXPlayer::computeNextGapRetransmitTimeout() { + if (kGS_NoGap == current_gap_status_) { + return -1; + } + + int64_t timeout_delta = next_retrans_req_time_ - monotonicUSecNow(); + + timeout_delta /= 1000; + if (timeout_delta <= 0) { + return 0; + } + + return static_cast<uint32_t>(timeout_delta); +} + +} // namespace android diff --git a/media/libaah_rtp/aah_rx_player_ring_buffer.cpp b/media/libaah_rtp/aah_rx_player_ring_buffer.cpp new file mode 100644 index 000000000000..0d8b31f5441d --- /dev/null +++ b/media/libaah_rtp/aah_rx_player_ring_buffer.cpp @@ -0,0 +1,366 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "LibAAH_RTP" +//#define LOG_NDEBUG 0 +#include <utils/Log.h> + +#include "aah_rx_player.h" + +namespace android { + +AAH_RXPlayer::RXRingBuffer::RXRingBuffer(uint32_t capacity) { + capacity_ = capacity; + rd_ = wr_ = 0; + ring_ = new PacketBuffer*[capacity]; + memset(ring_, 0, sizeof(PacketBuffer*) * capacity); + reset(); +} + +AAH_RXPlayer::RXRingBuffer::~RXRingBuffer() { + reset(); + delete[] ring_; +} + +void AAH_RXPlayer::RXRingBuffer::reset() { + AutoMutex lock(&lock_); + + if (NULL != ring_) { + while (rd_ != wr_) { + CHECK(rd_ < capacity_); + if (NULL != ring_[rd_]) { + PacketBuffer::destroy(ring_[rd_]); + ring_[rd_] = NULL; + } + rd_ = (rd_ + 1) % capacity_; + } + } + + rd_ = wr_ = 0; + rd_seq_known_ = false; + waiting_for_fast_start_ = true; + fetched_first_packet_ = false; + rtp_activity_timeout_valid_ = false; +} + +bool AAH_RXPlayer::RXRingBuffer::pushBuffer(PacketBuffer* buf, + uint16_t seq) { + AutoMutex lock(&lock_); + CHECK(NULL != ring_); + CHECK(NULL != buf); + + rtp_activity_timeout_valid_ = true; + rtp_activity_timeout_ = monotonicUSecNow() + kRTPActivityTimeoutUSec; + + // If the ring buffer is totally reset (we have never received a single + // payload) then we don't know the rd sequence number and this should be + // simple. We just store the payload, advance the wr pointer and record the + // initial sequence number. + if (!rd_seq_known_) { + CHECK(rd_ == wr_); + CHECK(NULL == ring_[wr_]); + CHECK(wr_ < capacity_); + + ring_[wr_] = buf; + wr_ = (wr_ + 1) % capacity_; + rd_seq_ = seq; + rd_seq_known_ = true; + return true; + } + + // Compute the seqence number of this payload and of the write pointer, + // normalized around the read pointer. IOW - transform the payload seq no + // and the wr pointer seq no into a space where the rd pointer seq no is + // zero. This will define 4 cases we can consider... + // + // 1) norm_seq == norm_wr_seq + // This payload is contiguous with the last. All is good. + // + // 2) ((norm_seq < norm_wr_seq) && (norm_seq >= norm_rd_seq) + // aka ((norm_seq < norm_wr_seq) && (norm_seq >= 0) + // This payload is in the past, in the unprocessed region of the ring + // buffer. It is probably a retransmit intended to fill in a dropped + // payload; it may be a duplicate. + // + // 3) ((norm_seq - norm_wr_seq) & 0x8000) != 0 + // This payload is in the past compared to the write pointer (or so very + // far in the future that it has wrapped the seq no space), but not in + // the unprocessed region of the ring buffer. This could be a duplicate + // retransmit; we just drop these payloads unless we are waiting for our + // first fast start packet. If we are waiting for fast start, than this + // packet is probably the first packet of the fast start retransmission. + // If it will fit in the buffer, back up the read pointer to its position + // and clear the fast start flag, otherwise just drop it. + // + // 4) ((norm_seq - norm_wr_seq) & 0x8000) == 0 + // This payload which is ahead of the next write pointer. This indicates + // that we have missed some payloads and need to request a retransmit. + // If norm_seq >= (capacity - 1), then the gap is so large that it would + // overflow the ring buffer and we should probably start to panic. + + uint16_t norm_wr_seq = ((wr_ + capacity_ - rd_) % capacity_); + uint16_t norm_seq = seq - rd_seq_; + + // Check for overflow first. + if ((!(norm_seq & 0x8000)) && (norm_seq >= (capacity_ - 1))) { + ALOGW("Ring buffer overflow; cap = %u, [rd, wr] = [%hu, %hu], seq = %hu", + capacity_, rd_seq_, norm_wr_seq + rd_seq_, seq); + PacketBuffer::destroy(buf); + return false; + } + + // Check for case #1 + if (norm_seq == norm_wr_seq) { + CHECK(wr_ < capacity_); + CHECK(NULL == ring_[wr_]); + + ring_[wr_] = buf; + wr_ = (wr_ + 1) % capacity_; + + CHECK(wr_ != rd_); + return true; + } + + // Check case #2 + uint32_t ring_pos = (rd_ + norm_seq) % capacity_; + if ((norm_seq < norm_wr_seq) && (!(norm_seq & 0x8000))) { + // Do we already have a payload for this slot? If so, then this looks + // like a duplicate retransmit. Just ignore it. + if (NULL != ring_[ring_pos]) { + ALOGD("RXed duplicate retransmit, seq = %hu", seq); + PacketBuffer::destroy(buf); + } else { + // Looks like we were missing this payload. Go ahead and store it. + ring_[ring_pos] = buf; + } + + return true; + } + + // Check case #3 + if ((norm_seq - norm_wr_seq) & 0x8000) { + if (!waiting_for_fast_start_) { + ALOGD("RXed duplicate retransmit from before rd pointer, seq = %hu", + seq); + PacketBuffer::destroy(buf); + } else { + // Looks like a fast start fill-in. Go ahead and store it, assuming + // that we can fit it in the buffer. + uint32_t implied_ring_size = static_cast<uint32_t>(norm_wr_seq) + + (rd_seq_ - seq); + + if (implied_ring_size >= (capacity_ - 1)) { + ALOGD("RXed what looks like a fast start packet (seq = %hu)," + " but packet is too far in the past to fit into the ring" + " buffer. Dropping.", seq); + PacketBuffer::destroy(buf); + } else { + ring_pos = (rd_ + capacity_ + seq - rd_seq_) % capacity_; + rd_seq_ = seq; + rd_ = ring_pos; + waiting_for_fast_start_ = false; + + CHECK(ring_pos < capacity_); + CHECK(NULL == ring_[ring_pos]); + ring_[ring_pos] = buf; + } + + } + return true; + } + + // Must be in case #4 with no overflow. This packet fits in the current + // ring buffer, but is discontiuguous. Advance the write pointer leaving a + // gap behind. + uint32_t gap_len = (ring_pos + capacity_ - wr_) % capacity_; + ALOGD("Drop detected; %u packets, seq_range [%hu, %hu]", + gap_len, + rd_seq_ + norm_wr_seq, + rd_seq_ + norm_wr_seq + gap_len - 1); + + CHECK(NULL == ring_[ring_pos]); + ring_[ring_pos] = buf; + wr_ = (ring_pos + 1) % capacity_; + CHECK(wr_ != rd_); + + return true; +} + +AAH_RXPlayer::PacketBuffer* +AAH_RXPlayer::RXRingBuffer::fetchBuffer(bool* is_discon) { + AutoMutex lock(&lock_); + CHECK(NULL != ring_); + CHECK(NULL != is_discon); + + // If the read seqence number is not known, then this ring buffer has not + // received a packet since being reset and there cannot be any packets to + // return. If we are still waiting for the first fast start packet to show + // up, we don't want to let any buffer be consumed yet because we expect to + // see a packet before the initial read sequence number show up shortly. + if (!rd_seq_known_ || waiting_for_fast_start_) { + *is_discon = false; + return NULL; + } + + PacketBuffer* ret = NULL; + *is_discon = !fetched_first_packet_; + + while ((rd_ != wr_) && (NULL == ret)) { + CHECK(rd_ < capacity_); + + // If we hit a gap, stall and do not advance the read pointer. Let the + // higher level code deal with requesting retries and/or deciding to + // skip the current gap. + ret = ring_[rd_]; + if (NULL == ret) { + break; + } + + ring_[rd_] = NULL; + rd_ = (rd_ + 1) % capacity_; + ++rd_seq_; + } + + if (NULL != ret) { + fetched_first_packet_ = true; + } + + return ret; +} + +AAH_RXPlayer::GapStatus +AAH_RXPlayer::RXRingBuffer::fetchCurrentGap(SeqNoGap* gap) { + AutoMutex lock(&lock_); + CHECK(NULL != ring_); + CHECK(NULL != gap); + + // If the read seqence number is not known, then this ring buffer has not + // received a packet since being reset and there cannot be any gaps. + if (!rd_seq_known_) { + return kGS_NoGap; + } + + // If we are waiting for fast start, then the current gap is a fast start + // gap and it includes all packets before the read sequence number. + if (waiting_for_fast_start_) { + gap->start_seq_ = + gap->end_seq_ = rd_seq_ - 1; + return kGS_FastStartGap; + } + + // If rd == wr, then the buffer is empty and there cannot be any gaps. + if (rd_ == wr_) { + return kGS_NoGap; + } + + // If rd_ is currently pointing at an unprocessed packet, then there is no + // current gap. + CHECK(rd_ < capacity_); + if (NULL != ring_[rd_]) { + return kGS_NoGap; + } + + // Looks like there must be a gap here. The start of the gap is the current + // rd sequence number, all we need to do now is determine its length in + // order to compute the end sequence number. + gap->start_seq_ = rd_seq_; + uint16_t end = rd_seq_; + uint32_t tmp = (rd_ + 1) % capacity_; + while ((tmp != wr_) && (NULL == ring_[tmp])) { + ++end; + tmp = (tmp + 1) % capacity_; + } + gap->end_seq_ = end; + + return kGS_NormalGap; +} + +void AAH_RXPlayer::RXRingBuffer::processNAK(const SeqNoGap* nak) { + AutoMutex lock(&lock_); + CHECK(NULL != ring_); + + // If we were waiting for our first fast start fill-in packet, and we + // received a NAK, then apparantly we are not getting our fast start. Just + // clear the waiting flag and go back to normal behavior. + if (waiting_for_fast_start_) { + waiting_for_fast_start_ = false; + } + + // If we have not received a packet since last reset, or there is no data in + // the ring, then there is nothing to skip. + if ((!rd_seq_known_) || (rd_ == wr_)) { + return; + } + + // If rd_ is currently pointing at an unprocessed packet, then there is no + // gap to skip. + CHECK(rd_ < capacity_); + if (NULL != ring_[rd_]) { + return; + } + + // Looks like there must be a gap here. Advance rd until we have passed + // over the portion of it indicated by nak (or all of the gap if nak is + // NULL). Then reset fetched_first_packet_ so that the next read will show + // up as being discontiguous. + uint16_t seq_after_gap = (NULL == nak) ? 0 : nak->end_seq_ + 1; + while ((rd_ != wr_) && + (NULL == ring_[rd_]) && + ((NULL == nak) || (seq_after_gap != rd_seq_))) { + rd_ = (rd_ + 1) % capacity_; + ++rd_seq_; + } + fetched_first_packet_ = false; +} + +int AAH_RXPlayer::RXRingBuffer::computeInactivityTimeout() { + AutoMutex lock(&lock_); + + if (!rtp_activity_timeout_valid_) { + return -1; + } + + uint64_t now = monotonicUSecNow(); + if (rtp_activity_timeout_ <= now) { + return 0; + } + + return (rtp_activity_timeout_ - now) / 1000; +} + +AAH_RXPlayer::PacketBuffer* +AAH_RXPlayer::PacketBuffer::allocate(ssize_t length) { + if (length <= 0) { + return NULL; + } + + uint32_t alloc_len = sizeof(PacketBuffer) + length; + PacketBuffer* ret = reinterpret_cast<PacketBuffer*>( + new uint8_t[alloc_len]); + + if (NULL != ret) { + ret->length_ = length; + } + + return ret; +} + +void AAH_RXPlayer::PacketBuffer::destroy(PacketBuffer* pb) { + uint8_t* kill_me = reinterpret_cast<uint8_t*>(pb); + delete[] kill_me; +} + +} // namespace android diff --git a/media/libaah_rtp/aah_rx_player_substream.cpp b/media/libaah_rtp/aah_rx_player_substream.cpp new file mode 100644 index 000000000000..1e4c784629a2 --- /dev/null +++ b/media/libaah_rtp/aah_rx_player_substream.cpp @@ -0,0 +1,498 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "LibAAH_RTP" +//#define LOG_NDEBUG 0 + +#include <utils/Log.h> + +#include <include/avc_utils.h> +#include <media/stagefright/MediaBuffer.h> +#include <media/stagefright/MediaDefs.h> +#include <media/stagefright/MetaData.h> +#include <media/stagefright/OMXCodec.h> +#include <media/stagefright/Utils.h> + +#include "aah_rx_player.h" + +namespace android { + +int64_t AAH_RXPlayer::Substream::kAboutToUnderflowThreshold = + 50ull * 1000; + +AAH_RXPlayer::Substream::Substream(uint32_t ssrc, OMXClient& omx) { + ssrc_ = ssrc; + substream_details_known_ = false; + buffer_in_progress_ = NULL; + status_ = OK; + + decoder_ = new AAH_DecoderPump(omx); + if (decoder_ == NULL) { + ALOGE("%s failed to allocate decoder pump!", __PRETTY_FUNCTION__); + } + if (OK != decoder_->initCheck()) { + ALOGE("%s failed to initialize decoder pump!", __PRETTY_FUNCTION__); + } + + // cleanupBufferInProgress will reset most of the internal state variables. + // Just need to make sure that buffer_in_progress_ is NULL before calling. + cleanupBufferInProgress(); +} + + +void AAH_RXPlayer::Substream::shutdown() { + substream_meta_ = NULL; + status_ = OK; + cleanupBufferInProgress(); + cleanupDecoder(); +} + +void AAH_RXPlayer::Substream::cleanupBufferInProgress() { + if (NULL != buffer_in_progress_) { + buffer_in_progress_->release(); + buffer_in_progress_ = NULL; + } + + expected_buffer_size_ = 0; + buffer_filled_ = 0; + waiting_for_rap_ = true; +} + +void AAH_RXPlayer::Substream::cleanupDecoder() { + if (decoder_ != NULL) { + decoder_->shutdown(); + } +} + +bool AAH_RXPlayer::Substream::shouldAbort(const char* log_tag) { + // If we have already encountered a fatal error, do nothing. We are just + // waiting for our owner to shut us down now. + if (OK != status_) { + ALOGV("Skipping %s, substream has encountered fatal error (%d).", + log_tag, status_); + return true; + } + + return false; +} + +void AAH_RXPlayer::Substream::processPayloadStart(uint8_t* buf, + uint32_t amt, + int32_t ts_lower) { + uint32_t min_length = 6; + + if (shouldAbort(__PRETTY_FUNCTION__)) { + return; + } + + // Do we have a buffer in progress already? If so, abort the buffer. In + // theory, this should never happen. If there were a discontinutity in the + // stream, the discon in the seq_nos at the RTP level should have already + // triggered a cleanup of the buffer in progress. To see a problem at this + // level is an indication either of a bug in the transmitter, or some form + // of terrible corruption/tampering on the wire. + if (NULL != buffer_in_progress_) { + ALOGE("processPayloadStart is aborting payload already in progress."); + cleanupBufferInProgress(); + } + + // Parse enough of the header to know where we stand. Since this is a + // payload start, it should begin with a TRTP header which has to be at + // least 6 bytes long. + if (amt < min_length) { + ALOGV("Discarding payload too short to contain TRTP header (len = %u)", + amt); + return; + } + + // Check the TRTP version number. + if (0x01 != buf[0]) { + ALOGV("Unexpected TRTP version (%u) in header. Expected %u.", + buf[0], 1); + return; + } + + // Extract the substream type field and make sure its one we understand (and + // one that does not conflict with any previously received substream type. + uint8_t header_type = (buf[1] >> 4) & 0xF; + switch (header_type) { + case 0x01: + // Audio, yay! Just break. We understand audio payloads. + break; + case 0x02: + ALOGV("RXed packet with unhandled TRTP header type (Video)."); + return; + case 0x03: + ALOGV("RXed packet with unhandled TRTP header type (Subpicture)."); + return; + case 0x04: + ALOGV("RXed packet with unhandled TRTP header type (Control)."); + return; + default: + ALOGV("RXed packet with unhandled TRTP header type (%u).", + header_type); + return; + } + + if (substream_details_known_ && (header_type != substream_type_)) { + ALOGV("RXed TRTP Payload for SSRC=0x%08x where header type (%u) does not" + " match previously received header type (%u)", + ssrc_, header_type, substream_type_); + return; + } + + // Check the flags to see if there is another 32 bits of timestamp present. + uint32_t trtp_header_len = 6; + bool ts_valid = buf[1] & 0x1; + if (ts_valid) { + min_length += 4; + trtp_header_len += 4; + if (amt < min_length) { + ALOGV("Discarding payload too short to contain TRTP timestamp" + " (len = %u)", amt); + return; + } + } + + // Extract the TRTP length field and sanity check it. + uint32_t trtp_len; + trtp_len = (static_cast<uint32_t>(buf[2]) << 24) | + (static_cast<uint32_t>(buf[3]) << 16) | + (static_cast<uint32_t>(buf[4]) << 8) | + static_cast<uint32_t>(buf[5]); + if (trtp_len < min_length) { + ALOGV("TRTP length (%u) is too short to be valid. Must be at least %u" + " bytes.", trtp_len, min_length); + return; + } + + // Extract the rest of the timestamp field if valid. + int64_t ts = 0; + uint32_t parse_offset = 6; + if (ts_valid) { + ts = (static_cast<int64_t>(buf[parse_offset ]) << 56) | + (static_cast<int64_t>(buf[parse_offset + 1]) << 48) | + (static_cast<int64_t>(buf[parse_offset + 2]) << 40) | + (static_cast<int64_t>(buf[parse_offset + 3]) << 32); + ts |= ts_lower; + parse_offset += 4; + } + + // Check the flags to see if there is another 24 bytes of timestamp + // transformation present. + if (buf[1] & 0x2) { + min_length += 24; + parse_offset += 24; + trtp_header_len += 24; + if (amt < min_length) { + ALOGV("Discarding payload too short to contain TRTP timestamp" + " transformation (len = %u)", amt); + return; + } + } + + // TODO : break the parsing into individual parsers for the different + // payload types (audio, video, etc). + // + // At this point in time, we know that this is audio. Go ahead and parse + // the basic header, check the codec type, and find the payload portion of + // the packet. + min_length += 3; + if (trtp_len < min_length) { + ALOGV("TRTP length (%u) is too short to be a valid audio payload. Must" + " be at least %u bytes.", trtp_len, min_length); + return; + } + + if (amt < min_length) { + ALOGV("TRTP porttion of RTP payload (%u bytes) too small to contain" + " entire TRTP header. TRTP does not currently support fragmenting" + " TRTP headers across RTP payloads", amt); + return; + } + + uint8_t codec_type = buf[parse_offset ]; + uint8_t flags = buf[parse_offset + 1]; + uint8_t volume = buf[parse_offset + 2]; + parse_offset += 3; + trtp_header_len += 3; + + if (!setupSubstreamType(header_type, codec_type)) { + return; + } + + if (decoder_ != NULL) { + decoder_->setRenderVolume(volume); + } + + // TODO : move all of the constant flag and offset definitions for TRTP up + // into some sort of common header file. + if (waiting_for_rap_ && !(flags & 0x08)) { + ALOGV("Dropping non-RAP TRTP Audio Payload while waiting for RAP."); + return; + } + + if (flags & 0x10) { + ALOGV("Dropping TRTP Audio Payload with aux codec data present (only" + " handle MP3 right now, and it has no aux data)"); + return; + } + + // OK - everything left is just payload. Compute the payload size, start + // the buffer in progress and pack as much payload as we can into it. If + // the payload is finished once we are done, go ahead and send the payload + // to the decoder. + expected_buffer_size_ = trtp_len - trtp_header_len; + if (!expected_buffer_size_) { + ALOGV("Dropping TRTP Audio Payload with 0 Access Unit length"); + return; + } + + CHECK(amt >= trtp_header_len); + uint32_t todo = amt - trtp_header_len; + if (expected_buffer_size_ < todo) { + ALOGV("Extra data (%u > %u) present in initial TRTP Audio Payload;" + " dropping payload.", todo, expected_buffer_size_); + return; + } + + buffer_filled_ = 0; + buffer_in_progress_ = new MediaBuffer(expected_buffer_size_); + if ((NULL == buffer_in_progress_) || + (NULL == buffer_in_progress_->data())) { + ALOGV("Failed to allocate MediaBuffer of length %u", + expected_buffer_size_); + cleanupBufferInProgress(); + return; + } + + sp<MetaData> meta = buffer_in_progress_->meta_data(); + if (meta == NULL) { + ALOGV("Missing metadata structure in allocated MediaBuffer; dropping" + " payload"); + cleanupBufferInProgress(); + return; + } + + // TODO : set this based on the codec type indicated in the TRTP stream. + // Right now, we only support MP3, so the choice is obvious. + meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG); + if (ts_valid) { + meta->setInt64(kKeyTime, ts); + } + + if (amt > 0) { + uint8_t* tgt = + reinterpret_cast<uint8_t*>(buffer_in_progress_->data()); + memcpy(tgt + buffer_filled_, buf + trtp_header_len, todo); + buffer_filled_ += amt; + } + + if (buffer_filled_ >= expected_buffer_size_) { + processCompletedBuffer(); + } +} + +void AAH_RXPlayer::Substream::processPayloadCont(uint8_t* buf, + uint32_t amt) { + if (shouldAbort(__PRETTY_FUNCTION__)) { + return; + } + + if (NULL == buffer_in_progress_) { + ALOGV("TRTP Receiver skipping payload continuation; no buffer currently" + " in progress."); + return; + } + + CHECK(buffer_filled_ < expected_buffer_size_); + uint32_t buffer_left = expected_buffer_size_ - buffer_filled_; + if (amt > buffer_left) { + ALOGV("Extra data (%u > %u) present in continued TRTP Audio Payload;" + " dropping payload.", amt, buffer_left); + cleanupBufferInProgress(); + return; + } + + if (amt > 0) { + uint8_t* tgt = + reinterpret_cast<uint8_t*>(buffer_in_progress_->data()); + memcpy(tgt + buffer_filled_, buf, amt); + buffer_filled_ += amt; + } + + if (buffer_filled_ >= expected_buffer_size_) { + processCompletedBuffer(); + } +} + +void AAH_RXPlayer::Substream::processCompletedBuffer() { + const uint8_t* buffer_data = NULL; + int sample_rate; + int channel_count; + size_t frame_size; + status_t res; + + CHECK(NULL != buffer_in_progress_); + + if (decoder_ == NULL) { + ALOGV("Dropping complete buffer, no decoder pump allocated"); + goto bailout; + } + + buffer_data = reinterpret_cast<const uint8_t*>(buffer_in_progress_->data()); + if (buffer_in_progress_->size() < 4) { + ALOGV("MP3 payload too short to contain header, dropping payload."); + goto bailout; + } + + // Extract the channel count and the sample rate from the MP3 header. The + // stagefright MP3 requires that these be delivered before decoing can + // begin. + if (!GetMPEGAudioFrameSize(U32_AT(buffer_data), + &frame_size, + &sample_rate, + &channel_count, + NULL, + NULL)) { + ALOGV("Failed to parse MP3 header in payload, droping payload."); + goto bailout; + } + + + // Make sure that our substream metadata is set up properly. If there has + // been a format change, be sure to reset the underlying decoder. In + // stagefright, it seems like the only way to do this is to destroy and + // recreate the decoder. + if (substream_meta_ == NULL) { + substream_meta_ = new MetaData(); + + if (substream_meta_ == NULL) { + ALOGE("Failed to allocate MetaData structure for substream"); + goto bailout; + } + + substream_meta_->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG); + substream_meta_->setInt32 (kKeyChannelCount, channel_count); + substream_meta_->setInt32 (kKeySampleRate, sample_rate); + } else { + int32_t prev_sample_rate; + int32_t prev_channel_count; + substream_meta_->findInt32(kKeySampleRate, &prev_sample_rate); + substream_meta_->findInt32(kKeyChannelCount, &prev_channel_count); + + if ((prev_channel_count != channel_count) || + (prev_sample_rate != sample_rate)) { + ALOGW("Format change detected, forcing decoder reset."); + cleanupDecoder(); + + substream_meta_->setInt32(kKeyChannelCount, channel_count); + substream_meta_->setInt32(kKeySampleRate, sample_rate); + } + } + + // If our decoder has not be set up, do so now. + res = decoder_->init(substream_meta_); + if (OK != res) { + ALOGE("Failed to init decoder (res = %d)", res); + cleanupDecoder(); + substream_meta_ = NULL; + goto bailout; + } + + // Queue the payload for decode. + res = decoder_->queueForDecode(buffer_in_progress_); + + if (res != OK) { + ALOGD("Failed to queue payload for decode, resetting decoder pump!" + " (res = %d)", res); + status_ = res; + cleanupDecoder(); + cleanupBufferInProgress(); + } + + // NULL out buffer_in_progress before calling the cleanup helper. + // + // MediaBuffers use something of a hybrid ref-counting pattern which prevent + // the AAH_DecoderPump's input queue from adding their own reference to the + // MediaBuffer. MediaBuffers start life with a reference count of 0, as + // well as an observer which starts as NULL. Before being given an + // observer, the ref count cannot be allowed to become non-zero as it will + // cause calls to release() to assert. Basically, before a MediaBuffer has + // an observer, they behave like non-ref counted obects where release() + // serves the roll of delete. After a MediaBuffer has an observer, they + // become more like ref counted objects where add ref and release can be + // used, and when the ref count hits zero, the MediaBuffer is handed off to + // the observer. + // + // Given all of this, when we give the buffer to the decoder pump to wait in + // the to-be-processed queue, the decoder cannot add a ref to the buffer as + // it would in a traditional ref counting system. Instead it needs to + // "steal" the non-existent ref. In the case of queue failure, we need to + // make certain to release this non-existent reference so that the buffer is + // cleaned up during the cleanupBufferInProgress helper. In the case of a + // successful queue operation, we need to make certain that the + // cleanupBufferInProgress helper does not release the buffer since it needs + // to remain alive in the queue. We acomplish this by NULLing out the + // buffer pointer before calling the cleanup helper. + buffer_in_progress_ = NULL; + +bailout: + cleanupBufferInProgress(); +} + + +void AAH_RXPlayer::Substream::processTSTransform(const LinearTransform& trans) { + if (decoder_ != NULL) { + decoder_->setRenderTSTransform(trans); + } +} + +bool AAH_RXPlayer::Substream::isAboutToUnderflow() { + if (decoder_ == NULL) { + return false; + } + + return decoder_->isAboutToUnderflow(kAboutToUnderflowThreshold); +} + +bool AAH_RXPlayer::Substream::setupSubstreamType(uint8_t substream_type, + uint8_t codec_type) { + // Sanity check the codec type. Right now we only support MP3. Also check + // for conflicts with previously delivered codec types. + if (substream_details_known_ && (codec_type != codec_type_)) { + ALOGV("RXed TRTP Payload for SSRC=0x%08x where codec type (%u) does not" + " match previously received codec type (%u)", + ssrc_, codec_type, codec_type_); + return false; + } + + if (codec_type != 0x03) { + ALOGV("RXed TRTP Audio Payload for SSRC=0x%08x with unsupported codec" + " type (%u)", ssrc_, codec_type); + return false; + } + + if (!substream_details_known_) { + substream_type_ = substream_type; + codec_type_ = codec_type; + substream_details_known_ = true; + } + + return true; +} + +} // namespace android diff --git a/media/libaah_rtp/aah_tx_packet.cpp b/media/libaah_rtp/aah_tx_packet.cpp new file mode 100644 index 000000000000..3f6e0e9520d6 --- /dev/null +++ b/media/libaah_rtp/aah_tx_packet.cpp @@ -0,0 +1,331 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "LibAAH_RTP" +#include <utils/Log.h> + +#include <arpa/inet.h> +#include <string.h> + +#include <media/stagefright/foundation/ADebug.h> + +#include "aah_tx_packet.h" + +namespace android { + +const int TRTPPacket::kRTPHeaderLen; +const uint32_t TRTPPacket::kTRTPEpochMask; + +TRTPPacket::~TRTPPacket() { + delete mPacket; +} + +/*** TRTP packet properties ***/ + +void TRTPPacket::setSeqNumber(uint16_t val) { + mSeqNumber = val; + + if (mIsPacked) { + const int kTRTPSeqNumberOffset = 2; + uint16_t* buf = reinterpret_cast<uint16_t*>( + mPacket + kTRTPSeqNumberOffset); + *buf = htons(mSeqNumber); + } +} + +uint16_t TRTPPacket::getSeqNumber() const { + return mSeqNumber; +} + +void TRTPPacket::setPTS(int64_t val) { + CHECK(!mIsPacked); + mPTS = val; + mPTSValid = true; +} + +int64_t TRTPPacket::getPTS() const { + return mPTS; +} + +void TRTPPacket::setEpoch(uint32_t val) { + mEpoch = val; + + if (mIsPacked) { + const int kTRTPEpochOffset = 8; + uint32_t* buf = reinterpret_cast<uint32_t*>( + mPacket + kTRTPEpochOffset); + uint32_t val = ntohl(*buf); + val &= ~(kTRTPEpochMask << kTRTPEpochShift); + val |= (mEpoch & kTRTPEpochMask) << kTRTPEpochShift; + *buf = htonl(val); + } +} + +void TRTPPacket::setProgramID(uint16_t val) { + CHECK(!mIsPacked); + mProgramID = val; +} + +void TRTPPacket::setSubstreamID(uint16_t val) { + CHECK(!mIsPacked); + mSubstreamID = val; +} + + +void TRTPPacket::setClockTransform(const LinearTransform& trans) { + CHECK(!mIsPacked); + mClockTranform = trans; + mClockTranformValid = true; +} + +uint8_t* TRTPPacket::getPacket() const { + CHECK(mIsPacked); + return mPacket; +} + +int TRTPPacket::getPacketLen() const { + CHECK(mIsPacked); + return mPacketLen; +} + +void TRTPPacket::setExpireTime(nsecs_t val) { + CHECK(!mIsPacked); + mExpireTime = val; +} + +nsecs_t TRTPPacket::getExpireTime() const { + return mExpireTime; +} + +/*** TRTP audio packet properties ***/ + +void TRTPAudioPacket::setCodecType(TRTPAudioCodecType val) { + CHECK(!mIsPacked); + mCodecType = val; +} + +void TRTPAudioPacket::setRandomAccessPoint(bool val) { + CHECK(!mIsPacked); + mRandomAccessPoint = val; +} + +void TRTPAudioPacket::setDropable(bool val) { + CHECK(!mIsPacked); + mDropable = val; +} + +void TRTPAudioPacket::setDiscontinuity(bool val) { + CHECK(!mIsPacked); + mDiscontinuity = val; +} + +void TRTPAudioPacket::setEndOfStream(bool val) { + CHECK(!mIsPacked); + mEndOfStream = val; +} + +void TRTPAudioPacket::setVolume(uint8_t val) { + CHECK(!mIsPacked); + mVolume = val; +} + +void TRTPAudioPacket::setAccessUnitData(void* data, int len) { + CHECK(!mIsPacked); + mAccessUnitData = data; + mAccessUnitLen = len; +} + +/*** TRTP control packet properties ***/ + +void TRTPControlPacket::setCommandID(TRTPCommandID val) { + CHECK(!mIsPacked); + mCommandID = val; +} + +/*** TRTP packet serializers ***/ + +void TRTPPacket::writeU8(uint8_t*& buf, uint8_t val) { + *buf = val; + buf++; +} + +void TRTPPacket::writeU16(uint8_t*& buf, uint16_t val) { + *reinterpret_cast<uint16_t*>(buf) = htons(val); + buf += 2; +} + +void TRTPPacket::writeU32(uint8_t*& buf, uint32_t val) { + *reinterpret_cast<uint32_t*>(buf) = htonl(val); + buf += 4; +} + +void TRTPPacket::writeU64(uint8_t*& buf, uint64_t val) { + buf[0] = static_cast<uint8_t>(val >> 56); + buf[1] = static_cast<uint8_t>(val >> 48); + buf[2] = static_cast<uint8_t>(val >> 40); + buf[3] = static_cast<uint8_t>(val >> 32); + buf[4] = static_cast<uint8_t>(val >> 24); + buf[5] = static_cast<uint8_t>(val >> 16); + buf[6] = static_cast<uint8_t>(val >> 8); + buf[7] = static_cast<uint8_t>(val); + buf += 8; +} + +void TRTPPacket::writeTRTPHeader(uint8_t*& buf, + bool isFirstFragment, + int totalPacketLen) { + // RTP header + writeU8(buf, + ((mVersion & 0x03) << 6) | + (static_cast<int>(mPadding) << 5) | + (static_cast<int>(mExtension) << 4) | + (mCsrcCount & 0x0F)); + writeU8(buf, + (static_cast<int>(isFirstFragment) << 7) | + (mPayloadType & 0x7F)); + writeU16(buf, mSeqNumber); + if (isFirstFragment && mPTSValid) { + writeU32(buf, mPTS & 0xFFFFFFFF); + } else { + writeU32(buf, 0); + } + writeU32(buf, + ((mEpoch & kTRTPEpochMask) << kTRTPEpochShift) | + ((mProgramID & 0x1F) << 5) | + (mSubstreamID & 0x1F)); + + // TRTP header + writeU8(buf, mTRTPVersion); + writeU8(buf, + ((mTRTPHeaderType & 0x0F) << 4) | + (mClockTranformValid ? 0x02 : 0x00) | + (mPTSValid ? 0x01 : 0x00)); + writeU32(buf, totalPacketLen - kRTPHeaderLen); + if (mPTSValid) { + writeU32(buf, mPTS >> 32); + } + + if (mClockTranformValid) { + writeU64(buf, mClockTranform.a_zero); + writeU32(buf, mClockTranform.a_to_b_numer); + writeU32(buf, mClockTranform.a_to_b_denom); + writeU64(buf, mClockTranform.b_zero); + } +} + +bool TRTPAudioPacket::pack() { + if (mIsPacked) { + return false; + } + + int packetLen = kRTPHeaderLen + + mAccessUnitLen + + TRTPHeaderLen(); + + // TODO : support multiple fragments + const int kMaxUDPPayloadLen = 65507; + if (packetLen > kMaxUDPPayloadLen) { + return false; + } + + mPacket = new uint8_t[packetLen]; + if (!mPacket) { + return false; + } + + mPacketLen = packetLen; + + uint8_t* cur = mPacket; + + writeTRTPHeader(cur, true, packetLen); + writeU8(cur, mCodecType); + writeU8(cur, + (static_cast<int>(mRandomAccessPoint) << 3) | + (static_cast<int>(mDropable) << 2) | + (static_cast<int>(mDiscontinuity) << 1) | + (static_cast<int>(mEndOfStream))); + writeU8(cur, mVolume); + + memcpy(cur, mAccessUnitData, mAccessUnitLen); + + mIsPacked = true; + return true; +} + +int TRTPPacket::TRTPHeaderLen() const { + // 6 bytes for version, payload type, flags and length. An additional 4 if + // there are upper timestamp bits present and another 24 if there is a clock + // transformation present. + return 6 + + (mClockTranformValid ? 24 : 0) + + (mPTSValid ? 4 : 0); +} + +int TRTPAudioPacket::TRTPHeaderLen() const { + // TRTPPacket::TRTPHeaderLen() for the base TRTPHeader. 3 bytes for audio's + // codec type, flags and volume field. Another 5 bytes if the codec type is + // PCM and we are sending sample rate/channel count. as well as however long + // the aux data (if present) is. + + int pcmParamLength; + switch(mCodecType) { + case kCodecPCMBigEndian: + case kCodecPCMLittleEndian: + pcmParamLength = 5; + break; + + default: + pcmParamLength = 0; + break; + } + + + // TODO : properly compute aux data length. Currently, nothing + // uses aux data, so its length is always 0. + int auxDataLength = 0; + return TRTPPacket::TRTPHeaderLen() + + 3 + + auxDataLength + + pcmParamLength; +} + +bool TRTPControlPacket::pack() { + if (mIsPacked) { + return false; + } + + // command packets contain a 2-byte command ID + int packetLen = kRTPHeaderLen + + TRTPHeaderLen() + + 2; + + mPacket = new uint8_t[packetLen]; + if (!mPacket) { + return false; + } + + mPacketLen = packetLen; + + uint8_t* cur = mPacket; + + writeTRTPHeader(cur, true, packetLen); + writeU16(cur, mCommandID); + + mIsPacked = true; + return true; +} + +} // namespace android diff --git a/media/libaah_rtp/aah_tx_packet.h b/media/libaah_rtp/aah_tx_packet.h new file mode 100644 index 000000000000..833803ea1bef --- /dev/null +++ b/media/libaah_rtp/aah_tx_packet.h @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __AAH_TX_PACKET_H__ +#define __AAH_TX_PACKET_H__ + +#include <media/stagefright/foundation/ABase.h> +#include <utils/LinearTransform.h> +#include <utils/RefBase.h> +#include <utils/Timers.h> + +namespace android { + +class TRTPPacket : public RefBase { + protected: + enum TRTPHeaderType { + kHeaderTypeAudio = 1, + kHeaderTypeVideo = 2, + kHeaderTypeSubpicture = 3, + kHeaderTypeControl = 4, + }; + + TRTPPacket(TRTPHeaderType headerType) + : mIsPacked(false) + , mVersion(2) + , mPadding(false) + , mExtension(false) + , mCsrcCount(0) + , mPayloadType(100) + , mSeqNumber(0) + , mPTSValid(false) + , mPTS(0) + , mEpoch(0) + , mProgramID(0) + , mSubstreamID(0) + , mClockTranformValid(false) + , mTRTPVersion(1) + , mTRTPLength(0) + , mTRTPHeaderType(headerType) + , mPacket(NULL) + , mPacketLen(0) { } + + public: + virtual ~TRTPPacket(); + + void setSeqNumber(uint16_t val); + uint16_t getSeqNumber() const; + + void setPTS(int64_t val); + int64_t getPTS() const; + + void setEpoch(uint32_t val); + void setProgramID(uint16_t val); + void setSubstreamID(uint16_t val); + void setClockTransform(const LinearTransform& trans); + + uint8_t* getPacket() const; + int getPacketLen() const; + + void setExpireTime(nsecs_t val); + nsecs_t getExpireTime() const; + + virtual bool pack() = 0; + + // mask for the number of bits in a TRTP epoch + static const uint32_t kTRTPEpochMask = (1 << 22) - 1; + static const int kTRTPEpochShift = 10; + + protected: + static const int kRTPHeaderLen = 12; + virtual int TRTPHeaderLen() const; + + void writeTRTPHeader(uint8_t*& buf, + bool isFirstFragment, + int totalPacketLen); + + void writeU8(uint8_t*& buf, uint8_t val); + void writeU16(uint8_t*& buf, uint16_t val); + void writeU32(uint8_t*& buf, uint32_t val); + void writeU64(uint8_t*& buf, uint64_t val); + + bool mIsPacked; + + uint8_t mVersion; + bool mPadding; + bool mExtension; + uint8_t mCsrcCount; + uint8_t mPayloadType; + uint16_t mSeqNumber; + bool mPTSValid; + int64_t mPTS; + uint32_t mEpoch; + uint16_t mProgramID; + uint16_t mSubstreamID; + LinearTransform mClockTranform; + bool mClockTranformValid; + uint8_t mTRTPVersion; + uint32_t mTRTPLength; + TRTPHeaderType mTRTPHeaderType; + + uint8_t* mPacket; + int mPacketLen; + + nsecs_t mExpireTime; + + DISALLOW_EVIL_CONSTRUCTORS(TRTPPacket); +}; + +class TRTPAudioPacket : public TRTPPacket { + public: + TRTPAudioPacket() + : TRTPPacket(kHeaderTypeAudio) + , mCodecType(kCodecInvalid) + , mRandomAccessPoint(false) + , mDropable(false) + , mDiscontinuity(false) + , mEndOfStream(false) + , mVolume(0) + , mAccessUnitData(NULL) { } + + enum TRTPAudioCodecType { + kCodecInvalid = 0, + kCodecPCMBigEndian = 1, + kCodecPCMLittleEndian = 2, + kCodecMPEG1Audio = 3, + }; + + void setCodecType(TRTPAudioCodecType val); + void setRandomAccessPoint(bool val); + void setDropable(bool val); + void setDiscontinuity(bool val); + void setEndOfStream(bool val); + void setVolume(uint8_t val); + void setAccessUnitData(void* data, int len); + + virtual bool pack(); + + protected: + virtual int TRTPHeaderLen() const; + + private: + TRTPAudioCodecType mCodecType; + bool mRandomAccessPoint; + bool mDropable; + bool mDiscontinuity; + bool mEndOfStream; + uint8_t mVolume; + void* mAccessUnitData; + int mAccessUnitLen; + + DISALLOW_EVIL_CONSTRUCTORS(TRTPAudioPacket); +}; + +class TRTPControlPacket : public TRTPPacket { + public: + TRTPControlPacket() + : TRTPPacket(kHeaderTypeControl) + , mCommandID(kCommandNop) {} + + enum TRTPCommandID { + kCommandNop = 1, + kCommandFlush = 2, + kCommandEOS = 3, + }; + + void setCommandID(TRTPCommandID val); + + virtual bool pack(); + + private: + TRTPCommandID mCommandID; + + DISALLOW_EVIL_CONSTRUCTORS(TRTPControlPacket); +}; + +} // namespace android + +#endif // __AAH_TX_PLAYER_H__ diff --git a/media/libaah_rtp/aah_tx_player.cpp b/media/libaah_rtp/aah_tx_player.cpp new file mode 100644 index 000000000000..a79a9891ef03 --- /dev/null +++ b/media/libaah_rtp/aah_tx_player.cpp @@ -0,0 +1,1139 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "LibAAH_RTP" +#include <utils/Log.h> + +#define __STDC_FORMAT_MACROS +#include <inttypes.h> +#include <netdb.h> +#include <netinet/ip.h> + +#include <common_time/cc_helper.h> +#include <media/IMediaPlayer.h> +#include <media/stagefright/foundation/ADebug.h> +#include <media/stagefright/foundation/AMessage.h> +#include <media/stagefright/FileSource.h> +#include <media/stagefright/MediaBuffer.h> +#include <media/stagefright/MetaData.h> +#include <utils/Timers.h> + +#include "aah_tx_packet.h" +#include "aah_tx_player.h" + +namespace android { + +static int64_t kLowWaterMarkUs = 2000000ll; // 2secs +static int64_t kHighWaterMarkUs = 10000000ll; // 10secs +static const size_t kLowWaterMarkBytes = 40000; +static const size_t kHighWaterMarkBytes = 200000; + +// When we start up, how much lead time should we put on the first access unit? +static const int64_t kAAHStartupLeadTimeUs = 300000LL; + +// How much time do we attempt to lead the clock by in steady state? +static const int64_t kAAHBufferTimeUs = 1000000LL; + +// how long do we keep data in our retransmit buffer after sending it. +const int64_t AAH_TXPlayer::kAAHRetryKeepAroundTimeNs = + kAAHBufferTimeUs * 1100; + +sp<MediaPlayerBase> createAAH_TXPlayer() { + sp<MediaPlayerBase> ret = new AAH_TXPlayer(); + return ret; +} + +template <typename T> static T clamp(T val, T min, T max) { + if (val < min) { + return min; + } else if (val > max) { + return max; + } else { + return val; + } +} + +struct AAH_TXEvent : public TimedEventQueue::Event { + AAH_TXEvent(AAH_TXPlayer *player, + void (AAH_TXPlayer::*method)()) : mPlayer(player) + , mMethod(method) {} + + protected: + virtual ~AAH_TXEvent() {} + + virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) { + (mPlayer->*mMethod)(); + } + + private: + AAH_TXPlayer *mPlayer; + void (AAH_TXPlayer::*mMethod)(); + + AAH_TXEvent(const AAH_TXEvent &); + AAH_TXEvent& operator=(const AAH_TXEvent &); +}; + +AAH_TXPlayer::AAH_TXPlayer() + : mQueueStarted(false) + , mFlags(0) + , mExtractorFlags(0) { + DataSource::RegisterDefaultSniffers(); + + mBufferingEvent = new AAH_TXEvent(this, &AAH_TXPlayer::onBufferingUpdate); + mBufferingEventPending = false; + + mPumpAudioEvent = new AAH_TXEvent(this, &AAH_TXPlayer::onPumpAudio); + mPumpAudioEventPending = false; + + reset_l(); +} + +AAH_TXPlayer::~AAH_TXPlayer() { + if (mQueueStarted) { + mQueue.stop(); + } + + reset_l(); +} + +void AAH_TXPlayer::cancelPlayerEvents(bool keepBufferingGoing) { + if (!keepBufferingGoing) { + mQueue.cancelEvent(mBufferingEvent->eventID()); + mBufferingEventPending = false; + + mQueue.cancelEvent(mPumpAudioEvent->eventID()); + mPumpAudioEventPending = false; + } +} + +status_t AAH_TXPlayer::initCheck() { + // Check for the presense of the common time service by attempting to query + // for CommonTime's frequency. If we get an error back, we cannot talk to + // the service at all and should abort now. + status_t res; + uint64_t freq; + res = mCCHelper.getCommonFreq(&freq); + if (OK != res) { + ALOGE("Failed to connect to common time service! (res %d)", res); + return res; + } + + return OK; +} + +status_t AAH_TXPlayer::setDataSource( + const char *url, + const KeyedVector<String8, String8> *headers) { + Mutex::Autolock autoLock(mLock); + return setDataSource_l(url, headers); +} + +status_t AAH_TXPlayer::setDataSource_l( + const char *url, + const KeyedVector<String8, String8> *headers) { + reset_l(); + + // the URL must consist of "aahTX://" followed by the real URL of + // the data source + const char *kAAHPrefix = "aahTX://"; + if (strncasecmp(url, kAAHPrefix, strlen(kAAHPrefix))) { + return INVALID_OPERATION; + } + + mUri.setTo(url + strlen(kAAHPrefix)); + + if (headers) { + mUriHeaders = *headers; + + ssize_t index = mUriHeaders.indexOfKey(String8("x-hide-urls-from-log")); + if (index >= 0) { + // Browser is in "incognito" mode, suppress logging URLs. + + // This isn't something that should be passed to the server. + mUriHeaders.removeItemsAt(index); + + mFlags |= INCOGNITO; + } + } + + // The URL may optionally contain a "#" character followed by a Skyjam + // cookie. Ideally the cookie header should just be passed in the headers + // argument, but the Java API for supplying headers is apparently not yet + // exposed in the SDK used by application developers. + const char kSkyjamCookieDelimiter = '#'; + char* skyjamCookie = strrchr(mUri.string(), kSkyjamCookieDelimiter); + if (skyjamCookie) { + skyjamCookie++; + mUriHeaders.add(String8("Cookie"), String8(skyjamCookie)); + mUri = String8(mUri.string(), skyjamCookie - mUri.string()); + } + + return OK; +} + +status_t AAH_TXPlayer::setDataSource(int fd, int64_t offset, int64_t length) { + Mutex::Autolock autoLock(mLock); + + reset_l(); + + sp<DataSource> dataSource = new FileSource(dup(fd), offset, length); + + status_t err = dataSource->initCheck(); + + if (err != OK) { + return err; + } + + mFileSource = dataSource; + + sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource); + + if (extractor == NULL) { + return UNKNOWN_ERROR; + } + + return setDataSource_l(extractor); +} + +status_t AAH_TXPlayer::setVideoSurface(const sp<Surface>& surface) { + return OK; +} + +status_t AAH_TXPlayer::setVideoSurfaceTexture( + const sp<ISurfaceTexture>& surfaceTexture) { + return OK; +} + +status_t AAH_TXPlayer::prepare() { + return INVALID_OPERATION; +} + +status_t AAH_TXPlayer::prepareAsync() { + Mutex::Autolock autoLock(mLock); + + return prepareAsync_l(); +} + +status_t AAH_TXPlayer::prepareAsync_l() { + if (mFlags & PREPARING) { + return UNKNOWN_ERROR; // async prepare already pending + } + + mAAH_Sender = AAH_TXSender::GetInstance(); + if (mAAH_Sender == NULL) { + return NO_MEMORY; + } + + if (!mQueueStarted) { + mQueue.start(); + mQueueStarted = true; + } + + mFlags |= PREPARING; + mAsyncPrepareEvent = new AAH_TXEvent( + this, &AAH_TXPlayer::onPrepareAsyncEvent); + + mQueue.postEvent(mAsyncPrepareEvent); + + return OK; +} + +status_t AAH_TXPlayer::finishSetDataSource_l() { + sp<DataSource> dataSource; + + if (!strncasecmp("http://", mUri.string(), 7) || + !strncasecmp("https://", mUri.string(), 8)) { + + mConnectingDataSource = HTTPBase::Create( + (mFlags & INCOGNITO) + ? HTTPBase::kFlagIncognito + : 0); + + mLock.unlock(); + status_t err = mConnectingDataSource->connect(mUri, &mUriHeaders); + mLock.lock(); + + if (err != OK) { + mConnectingDataSource.clear(); + + ALOGI("mConnectingDataSource->connect() returned %d", err); + return err; + } + + mCachedSource = new NuCachedSource2(mConnectingDataSource); + mConnectingDataSource.clear(); + + dataSource = mCachedSource; + + // We're going to prefill the cache before trying to instantiate + // the extractor below, as the latter is an operation that otherwise + // could block on the datasource for a significant amount of time. + // During that time we'd be unable to abort the preparation phase + // without this prefill. + + mLock.unlock(); + + for (;;) { + status_t finalStatus; + size_t cachedDataRemaining = + mCachedSource->approxDataRemaining(&finalStatus); + + if (finalStatus != OK || + cachedDataRemaining >= kHighWaterMarkBytes || + (mFlags & PREPARE_CANCELLED)) { + break; + } + + usleep(200000); + } + + mLock.lock(); + + if (mFlags & PREPARE_CANCELLED) { + ALOGI("Prepare cancelled while waiting for initial cache fill."); + return UNKNOWN_ERROR; + } + } else { + dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders); + } + + if (dataSource == NULL) { + return UNKNOWN_ERROR; + } + + sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource); + + if (extractor == NULL) { + return UNKNOWN_ERROR; + } + + return setDataSource_l(extractor); +} + +status_t AAH_TXPlayer::setDataSource_l(const sp<MediaExtractor> &extractor) { + // Attempt to approximate overall stream bitrate by summing all + // tracks' individual bitrates, if not all of them advertise bitrate, + // we have to fail. + + int64_t totalBitRate = 0; + + for (size_t i = 0; i < extractor->countTracks(); ++i) { + sp<MetaData> meta = extractor->getTrackMetaData(i); + + int32_t bitrate; + if (!meta->findInt32(kKeyBitRate, &bitrate)) { + totalBitRate = -1; + break; + } + + totalBitRate += bitrate; + } + + mBitrate = totalBitRate; + + ALOGV("mBitrate = %lld bits/sec", mBitrate); + + bool haveAudio = false; + for (size_t i = 0; i < extractor->countTracks(); ++i) { + sp<MetaData> meta = extractor->getTrackMetaData(i); + + const char *mime; + CHECK(meta->findCString(kKeyMIMEType, &mime)); + + if (!strncasecmp(mime, "audio/", 6)) { + mAudioSource = extractor->getTrack(i); + CHECK(mAudioSource != NULL); + haveAudio = true; + break; + } + } + + if (!haveAudio) { + return UNKNOWN_ERROR; + } + + mExtractorFlags = extractor->flags(); + + return OK; +} + +void AAH_TXPlayer::abortPrepare(status_t err) { + CHECK(err != OK); + + notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err); + + mPrepareResult = err; + mFlags &= ~(PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED); + mPreparedCondition.broadcast(); +} + +void AAH_TXPlayer::onPrepareAsyncEvent() { + Mutex::Autolock autoLock(mLock); + + if (mFlags & PREPARE_CANCELLED) { + ALOGI("prepare was cancelled before doing anything"); + abortPrepare(UNKNOWN_ERROR); + return; + } + + if (mUri.size() > 0) { + status_t err = finishSetDataSource_l(); + + if (err != OK) { + abortPrepare(err); + return; + } + } + + mAudioSource->getFormat()->findInt64(kKeyDuration, &mDurationUs); + + status_t err = mAudioSource->start(); + if (err != OK) { + ALOGI("failed to start audio source, err=%d", err); + abortPrepare(err); + return; + } + + mFlags |= PREPARING_CONNECTED; + + if (mCachedSource != NULL) { + postBufferingEvent_l(); + } else { + finishAsyncPrepare_l(); + } +} + +void AAH_TXPlayer::finishAsyncPrepare_l() { + notifyListener_l(MEDIA_PREPARED); + + mPrepareResult = OK; + mFlags &= ~(PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED); + mFlags |= PREPARED; + mPreparedCondition.broadcast(); +} + +status_t AAH_TXPlayer::start() { + Mutex::Autolock autoLock(mLock); + + mFlags &= ~CACHE_UNDERRUN; + + return play_l(); +} + +status_t AAH_TXPlayer::play_l() { + if (mFlags & PLAYING) { + return OK; + } + + if (!(mFlags & PREPARED)) { + return INVALID_OPERATION; + } + + { + Mutex::Autolock lock(mEndpointLock); + if (!mEndpointValid) { + return INVALID_OPERATION; + } + if (!mEndpointRegistered) { + mProgramID = mAAH_Sender->registerEndpoint(mEndpoint); + mEndpointRegistered = true; + } + } + + mFlags |= PLAYING; + + updateClockTransform_l(false); + + postPumpAudioEvent_l(-1); + + return OK; +} + +status_t AAH_TXPlayer::stop() { + status_t ret = pause(); + sendEOS_l(); + return ret; +} + +status_t AAH_TXPlayer::pause() { + Mutex::Autolock autoLock(mLock); + + mFlags &= ~CACHE_UNDERRUN; + + return pause_l(); +} + +status_t AAH_TXPlayer::pause_l(bool doClockUpdate) { + if (!(mFlags & PLAYING)) { + return OK; + } + + cancelPlayerEvents(true /* keepBufferingGoing */); + + mFlags &= ~PLAYING; + + if (doClockUpdate) { + updateClockTransform_l(true); + } + + return OK; +} + +void AAH_TXPlayer::updateClockTransform_l(bool pause) { + // record the new pause status so that onPumpAudio knows what rate to apply + // when it initializes the transform + mPlayRateIsPaused = pause; + + // if we haven't yet established a valid clock transform, then we can't + // do anything here + if (!mCurrentClockTransformValid) { + return; + } + + // sample the current common time + int64_t commonTimeNow; + if (OK != mCCHelper.getCommonTime(&commonTimeNow)) { + ALOGE("updateClockTransform_l get common time failed"); + mCurrentClockTransformValid = false; + return; + } + + // convert the current common time to media time using the old + // transform + int64_t mediaTimeNow; + if (!mCurrentClockTransform.doReverseTransform( + commonTimeNow, &mediaTimeNow)) { + ALOGE("updateClockTransform_l reverse transform failed"); + mCurrentClockTransformValid = false; + return; + } + + // calculate a new transform that preserves the old transform's + // result for the current time + mCurrentClockTransform.a_zero = mediaTimeNow; + mCurrentClockTransform.b_zero = commonTimeNow; + mCurrentClockTransform.a_to_b_numer = 1; + mCurrentClockTransform.a_to_b_denom = pause ? 0 : 1; + + // send a packet announcing the new transform + sp<TRTPControlPacket> packet = new TRTPControlPacket(); + packet->setClockTransform(mCurrentClockTransform); + packet->setCommandID(TRTPControlPacket::kCommandNop); + queuePacketToSender_l(packet); +} + +void AAH_TXPlayer::sendEOS_l() { + sp<TRTPControlPacket> packet = new TRTPControlPacket(); + packet->setCommandID(TRTPControlPacket::kCommandEOS); + queuePacketToSender_l(packet); +} + +bool AAH_TXPlayer::isPlaying() { + return (mFlags & PLAYING) || (mFlags & CACHE_UNDERRUN); +} + +status_t AAH_TXPlayer::seekTo(int msec) { + if (mExtractorFlags & MediaExtractor::CAN_SEEK) { + Mutex::Autolock autoLock(mLock); + return seekTo_l(static_cast<int64_t>(msec) * 1000); + } + + notifyListener_l(MEDIA_SEEK_COMPLETE); + return OK; +} + +status_t AAH_TXPlayer::seekTo_l(int64_t timeUs) { + mIsSeeking = true; + mSeekTimeUs = timeUs; + + mCurrentClockTransformValid = false; + mLastQueuedMediaTimePTSValid = false; + + // send a flush command packet + sp<TRTPControlPacket> packet = new TRTPControlPacket(); + packet->setCommandID(TRTPControlPacket::kCommandFlush); + queuePacketToSender_l(packet); + + return OK; +} + +status_t AAH_TXPlayer::getCurrentPosition(int *msec) { + if (!msec) { + return BAD_VALUE; + } + + Mutex::Autolock lock(mLock); + + int position; + + if (mIsSeeking) { + position = mSeekTimeUs / 1000; + } else if (mCurrentClockTransformValid) { + // sample the current common time + int64_t commonTimeNow; + if (OK != mCCHelper.getCommonTime(&commonTimeNow)) { + ALOGE("getCurrentPosition get common time failed"); + return INVALID_OPERATION; + } + + int64_t mediaTimeNow; + if (!mCurrentClockTransform.doReverseTransform(commonTimeNow, + &mediaTimeNow)) { + ALOGE("getCurrentPosition reverse transform failed"); + return INVALID_OPERATION; + } + + position = static_cast<int>(mediaTimeNow / 1000); + } else { + position = 0; + } + + int duration; + if (getDuration_l(&duration) == OK) { + *msec = clamp(position, 0, duration); + } else { + *msec = (position >= 0) ? position : 0; + } + + return OK; +} + +status_t AAH_TXPlayer::getDuration(int* msec) { + if (!msec) { + return BAD_VALUE; + } + + Mutex::Autolock lock(mLock); + + return getDuration_l(msec); +} + +status_t AAH_TXPlayer::getDuration_l(int* msec) { + if (mDurationUs < 0) { + return UNKNOWN_ERROR; + } + + *msec = (mDurationUs + 500) / 1000; + + return OK; +} + +status_t AAH_TXPlayer::reset() { + Mutex::Autolock autoLock(mLock); + reset_l(); + return OK; +} + +void AAH_TXPlayer::reset_l() { + if (mFlags & PREPARING) { + mFlags |= PREPARE_CANCELLED; + if (mConnectingDataSource != NULL) { + ALOGI("interrupting the connection process"); + mConnectingDataSource->disconnect(); + } + + if (mFlags & PREPARING_CONNECTED) { + // We are basically done preparing, we're just buffering + // enough data to start playback, we can safely interrupt that. + finishAsyncPrepare_l(); + } + } + + while (mFlags & PREPARING) { + mPreparedCondition.wait(mLock); + } + + cancelPlayerEvents(); + + sendEOS_l(); + + mCachedSource.clear(); + + if (mAudioSource != NULL) { + mAudioSource->stop(); + } + mAudioSource.clear(); + + mFlags = 0; + mExtractorFlags = 0; + + mDurationUs = -1; + mIsSeeking = false; + mSeekTimeUs = 0; + + mUri.setTo(""); + mUriHeaders.clear(); + + mFileSource.clear(); + + mBitrate = -1; + + { + Mutex::Autolock lock(mEndpointLock); + if (mAAH_Sender != NULL && mEndpointRegistered) { + mAAH_Sender->unregisterEndpoint(mEndpoint); + } + mEndpointRegistered = false; + mEndpointValid = false; + } + + mProgramID = 0; + + mAAH_Sender.clear(); + mLastQueuedMediaTimePTSValid = false; + mCurrentClockTransformValid = false; + mPlayRateIsPaused = false; + + mTRTPVolume = 255; +} + +status_t AAH_TXPlayer::setLooping(int loop) { + return OK; +} + +player_type AAH_TXPlayer::playerType() { + return AAH_TX_PLAYER; +} + +status_t AAH_TXPlayer::setParameter(int key, const Parcel &request) { + return ERROR_UNSUPPORTED; +} + +status_t AAH_TXPlayer::getParameter(int key, Parcel *reply) { + return ERROR_UNSUPPORTED; +} + +status_t AAH_TXPlayer::invoke(const Parcel& request, Parcel *reply) { + if (!reply) { + return BAD_VALUE; + } + + int32_t methodID; + status_t err = request.readInt32(&methodID); + if (err != android::OK) { + return err; + } + + switch (methodID) { + case kInvokeSetAAHDstIPPort: + case kInvokeSetAAHConfigBlob: { + if (mEndpointValid) { + return INVALID_OPERATION; + } + + String8 addr; + uint16_t port; + + if (methodID == kInvokeSetAAHDstIPPort) { + addr = String8(request.readString16()); + + int32_t port32; + err = request.readInt32(&port32); + if (err != android::OK) { + return err; + } + port = static_cast<uint16_t>(port32); + } else { + String8 blob(request.readString16()); + + char addr_buf[101]; + if (sscanf(blob.string(), "V1:%100s %" SCNu16, + addr_buf, &port) != 2) { + return BAD_VALUE; + } + if (addr.setTo(addr_buf) != OK) { + return NO_MEMORY; + } + } + + struct hostent* ent = gethostbyname(addr.string()); + if (ent == NULL) { + return ERROR_UNKNOWN_HOST; + } + if (!(ent->h_addrtype == AF_INET && ent->h_length == 4)) { + return BAD_VALUE; + } + + Mutex::Autolock lock(mEndpointLock); + mEndpoint = AAH_TXSender::Endpoint( + reinterpret_cast<struct in_addr*>(ent->h_addr)->s_addr, + port); + mEndpointValid = true; + return OK; + }; + + default: + return INVALID_OPERATION; + } +} + +status_t AAH_TXPlayer::getMetadata(const media::Metadata::Filter& ids, + Parcel* records) { + using media::Metadata; + + Metadata metadata(records); + + metadata.appendBool(Metadata::kPauseAvailable, true); + metadata.appendBool(Metadata::kSeekBackwardAvailable, false); + metadata.appendBool(Metadata::kSeekForwardAvailable, false); + metadata.appendBool(Metadata::kSeekAvailable, false); + + return OK; +} + +status_t AAH_TXPlayer::setVolume(float leftVolume, float rightVolume) { + if (leftVolume != rightVolume) { + ALOGE("%s does not support per channel volume: %f, %f", + __PRETTY_FUNCTION__, leftVolume, rightVolume); + } + + float volume = clamp(leftVolume, 0.0f, 1.0f); + + Mutex::Autolock lock(mLock); + mTRTPVolume = static_cast<uint8_t>((leftVolume * 255.0) + 0.5); + + return OK; +} + +status_t AAH_TXPlayer::setAudioStreamType(audio_stream_type_t streamType) { + return OK; +} + +void AAH_TXPlayer::notifyListener_l(int msg, int ext1, int ext2) { + sendEvent(msg, ext1, ext2); +} + +bool AAH_TXPlayer::getBitrate_l(int64_t *bitrate) { + off64_t size; + if (mDurationUs >= 0 && + mCachedSource != NULL && + mCachedSource->getSize(&size) == OK) { + *bitrate = size * 8000000ll / mDurationUs; // in bits/sec + return true; + } + + if (mBitrate >= 0) { + *bitrate = mBitrate; + return true; + } + + *bitrate = 0; + + return false; +} + +// Returns true iff cached duration is available/applicable. +bool AAH_TXPlayer::getCachedDuration_l(int64_t *durationUs, bool *eos) { + int64_t bitrate; + + if (mCachedSource != NULL && getBitrate_l(&bitrate)) { + status_t finalStatus; + size_t cachedDataRemaining = mCachedSource->approxDataRemaining( + &finalStatus); + *durationUs = cachedDataRemaining * 8000000ll / bitrate; + *eos = (finalStatus != OK); + return true; + } + + return false; +} + +void AAH_TXPlayer::ensureCacheIsFetching_l() { + if (mCachedSource != NULL) { + mCachedSource->resumeFetchingIfNecessary(); + } +} + +void AAH_TXPlayer::postBufferingEvent_l() { + if (mBufferingEventPending) { + return; + } + mBufferingEventPending = true; + mQueue.postEventWithDelay(mBufferingEvent, 1000000ll); +} + +void AAH_TXPlayer::postPumpAudioEvent_l(int64_t delayUs) { + if (mPumpAudioEventPending) { + return; + } + mPumpAudioEventPending = true; + mQueue.postEventWithDelay(mPumpAudioEvent, delayUs < 0 ? 10000 : delayUs); +} + +void AAH_TXPlayer::onBufferingUpdate() { + Mutex::Autolock autoLock(mLock); + if (!mBufferingEventPending) { + return; + } + mBufferingEventPending = false; + + if (mCachedSource != NULL) { + status_t finalStatus; + size_t cachedDataRemaining = mCachedSource->approxDataRemaining( + &finalStatus); + bool eos = (finalStatus != OK); + + if (eos) { + if (finalStatus == ERROR_END_OF_STREAM) { + notifyListener_l(MEDIA_BUFFERING_UPDATE, 100); + } + if (mFlags & PREPARING) { + ALOGV("cache has reached EOS, prepare is done."); + finishAsyncPrepare_l(); + } + } else { + int64_t bitrate; + if (getBitrate_l(&bitrate)) { + size_t cachedSize = mCachedSource->cachedSize(); + int64_t cachedDurationUs = cachedSize * 8000000ll / bitrate; + + int percentage = (100.0 * (double) cachedDurationUs) + / mDurationUs; + if (percentage > 100) { + percentage = 100; + } + + notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage); + } else { + // We don't know the bitrate of the stream, use absolute size + // limits to maintain the cache. + + if ((mFlags & PLAYING) && + !eos && + (cachedDataRemaining < kLowWaterMarkBytes)) { + ALOGI("cache is running low (< %d) , pausing.", + kLowWaterMarkBytes); + mFlags |= CACHE_UNDERRUN; + pause_l(); + ensureCacheIsFetching_l(); + notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START); + } else if (eos || cachedDataRemaining > kHighWaterMarkBytes) { + if (mFlags & CACHE_UNDERRUN) { + ALOGI("cache has filled up (> %d), resuming.", + kHighWaterMarkBytes); + mFlags &= ~CACHE_UNDERRUN; + play_l(); + notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END); + } else if (mFlags & PREPARING) { + ALOGV("cache has filled up (> %d), prepare is done", + kHighWaterMarkBytes); + finishAsyncPrepare_l(); + } + } + } + } + } + + int64_t cachedDurationUs; + bool eos; + if (getCachedDuration_l(&cachedDurationUs, &eos)) { + ALOGV("cachedDurationUs = %.2f secs, eos=%d", + cachedDurationUs / 1E6, eos); + + if ((mFlags & PLAYING) && + !eos && + (cachedDurationUs < kLowWaterMarkUs)) { + ALOGI("cache is running low (%.2f secs) , pausing.", + cachedDurationUs / 1E6); + mFlags |= CACHE_UNDERRUN; + pause_l(); + ensureCacheIsFetching_l(); + notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START); + } else if (eos || cachedDurationUs > kHighWaterMarkUs) { + if (mFlags & CACHE_UNDERRUN) { + ALOGI("cache has filled up (%.2f secs), resuming.", + cachedDurationUs / 1E6); + mFlags &= ~CACHE_UNDERRUN; + play_l(); + notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END); + } else if (mFlags & PREPARING) { + ALOGV("cache has filled up (%.2f secs), prepare is done", + cachedDurationUs / 1E6); + finishAsyncPrepare_l(); + } + } + } + + postBufferingEvent_l(); +} + +void AAH_TXPlayer::onPumpAudio() { + while (true) { + Mutex::Autolock autoLock(mLock); + // If this flag is clear, its because someone has externally canceled + // this pump operation (probably because we a resetting/shutting down). + // Get out immediately, do not reschedule ourselves. + if (!mPumpAudioEventPending) { + return; + } + + // Start by checking if there is still work to be doing. If we have + // never queued a payload (so we don't know what the last queued PTS is) + // or we have never established a MediaTime->CommonTime transformation, + // then we have work to do (one time through this loop should establish + // both). Otherwise, we want to keep a fixed amt of presentation time + // worth of data buffered. If we cannot get common time (service is + // unavailable, or common time is undefined)) then we don't have a lot + // of good options here. For now, signal an error up to the app level + // and shut down the transmission pump. + int64_t commonTimeNow; + if (OK != mCCHelper.getCommonTime(&commonTimeNow)) { + // Failed to get common time; either the service is down or common + // time is not synced. Raise an error and shutdown the player. + ALOGE("*** Cannot pump audio, unable to fetch common time." + " Shutting down."); + notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, UNKNOWN_ERROR); + mPumpAudioEventPending = false; + break; + } + + if (mCurrentClockTransformValid && mLastQueuedMediaTimePTSValid) { + int64_t mediaTimeNow; + bool conversionResult = mCurrentClockTransform.doReverseTransform( + commonTimeNow, + &mediaTimeNow); + CHECK(conversionResult); + + if ((mediaTimeNow + + kAAHBufferTimeUs - + mLastQueuedMediaTimePTS) <= 0) { + break; + } + } + + MediaSource::ReadOptions options; + if (mIsSeeking) { + options.setSeekTo(mSeekTimeUs); + } + + MediaBuffer* mediaBuffer; + status_t err = mAudioSource->read(&mediaBuffer, &options); + if (err != NO_ERROR) { + if (err == ERROR_END_OF_STREAM) { + ALOGI("*** %s reached end of stream", __PRETTY_FUNCTION__); + notifyListener_l(MEDIA_BUFFERING_UPDATE, 100); + notifyListener_l(MEDIA_PLAYBACK_COMPLETE); + pause_l(false); + sendEOS_l(); + } else { + ALOGE("*** %s read failed err=%d", __PRETTY_FUNCTION__, err); + } + return; + } + + if (mIsSeeking) { + mIsSeeking = false; + notifyListener_l(MEDIA_SEEK_COMPLETE); + } + + uint8_t* data = (static_cast<uint8_t*>(mediaBuffer->data()) + + mediaBuffer->range_offset()); + ALOGV("*** %s got media buffer data=[%02hhx %02hhx %02hhx %02hhx]" + " offset=%d length=%d", __PRETTY_FUNCTION__, + data[0], data[1], data[2], data[3], + mediaBuffer->range_offset(), mediaBuffer->range_length()); + + int64_t mediaTimeUs; + CHECK(mediaBuffer->meta_data()->findInt64(kKeyTime, &mediaTimeUs)); + ALOGV("*** timeUs=%lld", mediaTimeUs); + + if (!mCurrentClockTransformValid) { + if (OK == mCCHelper.getCommonTime(&commonTimeNow)) { + mCurrentClockTransform.a_zero = mediaTimeUs; + mCurrentClockTransform.b_zero = commonTimeNow + + kAAHStartupLeadTimeUs; + mCurrentClockTransform.a_to_b_numer = 1; + mCurrentClockTransform.a_to_b_denom = mPlayRateIsPaused ? 0 : 1; + mCurrentClockTransformValid = true; + } else { + // Failed to get common time; either the service is down or + // common time is not synced. Raise an error and shutdown the + // player. + ALOGE("*** Cannot begin transmission, unable to fetch common" + " time. Dropping sample with pts=%lld", mediaTimeUs); + notifyListener_l(MEDIA_ERROR, + MEDIA_ERROR_UNKNOWN, + UNKNOWN_ERROR); + mPumpAudioEventPending = false; + break; + } + } + + ALOGV("*** transmitting packet with pts=%lld", mediaTimeUs); + + sp<TRTPAudioPacket> packet = new TRTPAudioPacket(); + packet->setPTS(mediaTimeUs); + packet->setSubstreamID(1); + + packet->setCodecType(TRTPAudioPacket::kCodecMPEG1Audio); + packet->setVolume(mTRTPVolume); + // TODO : introduce a throttle for this so we can control the + // frequency with which transforms get sent. + packet->setClockTransform(mCurrentClockTransform); + packet->setAccessUnitData(data, mediaBuffer->range_length()); + packet->setRandomAccessPoint(true); + + queuePacketToSender_l(packet); + mediaBuffer->release(); + + mLastQueuedMediaTimePTSValid = true; + mLastQueuedMediaTimePTS = mediaTimeUs; + } + + { // Explicit scope for the autolock pattern. + Mutex::Autolock autoLock(mLock); + + // If someone externally has cleared this flag, its because we should be + // shutting down. Do not reschedule ourselves. + if (!mPumpAudioEventPending) { + return; + } + + // Looks like no one canceled us explicitly. Clear our flag and post a + // new event to ourselves. + mPumpAudioEventPending = false; + postPumpAudioEvent_l(10000); + } +} + +void AAH_TXPlayer::queuePacketToSender_l(const sp<TRTPPacket>& packet) { + if (mAAH_Sender == NULL) { + return; + } + + sp<AMessage> message = new AMessage(AAH_TXSender::kWhatSendPacket, + mAAH_Sender->handlerID()); + + { + Mutex::Autolock lock(mEndpointLock); + if (!mEndpointValid) { + return; + } + + message->setInt32(AAH_TXSender::kSendPacketIPAddr, mEndpoint.addr); + message->setInt32(AAH_TXSender::kSendPacketPort, mEndpoint.port); + } + + packet->setProgramID(mProgramID); + packet->setExpireTime(systemTime() + kAAHRetryKeepAroundTimeNs); + packet->pack(); + + message->setObject(AAH_TXSender::kSendPacketTRTPPacket, packet); + + message->post(); +} + +} // namespace android diff --git a/media/libaah_rtp/aah_tx_player.h b/media/libaah_rtp/aah_tx_player.h new file mode 100644 index 000000000000..64cf5dc11a03 --- /dev/null +++ b/media/libaah_rtp/aah_tx_player.h @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __AAH_TX_PLAYER_H__ +#define __AAH_TX_PLAYER_H__ + +#include <common_time/cc_helper.h> +#include <libstagefright/include/HTTPBase.h> +#include <libstagefright/include/NuCachedSource2.h> +#include <libstagefright/include/TimedEventQueue.h> +#include <media/MediaPlayerInterface.h> +#include <media/stagefright/MediaExtractor.h> +#include <media/stagefright/MediaSource.h> +#include <utils/LinearTransform.h> +#include <utils/String8.h> +#include <utils/threads.h> + +#include "aah_tx_sender.h" + +namespace android { + +class AAH_TXPlayer : public MediaPlayerHWInterface { + public: + AAH_TXPlayer(); + + virtual status_t initCheck(); + virtual status_t setDataSource(const char *url, + const KeyedVector<String8, String8>* + headers); + virtual status_t setDataSource(int fd, int64_t offset, int64_t length); + virtual status_t setVideoSurface(const sp<Surface>& surface); + virtual status_t setVideoSurfaceTexture(const sp<ISurfaceTexture>& + surfaceTexture); + virtual status_t prepare(); + virtual status_t prepareAsync(); + virtual status_t start(); + virtual status_t stop(); + virtual status_t pause(); + virtual bool isPlaying(); + virtual status_t seekTo(int msec); + virtual status_t getCurrentPosition(int *msec); + virtual status_t getDuration(int *msec); + virtual status_t reset(); + virtual status_t setLooping(int loop); + virtual player_type playerType(); + virtual status_t setParameter(int key, const Parcel &request); + virtual status_t getParameter(int key, Parcel *reply); + virtual status_t invoke(const Parcel& request, Parcel *reply); + virtual status_t getMetadata(const media::Metadata::Filter& ids, + Parcel* records); + virtual status_t setVolume(float leftVolume, float rightVolume); + virtual status_t setAudioStreamType(audio_stream_type_t streamType); + + // invoke method IDs + enum { + // set the IP address and port of the A@H receiver + kInvokeSetAAHDstIPPort = 1, + + // set the destination IP address and port (and perhaps any additional + // parameters added in the future) packaged in one string + kInvokeSetAAHConfigBlob, + }; + + static const int64_t kAAHRetryKeepAroundTimeNs; + + protected: + virtual ~AAH_TXPlayer(); + + private: + friend struct AwesomeEvent; + + enum { + PLAYING = 1, + PREPARING = 8, + PREPARED = 16, + PREPARE_CANCELLED = 64, + CACHE_UNDERRUN = 128, + + // We are basically done preparing but are currently buffering + // sufficient data to begin playback and finish the preparation + // phase for good. + PREPARING_CONNECTED = 2048, + + INCOGNITO = 32768, + }; + + status_t setDataSource_l(const char *url, + const KeyedVector<String8, String8> *headers); + status_t setDataSource_l(const sp<MediaExtractor>& extractor); + status_t finishSetDataSource_l(); + status_t prepareAsync_l(); + void onPrepareAsyncEvent(); + void finishAsyncPrepare_l(); + void abortPrepare(status_t err); + status_t play_l(); + status_t pause_l(bool doClockUpdate = true); + status_t seekTo_l(int64_t timeUs); + void updateClockTransform_l(bool pause); + void sendEOS_l(); + void cancelPlayerEvents(bool keepBufferingGoing = false); + void reset_l(); + void notifyListener_l(int msg, int ext1 = 0, int ext2 = 0); + bool getBitrate_l(int64_t* bitrate); + status_t getDuration_l(int* msec); + bool getCachedDuration_l(int64_t* durationUs, bool* eos); + void ensureCacheIsFetching_l(); + void postBufferingEvent_l(); + void postPumpAudioEvent_l(int64_t delayUs); + void onBufferingUpdate(); + void onPumpAudio(); + void queuePacketToSender_l(const sp<TRTPPacket>& packet); + + Mutex mLock; + + TimedEventQueue mQueue; + bool mQueueStarted; + + sp<TimedEventQueue::Event> mBufferingEvent; + bool mBufferingEventPending; + + uint32_t mFlags; + uint32_t mExtractorFlags; + + String8 mUri; + KeyedVector<String8, String8> mUriHeaders; + + sp<DataSource> mFileSource; + + sp<TimedEventQueue::Event> mAsyncPrepareEvent; + Condition mPreparedCondition; + status_t mPrepareResult; + + bool mIsSeeking; + int64_t mSeekTimeUs; + + sp<TimedEventQueue::Event> mPumpAudioEvent; + bool mPumpAudioEventPending; + + sp<HTTPBase> mConnectingDataSource; + sp<NuCachedSource2> mCachedSource; + + sp<MediaSource> mAudioSource; + int64_t mDurationUs; + int64_t mBitrate; + + sp<AAH_TXSender> mAAH_Sender; + LinearTransform mCurrentClockTransform; + bool mCurrentClockTransformValid; + int64_t mLastQueuedMediaTimePTS; + bool mLastQueuedMediaTimePTSValid; + bool mPlayRateIsPaused; + CCHelper mCCHelper; + + Mutex mEndpointLock; + AAH_TXSender::Endpoint mEndpoint; + bool mEndpointValid; + bool mEndpointRegistered; + uint16_t mProgramID; + uint8_t mTRTPVolume; + + DISALLOW_EVIL_CONSTRUCTORS(AAH_TXPlayer); +}; + +} // namespace android + +#endif // __AAH_TX_PLAYER_H__ diff --git a/media/libaah_rtp/aah_tx_sender.cpp b/media/libaah_rtp/aah_tx_sender.cpp new file mode 100644 index 000000000000..d991ea76afe2 --- /dev/null +++ b/media/libaah_rtp/aah_tx_sender.cpp @@ -0,0 +1,602 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "LibAAH_RTP" +#include <media/stagefright/foundation/ADebug.h> + +#include <netinet/in.h> +#include <poll.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <unistd.h> + +#include <media/stagefright/foundation/AMessage.h> +#include <utils/misc.h> + +#include "aah_tx_player.h" +#include "aah_tx_sender.h" + +namespace android { + +const char* AAH_TXSender::kSendPacketIPAddr = "ipaddr"; +const char* AAH_TXSender::kSendPacketPort = "port"; +const char* AAH_TXSender::kSendPacketTRTPPacket = "trtp"; + +const int AAH_TXSender::kRetryTrimIntervalUs = 100000; +const int AAH_TXSender::kHeartbeatIntervalUs = 1000000; +const int AAH_TXSender::kRetryBufferCapacity = 100; +const nsecs_t AAH_TXSender::kHeartbeatTimeout = 600ull * 1000000000ull; + +Mutex AAH_TXSender::sLock; +wp<AAH_TXSender> AAH_TXSender::sInstance; +uint32_t AAH_TXSender::sNextEpoch; +bool AAH_TXSender::sNextEpochValid = false; + +AAH_TXSender::AAH_TXSender() : mSocket(-1) { + mLastSentPacketTime = systemTime(); +} + +sp<AAH_TXSender> AAH_TXSender::GetInstance() { + Mutex::Autolock autoLock(sLock); + + sp<AAH_TXSender> sender = sInstance.promote(); + + if (sender == NULL) { + sender = new AAH_TXSender(); + if (sender == NULL) { + return NULL; + } + + sender->mLooper = new ALooper(); + if (sender->mLooper == NULL) { + return NULL; + } + + sender->mReflector = new AHandlerReflector<AAH_TXSender>(sender.get()); + if (sender->mReflector == NULL) { + return NULL; + } + + sender->mSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (sender->mSocket == -1) { + ALOGW("%s unable to create socket", __PRETTY_FUNCTION__); + return NULL; + } + + struct sockaddr_in bind_addr; + memset(&bind_addr, 0, sizeof(bind_addr)); + bind_addr.sin_family = AF_INET; + if (bind(sender->mSocket, + reinterpret_cast<const sockaddr*>(&bind_addr), + sizeof(bind_addr)) < 0) { + ALOGW("%s unable to bind socket (errno %d)", + __PRETTY_FUNCTION__, errno); + return NULL; + } + + sender->mRetryReceiver = new RetryReceiver(sender.get()); + if (sender->mRetryReceiver == NULL) { + return NULL; + } + + sender->mLooper->setName("AAH_TXSender"); + sender->mLooper->registerHandler(sender->mReflector); + sender->mLooper->start(false, false, PRIORITY_AUDIO); + + if (sender->mRetryReceiver->run("AAH_TXSenderRetry", PRIORITY_AUDIO) + != OK) { + ALOGW("%s unable to start retry thread", __PRETTY_FUNCTION__); + return NULL; + } + + sInstance = sender; + } + + return sender; +} + +AAH_TXSender::~AAH_TXSender() { + mLooper->stop(); + mLooper->unregisterHandler(mReflector->id()); + + if (mRetryReceiver != NULL) { + mRetryReceiver->requestExit(); + mRetryReceiver->mWakeupEvent.setEvent(); + if (mRetryReceiver->requestExitAndWait() != OK) { + ALOGW("%s shutdown of retry receiver failed", __PRETTY_FUNCTION__); + } + mRetryReceiver->mSender = NULL; + mRetryReceiver.clear(); + } + + if (mSocket != -1) { + close(mSocket); + } +} + +// Return the next epoch number usable for a newly instantiated endpoint. +uint32_t AAH_TXSender::getNextEpoch() { + Mutex::Autolock autoLock(sLock); + + if (sNextEpochValid) { + sNextEpoch = (sNextEpoch + 1) & TRTPPacket::kTRTPEpochMask; + } else { + sNextEpoch = ns2ms(systemTime()) & TRTPPacket::kTRTPEpochMask; + sNextEpochValid = true; + } + + return sNextEpoch; +} + +// Notify the sender that a player has started sending to this endpoint. +// Returns a program ID for use by the calling player. +uint16_t AAH_TXSender::registerEndpoint(const Endpoint& endpoint) { + Mutex::Autolock lock(mEndpointLock); + + EndpointState* eps = mEndpointMap.valueFor(endpoint); + if (eps) { + eps->playerRefCount++; + } else { + eps = new EndpointState(getNextEpoch()); + mEndpointMap.add(endpoint, eps); + } + + // if this is the first registered endpoint, then send a message to start + // trimming retry buffers and a message to start sending heartbeats. + if (mEndpointMap.size() == 1) { + sp<AMessage> trimMessage = new AMessage(kWhatTrimRetryBuffers, + handlerID()); + trimMessage->post(kRetryTrimIntervalUs); + + sp<AMessage> heartbeatMessage = new AMessage(kWhatSendHeartbeats, + handlerID()); + heartbeatMessage->post(kHeartbeatIntervalUs); + } + + eps->nextProgramID++; + return eps->nextProgramID; +} + +// Notify the sender that a player has ceased sending to this endpoint. +// An endpoint's state can not be deleted until all of the endpoint's +// registered players have called unregisterEndpoint. +void AAH_TXSender::unregisterEndpoint(const Endpoint& endpoint) { + Mutex::Autolock lock(mEndpointLock); + + EndpointState* eps = mEndpointMap.valueFor(endpoint); + if (eps) { + eps->playerRefCount--; + CHECK(eps->playerRefCount >= 0); + } +} + +void AAH_TXSender::onMessageReceived(const sp<AMessage>& msg) { + switch (msg->what()) { + case kWhatSendPacket: + onSendPacket(msg); + break; + + case kWhatTrimRetryBuffers: + trimRetryBuffers(); + break; + + case kWhatSendHeartbeats: + sendHeartbeats(); + break; + + default: + TRESPASS(); + break; + } +} + +void AAH_TXSender::onSendPacket(const sp<AMessage>& msg) { + sp<RefBase> obj; + CHECK(msg->findObject(kSendPacketTRTPPacket, &obj)); + sp<TRTPPacket> packet = static_cast<TRTPPacket*>(obj.get()); + + uint32_t ipAddr; + CHECK(msg->findInt32(kSendPacketIPAddr, + reinterpret_cast<int32_t*>(&ipAddr))); + + int32_t port32; + CHECK(msg->findInt32(kSendPacketPort, &port32)); + uint16_t port = port32; + + Mutex::Autolock lock(mEndpointLock); + doSendPacket_l(packet, Endpoint(ipAddr, port)); + mLastSentPacketTime = systemTime(); +} + +void AAH_TXSender::doSendPacket_l(const sp<TRTPPacket>& packet, + const Endpoint& endpoint) { + EndpointState* eps = mEndpointMap.valueFor(endpoint); + if (!eps) { + // the endpoint state has disappeared, so the player that sent this + // packet must be dead. + return; + } + + // assign the packet's sequence number + packet->setEpoch(eps->epoch); + packet->setSeqNumber(eps->trtpSeqNumber++); + + // add the packet to the retry buffer + RetryBuffer& retry = eps->retry; + retry.push_back(packet); + + // send the packet + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = endpoint.addr; + addr.sin_port = htons(endpoint.port); + + ssize_t result = sendto(mSocket, + packet->getPacket(), + packet->getPacketLen(), + 0, + (const struct sockaddr *) &addr, + sizeof(addr)); + if (result == -1) { + ALOGW("%s sendto failed", __PRETTY_FUNCTION__); + } +} + +void AAH_TXSender::trimRetryBuffers() { + Mutex::Autolock lock(mEndpointLock); + + nsecs_t localTimeNow = systemTime(); + + Vector<Endpoint> endpointsToRemove; + + for (size_t i = 0; i < mEndpointMap.size(); i++) { + EndpointState* eps = mEndpointMap.editValueAt(i); + RetryBuffer& retry = eps->retry; + + while (!retry.isEmpty()) { + if (retry[0]->getExpireTime() < localTimeNow) { + retry.pop_front(); + } else { + break; + } + } + + if (retry.isEmpty() && eps->playerRefCount == 0) { + endpointsToRemove.add(mEndpointMap.keyAt(i)); + } + } + + // remove the state for any endpoints that are no longer in use + for (size_t i = 0; i < endpointsToRemove.size(); i++) { + Endpoint& e = endpointsToRemove.editItemAt(i); + ALOGD("*** %s removing endpoint addr=%08x", __PRETTY_FUNCTION__, e.addr); + size_t index = mEndpointMap.indexOfKey(e); + delete mEndpointMap.valueAt(index); + mEndpointMap.removeItemsAt(index); + } + + // schedule the next trim + if (mEndpointMap.size()) { + sp<AMessage> trimMessage = new AMessage(kWhatTrimRetryBuffers, + handlerID()); + trimMessage->post(kRetryTrimIntervalUs); + } +} + +void AAH_TXSender::sendHeartbeats() { + Mutex::Autolock lock(mEndpointLock); + + if (shouldSendHeartbeats_l()) { + for (size_t i = 0; i < mEndpointMap.size(); i++) { + EndpointState* eps = mEndpointMap.editValueAt(i); + const Endpoint& ep = mEndpointMap.keyAt(i); + + sp<TRTPControlPacket> packet = new TRTPControlPacket(); + packet->setCommandID(TRTPControlPacket::kCommandNop); + + packet->setExpireTime(systemTime() + + AAH_TXPlayer::kAAHRetryKeepAroundTimeNs); + packet->pack(); + + doSendPacket_l(packet, ep); + } + } + + // schedule the next heartbeat + if (mEndpointMap.size()) { + sp<AMessage> heartbeatMessage = new AMessage(kWhatSendHeartbeats, + handlerID()); + heartbeatMessage->post(kHeartbeatIntervalUs); + } +} + +bool AAH_TXSender::shouldSendHeartbeats_l() { + // assert(holding endpoint lock) + return (systemTime() < (mLastSentPacketTime + kHeartbeatTimeout)); +} + +// Receiver + +// initial 4-byte ID of a retry request packet +const uint32_t AAH_TXSender::RetryReceiver::kRetryRequestID = 'Treq'; + +// initial 4-byte ID of a retry NAK packet +const uint32_t AAH_TXSender::RetryReceiver::kRetryNakID = 'Tnak'; + +// initial 4-byte ID of a fast start request packet +const uint32_t AAH_TXSender::RetryReceiver::kFastStartRequestID = 'Tfst'; + +AAH_TXSender::RetryReceiver::RetryReceiver(AAH_TXSender* sender) + : Thread(false), + mSender(sender) {} + + AAH_TXSender::RetryReceiver::~RetryReceiver() { + mWakeupEvent.clearPendingEvents(); + } + +// Returns true if val is within the interval bounded inclusively by +// start and end. Also handles the case where there is a rollover of the +// range between start and end. +template <typename T> +static inline bool withinIntervalWithRollover(T val, T start, T end) { + return ((start <= end && val >= start && val <= end) || + (start > end && (val >= start || val <= end))); +} + +bool AAH_TXSender::RetryReceiver::threadLoop() { + struct pollfd pollFds[2]; + pollFds[0].fd = mSender->mSocket; + pollFds[0].events = POLLIN; + pollFds[0].revents = 0; + pollFds[1].fd = mWakeupEvent.getWakeupHandle(); + pollFds[1].events = POLLIN; + pollFds[1].revents = 0; + + int pollResult = poll(pollFds, NELEM(pollFds), -1); + if (pollResult == -1) { + ALOGE("%s poll failed", __PRETTY_FUNCTION__); + return false; + } + + if (exitPending()) { + ALOGI("*** %s exiting", __PRETTY_FUNCTION__); + return false; + } + + if (pollFds[0].revents) { + handleRetryRequest(); + } + + return true; +} + +void AAH_TXSender::RetryReceiver::handleRetryRequest() { + ALOGV("*** RX %s start", __PRETTY_FUNCTION__); + + RetryPacket request; + struct sockaddr requestSrcAddr; + socklen_t requestSrcAddrLen = sizeof(requestSrcAddr); + + ssize_t result = recvfrom(mSender->mSocket, &request, sizeof(request), 0, + &requestSrcAddr, &requestSrcAddrLen); + if (result == -1) { + ALOGE("%s recvfrom failed, errno=%d", __PRETTY_FUNCTION__, errno); + return; + } + + if (static_cast<size_t>(result) < sizeof(RetryPacket)) { + ALOGW("%s short packet received", __PRETTY_FUNCTION__); + return; + } + + uint32_t host_request_id = ntohl(request.id); + if ((host_request_id != kRetryRequestID) && + (host_request_id != kFastStartRequestID)) { + ALOGW("%s received retry request with bogus ID (%08x)", + __PRETTY_FUNCTION__, host_request_id); + return; + } + + Endpoint endpoint(request.endpointIP, ntohs(request.endpointPort)); + + Mutex::Autolock lock(mSender->mEndpointLock); + + EndpointState* eps = mSender->mEndpointMap.valueFor(endpoint); + + if (eps == NULL || eps->retry.isEmpty()) { + // we have no retry buffer or an empty retry buffer for this endpoint, + // so NAK the entire request + RetryPacket nak = request; + nak.id = htonl(kRetryNakID); + result = sendto(mSender->mSocket, &nak, sizeof(nak), 0, + &requestSrcAddr, requestSrcAddrLen); + if (result == -1) { + ALOGW("%s sendto failed", __PRETTY_FUNCTION__); + } + return; + } + + RetryBuffer& retry = eps->retry; + + uint16_t startSeq = ntohs(request.seqStart); + uint16_t endSeq = ntohs(request.seqEnd); + + uint16_t retryFirstSeq = retry[0]->getSeqNumber(); + uint16_t retryLastSeq = retry[retry.size() - 1]->getSeqNumber(); + + // If this is a fast start, then force the start of the retry to match the + // start of the retransmit ring buffer (unless the end of the retransmit + // ring buffer is already past the point of fast start) + if ((host_request_id == kFastStartRequestID) && + !((startSeq - retryFirstSeq) & 0x8000)) { + startSeq = retryFirstSeq; + } + + int startIndex; + if (withinIntervalWithRollover(startSeq, retryFirstSeq, retryLastSeq)) { + startIndex = static_cast<uint16_t>(startSeq - retryFirstSeq); + } else { + startIndex = -1; + } + + int endIndex; + if (withinIntervalWithRollover(endSeq, retryFirstSeq, retryLastSeq)) { + endIndex = static_cast<uint16_t>(endSeq - retryFirstSeq); + } else { + endIndex = -1; + } + + if (startIndex == -1 && endIndex == -1) { + // no part of the request range is found in the retry buffer + RetryPacket nak = request; + nak.id = htonl(kRetryNakID); + result = sendto(mSender->mSocket, &nak, sizeof(nak), 0, + &requestSrcAddr, requestSrcAddrLen); + if (result == -1) { + ALOGW("%s sendto failed", __PRETTY_FUNCTION__); + } + return; + } + + if (startIndex == -1) { + // NAK a subrange at the front of the request range + RetryPacket nak = request; + nak.id = htonl(kRetryNakID); + nak.seqEnd = htons(retryFirstSeq - 1); + result = sendto(mSender->mSocket, &nak, sizeof(nak), 0, + &requestSrcAddr, requestSrcAddrLen); + if (result == -1) { + ALOGW("%s sendto failed", __PRETTY_FUNCTION__); + } + + startIndex = 0; + } else if (endIndex == -1) { + // NAK a subrange at the back of the request range + RetryPacket nak = request; + nak.id = htonl(kRetryNakID); + nak.seqStart = htons(retryLastSeq + 1); + result = sendto(mSender->mSocket, &nak, sizeof(nak), 0, + &requestSrcAddr, requestSrcAddrLen); + if (result == -1) { + ALOGW("%s sendto failed", __PRETTY_FUNCTION__); + } + + endIndex = retry.size() - 1; + } + + // send the retry packets + for (int i = startIndex; i <= endIndex; i++) { + const sp<TRTPPacket>& replyPacket = retry[i]; + + result = sendto(mSender->mSocket, + replyPacket->getPacket(), + replyPacket->getPacketLen(), + 0, + &requestSrcAddr, + requestSrcAddrLen); + + if (result == -1) { + ALOGW("%s sendto failed", __PRETTY_FUNCTION__); + } + } +} + +// Endpoint + +AAH_TXSender::Endpoint::Endpoint() + : addr(0) + , port(0) { } + +AAH_TXSender::Endpoint::Endpoint(uint32_t a, uint16_t p) + : addr(a) + , port(p) {} + +bool AAH_TXSender::Endpoint::operator<(const Endpoint& other) const { + return ((addr < other.addr) || + (addr == other.addr && port < other.port)); +} + +// EndpointState + +AAH_TXSender::EndpointState::EndpointState(uint32_t _epoch) + : retry(kRetryBufferCapacity) + , playerRefCount(1) + , trtpSeqNumber(0) + , nextProgramID(0) + , epoch(_epoch) { } + +// CircularBuffer + +template <typename T> +CircularBuffer<T>::CircularBuffer(size_t capacity) + : mCapacity(capacity) + , mHead(0) + , mTail(0) + , mFillCount(0) { + mBuffer = new T[capacity]; +} + +template <typename T> +CircularBuffer<T>::~CircularBuffer() { + delete [] mBuffer; +} + +template <typename T> +void CircularBuffer<T>::push_back(const T& item) { + if (this->isFull()) { + this->pop_front(); + } + mBuffer[mHead] = item; + mHead = (mHead + 1) % mCapacity; + mFillCount++; +} + +template <typename T> +void CircularBuffer<T>::pop_front() { + CHECK(!isEmpty()); + mBuffer[mTail] = T(); + mTail = (mTail + 1) % mCapacity; + mFillCount--; +} + +template <typename T> +size_t CircularBuffer<T>::size() const { + return mFillCount; +} + +template <typename T> +bool CircularBuffer<T>::isFull() const { + return (mFillCount == mCapacity); +} + +template <typename T> +bool CircularBuffer<T>::isEmpty() const { + return (mFillCount == 0); +} + +template <typename T> +const T& CircularBuffer<T>::itemAt(size_t index) const { + CHECK(index < mFillCount); + return mBuffer[(mTail + index) % mCapacity]; +} + +template <typename T> +const T& CircularBuffer<T>::operator[](size_t index) const { + return itemAt(index); +} + +} // namespace android diff --git a/media/libaah_rtp/aah_tx_sender.h b/media/libaah_rtp/aah_tx_sender.h new file mode 100644 index 000000000000..74206c49b28b --- /dev/null +++ b/media/libaah_rtp/aah_tx_sender.h @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __AAH_TX_SENDER_H__ +#define __AAH_TX_SENDER_H__ + +#include <media/stagefright/foundation/ALooper.h> +#include <media/stagefright/foundation/AHandlerReflector.h> +#include <utils/RefBase.h> +#include <utils/threads.h> + +#include "aah_tx_packet.h" +#include "pipe_event.h" + +namespace android { + +template <typename T> class CircularBuffer { + public: + CircularBuffer(size_t capacity); + ~CircularBuffer(); + void push_back(const T& item);; + void pop_front(); + size_t size() const; + bool isFull() const; + bool isEmpty() const; + const T& itemAt(size_t index) const; + const T& operator[](size_t index) const; + + private: + T* mBuffer; + size_t mCapacity; + size_t mHead; + size_t mTail; + size_t mFillCount; + + DISALLOW_EVIL_CONSTRUCTORS(CircularBuffer); +}; + +class AAH_TXSender : public virtual RefBase { + public: + ~AAH_TXSender(); + + static sp<AAH_TXSender> GetInstance(); + + ALooper::handler_id handlerID() { return mReflector->id(); } + + // an IP address and port + struct Endpoint { + Endpoint(); + Endpoint(uint32_t a, uint16_t p); + bool operator<(const Endpoint& other) const; + + uint32_t addr; + uint16_t port; + }; + + uint16_t registerEndpoint(const Endpoint& endpoint); + void unregisterEndpoint(const Endpoint& endpoint); + + enum { + kWhatSendPacket, + kWhatTrimRetryBuffers, + kWhatSendHeartbeats, + }; + + // fields for SendPacket messages + static const char* kSendPacketIPAddr; + static const char* kSendPacketPort; + static const char* kSendPacketTRTPPacket; + + private: + AAH_TXSender(); + + static Mutex sLock; + static wp<AAH_TXSender> sInstance; + static uint32_t sNextEpoch; + static bool sNextEpochValid; + + static uint32_t getNextEpoch(); + + typedef CircularBuffer<sp<TRTPPacket> > RetryBuffer; + + // state maintained on a per-endpoint basis + struct EndpointState { + EndpointState(uint32_t epoch); + RetryBuffer retry; + int playerRefCount; + uint16_t trtpSeqNumber; + uint16_t nextProgramID; + uint32_t epoch; + }; + + friend class AHandlerReflector<AAH_TXSender>; + void onMessageReceived(const sp<AMessage>& msg); + void onSendPacket(const sp<AMessage>& msg); + void doSendPacket_l(const sp<TRTPPacket>& packet, + const Endpoint& endpoint); + void trimRetryBuffers(); + void sendHeartbeats(); + bool shouldSendHeartbeats_l(); + + sp<ALooper> mLooper; + sp<AHandlerReflector<AAH_TXSender> > mReflector; + + int mSocket; + nsecs_t mLastSentPacketTime; + + DefaultKeyedVector<Endpoint, EndpointState*> mEndpointMap; + Mutex mEndpointLock; + + static const int kRetryTrimIntervalUs; + static const int kHeartbeatIntervalUs; + static const int kRetryBufferCapacity; + static const nsecs_t kHeartbeatTimeout; + + class RetryReceiver : public Thread { + private: + friend class AAH_TXSender; + + RetryReceiver(AAH_TXSender* sender); + virtual ~RetryReceiver(); + virtual bool threadLoop(); + void handleRetryRequest(); + + static const int kMaxReceiverPacketLen; + static const uint32_t kRetryRequestID; + static const uint32_t kFastStartRequestID; + static const uint32_t kRetryNakID; + + AAH_TXSender* mSender; + PipeEvent mWakeupEvent; + }; + + sp<RetryReceiver> mRetryReceiver; + + DISALLOW_EVIL_CONSTRUCTORS(AAH_TXSender); +}; + +struct RetryPacket { + uint32_t id; + uint32_t endpointIP; + uint16_t endpointPort; + uint16_t seqStart; + uint16_t seqEnd; +} __attribute__((packed)); + +} // namespace android + +#endif // __AAH_TX_SENDER_H__ diff --git a/media/libaah_rtp/pipe_event.cpp b/media/libaah_rtp/pipe_event.cpp new file mode 100644 index 000000000000..b8e696080ca9 --- /dev/null +++ b/media/libaah_rtp/pipe_event.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "LibAAH_RTP" +#include <utils/Log.h> + +#include <errno.h> +#include <fcntl.h> +#include <poll.h> +#include <unistd.h> + +#include "pipe_event.h" + +namespace android { + +PipeEvent::PipeEvent() { + pipe_[0] = -1; + pipe_[1] = -1; + + // Create the pipe. + if (pipe(pipe_) >= 0) { + // Set non-blocking mode on the read side of the pipe so we can + // easily drain it whenever we wakeup. + fcntl(pipe_[0], F_SETFL, O_NONBLOCK); + } else { + ALOGE("Failed to create pipe event %d %d %d", + pipe_[0], pipe_[1], errno); + pipe_[0] = -1; + pipe_[1] = -1; + } +} + +PipeEvent::~PipeEvent() { + if (pipe_[0] >= 0) { + close(pipe_[0]); + } + + if (pipe_[1] >= 0) { + close(pipe_[1]); + } +} + +void PipeEvent::clearPendingEvents() { + char drain_buffer[16]; + while (read(pipe_[0], drain_buffer, sizeof(drain_buffer)) > 0) { + // No body. + } +} + +bool PipeEvent::wait(int timeout) { + struct pollfd wait_fd; + + wait_fd.fd = getWakeupHandle(); + wait_fd.events = POLLIN; + wait_fd.revents = 0; + + int res = poll(&wait_fd, 1, timeout); + + if (res < 0) { + ALOGE("Wait error in PipeEvent; sleeping to prevent overload!"); + usleep(1000); + } + + return (res > 0); +} + +void PipeEvent::setEvent() { + char foo = 'q'; + write(pipe_[1], &foo, 1); +} + +} // namespace android + diff --git a/media/libaah_rtp/pipe_event.h b/media/libaah_rtp/pipe_event.h new file mode 100644 index 000000000000..e53b0fdb74c0 --- /dev/null +++ b/media/libaah_rtp/pipe_event.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __PIPE_EVENT_H__ +#define __PIPE_EVENT_H__ + +#include <media/stagefright/foundation/ABase.h> + +namespace android { + +class PipeEvent { + public: + PipeEvent(); + ~PipeEvent(); + + bool initCheck() const { + return ((pipe_[0] >= 0) && (pipe_[1] >= 0)); + } + + int getWakeupHandle() const { return pipe_[0]; } + + // block until the event fires; returns true if the event fired and false if + // the wait timed out. Timeout is expressed in milliseconds; negative + // values mean wait forever. + bool wait(int timeout = -1); + + void clearPendingEvents(); + void setEvent(); + + private: + int pipe_[2]; + + DISALLOW_EVIL_CONSTRUCTORS(PipeEvent); +}; + +} // namespace android + +#endif // __PIPE_EVENT_H__ diff --git a/media/libmedia/AudioEffect.cpp b/media/libmedia/AudioEffect.cpp index f9f997fe6a32..19b7e324b32b 100644 --- a/media/libmedia/AudioEffect.cpp +++ b/media/libmedia/AudioEffect.cpp @@ -202,7 +202,7 @@ bool AudioEffect::getEnabled() const status_t AudioEffect::setEnabled(bool enabled) { if (mStatus != NO_ERROR) { - return INVALID_OPERATION; + return (mStatus == ALREADY_EXISTS) ? INVALID_OPERATION : mStatus; } status_t status = NO_ERROR; @@ -231,7 +231,7 @@ status_t AudioEffect::command(uint32_t cmdCode, { if (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS) { ALOGV("command() bad status %d", mStatus); - return INVALID_OPERATION; + return mStatus; } if (cmdCode == EFFECT_CMD_ENABLE || cmdCode == EFFECT_CMD_DISABLE) { @@ -263,7 +263,7 @@ status_t AudioEffect::command(uint32_t cmdCode, status_t AudioEffect::setParameter(effect_param_t *param) { if (mStatus != NO_ERROR) { - return INVALID_OPERATION; + return (mStatus == ALREADY_EXISTS) ? INVALID_OPERATION : mStatus; } if (param == NULL || param->psize == 0 || param->vsize == 0) { @@ -281,7 +281,7 @@ status_t AudioEffect::setParameter(effect_param_t *param) status_t AudioEffect::setParameterDeferred(effect_param_t *param) { if (mStatus != NO_ERROR) { - return INVALID_OPERATION; + return (mStatus == ALREADY_EXISTS) ? INVALID_OPERATION : mStatus; } if (param == NULL || param->psize == 0 || param->vsize == 0) { @@ -307,7 +307,7 @@ status_t AudioEffect::setParameterDeferred(effect_param_t *param) status_t AudioEffect::setParameterCommit() { if (mStatus != NO_ERROR) { - return INVALID_OPERATION; + return (mStatus == ALREADY_EXISTS) ? INVALID_OPERATION : mStatus; } Mutex::Autolock _l(mCblk->lock); @@ -321,7 +321,7 @@ status_t AudioEffect::setParameterCommit() status_t AudioEffect::getParameter(effect_param_t *param) { if (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS) { - return INVALID_OPERATION; + return mStatus; } if (param == NULL || param->psize == 0 || param->vsize == 0) { @@ -341,7 +341,7 @@ status_t AudioEffect::getParameter(effect_param_t *param) void AudioEffect::binderDied() { ALOGW("IEffect died"); - mStatus = NO_INIT; + mStatus = DEAD_OBJECT; if (mCbf != NULL) { status_t status = DEAD_OBJECT; mCbf(EVENT_ERROR, mUserData, &status); diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index b74b3e35c8a7..a4068ff2abad 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -304,10 +304,25 @@ status_t AudioRecord::start() if (mActive == 0) { mActive = 1; + pid_t tid; + if (t != 0) { + mReadyToRun = WOULD_BLOCK; + t->run("ClientRecordThread", ANDROID_PRIORITY_AUDIO); + tid = t->getTid(); // pid_t is unknown until run() + ALOGV("getTid=%d", tid); + if (tid == -1) { + tid = 0; + } + // thread blocks in readyToRun() + } else { + tid = 0; // not gettid() + } + cblk->lock.lock(); if (!(cblk->flags & CBLK_INVALID_MSK)) { cblk->lock.unlock(); - ret = mAudioRecord->start(); + ALOGV("mAudioRecord->start(tid=%d)", tid); + ret = mAudioRecord->start(tid); cblk->lock.lock(); if (ret == DEAD_OBJECT) { android_atomic_or(CBLK_INVALID_ON, &cblk->flags); @@ -322,7 +337,9 @@ status_t AudioRecord::start() cblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS; cblk->waitTimeMs = 0; if (t != 0) { - t->run("ClientRecordThread", ANDROID_PRIORITY_AUDIO); + // thread unblocks in readyToRun() and returns NO_ERROR + mReadyToRun = NO_ERROR; + mCondition.signal(); } else { mPreviousPriority = getpriority(PRIO_PROCESS, 0); mPreviousSchedulingGroup = androidGetThreadSchedulingGroup(0); @@ -330,6 +347,9 @@ status_t AudioRecord::start() } } else { mActive = 0; + // thread unblocks in readyToRun() and returns NO_INIT + mReadyToRun = NO_INIT; + mCondition.signal(); } } @@ -522,7 +542,7 @@ status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) ALOGW( "obtainBuffer timed out (is the CPU pegged?) " "user=%08x, server=%08x", cblk->user, cblk->server); cblk->lock.unlock(); - result = mAudioRecord->start(); + result = mAudioRecord->start(0); // callback thread hasn't changed cblk->lock.lock(); if (result == DEAD_OBJECT) { android_atomic_or(CBLK_INVALID_ON, &cblk->flags); @@ -760,7 +780,7 @@ status_t AudioRecord::restoreRecord_l(audio_track_cblk_t*& cblk) result = openRecord_l(cblk->sampleRate, mFormat, mChannelMask, mFrameCount, mFlags, getInput_l()); if (result == NO_ERROR) { - result = mAudioRecord->start(); + result = mAudioRecord->start(0); // callback thread hasn't changed } if (result != NO_ERROR) { mActive = false; @@ -811,6 +831,15 @@ bool AudioRecord::ClientRecordThread::threadLoop() return mReceiver.processAudioBuffer(this); } +status_t AudioRecord::ClientRecordThread::readyToRun() +{ + AutoMutex(mReceiver.mLock); + while (mReceiver.mReadyToRun == WOULD_BLOCK) { + mReceiver.mCondition.wait(mReceiver.mLock); + } + return mReceiver.mReadyToRun; +} + // ------------------------------------------------------------------------- }; // namespace android diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 087d7b2096f3..74c97ed932cf 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -1,4 +1,4 @@ -/* frameworks/base/media/libmedia/AudioTrack.cpp +/* ** ** Copyright 2007, The Android Open Source Project ** @@ -80,7 +80,9 @@ status_t AudioTrack::getMinFrameCount( AudioTrack::AudioTrack() : mStatus(NO_INIT), - mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(ANDROID_TGROUP_DEFAULT) + mIsTimed(false), + mPreviousPriority(ANDROID_PRIORITY_NORMAL), + mPreviousSchedulingGroup(ANDROID_TGROUP_DEFAULT) { } @@ -96,7 +98,9 @@ AudioTrack::AudioTrack( int notificationFrames, int sessionId) : mStatus(NO_INIT), - mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(ANDROID_TGROUP_DEFAULT) + mIsTimed(false), + mPreviousPriority(ANDROID_PRIORITY_NORMAL), + mPreviousSchedulingGroup(ANDROID_TGROUP_DEFAULT) { mStatus = set(streamType, sampleRate, format, channelMask, frameCount, flags, cbf, user, notificationFrames, @@ -134,7 +138,9 @@ AudioTrack::AudioTrack( int notificationFrames, int sessionId) : mStatus(NO_INIT), - mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(ANDROID_TGROUP_DEFAULT) + mIsTimed(false), + mPreviousPriority(ANDROID_PRIORITY_NORMAL), + mPreviousSchedulingGroup(ANDROID_TGROUP_DEFAULT) { mStatus = set(streamType, sampleRate, format, channelMask, 0, flags, cbf, user, notificationFrames, @@ -362,18 +368,26 @@ void AudioTrack::start() cblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS; cblk->waitTimeMs = 0; android_atomic_and(~CBLK_DISABLED_ON, &cblk->flags); + pid_t tid; if (t != 0) { t->run("AudioTrackThread", ANDROID_PRIORITY_AUDIO); + tid = t->getTid(); // pid_t is unknown until run() + ALOGV("getTid=%d", tid); + if (tid == -1) { + tid = 0; + } } else { mPreviousPriority = getpriority(PRIO_PROCESS, 0); mPreviousSchedulingGroup = androidGetThreadSchedulingGroup(0); androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO); + tid = 0; // not gettid() } ALOGV("start %p before lock cblk %p", this, mCblk); if (!(cblk->flags & CBLK_INVALID_MSK)) { cblk->lock.unlock(); - status = mAudioTrack->start(); + ALOGV("mAudioTrack->start(tid=%d)", tid); + status = mAudioTrack->start(tid); cblk->lock.lock(); if (status == DEAD_OBJECT) { android_atomic_or(CBLK_INVALID_ON, &cblk->flags); @@ -532,6 +546,10 @@ status_t AudioTrack::setSampleRate(int rate) { int afSamplingRate; + if (mIsTimed) { + return INVALID_OPERATION; + } + if (AudioSystem::getOutputSamplingRate(&afSamplingRate, mStreamType) != NO_ERROR) { return NO_INIT; } @@ -545,6 +563,10 @@ status_t AudioTrack::setSampleRate(int rate) uint32_t AudioTrack::getSampleRate() const { + if (mIsTimed) { + return INVALID_OPERATION; + } + AutoMutex lock(mLock); return mCblk->sampleRate; } @@ -570,6 +592,10 @@ status_t AudioTrack::setLoop_l(uint32_t loopStart, uint32_t loopEnd, int loopCou return NO_ERROR; } + if (mIsTimed) { + return INVALID_OPERATION; + } + if (loopStart >= loopEnd || loopEnd - loopStart > cblk->frameCount || cblk->server > loopStart) { @@ -591,26 +617,6 @@ status_t AudioTrack::setLoop_l(uint32_t loopStart, uint32_t loopEnd, int loopCou return NO_ERROR; } -status_t AudioTrack::getLoop(uint32_t *loopStart, uint32_t *loopEnd, int *loopCount) const -{ - AutoMutex lock(mLock); - if (loopStart != NULL) { - *loopStart = mCblk->loopStart; - } - if (loopEnd != NULL) { - *loopEnd = mCblk->loopEnd; - } - if (loopCount != NULL) { - if (mCblk->loopCount < 0) { - *loopCount = -1; - } else { - *loopCount = mCblk->loopCount; - } - } - - return NO_ERROR; -} - status_t AudioTrack::setMarkerPosition(uint32_t marker) { if (mCbf == NULL) return INVALID_OPERATION; @@ -653,6 +659,8 @@ status_t AudioTrack::getPositionUpdatePeriod(uint32_t *updatePeriod) const status_t AudioTrack::setPosition(uint32_t position) { + if (mIsTimed) return INVALID_OPERATION; + AutoMutex lock(mLock); if (!stopped_l()) return INVALID_OPERATION; @@ -784,7 +792,7 @@ status_t AudioTrack::createTrack_l( } } } else { - // Ensure that buffer alignment matches channelcount + // Ensure that buffer alignment matches channelCount int channelCount = popcount(channelMask); if (((uint32_t)sharedBuffer->pointer() & (channelCount | 1)) != 0) { ALOGE("Invalid buffer alignement: address %p, channelCount %d", sharedBuffer->pointer(), channelCount); @@ -803,6 +811,7 @@ status_t AudioTrack::createTrack_l( ((uint16_t)flags) << 16, sharedBuffer, output, + mIsTimed, &mSessionId, &status); @@ -895,7 +904,7 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) "user=%08x, server=%08x", this, cblk->user, cblk->server); //unlock cblk mutex before calling mAudioTrack->start() (see issue #1617140) cblk->lock.unlock(); - result = mAudioTrack->start(); + result = mAudioTrack->start(0); // callback thread hasn't changed cblk->lock.lock(); if (result == DEAD_OBJECT) { android_atomic_or(CBLK_INVALID_ON, &cblk->flags); @@ -927,7 +936,7 @@ create_new_track: if (mActive && (cblk->flags & CBLK_DISABLED_MSK)) { android_atomic_and(~CBLK_DISABLED_ON, &cblk->flags); ALOGW("obtainBuffer() track %p disabled, restarting", this); - mAudioTrack->start(); + mAudioTrack->start(0); // callback thread hasn't changed } cblk->waitTimeMs = 0; @@ -969,9 +978,11 @@ ssize_t AudioTrack::write(const void* buffer, size_t userSize) { if (mSharedBuffer != 0) return INVALID_OPERATION; + if (mIsTimed) return INVALID_OPERATION; if (ssize_t(userSize) < 0) { - // sanity-check. user is most-likely passing an error code. + // Sanity-check: user is most-likely passing an error code, and it would + // make the return value ambiguous (actualSize vs error). ALOGE("AudioTrack::write(buffer=%p, size=%u (%d)", buffer, userSize, userSize); return BAD_VALUE; @@ -994,8 +1005,6 @@ ssize_t AudioTrack::write(const void* buffer, size_t userSize) do { audioBuffer.frameCount = userSize/frameSz; - // Calling obtainBuffer() with a negative wait count causes - // an (almost) infinite wait time. status_t err = obtainBuffer(&audioBuffer, -1); if (err < 0) { // out of buffers, return #bytes written @@ -1026,6 +1035,59 @@ ssize_t AudioTrack::write(const void* buffer, size_t userSize) // ------------------------------------------------------------------------- +TimedAudioTrack::TimedAudioTrack() { + mIsTimed = true; +} + +status_t TimedAudioTrack::allocateTimedBuffer(size_t size, sp<IMemory>* buffer) +{ + status_t result = UNKNOWN_ERROR; + + // If the track is not invalid already, try to allocate a buffer. alloc + // fails indicating that the server is dead, flag the track as invalid so + // we can attempt to restore in in just a bit. + if (!(mCblk->flags & CBLK_INVALID_MSK)) { + result = mAudioTrack->allocateTimedBuffer(size, buffer); + if (result == DEAD_OBJECT) { + android_atomic_or(CBLK_INVALID_ON, &mCblk->flags); + } + } + + // If the track is invalid at this point, attempt to restore it. and try the + // allocation one more time. + if (mCblk->flags & CBLK_INVALID_MSK) { + mCblk->lock.lock(); + result = restoreTrack_l(mCblk, false); + mCblk->lock.unlock(); + + if (result == OK) + result = mAudioTrack->allocateTimedBuffer(size, buffer); + } + + return result; +} + +status_t TimedAudioTrack::queueTimedBuffer(const sp<IMemory>& buffer, + int64_t pts) +{ + // restart track if it was disabled by audioflinger due to previous underrun + if (mActive && (mCblk->flags & CBLK_DISABLED_MSK)) { + android_atomic_and(~CBLK_DISABLED_ON, &mCblk->flags); + ALOGW("queueTimedBuffer() track %p disabled, restarting", this); + mAudioTrack->start(0); + } + + return mAudioTrack->queueTimedBuffer(buffer, pts); +} + +status_t TimedAudioTrack::setMediaTimeTransform(const LinearTransform& xform, + TargetTimeline target) +{ + return mAudioTrack->setMediaTimeTransform(xform, target); +} + +// ------------------------------------------------------------------------- + bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread) { Buffer audioBuffer; @@ -1085,6 +1147,9 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread) frames = mRemainingFrames; } + // See description of waitCount parameter at declaration of obtainBuffer(). + // The logic below prevents us from being stuck below at obtainBuffer() + // not being able to handle timed events (position, markers, loops). int32_t waitCount = -1; if (mUpdatePeriod || (!mMarkerReached && mMarkerPosition) || mLoopCount) { waitCount = 1; @@ -1094,9 +1159,6 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread) audioBuffer.frameCount = frames; - // Calling obtainBuffer() with a wait count of 1 - // limits wait time to WAIT_PERIOD_MS. This prevents from being - // stuck here not being able to handle timed events (position, markers, loops). status_t err = obtainBuffer(&audioBuffer, waitCount); if (err < NO_ERROR) { if (err != TIMED_OUT) { @@ -1218,7 +1280,7 @@ status_t AudioTrack::restoreTrack_l(audio_track_cblk_t*& cblk, bool fromStart) } } if (mActive) { - result = mAudioTrack->start(); + result = mAudioTrack->start(0); // callback thread hasn't changed ALOGW_IF(result != NO_ERROR, "restoreTrack_l() start() failed status %d", result); } if (fromStart && result == NO_ERROR) { diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp index 4507e5db7683..ebadbfa5499c 100644 --- a/media/libmedia/IAudioFlinger.cpp +++ b/media/libmedia/IAudioFlinger.cpp @@ -90,6 +90,7 @@ public: uint32_t flags, const sp<IMemory>& sharedBuffer, audio_io_handle_t output, + bool isTimed, int *sessionId, status_t *status) { @@ -105,6 +106,7 @@ public: data.writeInt32(flags); data.writeStrongBinder(sharedBuffer->asBinder()); data.writeInt32((int32_t) output); + data.writeInt32(isTimed); int lSessionId = 0; if (sessionId != NULL) { lSessionId = *sessionId; @@ -689,11 +691,12 @@ status_t BnAudioFlinger::onTransact( uint32_t flags = data.readInt32(); sp<IMemory> buffer = interface_cast<IMemory>(data.readStrongBinder()); audio_io_handle_t output = (audio_io_handle_t) data.readInt32(); + bool isTimed = data.readInt32(); int sessionId = data.readInt32(); status_t status; sp<IAudioTrack> track = createTrack(pid, (audio_stream_type_t) streamType, sampleRate, format, - channelCount, bufferCount, flags, buffer, output, &sessionId, &status); + channelCount, bufferCount, flags, buffer, output, isTimed, &sessionId, &status); reply->writeInt32(sessionId); reply->writeInt32(status); reply->writeStrongBinder(track->asBinder()); diff --git a/media/libmedia/IAudioRecord.cpp b/media/libmedia/IAudioRecord.cpp index 8c7a96023498..6b473c943692 100644 --- a/media/libmedia/IAudioRecord.cpp +++ b/media/libmedia/IAudioRecord.cpp @@ -42,10 +42,11 @@ public: { } - virtual status_t start() + virtual status_t start(pid_t tid) { Parcel data, reply; data.writeInterfaceToken(IAudioRecord::getInterfaceDescriptor()); + data.writeInt32(tid); status_t status = remote()->transact(START, data, &reply); if (status == NO_ERROR) { status = reply.readInt32(); @@ -90,7 +91,7 @@ status_t BnAudioRecord::onTransact( } break; case START: { CHECK_INTERFACE(IAudioRecord, data, reply); - reply->writeInt32(start()); + reply->writeInt32(start(data.readInt32())); return NO_ERROR; } break; case STOP: { diff --git a/media/libmedia/IAudioTrack.cpp b/media/libmedia/IAudioTrack.cpp index e6186193656b..28ebbbfc73be 100644 --- a/media/libmedia/IAudioTrack.cpp +++ b/media/libmedia/IAudioTrack.cpp @@ -1,4 +1,4 @@ -/* //device/extlibs/pv/android/IAudioTrack.cpp +/* ** ** Copyright 2007, The Android Open Source Project ** @@ -35,7 +35,10 @@ enum { FLUSH, MUTE, PAUSE, - ATTACH_AUX_EFFECT + ATTACH_AUX_EFFECT, + ALLOCATE_TIMED_BUFFER, + QUEUE_TIMED_BUFFER, + SET_MEDIA_TIME_TRANSFORM, }; class BpAudioTrack : public BpInterface<IAudioTrack> @@ -58,10 +61,11 @@ public: return cblk; } - virtual status_t start() + virtual status_t start(pid_t tid) { Parcel data, reply; data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor()); + data.writeInt32(tid); status_t status = remote()->transact(START, data, &reply); if (status == NO_ERROR) { status = reply.readInt32(); @@ -113,6 +117,52 @@ public: } return status; } + + virtual status_t allocateTimedBuffer(size_t size, sp<IMemory>* buffer) { + Parcel data, reply; + data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor()); + data.writeInt32(size); + status_t status = remote()->transact(ALLOCATE_TIMED_BUFFER, + data, &reply); + if (status == NO_ERROR) { + status = reply.readInt32(); + if (status == NO_ERROR) { + *buffer = interface_cast<IMemory>(reply.readStrongBinder()); + } + } + return status; + } + + virtual status_t queueTimedBuffer(const sp<IMemory>& buffer, + int64_t pts) { + Parcel data, reply; + data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor()); + data.writeStrongBinder(buffer->asBinder()); + data.writeInt64(pts); + status_t status = remote()->transact(QUEUE_TIMED_BUFFER, + data, &reply); + if (status == NO_ERROR) { + status = reply.readInt32(); + } + return status; + } + + virtual status_t setMediaTimeTransform(const LinearTransform& xform, + int target) { + Parcel data, reply; + data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor()); + data.writeInt64(xform.a_zero); + data.writeInt64(xform.b_zero); + data.writeInt32(xform.a_to_b_numer); + data.writeInt32(xform.a_to_b_denom); + data.writeInt32(target); + status_t status = remote()->transact(SET_MEDIA_TIME_TRANSFORM, + data, &reply); + if (status == NO_ERROR) { + status = reply.readInt32(); + } + return status; + } }; IMPLEMENT_META_INTERFACE(AudioTrack, "android.media.IAudioTrack"); @@ -130,7 +180,7 @@ status_t BnAudioTrack::onTransact( } break; case START: { CHECK_INTERFACE(IAudioTrack, data, reply); - reply->writeInt32(start()); + reply->writeInt32(start(data.readInt32())); return NO_ERROR; } break; case STOP: { @@ -158,10 +208,38 @@ status_t BnAudioTrack::onTransact( reply->writeInt32(attachAuxEffect(data.readInt32())); return NO_ERROR; } break; + case ALLOCATE_TIMED_BUFFER: { + CHECK_INTERFACE(IAudioTrack, data, reply); + sp<IMemory> buffer; + status_t status = allocateTimedBuffer(data.readInt32(), &buffer); + reply->writeInt32(status); + if (status == NO_ERROR) { + reply->writeStrongBinder(buffer->asBinder()); + } + return NO_ERROR; + } break; + case QUEUE_TIMED_BUFFER: { + CHECK_INTERFACE(IAudioTrack, data, reply); + sp<IMemory> buffer = interface_cast<IMemory>( + data.readStrongBinder()); + uint64_t pts = data.readInt64(); + reply->writeInt32(queueTimedBuffer(buffer, pts)); + return NO_ERROR; + } break; + case SET_MEDIA_TIME_TRANSFORM: { + CHECK_INTERFACE(IAudioTrack, data, reply); + LinearTransform xform; + xform.a_zero = data.readInt64(); + xform.b_zero = data.readInt64(); + xform.a_to_b_numer = data.readInt32(); + xform.a_to_b_denom = data.readInt32(); + int target = data.readInt32(); + reply->writeInt32(setMediaTimeTransform(xform, target)); + return NO_ERROR; + } break; default: return BBinder::onTransact(code, data, reply, flags); } } }; // namespace android - diff --git a/media/libmedia/IEffect.cpp b/media/libmedia/IEffect.cpp index d469e280f647..5d40cc82af48 100644 --- a/media/libmedia/IEffect.cpp +++ b/media/libmedia/IEffect.cpp @@ -83,8 +83,15 @@ public: size = *pReplySize; } data.writeInt32(size); - remote()->transact(COMMAND, data, &reply); - status_t status = reply.readInt32(); + + status_t status = remote()->transact(COMMAND, data, &reply); + if (status != NO_ERROR) { + if (pReplySize != NULL) + *pReplySize = 0; + return status; + } + + status = reply.readInt32(); size = reply.readInt32(); if (size != 0 && pReplyData != NULL && pReplySize != NULL) { reply.read(pReplyData, size); diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp index 6cb10aa4e3ad..54eb98a963c9 100644 --- a/media/libmedia/ToneGenerator.cpp +++ b/media/libmedia/ToneGenerator.cpp @@ -791,7 +791,7 @@ const unsigned char /*tone_type*/ ToneGenerator::sToneMappingTable[NUM_REGIONS-1 // generators, instantiates output audio track. // // Input: -// streamType: Type of stream used for tone playback (enum AudioTrack::stream_type) +// streamType: Type of stream used for tone playback // volume: volume applied to tone (0.0 to 1.0) // // Output: diff --git a/media/libmedia/Visualizer.cpp b/media/libmedia/Visualizer.cpp index 13b64e9f2917..70f8c0c28e8e 100644 --- a/media/libmedia/Visualizer.cpp +++ b/media/libmedia/Visualizer.cpp @@ -168,7 +168,7 @@ status_t Visualizer::getWaveForm(uint8_t *waveform) uint32_t replySize = mCaptureSize; status = command(VISUALIZER_CMD_CAPTURE, 0, NULL, &replySize, waveform); ALOGV("getWaveForm() command returned %d", status); - if (replySize == 0) { + if ((status == NO_ERROR) && (replySize == 0)) { status = NOT_ENOUGH_DATA; } } else { diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp index f1c47dd91b40..250425b5d5b0 100644 --- a/media/libmedia/mediaplayer.cpp +++ b/media/libmedia/mediaplayer.cpp @@ -1,4 +1,4 @@ -/* mediaplayer.cpp +/* ** ** Copyright 2006, The Android Open Source Project ** diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk index a3e2517b37d2..e521648fde9f 100644 --- a/media/libmediaplayerservice/Android.mk +++ b/media/libmediaplayerservice/Android.mk @@ -29,7 +29,8 @@ LOCAL_SHARED_LIBRARIES := \ libstagefright_omx \ libstagefright_foundation \ libgui \ - libdl + libdl \ + libaah_rtp LOCAL_STATIC_LIBRARIES := \ libstagefright_nuplayer \ diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index 4df7f3d654c4..764eddc840a8 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -70,6 +70,11 @@ #include <OMX.h> +namespace android { +sp<MediaPlayerBase> createAAH_TXPlayer(); +sp<MediaPlayerBase> createAAH_RXPlayer(); +} + namespace { using android::media::Metadata; using android::status_t; @@ -593,6 +598,14 @@ player_type getPlayerType(const char* url) return NU_PLAYER; } + if (!strncasecmp("aahRX://", url, 8)) { + return AAH_RX_PLAYER; + } + + if (!strncasecmp("aahTX://", url, 8)) { + return AAH_TX_PLAYER; + } + // use MidiFile for MIDI extensions int lenURL = strlen(url); for (int i = 0; i < NELEM(FILE_EXTS); ++i) { @@ -629,6 +642,14 @@ static sp<MediaPlayerBase> createPlayer(player_type playerType, void* cookie, ALOGV("Create Test Player stub"); p = new TestPlayerStub(); break; + case AAH_RX_PLAYER: + ALOGV(" create A@H RX Player"); + p = createAAH_RXPlayer(); + break; + case AAH_TX_PLAYER: + ALOGV(" create A@H TX Player"); + p = createAAH_TXPlayer(); + break; default: ALOGE("Unknown player type: %d", playerType); return NULL; @@ -1031,9 +1052,21 @@ status_t MediaPlayerService::Client::setLooping(int loop) status_t MediaPlayerService::Client::setVolume(float leftVolume, float rightVolume) { ALOGV("[%d] setVolume(%f, %f)", mConnId, leftVolume, rightVolume); - // TODO: for hardware output, call player instead - Mutex::Autolock l(mLock); - if (mAudioOutput != 0) mAudioOutput->setVolume(leftVolume, rightVolume); + + // for hardware output, call player instead + sp<MediaPlayerBase> p = getPlayer(); + { + Mutex::Autolock l(mLock); + if (p != 0 && p->hardwareOutput()) { + MediaPlayerHWInterface* hwp = + reinterpret_cast<MediaPlayerHWInterface*>(p.get()); + return hwp->setVolume(leftVolume, rightVolume); + } else { + if (mAudioOutput != 0) mAudioOutput->setVolume(leftVolume, rightVolume); + return NO_ERROR; + } + } + return NO_ERROR; } diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk index 483e5ab0c160..3f9ba47e1345 100644 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -93,13 +93,7 @@ LOCAL_STATIC_LIBRARIES := \ # The following was shamelessly copied from external/webkit/Android.mk and # currently must follow the same logic to determine how webkit was built and -# if it's safe to link against libchromium.net - -# V8 also requires an ARMv7 CPU, and since we must use jsc, we cannot -# use the Chrome http stack either. -ifneq ($(strip $(ARCH_ARM_HAVE_ARMV7A)),true) - USE_ALT_HTTP := true -endif +# if it's safe to link against libchromium_net # See if the user has specified a stack they want to use HTTP_STACK = $(HTTP) diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp index fef2a006baa0..5b2ea1f80232 100644 --- a/media/libstagefright/AudioSource.cpp +++ b/media/libstagefright/AudioSource.cpp @@ -282,8 +282,6 @@ status_t AudioSource::dataCallbackTimestamp( mPrevSampleTimeUs = mStartTimeUs; } - int64_t timestampUs = mPrevSampleTimeUs; - size_t numLostBytes = 0; if (mNumFramesReceived > 0) { // Ignore earlier frame lost // getInputFramesLost() returns the number of lost frames. @@ -293,37 +291,58 @@ status_t AudioSource::dataCallbackTimestamp( CHECK_EQ(numLostBytes & 1, 0u); CHECK_EQ(audioBuffer.size & 1, 0u); - size_t bufferSize = numLostBytes + audioBuffer.size; - MediaBuffer *buffer = new MediaBuffer(bufferSize); if (numLostBytes > 0) { - memset(buffer->data(), 0, numLostBytes); - memcpy((uint8_t *) buffer->data() + numLostBytes, - audioBuffer.i16, audioBuffer.size); - } else { - if (audioBuffer.size == 0) { - ALOGW("Nothing is available from AudioRecord callback buffer"); - buffer->release(); - return OK; + // Loss of audio frames should happen rarely; thus the LOGW should + // not cause a logging spam + ALOGW("Lost audio record data: %d bytes", numLostBytes); + } + + while (numLostBytes > 0) { + size_t bufferSize = numLostBytes; + if (numLostBytes > kMaxBufferSize) { + numLostBytes -= kMaxBufferSize; + bufferSize = kMaxBufferSize; + } else { + numLostBytes = 0; } - memcpy((uint8_t *) buffer->data(), - audioBuffer.i16, audioBuffer.size); + MediaBuffer *lostAudioBuffer = new MediaBuffer(bufferSize); + memset(lostAudioBuffer->data(), 0, bufferSize); + lostAudioBuffer->set_range(0, bufferSize); + queueInputBuffer_l(lostAudioBuffer, timeUs); + } + + if (audioBuffer.size == 0) { + ALOGW("Nothing is available from AudioRecord callback buffer"); + return OK; } + const size_t bufferSize = audioBuffer.size; + MediaBuffer *buffer = new MediaBuffer(bufferSize); + memcpy((uint8_t *) buffer->data(), + audioBuffer.i16, audioBuffer.size); buffer->set_range(0, bufferSize); - timestampUs += ((1000000LL * (bufferSize >> 1)) + - (mSampleRate >> 1)) / mSampleRate; + queueInputBuffer_l(buffer, timeUs); + return OK; +} + +void AudioSource::queueInputBuffer_l(MediaBuffer *buffer, int64_t timeUs) { + const size_t bufferSize = buffer->range_length(); + const size_t frameSize = mRecord->frameSize(); + const int64_t timestampUs = + mPrevSampleTimeUs + + ((1000000LL * (bufferSize / frameSize)) + + (mSampleRate >> 1)) / mSampleRate; if (mNumFramesReceived == 0) { buffer->meta_data()->setInt64(kKeyAnchorTime, mStartTimeUs); } + buffer->meta_data()->setInt64(kKeyTime, mPrevSampleTimeUs); buffer->meta_data()->setInt64(kKeyDriftTime, timeUs - mInitialReadTimeUs); mPrevSampleTimeUs = timestampUs; - mNumFramesReceived += buffer->range_length() / sizeof(int16_t); + mNumFramesReceived += bufferSize / frameSize; mBuffersReceived.push_back(buffer); mFrameAvailableCondition.signal(); - - return OK; } void AudioSource::trackMaxAmplitude(int16_t *data, int nSamples) { diff --git a/native/android/asset_manager.cpp b/native/android/asset_manager.cpp index f5db57c1ff85..01db1d3cace4 100644 --- a/native/android/asset_manager.cpp +++ b/native/android/asset_manager.cpp @@ -18,9 +18,9 @@ #include <utils/Log.h> #include <android/asset_manager_jni.h> -#include <utils/AssetManager.h> -#include <utils/AssetDir.h> -#include <utils/Asset.h> +#include <androidfw/Asset.h> +#include <androidfw/AssetDir.h> +#include <androidfw/AssetManager.h> #include <utils/threads.h> #include "jni.h" diff --git a/native/android/configuration.cpp b/native/android/configuration.cpp index 687924be72ee..7eb51ddacc37 100644 --- a/native/android/configuration.cpp +++ b/native/android/configuration.cpp @@ -17,7 +17,7 @@ #define LOG_TAG "Configuration" #include <utils/Log.h> -#include <utils/AssetManager.h> +#include <androidfw/AssetManager.h> #include <android_runtime/android_content_res_Configuration.h> diff --git a/native/android/input.cpp b/native/android/input.cpp index 91671c3e9d54..6eb29902fd82 100644 --- a/native/android/input.cpp +++ b/native/android/input.cpp @@ -18,8 +18,8 @@ #include <utils/Log.h> #include <android/input.h> -#include <ui/Input.h> -#include <ui/InputTransport.h> +#include <androidfw/Input.h> +#include <androidfw/InputTransport.h> #include <utils/Looper.h> #include <utils/RefBase.h> #include <utils/Vector.h> diff --git a/native/android/obb.cpp b/native/android/obb.cpp index e0cb1a6a9aa6..e9900249b289 100644 --- a/native/android/obb.cpp +++ b/native/android/obb.cpp @@ -18,8 +18,8 @@ #include <android/obb.h> +#include <androidfw/ObbFile.h> #include <utils/Log.h> -#include <utils/ObbFile.h> using namespace android; diff --git a/opengl/java/android/opengl/Group.java b/opengl/java/android/opengl/Group.java deleted file mode 100644 index 1ef29539d2c6..000000000000 --- a/opengl/java/android/opengl/Group.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.opengl; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.ShortBuffer; -import java.io.DataInputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Iterator; -import javax.microedition.khronos.opengles.*; - -class MaterialIndices { - - private Material material = null; - private ShortBuffer indexBuffer = null; - - public MaterialIndices(Material material, ShortBuffer indexBuffer) { - this.material = material; - this.indexBuffer = indexBuffer; - } - - public Material getMaterial() { - return material; - } - - public ShortBuffer getIndexBuffer() { - return indexBuffer; - } -} - -/** - * {@hide} - */ -public class Group { - - private Object3D parent; - private String name; - - private List<MaterialIndices> materialIndices = - new ArrayList<MaterialIndices>(); - - public Group(Object3D parent) { - this.parent = parent; - } - - public String getName() { - return name; - } - - public void load(DataInputStream dis) throws IOException { - dis.readInt(); // name length - this.name = dis.readUTF(); - - int numMaterials = dis.readInt(); - - for (int i = 0; i < numMaterials; i++) { - dis.readInt(); // material name length - String matName = dis.readUTF(); - Material material = parent.getMaterial(matName); - - int numIndices = dis.readInt(); - byte[] indicesBytes = new byte[numIndices * 2]; - dis.readFully(indicesBytes); - - // Swap bytes from network to native order if necessary - if (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) { - int idx = 0; - for (int j = 0; j < numIndices; j++) { - byte b0 = indicesBytes[idx]; - byte b1 = indicesBytes[idx + 1]; - indicesBytes[idx] = b1; - indicesBytes[idx + 1] = b0; - idx += 2; - } - } - - ByteBuffer ibb = ByteBuffer.allocateDirect(2*numIndices); - ibb.order(ByteOrder.nativeOrder()); - ibb.put(indicesBytes); - ibb.position(0); - - ShortBuffer sb = ibb.asShortBuffer(); - materialIndices.add(new MaterialIndices(material, sb)); - } - } - - public int getNumTriangles() { - int numTriangles = 0; - Iterator<MaterialIndices> iter = materialIndices.iterator(); - while (iter.hasNext()) { - MaterialIndices matIdx = iter.next(); - ShortBuffer indexBuffer = matIdx.getIndexBuffer(); - numTriangles += indexBuffer.capacity()/3; - } - return numTriangles; - } - - public void draw(GL10 gl) { - gl.glDisableClientState(gl.GL_COLOR_ARRAY); - - gl.glVertexPointer(3, gl.GL_FIXED, 0, parent.getVertexBuffer()); - gl.glEnableClientState(gl.GL_VERTEX_ARRAY); - - gl.glNormalPointer(gl.GL_FIXED, 0, parent.getNormalBuffer()); - gl.glEnableClientState(gl.GL_NORMAL_ARRAY); - - if (parent.hasTexcoords()) { - gl.glTexCoordPointer(2, gl.GL_FIXED, 0, parent.getTexcoordBuffer()); - gl.glEnableClientState(gl.GL_TEXTURE_COORD_ARRAY); - gl.glEnable(gl.GL_TEXTURE_2D); - } else { - gl.glDisable(gl.GL_TEXTURE_2D); - } - - Iterator<MaterialIndices> iter = materialIndices.iterator(); - while (iter.hasNext()) { - MaterialIndices matIdx = iter.next(); - ShortBuffer indexBuffer = matIdx.getIndexBuffer(); - Material mat = matIdx.getMaterial(); - mat.setMaterialParameters(gl); - if (parent.hasTexcoords() && mat.getMap_Kd().length() > 0) { - Texture texture = parent.getTexture(mat.getMap_Kd()); - texture.setTextureParameters(gl); - } - - gl.glDrawElements(gl.GL_TRIANGLES, - indexBuffer.capacity(), - gl.GL_UNSIGNED_SHORT, - indexBuffer); - } - } - - public String toString() { - return "Group[" + - "name=" + name + - "]"; - } -} diff --git a/opengl/java/android/opengl/Material.java b/opengl/java/android/opengl/Material.java deleted file mode 100644 index 60a3e7256eac..000000000000 --- a/opengl/java/android/opengl/Material.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.opengl; - -import java.io.DataInputStream; -import java.io.IOException; -import javax.microedition.khronos.opengles.GL10; - -/** - * {@hide} - */ -public class Material { - - private Object3D parent; - private String name; - private String map_kd; - private float[] ka = new float[4]; - private float[] kd = new float[4]; - private float[] ks = new float[4]; - private float ns; - private int illum; - private float d; - - private static float[] black = { 0.0f, 0.0f, 0.0f, 1.0f }; - - public Material(Object3D parent) { - this.parent = parent; - } - - public String getName() { - return name; - } - - public String getMap_Kd() { - return map_kd; - } - - public void setMaterialParameters(GL10 gl) { - gl.glMaterialfv(gl.GL_FRONT_AND_BACK, gl.GL_AMBIENT, kd, 0); - gl.glMaterialfv(gl.GL_FRONT_AND_BACK, gl.GL_DIFFUSE, kd, 0); - gl.glMaterialfv(gl.GL_FRONT_AND_BACK, gl.GL_SPECULAR, ks, 0); - gl.glMaterialf(gl.GL_FRONT_AND_BACK, gl.GL_SHININESS, - Math.min(Math.max(ns, 0), 128)); - -// if (illum == 0) { -// gl.glMaterialfv(gl.GL_FRONT_AND_BACK, gl.GL_AMBIENT, kd, 0); -// } else { -// gl.glMaterialfv(gl.GL_FRONT_AND_BACK, gl.GL_AMBIENT, ka, 0); -// gl.glMaterialfv(gl.GL_FRONT_AND_BACK, gl.GL_DIFFUSE, kd, 0); -// } - -// if (illum > 1) { -// gl.glMaterialfv(gl.GL_FRONT_AND_BACK, gl.GL_SPECULAR, ks, 0); -// gl.glMaterialf(gl.GL_FRONT_AND_BACK, gl.GL_SHININESS, -// Math.min(Math.max(ns, 0), 128)); -// } else { -// gl.glMaterialfv(gl.GL_FRONT_AND_BACK, gl.GL_SPECULAR, black, 0); -// } - } - - public void load(DataInputStream dis) throws IOException { - dis.readInt(); // name length - this.name = dis.readUTF(); - - dis.readInt(); // map_kdLength - this.map_kd = dis.readUTF(); - - if (parent.hasTexcoords() && map_kd.length() > 0) { - parent.loadTexture(map_kd); - } - - this.ka[0] = dis.readFloat(); - this.ka[1] = dis.readFloat(); - this.ka[2] = dis.readFloat(); - this.ka[3] = dis.readFloat(); - - this.kd[0] = dis.readFloat(); - this.kd[1] = dis.readFloat(); - this.kd[2] = dis.readFloat(); - this.kd[3] = dis.readFloat(); - - this.ks[0] = dis.readFloat(); - this.ks[1] = dis.readFloat(); - this.ks[2] = dis.readFloat(); - this.ks[3] = dis.readFloat(); - - this.ns = dis.readFloat(); - this.illum = dis.readInt(); - this.d = dis.readFloat(); - } - - public String toString() { - return "Material[" + - "name=\"" + name + "\"," + - "ka={" + ka[0] + "," + ka[1] + "," + ka[2] + "}," + - "kd={" + kd[0] + "," + kd[1] + "," + kd[2] + "}," + - "ks={" + ks[0] + "," + ks[1] + "," + ks[2] + "}," + - "ns=" + ns + "," + - "map_kd=\"" + - (map_kd == null ? "" : map_kd) + - "\"," + - "illum=" + illum + "," + - "d=" + d + - "]"; - } -} diff --git a/opengl/java/android/opengl/Object3D.java b/opengl/java/android/opengl/Object3D.java deleted file mode 100644 index 340c6a788155..000000000000 --- a/opengl/java/android/opengl/Object3D.java +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.opengl; - -import java.io.BufferedReader; -import java.io.DataInputStream; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.IntBuffer; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import javax.microedition.khronos.opengles.*; - -/** - * {@hide} - */ -public abstract class Object3D { - - private boolean mHasTexcoords = false; - - private float mBoundsMinX = Float.MAX_VALUE; - private float mBoundsMaxX = Float.MIN_VALUE; - private float mBoundsMinY = Float.MAX_VALUE; - private float mBoundsMaxY = Float.MIN_VALUE; - private float mBoundsMinZ = Float.MAX_VALUE; - private float mBoundsMaxZ = Float.MIN_VALUE; - - private IntBuffer mVertexBuffer; - private IntBuffer mNormalBuffer; - private IntBuffer mTexcoordBuffer; - - // All groups, by name - private Map<String, Group> mGroups; - - // All materials, by name - private Map<String, Material> mMaterials; - - // All texture maps, by name - private Map<String, Texture> mTextures; - - public Object3D() { - reset(); - } - - /** - * Override this method with an implementation that contructs - * and InputStream from the given filename. For example, if the - * source files are to be retrieved using an AssetManager, - * the implementation would use AssetManager.load() to - * get the input stream. - */ - public abstract InputStream readFile(String filename) throws IOException; - - private void reset() { - mVertexBuffer = mNormalBuffer = mTexcoordBuffer = null; - - mGroups = new HashMap<String,Group>(); - mMaterials = new HashMap<String,Material>(); - mTextures = new HashMap<String,Texture>(); - } - - public Material getMaterial(String name) { - Material mat = mMaterials.get(name); - return mat; - } - - public Texture getTexture(String name) { - return mTextures.get(name); - } - - public IntBuffer getVertexBuffer() { - return mVertexBuffer; - } - - public IntBuffer getNormalBuffer() { - return mNormalBuffer; - } - - public IntBuffer getTexcoordBuffer() { - return mTexcoordBuffer; - } - - public int getNumTriangles() { - int numTriangles = 0; - Iterator<Group> iter = mGroups.values().iterator(); - while (iter.hasNext()) { - numTriangles += iter.next().getNumTriangles(); - } - return numTriangles; - } - - public boolean hasTexcoords() { - return mHasTexcoords; - } - - public float getBoundsMinX() { - return mBoundsMinX; - } - - public float getBoundsMaxX() { - return mBoundsMaxX; - } - - public float getBoundsMinY() { - return mBoundsMinY; - } - - public float getBoundsMaxY() { - return mBoundsMaxY; - } - - public float getBoundsMinZ() { - return mBoundsMinZ; - } - - public float getBoundsMaxZ() { - return mBoundsMaxZ; - } - - public void loadTexture(String name) throws IOException { - InputStream is = readFile(name + ".raw"); - Texture texture = new Texture(is); - mTextures.put(name, texture); - } - - private static void verifyByte(DataInputStream dis, int b) - throws IOException { - int x = dis.read() & 0xff; - if (x != b) { - throw new RuntimeException("Bad byte: " + - x + - " (expected " + b + ")"); - } - } - - public void load(String filename) throws IOException { - reset(); - - DataInputStream dis = new DataInputStream(readFile(filename)); - verifyByte(dis, 'g' + 128); - verifyByte(dis, 'l'); - verifyByte(dis, 'e'); - verifyByte(dis, 's'); - - int numTuples = dis.readInt(); - - this.mBoundsMinX = dis.readFloat(); - this.mBoundsMaxX = dis.readFloat(); - this.mBoundsMinY = dis.readFloat(); - this.mBoundsMaxY = dis.readFloat(); - this.mBoundsMinZ = dis.readFloat(); - this.mBoundsMaxZ = dis.readFloat(); - - this.mHasTexcoords = dis.readInt() == 1; - - int intsPerTuple = mHasTexcoords ? 8 : 6; - int numInts = numTuples*intsPerTuple; - - int len = 4*numTuples*(mHasTexcoords ? 8 : 6); - - byte[] tmp = new byte[len]; - int tidx = 0; - while (tidx < len) { - tidx += dis.read(tmp, tidx, len - tidx); - } - if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) { - for (int i = 0; i < len; i += 4) { - byte tmp0 = tmp[i]; - byte tmp1 = tmp[i + 1]; - byte tmp2 = tmp[i + 2]; - byte tmp3 = tmp[i + 3]; - tmp[i] = tmp3; - tmp[i + 1] = tmp2; - tmp[i + 2] = tmp1; - tmp[i + 3] = tmp0; - } - } - - ByteBuffer allbb = ByteBuffer.allocateDirect(len); - allbb.order(ByteOrder.nativeOrder()); - allbb.put(tmp); - - allbb.position(0); - allbb.limit(4*3*numTuples); - ByteBuffer vbb = allbb.slice(); - this.mVertexBuffer = vbb.asIntBuffer(); - mVertexBuffer.position(0); - - if (mHasTexcoords) { - allbb.position(allbb.limit()); - allbb.limit(allbb.position() + 4*2*numTuples); - ByteBuffer tbb = allbb.slice(); - this.mTexcoordBuffer = tbb.asIntBuffer(); - mTexcoordBuffer.position(0); - } - - allbb.position(allbb.limit()); - allbb.limit(allbb.position() + 4*3*numTuples); - ByteBuffer nbb = allbb.slice(); - this.mNormalBuffer = nbb.asIntBuffer(); - mNormalBuffer.position(0); - - int numMaterials = dis.readInt(); - for (int i = 0; i < numMaterials; i++) { - Material mat = new Material(this); - mat.load(dis); - mMaterials.put(mat.getName(), mat); - } - - int numGroups = dis.readInt(); - for (int i = 0; i < numGroups; i++) { - Group g = new Group(this); - g.load(dis); - mGroups.put(g.getName(), g); - } - } - - public void draw(GL10 gl) { - Iterator<Group> iter = mGroups.values().iterator(); - while (iter.hasNext()) { - iter.next().draw(gl); - } - } -} - diff --git a/opengl/java/android/opengl/Texture.java b/opengl/java/android/opengl/Texture.java deleted file mode 100644 index dcd894d19cfc..000000000000 --- a/opengl/java/android/opengl/Texture.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.opengl; - -import java.io.InputStream; -import java.io.IOException; -import java.nio.Buffer; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import javax.microedition.khronos.opengles.GL10; - -import android.content.res.AssetManager; - -/** - * {@hide} - */ -public class Texture { - - private int width, height, bpp; - private ByteBuffer data; - private int name = -1; - - // Texture maps have the following format. All integers - // are 16 bits, high byte first. Pixels are in 5/6/5 - // RGB format, low byte first. - // - // width - // height - // pixel (0, 0) - // pixel (1, 0) - // ... - // pixel (width - 1, height - 1) - - private int readInt16(InputStream is) throws IOException { - return is.read() | (is.read() << 8); - } - - public Texture(InputStream is) throws IOException { - this.width = readInt16(is); - this.height = readInt16(is); - this.bpp = 2; - - int npixels = width*height; - int nbytes = npixels*bpp; - byte[] arr = new byte[nbytes]; - - int idx = 0; - while (idx < nbytes) { - int nread = is.read(arr, idx, nbytes - idx); - idx += nread; - } - - if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) { - // Swap pairs of bytes on big-endian platforms - for (int i = 0; i < npixels; i++) { - int j = i*2; - int k = j + 1; - - byte tmp = arr[j]; - arr[j] = arr[k]; - arr[k] = tmp; - } - } - - this.data = ByteBuffer.allocateDirect(arr.length); - this.data.order(ByteOrder.nativeOrder()); - data.put(arr); - data.position(0); - } - - private int loadTexture(GL10 gl, - int textureUnit, - int minFilter, int magFilter, - int wrapS, int wrapT, - int mode, - int width, int height, - int dataType, - Buffer data) { - int[] texture = new int[1]; - gl.glGenTextures(1, texture, 0); - - gl.glEnable(gl.GL_TEXTURE_2D); - gl.glClientActiveTexture(textureUnit); - gl.glBindTexture(gl.GL_TEXTURE_2D, texture[0]); - gl.glTexParameterf(gl.GL_TEXTURE_2D, - gl.GL_TEXTURE_MIN_FILTER, - minFilter); - gl.glTexParameterf(gl.GL_TEXTURE_2D, - gl.GL_TEXTURE_MAG_FILTER, - magFilter); - gl.glTexParameterf(gl.GL_TEXTURE_2D, - gl.GL_TEXTURE_WRAP_S, - wrapS); - gl.glTexParameterf(gl.GL_TEXTURE_2D, - gl.GL_TEXTURE_WRAP_T, - wrapT); - gl.glTexEnvf(gl.GL_TEXTURE_ENV, gl.GL_TEXTURE_ENV_MODE, mode); - - gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_RGB, - width, height, - 0, gl.GL_RGB, dataType, - data); - - return texture[0]; - } - - public void setTextureParameters(GL10 gl) { - if (name < 0) { - name = loadTexture(gl, - gl.GL_TEXTURE0, - gl.GL_NEAREST, gl.GL_NEAREST, - gl.GL_REPEAT, gl.GL_REPEAT, - gl.GL_MODULATE, - width, height, - gl.GL_UNSIGNED_SHORT_5_6_5, - data); - } - - gl.glBindTexture(gl.GL_TEXTURE_2D, name); - } -} diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp index 06be2ef1147f..0b1016c23f12 100644 --- a/opengl/libs/EGL/Loader.cpp +++ b/opengl/libs/EGL/Loader.cpp @@ -118,12 +118,6 @@ status_t Loader::driver_t::set(void* hnd, int32_t api) // ---------------------------------------------------------------------------- -Loader::entry_t::entry_t(int dpy, int impl, const char* tag) - : dpy(dpy), impl(impl), tag(tag) { -} - -// ---------------------------------------------------------------------------- - Loader::Loader() { char line[256]; @@ -131,8 +125,9 @@ Loader::Loader() /* Special case for GLES emulation */ if (checkGlesEmulationStatus() == 0) { - ALOGD("Emulator without GPU support detected. Fallback to software renderer."); - gConfig.add( entry_t(0, 0, "android") ); + ALOGD("Emulator without GPU support detected. " + "Fallback to software renderer."); + mDriverTag.setTo("android"); return; } @@ -141,14 +136,16 @@ Loader::Loader() if (cfg == NULL) { // default config ALOGD("egl.cfg not found, using default config"); - gConfig.add( entry_t(0, 0, "android") ); + mDriverTag.setTo("android"); } else { while (fgets(line, 256, cfg)) { - int dpy; - int impl; + int dpy, impl; if (sscanf(line, "%u %u %s", &dpy, &impl, tag) == 3) { //ALOGD(">>> %u %u %s", dpy, impl, tag); - gConfig.add( entry_t(dpy, impl, tag) ); + // We only load the h/w accelerated implementation + if (tag != String8("android")) { + mDriverTag = tag; + } } } fclose(cfg); @@ -160,30 +157,12 @@ Loader::~Loader() GLTrace_stop(); } -const char* Loader::getTag(int dpy, int impl) +void* Loader::open(egl_connection_t* cnx) { - const Vector<entry_t>& cfgs(gConfig); - const size_t c = cfgs.size(); - for (size_t i=0 ; i<c ; i++) { - if (dpy == cfgs[i].dpy) - if (impl == cfgs[i].impl) - return cfgs[i].tag.string(); - } - return 0; -} - -void* Loader::open(EGLNativeDisplayType display, int impl, egl_connection_t* cnx) -{ - /* - * TODO: if we don't find display/0, then use 0/0 - * (0/0 should always work) - */ - void* dso; - int index = int(display); driver_t* hnd = 0; - char const* tag = getTag(index, impl); + char const* tag = mDriverTag.string(); if (tag) { dso = load_driver("GLES", tag, cnx, EGL | GLESv1_CM | GLESv2); if (dso) { @@ -193,16 +172,14 @@ void* Loader::open(EGLNativeDisplayType display, int impl, egl_connection_t* cnx dso = load_driver("EGL", tag, cnx, EGL); if (dso) { hnd = new driver_t(dso); - // TODO: make this more automated hnd->set( load_driver("GLESv1_CM", tag, cnx, GLESv1_CM), GLESv1_CM ); - - hnd->set( load_driver("GLESv2", tag, cnx, GLESv2), GLESv2 ); + hnd->set( load_driver("GLESv2", tag, cnx, GLESv2), GLESv2 ); } } } - LOG_FATAL_IF(!index && !impl && !hnd, + LOG_FATAL_IF(!index && !hnd, "couldn't find the default OpenGL ES implementation " "for default display"); @@ -221,7 +198,7 @@ void Loader::init_api(void* dso, __eglMustCastToProperFunctionPointerType* curr, getProcAddressType getProcAddress) { - const size_t SIZE = 256; + const ssize_t SIZE = 256; char scrap[SIZE]; while (*api) { char const * name = *api; @@ -326,14 +303,14 @@ void *Loader::load_driver(const char* kind, const char *tag, if (mask & GLESv1_CM) { init_api(dso, gl_names, (__eglMustCastToProperFunctionPointerType*) - &cnx->hooks[GLESv1_INDEX]->gl, + &cnx->hooks[egl_connection_t::GLESv1_INDEX]->gl, getProcAddress); } if (mask & GLESv2) { init_api(dso, gl_names, (__eglMustCastToProperFunctionPointerType*) - &cnx->hooks[GLESv2_INDEX]->gl, + &cnx->hooks[egl_connection_t::GLESv2_INDEX]->gl, getProcAddress); } diff --git a/opengl/libs/EGL/Loader.h b/opengl/libs/EGL/Loader.h index 580d6e4c39c8..30773cb6db03 100644 --- a/opengl/libs/EGL/Loader.h +++ b/opengl/libs/EGL/Loader.h @@ -24,7 +24,6 @@ #include <utils/Errors.h> #include <utils/Singleton.h> #include <utils/String8.h> -#include <utils/Vector.h> #include <EGL/egl.h> @@ -53,23 +52,13 @@ class Loader : public Singleton<Loader> void* dso[3]; }; - struct entry_t { - entry_t() { } - entry_t(int dpy, int impl, const char* tag); - int dpy; - int impl; - String8 tag; - }; - - Vector<entry_t> gConfig; + String8 mDriverTag; getProcAddressType getProcAddress; - const char* getTag(int dpy, int impl); - public: ~Loader(); - void* open(EGLNativeDisplayType display, int impl, egl_connection_t* cnx); + void* open(egl_connection_t* cnx); status_t close(void* driver); private: diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp index 83933e525211..eec5ce1a0677 100644 --- a/opengl/libs/EGL/egl.cpp +++ b/opengl/libs/EGL/egl.cpp @@ -48,8 +48,8 @@ namespace android { // ---------------------------------------------------------------------------- -egl_connection_t gEGLImpl[IMPL_NUM_IMPLEMENTATIONS]; -gl_hooks_t gHooks[2][IMPL_NUM_IMPLEMENTATIONS]; +egl_connection_t gEGLImpl; +gl_hooks_t gHooks[2]; gl_hooks_t gHooksNoContext; pthread_key_t gGLWrapperKey = -1; @@ -187,16 +187,13 @@ egl_display_t* validate_display(EGLDisplay dpy) { return dp; } -egl_connection_t* validate_display_config(EGLDisplay dpy, EGLConfig config, +egl_connection_t* validate_display_config(EGLDisplay dpy, EGLConfig, egl_display_t const*& dp) { dp = validate_display(dpy); if (!dp) return (egl_connection_t*) NULL; - if (intptr_t(config) >= dp->numTotalConfigs) { - return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL); - } - egl_connection_t* const cnx = &gEGLImpl[dp->configs[intptr_t(config)].impl]; + egl_connection_t* const cnx = &gEGLImpl; if (cnx->dso == 0) { return setError(EGL_BAD_CONFIG, (egl_connection_t*)NULL); } @@ -205,34 +202,6 @@ egl_connection_t* validate_display_config(EGLDisplay dpy, EGLConfig config, // ---------------------------------------------------------------------------- -EGLImageKHR egl_get_image_for_current_context(EGLImageKHR image) -{ - EGLContext context = egl_tls_t::getContext(); - if (context == EGL_NO_CONTEXT || image == EGL_NO_IMAGE_KHR) - return EGL_NO_IMAGE_KHR; - - egl_context_t const * const c = get_context(context); - if (c == NULL) // this should never happen, by construction - return EGL_NO_IMAGE_KHR; - - egl_display_t* display = egl_display_t::get(c->dpy); - if (display == NULL) // this should never happen, by construction - return EGL_NO_IMAGE_KHR; - - ImageRef _i(display, image); - if (!_i.get()) - return EGL_NO_IMAGE_KHR; - - // here we don't validate the context because if it's been marked for - // termination, this call should still succeed since it's internal to - // EGL. - - egl_image_t const * const i = get_image(image); - return i->images[c->impl]; -} - -// ---------------------------------------------------------------------------- - const GLubyte * egl_get_string_for_current_context(GLenum name) { // NOTE: returning NULL here will fall-back to the default // implementation. @@ -266,34 +235,17 @@ static EGLBoolean egl_init_drivers_locked() { // get our driver loader Loader& loader(Loader::getInstance()); - // dynamically load all our EGL implementations - egl_connection_t* cnx; - - cnx = &gEGLImpl[IMPL_SOFTWARE]; - if (cnx->dso == 0) { - cnx->hooks[GLESv1_INDEX] = &gHooks[GLESv1_INDEX][IMPL_SOFTWARE]; - cnx->hooks[GLESv2_INDEX] = &gHooks[GLESv2_INDEX][IMPL_SOFTWARE]; - cnx->dso = loader.open(EGL_DEFAULT_DISPLAY, 0, cnx); - } - - cnx = &gEGLImpl[IMPL_HARDWARE]; + // dynamically load our EGL implementation + egl_connection_t* cnx = &gEGLImpl; if (cnx->dso == 0) { - char value[PROPERTY_VALUE_MAX]; - property_get("debug.egl.hw", value, "1"); - if (atoi(value) != 0) { - cnx->hooks[GLESv1_INDEX] = &gHooks[GLESv1_INDEX][IMPL_HARDWARE]; - cnx->hooks[GLESv2_INDEX] = &gHooks[GLESv2_INDEX][IMPL_HARDWARE]; - cnx->dso = loader.open(EGL_DEFAULT_DISPLAY, 1, cnx); - } else { - ALOGD("3D hardware acceleration is disabled"); - } - } - - if (!gEGLImpl[IMPL_SOFTWARE].dso && !gEGLImpl[IMPL_HARDWARE].dso) { - return EGL_FALSE; + cnx->hooks[egl_connection_t::GLESv1_INDEX] = + &gHooks[egl_connection_t::GLESv1_INDEX]; + cnx->hooks[egl_connection_t::GLESv2_INDEX] = + &gHooks[egl_connection_t::GLESv2_INDEX]; + cnx->dso = loader.open(cnx); } - return EGL_TRUE; + return cnx->dso ? EGL_TRUE : EGL_FALSE; } static pthread_mutex_t sInitDriverMutex = PTHREAD_MUTEX_INITIALIZER; diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp index 73aab26cc76c..a5dc832bf6de 100644 --- a/opengl/libs/EGL/eglApi.cpp +++ b/opengl/libs/EGL/eglApi.cpp @@ -44,6 +44,7 @@ #include "egl_impl.h" #include "egl_object.h" #include "egl_tls.h" +#include "egldefs.h" using namespace android; @@ -88,24 +89,6 @@ static void(*findProcAddress(const char* name, // ---------------------------------------------------------------------------- -template<typename T> -static __attribute__((noinline)) -int binarySearch(T const sortedArray[], int first, int last, T key) { - while (first <= last) { - int mid = (first + last) / 2; - if (sortedArray[mid] < key) { - first = mid + 1; - } else if (key < sortedArray[mid]) { - last = mid - 1; - } else { - return mid; - } - } - return -1; -} - -// ---------------------------------------------------------------------------- - namespace android { extern void setGLHooksThreadSpecific(gl_hooks_t const *value); extern EGLBoolean egl_init_drivers(); @@ -183,21 +166,20 @@ EGLBoolean eglGetConfigs( EGLDisplay dpy, egl_display_t const * const dp = validate_display(dpy); if (!dp) return EGL_FALSE; - GLint numConfigs = dp->numTotalConfigs; - if (!configs) { - *num_config = numConfigs; - return EGL_TRUE; + if (num_config==0) { + return setError(EGL_BAD_PARAMETER, EGL_FALSE); } - GLint n = 0; - for (intptr_t i=0 ; i<dp->numTotalConfigs && config_size ; i++) { - *configs++ = EGLConfig(i); - config_size--; - n++; + EGLBoolean res = EGL_FALSE; + *num_config = 0; + + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso) { + res = cnx->egl.eglGetConfigs( + dp->disp.dpy, configs, config_size, num_config); } - - *num_config = n; - return EGL_TRUE; + + return res; } EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list, @@ -213,105 +195,13 @@ EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list, return setError(EGL_BAD_PARAMETER, EGL_FALSE); } - EGLint n; EGLBoolean res = EGL_FALSE; *num_config = 0; - - // It is unfortunate, but we need to remap the EGL_CONFIG_IDs, - // to do this, we have to go through the attrib_list array once - // to figure out both its size and if it contains an EGL_CONFIG_ID - // key. If so, the full array is copied and patched. - // NOTE: we assume that there can be only one occurrence - // of EGL_CONFIG_ID. - - EGLint patch_index = -1; - GLint attr; - size_t size = 0; - if (attrib_list) { - while ((attr=attrib_list[size]) != EGL_NONE) { - if (attr == EGL_CONFIG_ID) - patch_index = size; - size += 2; - } - } - if (patch_index >= 0) { - size += 2; // we need copy the sentinel as well - EGLint* new_list = (EGLint*)malloc(size*sizeof(EGLint)); - if (new_list == 0) - return setError(EGL_BAD_ALLOC, EGL_FALSE); - memcpy(new_list, attrib_list, size*sizeof(EGLint)); - - // patch the requested EGL_CONFIG_ID - bool found = false; - EGLConfig ourConfig(0); - EGLint& configId(new_list[patch_index+1]); - for (intptr_t i=0 ; i<dp->numTotalConfigs ; i++) { - if (dp->configs[i].configId == configId) { - ourConfig = EGLConfig(i); - configId = dp->configs[i].implConfigId; - found = true; - break; - } - } - - egl_connection_t* const cnx = &gEGLImpl[dp->configs[intptr_t(ourConfig)].impl]; - if (found && cnx->dso) { - // and switch to the new list - attrib_list = const_cast<const EGLint *>(new_list); - - // At this point, the only configuration that can match is - // dp->configs[i][index], however, we don't know if it would be - // rejected because of the other attributes, so we do have to call - // cnx->egl.eglChooseConfig() -- but we don't have to loop - // through all the EGLimpl[]. - // We also know we can only get a single config back, and we know - // which one. - - res = cnx->egl.eglChooseConfig( - dp->disp[ dp->configs[intptr_t(ourConfig)].impl ].dpy, - attrib_list, configs, config_size, &n); - if (res && n>0) { - // n has to be 0 or 1, by construction, and we already know - // which config it will return (since there can be only one). - if (configs) { - configs[0] = ourConfig; - } - *num_config = 1; - } - } - - free(const_cast<EGLint *>(attrib_list)); - return res; - } - - - for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) { - egl_connection_t* const cnx = &gEGLImpl[i]; - if (cnx->dso) { - if (cnx->egl.eglChooseConfig( - dp->disp[i].dpy, attrib_list, configs, config_size, &n)) { - if (configs) { - // now we need to convert these client EGLConfig to our - // internal EGLConfig format. - // This is done in O(n Log(n)) time. - for (int j=0 ; j<n ; j++) { - egl_config_t key(i, configs[j]); - intptr_t index = binarySearch<egl_config_t>( - dp->configs, 0, dp->numTotalConfigs, key); - if (index >= 0) { - configs[j] = EGLConfig(index); - } else { - return setError(EGL_BAD_CONFIG, EGL_FALSE); - } - } - configs += n; - config_size -= n; - } - *num_config += n; - res = EGL_TRUE; - } - } + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso) { + res = cnx->egl.eglChooseConfig( + dp->disp.dpy, attrib_list, configs, config_size, num_config); } return res; } @@ -325,13 +215,8 @@ EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, egl_connection_t* cnx = validate_display_config(dpy, config, dp); if (!cnx) return EGL_FALSE; - if (attribute == EGL_CONFIG_ID) { - *value = dp->configs[intptr_t(config)].configId; - return EGL_TRUE; - } return cnx->egl.eglGetConfigAttrib( - dp->disp[ dp->configs[intptr_t(config)].impl ].dpy, - dp->configs[intptr_t(config)].config, attribute, value); + dp->disp.dpy, config, attribute, value); } // ---------------------------------------------------------------------------- @@ -347,8 +232,7 @@ EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, egl_display_t const* dp = 0; egl_connection_t* cnx = validate_display_config(dpy, config, dp); if (cnx) { - EGLDisplay iDpy = dp->disp[ dp->configs[intptr_t(config)].impl ].dpy; - EGLConfig iConfig = dp->configs[intptr_t(config)].config; + EGLDisplay iDpy = dp->disp.dpy; EGLint format; if (native_window_api_connect(window, NATIVE_WINDOW_API_EGL) != OK) { @@ -359,7 +243,7 @@ EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, // set the native window's buffers format to match this config if (cnx->egl.eglGetConfigAttrib(iDpy, - iConfig, EGL_NATIVE_VISUAL_ID, &format)) { + config, EGL_NATIVE_VISUAL_ID, &format)) { if (format != 0) { int err = native_window_set_buffers_format(window, format); if (err != 0) { @@ -377,10 +261,9 @@ EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config, anw->setSwapInterval(anw, 1); EGLSurface surface = cnx->egl.eglCreateWindowSurface( - iDpy, iConfig, window, attrib_list); + iDpy, config, window, attrib_list); if (surface != EGL_NO_SURFACE) { - egl_surface_t* s = new egl_surface_t(dpy, config, window, surface, - dp->configs[intptr_t(config)].impl, cnx); + egl_surface_t* s = new egl_surface_t(dpy, config, window, surface, cnx); return s; } @@ -401,11 +284,9 @@ EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config, egl_connection_t* cnx = validate_display_config(dpy, config, dp); if (cnx) { EGLSurface surface = cnx->egl.eglCreatePixmapSurface( - dp->disp[ dp->configs[intptr_t(config)].impl ].dpy, - dp->configs[intptr_t(config)].config, pixmap, attrib_list); + dp->disp.dpy, config, pixmap, attrib_list); if (surface != EGL_NO_SURFACE) { - egl_surface_t* s = new egl_surface_t(dpy, config, NULL, surface, - dp->configs[intptr_t(config)].impl, cnx); + egl_surface_t* s = new egl_surface_t(dpy, config, NULL, surface, cnx); return s; } } @@ -421,11 +302,9 @@ EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config, egl_connection_t* cnx = validate_display_config(dpy, config, dp); if (cnx) { EGLSurface surface = cnx->egl.eglCreatePbufferSurface( - dp->disp[ dp->configs[intptr_t(config)].impl ].dpy, - dp->configs[intptr_t(config)].config, attrib_list); + dp->disp.dpy, config, attrib_list); if (surface != EGL_NO_SURFACE) { - egl_surface_t* s = new egl_surface_t(dpy, config, NULL, surface, - dp->configs[intptr_t(config)].impl, cnx); + egl_surface_t* s = new egl_surface_t(dpy, config, NULL, surface, cnx); return s; } } @@ -444,8 +323,7 @@ EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface) return setError(EGL_BAD_SURFACE, EGL_FALSE); egl_surface_t * const s = get_surface(surface); - EGLBoolean result = s->cnx->egl.eglDestroySurface( - dp->disp[s->impl].dpy, s->surface); + EGLBoolean result = s->cnx->egl.eglDestroySurface(dp->disp.dpy, s->surface); if (result == EGL_TRUE) { _s.terminate(); } @@ -465,16 +343,8 @@ EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface, return setError(EGL_BAD_SURFACE, EGL_FALSE); egl_surface_t const * const s = get_surface(surface); - EGLBoolean result(EGL_TRUE); - if (attribute == EGL_CONFIG_ID) { - // We need to remap EGL_CONFIG_IDs - *value = dp->configs[intptr_t(s->config)].configId; - } else { - result = s->cnx->egl.eglQuerySurface( - dp->disp[s->impl].dpy, s->surface, attribute, value); - } - - return result; + return s->cnx->egl.eglQuerySurface( + dp->disp.dpy, s->surface, attribute, value); } void EGLAPI eglBeginFrame(EGLDisplay dpy, EGLSurface surface) { @@ -514,9 +384,7 @@ EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, share_list = c->context; } EGLContext context = cnx->egl.eglCreateContext( - dp->disp[ dp->configs[intptr_t(config)].impl ].dpy, - dp->configs[intptr_t(config)].config, - share_list, attrib_list); + dp->disp.dpy, config, share_list, attrib_list); if (context != EGL_NO_CONTEXT) { // figure out if it's a GLESv1 or GLESv2 int version = 0; @@ -526,15 +394,14 @@ EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, GLint value = *attrib_list++; if (attr == EGL_CONTEXT_CLIENT_VERSION) { if (value == 1) { - version = GLESv1_INDEX; + version = egl_connection_t::GLESv1_INDEX; } else if (value == 2) { - version = GLESv2_INDEX; + version = egl_connection_t::GLESv2_INDEX; } } }; } - egl_context_t* c = new egl_context_t(dpy, context, config, - dp->configs[intptr_t(config)].impl, cnx, version); + egl_context_t* c = new egl_context_t(dpy, context, config, cnx, version); #if EGL_TRACE if (gEGLDebugLevel > 0) GLTrace_eglCreateContext(version, c); @@ -558,8 +425,7 @@ EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx) return setError(EGL_BAD_CONTEXT, EGL_FALSE); egl_context_t * const c = get_context(ctx); - EGLBoolean result = c->cnx->egl.eglDestroyContext( - dp->disp[c->impl].dpy, c->context); + EGLBoolean result = c->cnx->egl.eglDestroyContext(dp->disp.dpy, c->context); if (result == EGL_TRUE) { _c.terminate(); } @@ -625,20 +491,12 @@ EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw, // retrieve the underlying implementation's draw EGLSurface if (draw != EGL_NO_SURFACE) { d = get_surface(draw); - // make sure the EGLContext and EGLSurface passed in are for - // the same driver - if (c && d->impl != c->impl) - return setError(EGL_BAD_MATCH, EGL_FALSE); impl_draw = d->surface; } // retrieve the underlying implementation's read EGLSurface if (read != EGL_NO_SURFACE) { r = get_surface(read); - // make sure the EGLContext and EGLSurface passed in are for - // the same driver - if (c && r->impl != c->impl) - return setError(EGL_BAD_MATCH, EGL_FALSE); impl_read = r->surface; } @@ -682,17 +540,9 @@ EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx, if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE); egl_context_t * const c = get_context(ctx); + return c->cnx->egl.eglQueryContext( + dp->disp.dpy, c->context, attribute, value); - EGLBoolean result(EGL_TRUE); - if (attribute == EGL_CONFIG_ID) { - *value = dp->configs[intptr_t(c->config)].configId; - } else { - // We need to remap EGL_CONFIG_IDs - result = c->cnx->egl.eglQueryContext( - dp->disp[c->impl].dpy, c->context, attribute, value); - } - - return result; } EGLContext eglGetCurrentContext(void) @@ -744,87 +594,37 @@ EGLDisplay eglGetCurrentDisplay(void) EGLBoolean eglWaitGL(void) { - // could be called before eglInitialize(), but we wouldn't have a context - // then, and this function would return GL_TRUE, which isn't wrong. - clearError(); - EGLBoolean res = EGL_TRUE; - EGLContext ctx = getContext(); - if (ctx) { - egl_context_t const * const c = get_context(ctx); - if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE); - if (uint32_t(c->impl)>=2) - return setError(EGL_BAD_CONTEXT, EGL_FALSE); - egl_connection_t* const cnx = &gEGLImpl[c->impl]; - if (!cnx->dso) - return setError(EGL_BAD_CONTEXT, EGL_FALSE); - res = cnx->egl.eglWaitGL(); - } - return res; + egl_connection_t* const cnx = &gEGLImpl; + if (!cnx->dso) + return setError(EGL_BAD_CONTEXT, EGL_FALSE); + + return cnx->egl.eglWaitGL(); } EGLBoolean eglWaitNative(EGLint engine) { - // could be called before eglInitialize(), but we wouldn't have a context - // then, and this function would return GL_TRUE, which isn't wrong. - clearError(); - EGLBoolean res = EGL_TRUE; - EGLContext ctx = getContext(); - if (ctx) { - egl_context_t const * const c = get_context(ctx); - if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE); - if (uint32_t(c->impl)>=2) - return setError(EGL_BAD_CONTEXT, EGL_FALSE); - egl_connection_t* const cnx = &gEGLImpl[c->impl]; - if (!cnx->dso) - return setError(EGL_BAD_CONTEXT, EGL_FALSE); - res = cnx->egl.eglWaitNative(engine); - } - return res; + egl_connection_t* const cnx = &gEGLImpl; + if (!cnx->dso) + return setError(EGL_BAD_CONTEXT, EGL_FALSE); + + return cnx->egl.eglWaitNative(engine); } EGLint eglGetError(void) { - EGLint result = EGL_SUCCESS; - EGLint err; - for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) { - err = EGL_SUCCESS; - egl_connection_t* const cnx = &gEGLImpl[i]; - if (cnx->dso) - err = cnx->egl.eglGetError(); - if (err!=EGL_SUCCESS && result==EGL_SUCCESS) - result = err; + EGLint err = EGL_SUCCESS; + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso) { + err = cnx->egl.eglGetError(); } - err = egl_tls_t::getError(); - if (result == EGL_SUCCESS) - result = err; - return result; -} - -// Note: Similar implementations of these functions also exist in -// gl2.cpp and gl.cpp, and are used by applications that call the -// exported entry points directly. -typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image); -typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image); - -static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES_impl = NULL; -static PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES_impl = NULL; - -static void glEGLImageTargetTexture2DOES_wrapper(GLenum target, GLeglImageOES image) -{ - GLeglImageOES implImage = - (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image); - glEGLImageTargetTexture2DOES_impl(target, implImage); -} - -static void glEGLImageTargetRenderbufferStorageOES_wrapper(GLenum target, GLeglImageOES image) -{ - GLeglImageOES implImage = - (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image); - glEGLImageTargetRenderbufferStorageOES_impl(target, implImage); + if (err == EGL_SUCCESS) { + err = egl_tls_t::getError(); + } + return err; } __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname) @@ -885,32 +685,22 @@ __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname) if (!addr && (slot < MAX_NUMBER_OF_GL_EXTENSIONS)) { bool found = false; - for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) { - egl_connection_t* const cnx = &gEGLImpl[i]; - if (cnx->dso && cnx->egl.eglGetProcAddress) { - found = true; - // Extensions are independent of the bound context - cnx->hooks[GLESv1_INDEX]->ext.extensions[slot] = - cnx->hooks[GLESv2_INDEX]->ext.extensions[slot] = + + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglGetProcAddress) { + found = true; + // Extensions are independent of the bound context + cnx->hooks[egl_connection_t::GLESv1_INDEX]->ext.extensions[slot] = + cnx->hooks[egl_connection_t::GLESv2_INDEX]->ext.extensions[slot] = #if EGL_TRACE - debugHooks->ext.extensions[slot] = - gHooksTrace.ext.extensions[slot] = + debugHooks->ext.extensions[slot] = + gHooksTrace.ext.extensions[slot] = #endif - cnx->egl.eglGetProcAddress(procname); - } + cnx->egl.eglGetProcAddress(procname); } + if (found) { addr = gExtensionForwarders[slot]; - - if (!strcmp(procname, "glEGLImageTargetTexture2DOES")) { - glEGLImageTargetTexture2DOES_impl = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)addr; - addr = (__eglMustCastToProperFunctionPointerType)glEGLImageTargetTexture2DOES_wrapper; - } - if (!strcmp(procname, "glEGLImageTargetRenderbufferStorageOES")) { - glEGLImageTargetRenderbufferStorageOES_impl = (PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC)addr; - addr = (__eglMustCastToProperFunctionPointerType)glEGLImageTargetRenderbufferStorageOES_wrapper; - } - sGLExtentionMap.add(name, addr); sGLExtentionSlot++; } @@ -937,7 +727,7 @@ EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw) #endif egl_surface_t const * const s = get_surface(draw); - return s->cnx->egl.eglSwapBuffers(dp->disp[s->impl].dpy, s->surface); + return s->cnx->egl.eglSwapBuffers(dp->disp.dpy, s->surface); } EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface, @@ -953,8 +743,7 @@ EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface surface, return setError(EGL_BAD_SURFACE, EGL_FALSE); egl_surface_t const * const s = get_surface(surface); - return s->cnx->egl.eglCopyBuffers( - dp->disp[s->impl].dpy, s->surface, target); + return s->cnx->egl.eglCopyBuffers(dp->disp.dpy, s->surface, target); } const char* eglQueryString(EGLDisplay dpy, EGLint name) @@ -973,12 +762,8 @@ const char* eglQueryString(EGLDisplay dpy, EGLint name) return dp->getExtensionString(); case EGL_CLIENT_APIS: return dp->getClientApiString(); - case EGL_VERSION_HW_ANDROID: { - if (gEGLImpl[IMPL_HARDWARE].dso) { - return dp->disp[IMPL_HARDWARE].queryString.version; - } - return dp->disp[IMPL_SOFTWARE].queryString.version; - } + case EGL_VERSION_HW_ANDROID: + return dp->disp.queryString.version; } return setError(EGL_BAD_PARAMETER, (const char *)0); } @@ -1003,7 +788,7 @@ EGLBoolean eglSurfaceAttrib( egl_surface_t const * const s = get_surface(surface); if (s->cnx->egl.eglSurfaceAttrib) { return s->cnx->egl.eglSurfaceAttrib( - dp->disp[s->impl].dpy, s->surface, attribute, value); + dp->disp.dpy, s->surface, attribute, value); } return setError(EGL_BAD_SURFACE, EGL_FALSE); } @@ -1023,7 +808,7 @@ EGLBoolean eglBindTexImage( egl_surface_t const * const s = get_surface(surface); if (s->cnx->egl.eglBindTexImage) { return s->cnx->egl.eglBindTexImage( - dp->disp[s->impl].dpy, s->surface, buffer); + dp->disp.dpy, s->surface, buffer); } return setError(EGL_BAD_SURFACE, EGL_FALSE); } @@ -1043,7 +828,7 @@ EGLBoolean eglReleaseTexImage( egl_surface_t const * const s = get_surface(surface); if (s->cnx->egl.eglReleaseTexImage) { return s->cnx->egl.eglReleaseTexImage( - dp->disp[s->impl].dpy, s->surface, buffer); + dp->disp.dpy, s->surface, buffer); } return setError(EGL_BAD_SURFACE, EGL_FALSE); } @@ -1056,17 +841,11 @@ EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval) if (!dp) return EGL_FALSE; EGLBoolean res = EGL_TRUE; - for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) { - egl_connection_t* const cnx = &gEGLImpl[i]; - if (cnx->dso) { - if (cnx->egl.eglSwapInterval) { - if (cnx->egl.eglSwapInterval( - dp->disp[i].dpy, interval) == EGL_FALSE) { - res = EGL_FALSE; - } - } - } + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglSwapInterval) { + res = cnx->egl.eglSwapInterval(dp->disp.dpy, interval); } + return res; } @@ -1079,23 +858,15 @@ EGLBoolean eglWaitClient(void) { clearError(); - // could be called before eglInitialize(), but we wouldn't have a context - // then, and this function would return GL_TRUE, which isn't wrong. - EGLBoolean res = EGL_TRUE; - EGLContext ctx = getContext(); - if (ctx) { - egl_context_t const * const c = get_context(ctx); - if (!c) return setError(EGL_BAD_CONTEXT, EGL_FALSE); - if (uint32_t(c->impl)>=2) - return setError(EGL_BAD_CONTEXT, EGL_FALSE); - egl_connection_t* const cnx = &gEGLImpl[c->impl]; - if (!cnx->dso) - return setError(EGL_BAD_CONTEXT, EGL_FALSE); - if (cnx->egl.eglWaitClient) { - res = cnx->egl.eglWaitClient(); - } else { - res = cnx->egl.eglWaitGL(); - } + egl_connection_t* const cnx = &gEGLImpl; + if (!cnx->dso) + return setError(EGL_BAD_CONTEXT, EGL_FALSE); + + EGLBoolean res; + if (cnx->egl.eglWaitClient) { + res = cnx->egl.eglWaitClient(); + } else { + res = cnx->egl.eglWaitGL(); } return res; } @@ -1110,15 +881,9 @@ EGLBoolean eglBindAPI(EGLenum api) // bind this API on all EGLs EGLBoolean res = EGL_TRUE; - for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) { - egl_connection_t* const cnx = &gEGLImpl[i]; - if (cnx->dso) { - if (cnx->egl.eglBindAPI) { - if (cnx->egl.eglBindAPI(api) == EGL_FALSE) { - res = EGL_FALSE; - } - } - } + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglBindAPI) { + res = cnx->egl.eglBindAPI(api); } return res; } @@ -1131,16 +896,11 @@ EGLenum eglQueryAPI(void) return setError(EGL_BAD_PARAMETER, EGL_FALSE); } - for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) { - egl_connection_t* const cnx = &gEGLImpl[i]; - if (cnx->dso) { - if (cnx->egl.eglQueryAPI) { - // the first one we find is okay, because they all - // should be the same - return cnx->egl.eglQueryAPI(); - } - } + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglQueryAPI) { + return cnx->egl.eglQueryAPI(); } + // or, it can only be OpenGL ES return EGL_OPENGL_ES_API; } @@ -1152,14 +912,11 @@ EGLBoolean eglReleaseThread(void) // If there is context bound to the thread, release it egl_display_t::loseCurrent(get_context(getContext())); - for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) { - egl_connection_t* const cnx = &gEGLImpl[i]; - if (cnx->dso) { - if (cnx->egl.eglReleaseThread) { - cnx->egl.eglReleaseThread(); - } - } + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglReleaseThread) { + cnx->egl.eglReleaseThread(); } + egl_tls_t::clearTLS(); #if EGL_TRACE if (gEGLDebugLevel > 0) @@ -1179,9 +936,7 @@ EGLSurface eglCreatePbufferFromClientBuffer( if (!cnx) return EGL_FALSE; if (cnx->egl.eglCreatePbufferFromClientBuffer) { return cnx->egl.eglCreatePbufferFromClientBuffer( - dp->disp[ dp->configs[intptr_t(config)].impl ].dpy, - buftype, buffer, - dp->configs[intptr_t(config)].config, attrib_list); + dp->disp.dpy, buftype, buffer, config, attrib_list); } return setError(EGL_BAD_CONFIG, EGL_NO_SURFACE); } @@ -1205,7 +960,7 @@ EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface, egl_surface_t const * const s = get_surface(surface); if (s->cnx->egl.eglLockSurfaceKHR) { return s->cnx->egl.eglLockSurfaceKHR( - dp->disp[s->impl].dpy, s->surface, attrib_list); + dp->disp.dpy, s->surface, attrib_list); } return setError(EGL_BAD_DISPLAY, EGL_FALSE); } @@ -1223,8 +978,7 @@ EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface) egl_surface_t const * const s = get_surface(surface); if (s->cnx->egl.eglUnlockSurfaceKHR) { - return s->cnx->egl.eglUnlockSurfaceKHR( - dp->disp[s->impl].dpy, s->surface); + return s->cnx->egl.eglUnlockSurfaceKHR(dp->disp.dpy, s->surface); } return setError(EGL_BAD_DISPLAY, EGL_FALSE); } @@ -1237,67 +991,18 @@ EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, egl_display_t const * const dp = validate_display(dpy); if (!dp) return EGL_NO_IMAGE_KHR; - if (ctx != EGL_NO_CONTEXT) { - ContextRef _c(dp, ctx); - if (!_c.get()) - return setError(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR); - egl_context_t * const c = get_context(ctx); - // since we have an EGLContext, we know which implementation to use - EGLImageKHR image = c->cnx->egl.eglCreateImageKHR( - dp->disp[c->impl].dpy, c->context, target, buffer, attrib_list); - if (image == EGL_NO_IMAGE_KHR) - return image; - - egl_image_t* result = new egl_image_t(dpy, ctx); - result->images[c->impl] = image; - return (EGLImageKHR)result; - } else { - // EGL_NO_CONTEXT is a valid parameter - - /* Since we don't have a way to know which implementation to call, - * we're calling all of them. If at least one of the implementation - * succeeded, this is a success. - */ - - EGLint currentError = eglGetError(); - - EGLImageKHR implImages[IMPL_NUM_IMPLEMENTATIONS]; - bool success = false; - for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) { - egl_connection_t* const cnx = &gEGLImpl[i]; - implImages[i] = EGL_NO_IMAGE_KHR; - if (cnx->dso) { - if (cnx->egl.eglCreateImageKHR) { - implImages[i] = cnx->egl.eglCreateImageKHR( - dp->disp[i].dpy, ctx, target, buffer, attrib_list); - if (implImages[i] != EGL_NO_IMAGE_KHR) { - success = true; - } - } - } - } - - if (!success) { - // failure, if there was an error when we entered this function, - // the error flag must not be updated. - // Otherwise, the error is whatever happened in the implementation - // that faulted. - if (currentError != EGL_SUCCESS) { - setError(currentError, EGL_NO_IMAGE_KHR); - } - return EGL_NO_IMAGE_KHR; - } else { - // In case of success, we need to clear all error flags - // (especially those caused by the implementation that didn't - // succeed). TODO: we could avoid this if we knew this was - // a "full" success (all implementation succeeded). - eglGetError(); - } - - egl_image_t* result = new egl_image_t(dpy, ctx); - memcpy(result->images, implImages, sizeof(implImages)); - return (EGLImageKHR)result; + ContextRef _c(dp, ctx); + egl_context_t * const c = _c.get(); + + EGLImageKHR result = EGL_NO_IMAGE_KHR; + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglCreateImageKHR) { + result = cnx->egl.eglCreateImageKHR( + dp->disp.dpy, + c ? c->context : EGL_NO_CONTEXT, + target, buffer, attrib_list); } + return result; } EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img) @@ -1307,29 +1012,10 @@ EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img) egl_display_t const * const dp = validate_display(dpy); if (!dp) return EGL_FALSE; - ImageRef _i(dp, img); - if (!_i.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE); - - egl_image_t* image = get_image(img); - bool success = false; - for (int i=0 ; i<IMPL_NUM_IMPLEMENTATIONS ; i++) { - egl_connection_t* const cnx = &gEGLImpl[i]; - if (image->images[i] != EGL_NO_IMAGE_KHR) { - if (cnx->dso) { - if (cnx->egl.eglDestroyImageKHR) { - if (cnx->egl.eglDestroyImageKHR( - dp->disp[i].dpy, image->images[i])) { - success = true; - } - } - } - } + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglDestroyImageKHR) { + cnx->egl.eglDestroyImageKHR(dp->disp.dpy, img); } - if (!success) - return EGL_FALSE; - - _i.terminate(); - return EGL_TRUE; } @@ -1345,21 +1031,12 @@ EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_l egl_display_t const * const dp = validate_display(dpy); if (!dp) return EGL_NO_SYNC_KHR; - EGLContext ctx = eglGetCurrentContext(); - ContextRef _c(dp, ctx); - if (!_c.get()) - return setError(EGL_BAD_CONTEXT, EGL_NO_SYNC_KHR); - - egl_context_t * const c = get_context(ctx); EGLSyncKHR result = EGL_NO_SYNC_KHR; - if (c->cnx->egl.eglCreateSyncKHR) { - EGLSyncKHR sync = c->cnx->egl.eglCreateSyncKHR( - dp->disp[c->impl].dpy, type, attrib_list); - if (sync == EGL_NO_SYNC_KHR) - return sync; - result = (egl_sync_t*)new egl_sync_t(dpy, ctx, sync); + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglCreateSyncKHR) { + result = cnx->egl.eglCreateSyncKHR(dp->disp.dpy, type, attrib_list); } - return (EGLSyncKHR)result; + return result; } EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync) @@ -1369,75 +1046,46 @@ EGLBoolean eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync) egl_display_t const * const dp = validate_display(dpy); if (!dp) return EGL_FALSE; - SyncRef _s(dp, sync); - if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE); - egl_sync_t* syncObject = get_sync(sync); - - EGLContext ctx = syncObject->context; - ContextRef _c(dp, ctx); - if (!_c.get()) - return setError(EGL_BAD_CONTEXT, EGL_FALSE); - EGLBoolean result = EGL_FALSE; - egl_context_t * const c = get_context(ctx); - if (c->cnx->egl.eglDestroySyncKHR) { - result = c->cnx->egl.eglDestroySyncKHR( - dp->disp[c->impl].dpy, syncObject->sync); - if (result) - _s.terminate(); + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglDestroySyncKHR) { + result = cnx->egl.eglDestroySyncKHR(dp->disp.dpy, sync); } return result; } -EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout) +EGLint eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, + EGLint flags, EGLTimeKHR timeout) { clearError(); egl_display_t const * const dp = validate_display(dpy); if (!dp) return EGL_FALSE; - SyncRef _s(dp, sync); - if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE); - egl_sync_t* syncObject = get_sync(sync); - - EGLContext ctx = syncObject->context; - ContextRef _c(dp, ctx); - if (!_c.get()) - return setError(EGL_BAD_CONTEXT, EGL_FALSE); - - egl_context_t * const c = get_context(ctx); - if (c->cnx->egl.eglClientWaitSyncKHR) { - return c->cnx->egl.eglClientWaitSyncKHR( - dp->disp[c->impl].dpy, syncObject->sync, flags, timeout); + EGLBoolean result = EGL_FALSE; + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglClientWaitSyncKHR) { + result = cnx->egl.eglClientWaitSyncKHR( + dp->disp.dpy, sync, flags, timeout); } - - return EGL_FALSE; + return result; } -EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value) +EGLBoolean eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, + EGLint attribute, EGLint *value) { clearError(); egl_display_t const * const dp = validate_display(dpy); if (!dp) return EGL_FALSE; - SyncRef _s(dp, sync); - if (!_s.get()) - return setError(EGL_BAD_PARAMETER, EGL_FALSE); - - egl_sync_t* syncObject = get_sync(sync); - EGLContext ctx = syncObject->context; - ContextRef _c(dp, ctx); - if (!_c.get()) - return setError(EGL_BAD_CONTEXT, EGL_FALSE); - - egl_context_t * const c = get_context(ctx); - if (c->cnx->egl.eglGetSyncAttribKHR) { - return c->cnx->egl.eglGetSyncAttribKHR( - dp->disp[c->impl].dpy, syncObject->sync, attribute, value); + EGLBoolean result = EGL_FALSE; + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->egl.eglGetSyncAttribKHR) { + result = cnx->egl.eglGetSyncAttribKHR( + dp->disp.dpy, sync, attribute, value); } - - return EGL_FALSE; + return result; } // ---------------------------------------------------------------------------- @@ -1458,12 +1106,10 @@ EGLuint64NV eglGetSystemTimeFrequencyNV() } EGLuint64NV ret = 0; - egl_connection_t* const cnx = &gEGLImpl[IMPL_HARDWARE]; + egl_connection_t* const cnx = &gEGLImpl; - if (cnx->dso) { - if (cnx->egl.eglGetSystemTimeFrequencyNV) { - return cnx->egl.eglGetSystemTimeFrequencyNV(); - } + if (cnx->dso && cnx->egl.eglGetSystemTimeFrequencyNV) { + return cnx->egl.eglGetSystemTimeFrequencyNV(); } return setErrorQuiet(EGL_BAD_DISPLAY, 0); @@ -1478,12 +1124,10 @@ EGLuint64NV eglGetSystemTimeNV() } EGLuint64NV ret = 0; - egl_connection_t* const cnx = &gEGLImpl[IMPL_HARDWARE]; + egl_connection_t* const cnx = &gEGLImpl; - if (cnx->dso) { - if (cnx->egl.eglGetSystemTimeNV) { - return cnx->egl.eglGetSystemTimeNV(); - } + if (cnx->dso && cnx->egl.eglGetSystemTimeNV) { + return cnx->egl.eglGetSystemTimeNV(); } return setErrorQuiet(EGL_BAD_DISPLAY, 0); diff --git a/opengl/libs/EGL/egl_cache.cpp b/opengl/libs/EGL/egl_cache.cpp index 7fd6519c2de7..c79fb5f2858e 100644 --- a/opengl/libs/EGL/egl_cache.cpp +++ b/opengl/libs/EGL/egl_cache.cpp @@ -83,39 +83,39 @@ egl_cache_t* egl_cache_t::get() { void egl_cache_t::initialize(egl_display_t *display) { Mutex::Autolock lock(mMutex); - for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) { - egl_connection_t* const cnx = &gEGLImpl[i]; - if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) { - const char* exts = display->disp[i].queryString.extensions; - size_t bcExtLen = strlen(BC_EXT_STR); - size_t extsLen = strlen(exts); - bool equal = !strcmp(BC_EXT_STR, exts); - bool atStart = !strncmp(BC_EXT_STR " ", exts, bcExtLen+1); - bool atEnd = (bcExtLen+1) < extsLen && - !strcmp(" " BC_EXT_STR, exts + extsLen - (bcExtLen+1)); - bool inMiddle = strstr(exts, " " BC_EXT_STR " "); - if (equal || atStart || atEnd || inMiddle) { - PFNEGLSETBLOBCACHEFUNCSANDROIDPROC eglSetBlobCacheFuncsANDROID; - eglSetBlobCacheFuncsANDROID = - reinterpret_cast<PFNEGLSETBLOBCACHEFUNCSANDROIDPROC>( + + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) { + const char* exts = display->disp.queryString.extensions; + size_t bcExtLen = strlen(BC_EXT_STR); + size_t extsLen = strlen(exts); + bool equal = !strcmp(BC_EXT_STR, exts); + bool atStart = !strncmp(BC_EXT_STR " ", exts, bcExtLen+1); + bool atEnd = (bcExtLen+1) < extsLen && + !strcmp(" " BC_EXT_STR, exts + extsLen - (bcExtLen+1)); + bool inMiddle = strstr(exts, " " BC_EXT_STR " "); + if (equal || atStart || atEnd || inMiddle) { + PFNEGLSETBLOBCACHEFUNCSANDROIDPROC eglSetBlobCacheFuncsANDROID; + eglSetBlobCacheFuncsANDROID = + reinterpret_cast<PFNEGLSETBLOBCACHEFUNCSANDROIDPROC>( cnx->egl.eglGetProcAddress( "eglSetBlobCacheFuncsANDROID")); - if (eglSetBlobCacheFuncsANDROID == NULL) { - ALOGE("EGL_ANDROID_blob_cache advertised by display %d, " - "but unable to get eglSetBlobCacheFuncsANDROID", i); - continue; - } + if (eglSetBlobCacheFuncsANDROID == NULL) { + ALOGE("EGL_ANDROID_blob_cache advertised, " + "but unable to get eglSetBlobCacheFuncsANDROID"); + return; + } - eglSetBlobCacheFuncsANDROID(display->disp[i].dpy, - android::setBlob, android::getBlob); - EGLint err = cnx->egl.eglGetError(); - if (err != EGL_SUCCESS) { - ALOGE("eglSetBlobCacheFuncsANDROID resulted in an error: " - "%#x", err); - } + eglSetBlobCacheFuncsANDROID(display->disp.dpy, + android::setBlob, android::getBlob); + EGLint err = cnx->egl.eglGetError(); + if (err != EGL_SUCCESS) { + ALOGE("eglSetBlobCacheFuncsANDROID resulted in an error: " + "%#x", err); } } } + mInitialized = true; } diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp index 6b2ae51135f1..c85b4ce20ad8 100644 --- a/opengl/libs/EGL/egl_display.cpp +++ b/opengl/libs/EGL/egl_display.cpp @@ -60,18 +60,12 @@ static char const * const sExtensionString = extern void initEglTraceLevel(); extern void setGLHooksThreadSpecific(gl_hooks_t const *value); -static int cmp_configs(const void* a, const void *b) { - const egl_config_t& c0 = *(egl_config_t const *)a; - const egl_config_t& c1 = *(egl_config_t const *)b; - return c0<c1 ? -1 : (c1<c0 ? 1 : 0); -} - // ---------------------------------------------------------------------------- egl_display_t egl_display_t::sDisplay[NUM_DISPLAYS]; egl_display_t::egl_display_t() : - magic('_dpy'), numTotalConfigs(0), configs(0), refs(0) { + magic('_dpy'), refs(0) { } egl_display_t::~egl_display_t() { @@ -119,15 +113,13 @@ EGLDisplay egl_display_t::getDisplay(EGLNativeDisplayType display) { // get our driver loader Loader& loader(Loader::getInstance()); - for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) { - egl_connection_t* const cnx = &gEGLImpl[i]; - if (cnx->dso && disp[i].dpy == EGL_NO_DISPLAY) { - EGLDisplay dpy = cnx->egl.eglGetDisplay(display); - disp[i].dpy = dpy; - if (dpy == EGL_NO_DISPLAY) { - loader.close(cnx->dso); - cnx->dso = NULL; - } + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && disp.dpy == EGL_NO_DISPLAY) { + EGLDisplay dpy = cnx->egl.eglGetDisplay(display); + disp.dpy = dpy; + if (dpy == EGL_NO_DISPLAY) { + loader.close(cnx->dso); + cnx->dso = NULL; } } @@ -160,12 +152,11 @@ EGLBoolean egl_display_t::initialize(EGLint *major, EGLint *minor) { // initialize each EGL and // build our own extension string first, based on the extension we know // and the extension supported by our client implementation - for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) { - egl_connection_t* const cnx = &gEGLImpl[i]; - cnx->major = -1; - cnx->minor = -1; - if (!cnx->dso) - continue; + + egl_connection_t* const cnx = &gEGLImpl; + cnx->major = -1; + cnx->minor = -1; + if (cnx->dso) { #if defined(ADRENO130) #warning "Adreno-130 eglInitialize() workaround" @@ -177,31 +168,30 @@ EGLBoolean egl_display_t::initialize(EGLint *major, EGLint *minor) { * eglGetDisplay() before calling eglInitialize(); */ if (i == IMPL_HARDWARE) { - disp[i].dpy = - cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY); + disp[i].dpy = cnx->egl.eglGetDisplay(EGL_DEFAULT_DISPLAY); } #endif - EGLDisplay idpy = disp[i].dpy; + EGLDisplay idpy = disp.dpy; if (cnx->egl.eglInitialize(idpy, &cnx->major, &cnx->minor)) { - //ALOGD("initialized %d dpy=%p, ver=%d.%d, cnx=%p", - // i, idpy, cnx->major, cnx->minor, cnx); + //ALOGD("initialized dpy=%p, ver=%d.%d, cnx=%p", + // idpy, cnx->major, cnx->minor, cnx); // display is now initialized - disp[i].state = egl_display_t::INITIALIZED; + disp.state = egl_display_t::INITIALIZED; // get the query-strings for this display for each implementation - disp[i].queryString.vendor = cnx->egl.eglQueryString(idpy, + disp.queryString.vendor = cnx->egl.eglQueryString(idpy, EGL_VENDOR); - disp[i].queryString.version = cnx->egl.eglQueryString(idpy, + disp.queryString.version = cnx->egl.eglQueryString(idpy, EGL_VERSION); - disp[i].queryString.extensions = cnx->egl.eglQueryString(idpy, + disp.queryString.extensions = cnx->egl.eglQueryString(idpy, EGL_EXTENSIONS); - disp[i].queryString.clientApi = cnx->egl.eglQueryString(idpy, + disp.queryString.clientApi = cnx->egl.eglQueryString(idpy, EGL_CLIENT_APIS); } else { - ALOGW("%d: eglInitialize(%p) failed (%s)", i, idpy, + ALOGW("eglInitialize(%p) failed (%s)", idpy, egl_tls_t::egl_strerror(cnx->egl.eglGetError())); } } @@ -211,7 +201,7 @@ EGLBoolean egl_display_t::initialize(EGLint *major, EGLint *minor) { mVersionString.setTo(sVersionString); mClientApiString.setTo(sClientApiString); - // we only add extensions that exist in at least one implementation + // we only add extensions that exist in the implementation char const* start = sExtensionString; char const* end; do { @@ -223,15 +213,13 @@ EGLBoolean egl_display_t::initialize(EGLint *major, EGLint *minor) { if (len) { // NOTE: we could avoid the copy if we had strnstr. const String8 ext(start, len); - // now go through all implementations and look for this extension - for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) { - if (disp[i].queryString.extensions) { - // if we find it, add this extension string to our list - // (and don't forget the space) - const char* match = strstr(disp[i].queryString.extensions, ext.string()); - if (match && (match[len] == ' ' || match[len] == 0)) { - mExtensionString.append(start, len+1); - } + // now look for this extension + if (disp.queryString.extensions) { + // if we find it, add this extension string to our list + // (and don't forget the space) + const char* match = strstr(disp.queryString.extensions, ext.string()); + if (match && (match[len] == ' ' || match[len] == 0)) { + mExtensionString.append(start, len+1); } } } @@ -242,52 +230,12 @@ EGLBoolean egl_display_t::initialize(EGLint *major, EGLint *minor) { egl_cache_t::get()->initialize(this); - EGLBoolean res = EGL_FALSE; - for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) { - egl_connection_t* const cnx = &gEGLImpl[i]; - if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) { - EGLint n; - if (cnx->egl.eglGetConfigs(disp[i].dpy, 0, 0, &n)) { - disp[i].config = (EGLConfig*) malloc(sizeof(EGLConfig) * n); - if (disp[i].config) { - if (cnx->egl.eglGetConfigs(disp[i].dpy, disp[i].config, n, - &disp[i].numConfigs)) { - numTotalConfigs += n; - res = EGL_TRUE; - } - } - } - } - } - - if (res == EGL_TRUE) { - configs = new egl_config_t[numTotalConfigs]; - for (int i = 0, k = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) { - egl_connection_t* const cnx = &gEGLImpl[i]; - if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) { - for (int j = 0; j < disp[i].numConfigs; j++) { - configs[k].impl = i; - configs[k].config = disp[i].config[j]; - configs[k].configId = k + 1; // CONFIG_ID start at 1 - // store the implementation's CONFIG_ID - cnx->egl.eglGetConfigAttrib(disp[i].dpy, disp[i].config[j], - EGL_CONFIG_ID, &configs[k].implConfigId); - k++; - } - } - } - - // sort our configurations so we can do binary-searches - qsort(configs, numTotalConfigs, sizeof(egl_config_t), cmp_configs); - - refs++; - if (major != NULL) - *major = VERSION_MAJOR; - if (minor != NULL) - *minor = VERSION_MINOR; - return EGL_TRUE; - } - return setError(EGL_NOT_INITIALIZED, EGL_FALSE); + refs++; + if (major != NULL) + *major = VERSION_MAJOR; + if (minor != NULL) + *minor = VERSION_MINOR; + return EGL_TRUE; } EGLBoolean egl_display_t::terminate() { @@ -305,22 +253,15 @@ EGLBoolean egl_display_t::terminate() { } EGLBoolean res = EGL_FALSE; - for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) { - egl_connection_t* const cnx = &gEGLImpl[i]; - if (cnx->dso && disp[i].state == egl_display_t::INITIALIZED) { - if (cnx->egl.eglTerminate(disp[i].dpy) == EGL_FALSE) { - ALOGW("%d: eglTerminate(%p) failed (%s)", i, disp[i].dpy, - egl_tls_t::egl_strerror(cnx->egl.eglGetError())); - } - // REVISIT: it's unclear what to do if eglTerminate() fails - free(disp[i].config); - - disp[i].numConfigs = 0; - disp[i].config = 0; - disp[i].state = egl_display_t::TERMINATED; - - res = EGL_TRUE; + egl_connection_t* const cnx = &gEGLImpl; + if (cnx->dso && disp.state == egl_display_t::INITIALIZED) { + if (cnx->egl.eglTerminate(disp.dpy) == EGL_FALSE) { + ALOGW("eglTerminate(%p) failed (%s)", disp.dpy, + egl_tls_t::egl_strerror(cnx->egl.eglGetError())); } + // REVISIT: it's unclear what to do if eglTerminate() fails + disp.state = egl_display_t::TERMINATED; + res = EGL_TRUE; } // Mark all objects remaining in the list as terminated, unless @@ -337,8 +278,6 @@ EGLBoolean egl_display_t::terminate() { objects.clear(); refs--; - numTotalConfigs = 0; - delete[] configs; return res; } @@ -390,13 +329,13 @@ EGLBoolean egl_display_t::makeCurrent(egl_context_t* c, egl_context_t* cur_c, Mutex::Autolock _l(lock); if (c) { result = c->cnx->egl.eglMakeCurrent( - disp[c->impl].dpy, impl_draw, impl_read, impl_ctx); + disp.dpy, impl_draw, impl_read, impl_ctx); if (result == EGL_TRUE) { c->onMakeCurrent(draw, read); } } else { result = cur_c->cnx->egl.eglMakeCurrent( - disp[cur_c->impl].dpy, impl_draw, impl_read, impl_ctx); + disp.dpy, impl_draw, impl_read, impl_ctx); if (result == EGL_TRUE) { cur_c->onLooseCurrent(); } diff --git a/opengl/libs/EGL/egl_display.h b/opengl/libs/EGL/egl_display.h index f3c4ddfcabc3..63482284fcac 100644 --- a/opengl/libs/EGL/egl_display.h +++ b/opengl/libs/EGL/egl_display.h @@ -44,23 +44,6 @@ class egl_connection_t; // ---------------------------------------------------------------------------- -struct egl_config_t { - egl_config_t() {} - egl_config_t(int impl, EGLConfig config) - : impl(impl), config(config), configId(0), implConfigId(0) { } - int impl; // the implementation this config is for - EGLConfig config; // the implementation's EGLConfig - EGLint configId; // our CONFIG_ID - EGLint implConfigId; // the implementation's CONFIG_ID - inline bool operator < (const egl_config_t& rhs) const { - if (impl < rhs.impl) return true; - if (impl > rhs.impl) return false; - return config < rhs.config; - } -}; - -// ---------------------------------------------------------------------------- - class EGLAPI egl_display_t { // marked as EGLAPI for testing purposes static egl_display_t sDisplay[NUM_DISPLAYS]; EGLDisplay getDisplay(EGLNativeDisplayType display); @@ -113,12 +96,9 @@ public: }; struct DisplayImpl { - DisplayImpl() : dpy(EGL_NO_DISPLAY), config(0), - state(NOT_INITIALIZED), numConfigs(0) { } + DisplayImpl() : dpy(EGL_NO_DISPLAY), state(NOT_INITIALIZED) { } EGLDisplay dpy; - EGLConfig* config; EGLint state; - EGLint numConfigs; strings_t queryString; }; @@ -126,9 +106,7 @@ private: uint32_t magic; public: - DisplayImpl disp[IMPL_NUM_IMPLEMENTATIONS]; - EGLint numTotalConfigs; - egl_config_t* configs; + DisplayImpl disp; private: uint32_t refs; diff --git a/opengl/libs/EGL/egl_object.cpp b/opengl/libs/EGL/egl_object.cpp index b660c53142ac..d0cbb31b15b1 100644 --- a/opengl/libs/EGL/egl_object.cpp +++ b/opengl/libs/EGL/egl_object.cpp @@ -64,9 +64,9 @@ bool egl_object_t::get(egl_display_t const* display, egl_object_t* object) { // ---------------------------------------------------------------------------- egl_context_t::egl_context_t(EGLDisplay dpy, EGLContext context, EGLConfig config, - int impl, egl_connection_t const* cnx, int version) : + egl_connection_t const* cnx, int version) : egl_object_t(get_display(dpy)), dpy(dpy), context(context), - config(config), read(0), draw(0), impl(impl), cnx(cnx), + config(config), read(0), draw(0), cnx(cnx), version(version) { } @@ -87,7 +87,7 @@ void egl_context_t::onMakeCurrent(EGLSurface draw, EGLSurface read) { if (gl_extensions.isEmpty()) { // call the implementation's glGetString(GL_EXTENSIONS) - const char* exts = (const char *)gEGLImpl[impl].hooks[version]->gl.glGetString(GL_EXTENSIONS); + const char* exts = (const char *)gEGLImpl.hooks[version]->gl.glGetString(GL_EXTENSIONS); gl_extensions.setTo(exts); if (gl_extensions.find("GL_EXT_debug_marker") < 0) { String8 temp("GL_EXT_debug_marker "); diff --git a/opengl/libs/EGL/egl_object.h b/opengl/libs/EGL/egl_object.h index abd4cbb962a6..4d91f5417b0b 100644 --- a/opengl/libs/EGL/egl_object.h +++ b/opengl/libs/EGL/egl_object.h @@ -125,7 +125,7 @@ void egl_object_t::LocalRef<N,T>::terminate() { // ---------------------------------------------------------------------------- -class egl_surface_t: public egl_object_t { +class egl_surface_t : public egl_object_t { protected: ~egl_surface_t() { ANativeWindow* const window = win.get(); @@ -140,15 +140,14 @@ public: typedef egl_object_t::LocalRef<egl_surface_t, EGLSurface> Ref; egl_surface_t(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, - EGLSurface surface, int impl, egl_connection_t const* cnx) : + EGLSurface surface, egl_connection_t const* cnx) : egl_object_t(get_display(dpy)), dpy(dpy), surface(surface), - config(config), win(win), impl(impl), cnx(cnx) { + config(config), win(win), cnx(cnx) { } EGLDisplay dpy; EGLSurface surface; EGLConfig config; sp<ANativeWindow> win; - int impl; egl_connection_t const* cnx; }; @@ -159,7 +158,7 @@ public: typedef egl_object_t::LocalRef<egl_context_t, EGLContext> Ref; egl_context_t(EGLDisplay dpy, EGLContext context, EGLConfig config, - int impl, egl_connection_t const* cnx, int version); + egl_connection_t const* cnx, int version); void onLooseCurrent(); void onMakeCurrent(EGLSurface draw, EGLSurface read); @@ -169,47 +168,15 @@ public: EGLConfig config; EGLSurface read; EGLSurface draw; - int impl; egl_connection_t const* cnx; int version; String8 gl_extensions; }; -class egl_image_t: public egl_object_t { -protected: - ~egl_image_t() {} -public: - typedef egl_object_t::LocalRef<egl_image_t, EGLImageKHR> Ref; - - egl_image_t(EGLDisplay dpy, EGLContext context) : - egl_object_t(get_display(dpy)), dpy(dpy), context(context) { - memset(images, 0, sizeof(images)); - } - EGLDisplay dpy; - EGLContext context; - EGLImageKHR images[IMPL_NUM_IMPLEMENTATIONS]; -}; - -class egl_sync_t: public egl_object_t { -protected: - ~egl_sync_t() {} -public: - typedef egl_object_t::LocalRef<egl_sync_t, EGLSyncKHR> Ref; - - egl_sync_t(EGLDisplay dpy, EGLContext context, EGLSyncKHR sync) : - egl_object_t(get_display(dpy)), dpy(dpy), context(context), sync(sync) { - } - EGLDisplay dpy; - EGLContext context; - EGLSyncKHR sync; -}; - // ---------------------------------------------------------------------------- typedef egl_surface_t::Ref SurfaceRef; typedef egl_context_t::Ref ContextRef; -typedef egl_image_t::Ref ImageRef; -typedef egl_sync_t::Ref SyncRef; // ---------------------------------------------------------------------------- @@ -228,16 +195,6 @@ egl_context_t* get_context(EGLContext context) { return egl_to_native_cast<egl_context_t>(context); } -static inline -egl_image_t* get_image(EGLImageKHR image) { - return egl_to_native_cast<egl_image_t>(image); -} - -static inline -egl_sync_t* get_sync(EGLSyncKHR sync) { - return egl_to_native_cast<egl_sync_t>(sync); -} - // ---------------------------------------------------------------------------- }; // namespace android // ---------------------------------------------------------------------------- diff --git a/opengl/libs/EGL/egldefs.h b/opengl/libs/EGL/egldefs.h index ff20957f3e41..c900c1c5fe0f 100644 --- a/opengl/libs/EGL/egldefs.h +++ b/opengl/libs/EGL/egldefs.h @@ -19,31 +19,24 @@ #include "hooks.h" +#define VERSION_MAJOR 1 +#define VERSION_MINOR 4 + // ---------------------------------------------------------------------------- namespace android { // ---------------------------------------------------------------------------- -#define VERSION_MAJOR 1 -#define VERSION_MINOR 4 - // EGLDisplay are global, not attached to a given thread const unsigned int NUM_DISPLAYS = 1; -enum { - IMPL_HARDWARE = 0, - IMPL_SOFTWARE, - IMPL_NUM_IMPLEMENTATIONS -}; - -enum { - GLESv1_INDEX = 0, - GLESv2_INDEX = 1, -}; - // ---------------------------------------------------------------------------- -struct egl_connection_t -{ +struct egl_connection_t { + enum { + GLESv1_INDEX = 0, + GLESv2_INDEX = 1 + }; + inline egl_connection_t() : dso(0) { } void * dso; gl_hooks_t * hooks[2]; @@ -54,7 +47,7 @@ struct egl_connection_t // ---------------------------------------------------------------------------- -extern gl_hooks_t gHooks[2][IMPL_NUM_IMPLEMENTATIONS]; +extern gl_hooks_t gHooks[2]; extern gl_hooks_t gHooksNoContext; extern pthread_key_t gGLWrapperKey; extern "C" void gl_unimplemented(); @@ -63,7 +56,7 @@ extern "C" void gl_noop(); extern char const * const gl_names[]; extern char const * const egl_names[]; -extern egl_connection_t gEGLImpl[IMPL_NUM_IMPLEMENTATIONS]; +extern egl_connection_t gEGLImpl; // ---------------------------------------------------------------------------- }; // namespace android diff --git a/opengl/libs/GLES2/gl2.cpp b/opengl/libs/GLES2/gl2.cpp index 79aa3cd59eeb..4345c2b89463 100644 --- a/opengl/libs/GLES2/gl2.cpp +++ b/opengl/libs/GLES2/gl2.cpp @@ -124,27 +124,3 @@ const GLubyte * glGetString(GLenum name) } return ret; } - -/* - * These GL calls are special because they need to EGL to retrieve some - * informations before they can execute. - */ - -extern "C" void __glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image); -extern "C" void __glEGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image); - - -void glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image) -{ - GLeglImageOES implImage = - (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image); - __glEGLImageTargetTexture2DOES(target, implImage); -} - -void glEGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image) -{ - GLeglImageOES implImage = - (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image); - __glEGLImageTargetRenderbufferStorageOES(target, implImage); -} - diff --git a/opengl/libs/GLES2/gl2ext_api.in b/opengl/libs/GLES2/gl2ext_api.in index a8907fd40bbe..c381075b9862 100644 --- a/opengl/libs/GLES2/gl2ext_api.in +++ b/opengl/libs/GLES2/gl2ext_api.in @@ -1,7 +1,7 @@ -void API_ENTRY(__glEGLImageTargetTexture2DOES)(GLenum target, GLeglImageOES image) { +void API_ENTRY(glEGLImageTargetTexture2DOES)(GLenum target, GLeglImageOES image) { CALL_GL_API(glEGLImageTargetTexture2DOES, target, image); } -void API_ENTRY(__glEGLImageTargetRenderbufferStorageOES)(GLenum target, GLeglImageOES image) { +void API_ENTRY(glEGLImageTargetRenderbufferStorageOES)(GLenum target, GLeglImageOES image) { CALL_GL_API(glEGLImageTargetRenderbufferStorageOES, target, image); } void API_ENTRY(glGetProgramBinaryOES)(GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary) { diff --git a/opengl/libs/GLES_CM/gl.cpp b/opengl/libs/GLES_CM/gl.cpp index adeaa5b8233d..adcb60d711f2 100644 --- a/opengl/libs/GLES_CM/gl.cpp +++ b/opengl/libs/GLES_CM/gl.cpp @@ -179,27 +179,3 @@ const GLubyte * glGetString(GLenum name) } return ret; } - -/* - * These GL calls are special because they need to EGL to retrieve some - * informations before they can execute. - */ - -extern "C" void __glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image); -extern "C" void __glEGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image); - - -void glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image) -{ - GLeglImageOES implImage = - (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image); - __glEGLImageTargetTexture2DOES(target, implImage); -} - -void glEGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image) -{ - GLeglImageOES implImage = - (GLeglImageOES)egl_get_image_for_current_context((EGLImageKHR)image); - __glEGLImageTargetRenderbufferStorageOES(target, implImage); -} - diff --git a/opengl/libs/GLES_CM/glext_api.in b/opengl/libs/GLES_CM/glext_api.in index 268a5352bab5..7cd6cb539251 100644 --- a/opengl/libs/GLES_CM/glext_api.in +++ b/opengl/libs/GLES_CM/glext_api.in @@ -31,10 +31,10 @@ void API_ENTRY(glDrawTexfOES)(GLfloat x, GLfloat y, GLfloat z, GLfloat width, GL void API_ENTRY(glDrawTexfvOES)(const GLfloat *coords) { CALL_GL_API(glDrawTexfvOES, coords); } -void API_ENTRY(__glEGLImageTargetTexture2DOES)(GLenum target, GLeglImageOES image) { +void API_ENTRY(glEGLImageTargetTexture2DOES)(GLenum target, GLeglImageOES image) { CALL_GL_API(glEGLImageTargetTexture2DOES, target, image); } -void API_ENTRY(__glEGLImageTargetRenderbufferStorageOES)(GLenum target, GLeglImageOES image) { +void API_ENTRY(glEGLImageTargetRenderbufferStorageOES)(GLenum target, GLeglImageOES image) { CALL_GL_API(glEGLImageTargetRenderbufferStorageOES, target, image); } void API_ENTRY(glAlphaFuncxOES)(GLenum func, GLclampx ref) { diff --git a/opengl/libs/GLES_trace/TODO.txt b/opengl/libs/GLES_trace/TODO.txt deleted file mode 100644 index f5e6e9518c7c..000000000000 --- a/opengl/libs/GLES_trace/TODO.txt +++ /dev/null @@ -1,14 +0,0 @@ -TODO: - - Context - Currently, we don't do anything regarding the contexts that are created. - Need to maintain more state regarding contexts, and figure out what happens in the - presence of multiple contexts. - - - Transport: Each GLMessage is sent via a socket as soon as the message is received. - i.e., there is no buffering of messages. Buffering should improve performance. - - - Initialization: On first connection, send some basic information that includes: - 1. version of the trace library - 2. implementation dependent GL state variables such as # of vertex arrays etc. - - - eglSwapBuffers: The images are lzf compressed, but there is no mode that transfers - only the differences from the previous images. diff --git a/opengl/libs/GLES_trace/gltrace.proto b/opengl/libs/GLES_trace/gltrace.proto index 11cf24f5900b..2893e6e87454 100644 --- a/opengl/libs/GLES_trace/gltrace.proto +++ b/opengl/libs/GLES_trace/gltrace.proto @@ -543,11 +543,13 @@ message GLMessage { required int32 context_id = 1; // GL context ID required int64 start_time = 2; // time when call was invoked - required int32 duration = 3; // duration of the call + required int32 duration = 3; // duration of the call (MONOTONIC TIME) required Function function = 4 [default = invalid]; // GL function called repeated DataType args = 5; // GL function's arguments optional DataType returnValue = 6; // GL function's return value optional FrameBuffer fb = 7; // contents of the framebuffer + + optional int32 threadtime = 8; // duration of the call (THREAD TIME) }; diff --git a/opengl/libs/GLES_trace/src/gltrace.pb.cpp b/opengl/libs/GLES_trace/src/gltrace.pb.cpp index bb9d4a70e829..d5f8180e2630 100644 --- a/opengl/libs/GLES_trace/src/gltrace.pb.cpp +++ b/opengl/libs/GLES_trace/src/gltrace.pb.cpp @@ -1663,6 +1663,7 @@ const int GLMessage::kFunctionFieldNumber; const int GLMessage::kArgsFieldNumber; const int GLMessage::kReturnValueFieldNumber; const int GLMessage::kFbFieldNumber; +const int GLMessage::kThreadtimeFieldNumber; #endif // !_MSC_VER GLMessage::GLMessage() @@ -1689,6 +1690,7 @@ void GLMessage::SharedCtor() { function_ = 3000; returnvalue_ = NULL; fb_ = NULL; + threadtime_ = 0; ::memset(_has_bits_, 0, sizeof(_has_bits_)); } @@ -1730,6 +1732,7 @@ void GLMessage::Clear() { if (_has_bit(6)) { if (fb_ != NULL) fb_->::android::gltrace::GLMessage_FrameBuffer::Clear(); } + threadtime_ = 0; } args_.Clear(); ::memset(_has_bits_, 0, sizeof(_has_bits_)); @@ -1846,6 +1849,22 @@ bool GLMessage::MergePartialFromCodedStream( } else { goto handle_uninterpreted; } + if (input->ExpectTag(64)) goto parse_threadtime; + break; + } + + // optional int32 threadtime = 8; + case 8: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_threadtime: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( + input, &threadtime_))); + _set_bit(7); + } else { + goto handle_uninterpreted; + } if (input->ExpectAtEnd()) return true; break; } @@ -1906,6 +1925,11 @@ void GLMessage::SerializeWithCachedSizes( 7, this->fb(), output); } + // optional int32 threadtime = 8; + if (_has_bit(7)) { + ::google::protobuf::internal::WireFormatLite::WriteInt32(8, this->threadtime(), output); + } + } int GLMessage::ByteSize() const { @@ -1953,6 +1977,13 @@ int GLMessage::ByteSize() const { this->fb()); } + // optional int32 threadtime = 8; + if (has_threadtime()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::Int32Size( + this->threadtime()); + } + } // repeated .android.gltrace.GLMessage.DataType args = 5; total_size += 1 * this->args_size(); @@ -1995,6 +2026,9 @@ void GLMessage::MergeFrom(const GLMessage& from) { if (from._has_bit(6)) { mutable_fb()->::android::gltrace::GLMessage_FrameBuffer::MergeFrom(from.fb()); } + if (from._has_bit(7)) { + set_threadtime(from.threadtime()); + } } } @@ -2028,6 +2062,7 @@ void GLMessage::Swap(GLMessage* other) { args_.Swap(&other->args_); std::swap(returnvalue_, other->returnvalue_); std::swap(fb_, other->fb_); + std::swap(threadtime_, other->threadtime_); std::swap(_has_bits_[0], other->_has_bits_[0]); std::swap(_cached_size_, other->_cached_size_); } diff --git a/opengl/libs/GLES_trace/src/gltrace.pb.h b/opengl/libs/GLES_trace/src/gltrace.pb.h index e3b8990faee7..a4fcbd3545eb 100644 --- a/opengl/libs/GLES_trace/src/gltrace.pb.h +++ b/opengl/libs/GLES_trace/src/gltrace.pb.h @@ -1418,6 +1418,13 @@ class GLMessage : public ::google::protobuf::MessageLite { inline const ::android::gltrace::GLMessage_FrameBuffer& fb() const; inline ::android::gltrace::GLMessage_FrameBuffer* mutable_fb(); + // optional int32 threadtime = 8; + inline bool has_threadtime() const; + inline void clear_threadtime(); + static const int kThreadtimeFieldNumber = 8; + inline ::google::protobuf::int32 threadtime() const; + inline void set_threadtime(::google::protobuf::int32 value); + // @@protoc_insertion_point(class_scope:android.gltrace.GLMessage) private: mutable int _cached_size_; @@ -1429,11 +1436,12 @@ class GLMessage : public ::google::protobuf::MessageLite { ::google::protobuf::RepeatedPtrField< ::android::gltrace::GLMessage_DataType > args_; ::android::gltrace::GLMessage_DataType* returnvalue_; ::android::gltrace::GLMessage_FrameBuffer* fb_; + ::google::protobuf::int32 threadtime_; friend void protobuf_AddDesc_gltrace_2eproto(); friend void protobuf_AssignDesc_gltrace_2eproto(); friend void protobuf_ShutdownFile_gltrace_2eproto(); - ::google::protobuf::uint32 _has_bits_[(7 + 31) / 32]; + ::google::protobuf::uint32 _has_bits_[(8 + 31) / 32]; // WHY DOES & HAVE LOWER PRECEDENCE THAN != !? inline bool _has_bit(int index) const { @@ -1860,6 +1868,22 @@ inline ::android::gltrace::GLMessage_FrameBuffer* GLMessage::mutable_fb() { return fb_; } +// optional int32 threadtime = 8; +inline bool GLMessage::has_threadtime() const { + return _has_bit(7); +} +inline void GLMessage::clear_threadtime() { + threadtime_ = 0; + _clear_bit(7); +} +inline ::google::protobuf::int32 GLMessage::threadtime() const { + return threadtime_; +} +inline void GLMessage::set_threadtime(::google::protobuf::int32 value) { + _set_bit(7); + threadtime_ = value; +} + // @@protoc_insertion_point(namespace_scope) diff --git a/opengl/libs/GLES_trace/src/gltrace_api.cpp b/opengl/libs/GLES_trace/src/gltrace_api.cpp index a2366ac9b95a..358bf54ce445 100644 --- a/opengl/libs/GLES_trace/src/gltrace_api.cpp +++ b/opengl/libs/GLES_trace/src/gltrace_api.cpp @@ -43,11 +43,15 @@ void GLTrace_glActiveTexture(GLenum texture) { arg_texture->add_intvalue((int)texture); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glActiveTexture(texture); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -70,11 +74,15 @@ void GLTrace_glAttachShader(GLuint program, GLuint shader) { arg_shader->add_intvalue(shader); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glAttachShader(program, shader); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -103,11 +111,15 @@ void GLTrace_glBindAttribLocation(GLuint program, GLuint index, const GLchar* na arg_name->add_intvalue((int)name); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glBindAttribLocation(program, index, name); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -130,11 +142,15 @@ void GLTrace_glBindBuffer(GLenum target, GLuint buffer) { arg_buffer->add_intvalue(buffer); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glBindBuffer(target, buffer); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -157,11 +173,15 @@ void GLTrace_glBindFramebuffer(GLenum target, GLuint framebuffer) { arg_framebuffer->add_intvalue(framebuffer); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glBindFramebuffer(target, framebuffer); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -184,11 +204,15 @@ void GLTrace_glBindRenderbuffer(GLenum target, GLuint renderbuffer) { arg_renderbuffer->add_intvalue(renderbuffer); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glBindRenderbuffer(target, renderbuffer); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -211,11 +235,15 @@ void GLTrace_glBindTexture(GLenum target, GLuint texture) { arg_texture->add_intvalue(texture); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glBindTexture(target, texture); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -250,11 +278,15 @@ void GLTrace_glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf arg_alpha->add_floatvalue(alpha); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glBlendColor(red, green, blue, alpha); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -271,11 +303,15 @@ void GLTrace_glBlendEquation(GLenum mode) { arg_mode->add_intvalue((int)mode); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glBlendEquation(mode); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -298,11 +334,15 @@ void GLTrace_glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) { arg_modeAlpha->add_intvalue((int)modeAlpha); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glBlendEquationSeparate(modeRGB, modeAlpha); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -325,11 +365,15 @@ void GLTrace_glBlendFunc(GLenum sfactor, GLenum dfactor) { arg_dfactor->add_intvalue((int)dfactor); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glBlendFunc(sfactor, dfactor); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -364,11 +408,15 @@ void GLTrace_glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, arg_dstAlpha->add_intvalue((int)dstAlpha); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -403,11 +451,15 @@ void GLTrace_glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GL arg_usage->add_intvalue((int)usage); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glBufferData(target, size, data, usage); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -442,11 +494,15 @@ void GLTrace_glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, co arg_data->add_intvalue((int)data); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glBufferSubData(target, offset, size, data); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -463,9 +519,11 @@ GLenum GLTrace_glCheckFramebufferStatus(GLenum target) { arg_target->add_intvalue((int)target); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); GLenum retValue = glContext->hooks->gl.glCheckFramebufferStatus(target); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); // set return value GLMessage_DataType *rt = glmsg.mutable_returnvalue(); @@ -473,7 +531,9 @@ GLenum GLTrace_glCheckFramebufferStatus(GLenum target) { rt->set_type(GLMessage::DataType::ENUM); rt->add_intvalue((int)retValue); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); return retValue; @@ -492,11 +552,15 @@ void GLTrace_glClear(GLbitfield mask) { arg_mask->add_intvalue(mask); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glClear(mask); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -531,11 +595,15 @@ void GLTrace_glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf arg_alpha->add_floatvalue(alpha); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glClearColor(red, green, blue, alpha); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -552,11 +620,15 @@ void GLTrace_glClearDepthf(GLclampf depth) { arg_depth->add_floatvalue(depth); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glClearDepthf(depth); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -573,11 +645,15 @@ void GLTrace_glClearStencil(GLint s) { arg_s->add_intvalue(s); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glClearStencil(s); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -612,11 +688,15 @@ void GLTrace_glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboole arg_alpha->add_boolvalue(alpha); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glColorMask(red, green, blue, alpha); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -633,11 +713,15 @@ void GLTrace_glCompileShader(GLuint shader) { arg_shader->add_intvalue(shader); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glCompileShader(shader); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -696,11 +780,15 @@ void GLTrace_glCompressedTexImage2D(GLenum target, GLint level, GLenum internalf arg_data->add_intvalue((int)data); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glCompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -765,11 +853,15 @@ void GLTrace_glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset arg_data->add_intvalue((int)data); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -828,11 +920,15 @@ void GLTrace_glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, arg_border->add_intvalue(border); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glCopyTexImage2D(target, level, internalformat, x, y, width, height, border); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -891,11 +987,15 @@ void GLTrace_glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLin arg_height->add_intvalue(height); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -906,9 +1006,11 @@ GLuint GLTrace_glCreateProgram(void) { glmsg.set_function(GLMessage::glCreateProgram); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); GLuint retValue = glContext->hooks->gl.glCreateProgram(); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); // set return value GLMessage_DataType *rt = glmsg.mutable_returnvalue(); @@ -916,7 +1018,9 @@ GLuint GLTrace_glCreateProgram(void) { rt->set_type(GLMessage::DataType::INT); rt->add_intvalue(retValue); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); return retValue; @@ -935,9 +1039,11 @@ GLuint GLTrace_glCreateShader(GLenum type) { arg_type->add_intvalue((int)type); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); GLuint retValue = glContext->hooks->gl.glCreateShader(type); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); // set return value GLMessage_DataType *rt = glmsg.mutable_returnvalue(); @@ -945,7 +1051,9 @@ GLuint GLTrace_glCreateShader(GLenum type) { rt->set_type(GLMessage::DataType::INT); rt->add_intvalue(retValue); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); return retValue; @@ -964,11 +1072,15 @@ void GLTrace_glCullFace(GLenum mode) { arg_mode->add_intvalue((int)mode); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glCullFace(mode); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -991,11 +1103,15 @@ void GLTrace_glDeleteBuffers(GLsizei n, const GLuint* buffers) { arg_buffers->add_intvalue((int)buffers); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glDeleteBuffers(n, buffers); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -1018,11 +1134,15 @@ void GLTrace_glDeleteFramebuffers(GLsizei n, const GLuint* framebuffers) { arg_framebuffers->add_intvalue((int)framebuffers); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glDeleteFramebuffers(n, framebuffers); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -1039,11 +1159,15 @@ void GLTrace_glDeleteProgram(GLuint program) { arg_program->add_intvalue(program); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glDeleteProgram(program); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -1066,11 +1190,15 @@ void GLTrace_glDeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers) { arg_renderbuffers->add_intvalue((int)renderbuffers); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glDeleteRenderbuffers(n, renderbuffers); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -1087,11 +1215,15 @@ void GLTrace_glDeleteShader(GLuint shader) { arg_shader->add_intvalue(shader); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glDeleteShader(shader); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -1114,11 +1246,15 @@ void GLTrace_glDeleteTextures(GLsizei n, const GLuint* textures) { arg_textures->add_intvalue((int)textures); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glDeleteTextures(n, textures); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -1135,11 +1271,15 @@ void GLTrace_glDepthFunc(GLenum func) { arg_func->add_intvalue((int)func); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glDepthFunc(func); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -1156,11 +1296,15 @@ void GLTrace_glDepthMask(GLboolean flag) { arg_flag->add_boolvalue(flag); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glDepthMask(flag); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -1183,11 +1327,15 @@ void GLTrace_glDepthRangef(GLclampf zNear, GLclampf zFar) { arg_zFar->add_floatvalue(zFar); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glDepthRangef(zNear, zFar); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -1210,11 +1358,15 @@ void GLTrace_glDetachShader(GLuint program, GLuint shader) { arg_shader->add_intvalue(shader); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glDetachShader(program, shader); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -1231,11 +1383,15 @@ void GLTrace_glDisable(GLenum cap) { arg_cap->add_intvalue((int)cap); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glDisable(cap); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -1252,11 +1408,15 @@ void GLTrace_glDisableVertexAttribArray(GLuint index) { arg_index->add_intvalue(index); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glDisableVertexAttribArray(index); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -1285,11 +1445,15 @@ void GLTrace_glDrawArrays(GLenum mode, GLint first, GLsizei count) { arg_count->add_intvalue(count); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glDrawArrays(mode, first, count); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -1324,11 +1488,15 @@ void GLTrace_glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoi arg_indices->add_intvalue((int)indices); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glDrawElements(mode, count, type, indices); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -1345,11 +1513,15 @@ void GLTrace_glEnable(GLenum cap) { arg_cap->add_intvalue((int)cap); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glEnable(cap); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -1366,11 +1538,15 @@ void GLTrace_glEnableVertexAttribArray(GLuint index) { arg_index->add_intvalue(index); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glEnableVertexAttribArray(index); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -1381,11 +1557,15 @@ void GLTrace_glFinish(void) { glmsg.set_function(GLMessage::glFinish); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glFinish(); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -1396,11 +1576,15 @@ void GLTrace_glFlush(void) { glmsg.set_function(GLMessage::glFlush); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glFlush(); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -1435,11 +1619,15 @@ void GLTrace_glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum arg_renderbuffer->add_intvalue(renderbuffer); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glFramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -1480,11 +1668,15 @@ void GLTrace_glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum tex arg_level->add_intvalue(level); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glFramebufferTexture2D(target, attachment, textarget, texture, level); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -1501,11 +1693,15 @@ void GLTrace_glFrontFace(GLenum mode) { arg_mode->add_intvalue((int)mode); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glFrontFace(mode); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -1528,11 +1724,15 @@ void GLTrace_glGenBuffers(GLsizei n, GLuint* buffers) { arg_buffers->add_intvalue((int)buffers); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGenBuffers(n, buffers); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -1549,11 +1749,15 @@ void GLTrace_glGenerateMipmap(GLenum target) { arg_target->add_intvalue((int)target); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGenerateMipmap(target); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -1576,11 +1780,15 @@ void GLTrace_glGenFramebuffers(GLsizei n, GLuint* framebuffers) { arg_framebuffers->add_intvalue((int)framebuffers); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGenFramebuffers(n, framebuffers); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -1603,11 +1811,15 @@ void GLTrace_glGenRenderbuffers(GLsizei n, GLuint* renderbuffers) { arg_renderbuffers->add_intvalue((int)renderbuffers); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGenRenderbuffers(n, renderbuffers); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -1630,11 +1842,15 @@ void GLTrace_glGenTextures(GLsizei n, GLuint* textures) { arg_textures->add_intvalue((int)textures); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGenTextures(n, textures); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -1687,11 +1903,15 @@ void GLTrace_glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GL arg_name->add_intvalue((int)name); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetActiveAttrib(program, index, bufsize, length, size, type, name); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -1744,11 +1964,15 @@ void GLTrace_glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, G arg_name->add_intvalue((int)name); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetActiveUniform(program, index, bufsize, length, size, type, name); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -1783,11 +2007,15 @@ void GLTrace_glGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* cou arg_shaders->add_intvalue((int)shaders); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetAttachedShaders(program, maxcount, count, shaders); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -1810,9 +2038,11 @@ int GLTrace_glGetAttribLocation(GLuint program, const GLchar* name) { arg_name->add_intvalue((int)name); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); int retValue = glContext->hooks->gl.glGetAttribLocation(program, name); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); // set return value GLMessage_DataType *rt = glmsg.mutable_returnvalue(); @@ -1820,7 +2050,9 @@ int GLTrace_glGetAttribLocation(GLuint program, const GLchar* name) { rt->set_type(GLMessage::DataType::INT); rt->add_intvalue(retValue); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); return retValue; @@ -1845,11 +2077,15 @@ void GLTrace_glGetBooleanv(GLenum pname, GLboolean* params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetBooleanv(pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -1878,11 +2114,15 @@ void GLTrace_glGetBufferParameteriv(GLenum target, GLenum pname, GLint* params) arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetBufferParameteriv(target, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -1893,9 +2133,11 @@ GLenum GLTrace_glGetError(void) { glmsg.set_function(GLMessage::glGetError); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); GLenum retValue = glContext->hooks->gl.glGetError(); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); // set return value GLMessage_DataType *rt = glmsg.mutable_returnvalue(); @@ -1903,7 +2145,9 @@ GLenum GLTrace_glGetError(void) { rt->set_type(GLMessage::DataType::ENUM); rt->add_intvalue((int)retValue); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); return retValue; @@ -1928,11 +2172,15 @@ void GLTrace_glGetFloatv(GLenum pname, GLfloat* params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetFloatv(pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -1967,11 +2215,15 @@ void GLTrace_glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachm arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetFramebufferAttachmentParameteriv(target, attachment, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -1994,11 +2246,15 @@ void GLTrace_glGetIntegerv(GLenum pname, GLint* params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetIntegerv(pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -2027,11 +2283,15 @@ void GLTrace_glGetProgramiv(GLuint program, GLenum pname, GLint* params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetProgramiv(program, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -2066,11 +2326,15 @@ void GLTrace_glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* lengt arg_infolog->add_intvalue((int)infolog); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetProgramInfoLog(program, bufsize, length, infolog); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -2099,11 +2363,15 @@ void GLTrace_glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* pa arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetRenderbufferParameteriv(target, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -2132,11 +2400,15 @@ void GLTrace_glGetShaderiv(GLuint shader, GLenum pname, GLint* params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetShaderiv(shader, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -2171,11 +2443,15 @@ void GLTrace_glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, arg_infolog->add_intvalue((int)infolog); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetShaderInfoLog(shader, bufsize, length, infolog); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -2210,11 +2486,15 @@ void GLTrace_glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, arg_precision->add_intvalue((int)precision); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetShaderPrecisionFormat(shadertype, precisiontype, range, precision); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -2249,11 +2529,15 @@ void GLTrace_glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, arg_source->add_intvalue((int)source); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetShaderSource(shader, bufsize, length, source); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -2270,9 +2554,11 @@ const GLubyte* GLTrace_glGetString(GLenum name) { arg_name->add_intvalue((int)name); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); const GLubyte* retValue = glContext->hooks->gl.glGetString(name); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); // set return value GLMessage_DataType *rt = glmsg.mutable_returnvalue(); @@ -2280,7 +2566,9 @@ const GLubyte* GLTrace_glGetString(GLenum name) { rt->set_type(GLMessage::DataType::INT); rt->add_intvalue((int)retValue); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); return retValue; @@ -2311,11 +2599,15 @@ void GLTrace_glGetTexParameterfv(GLenum target, GLenum pname, GLfloat* params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetTexParameterfv(target, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -2344,11 +2636,15 @@ void GLTrace_glGetTexParameteriv(GLenum target, GLenum pname, GLint* params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetTexParameteriv(target, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -2377,11 +2673,15 @@ void GLTrace_glGetUniformfv(GLuint program, GLint location, GLfloat* params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetUniformfv(program, location, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -2410,11 +2710,15 @@ void GLTrace_glGetUniformiv(GLuint program, GLint location, GLint* params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetUniformiv(program, location, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -2437,9 +2741,11 @@ int GLTrace_glGetUniformLocation(GLuint program, const GLchar* name) { arg_name->add_intvalue((int)name); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); int retValue = glContext->hooks->gl.glGetUniformLocation(program, name); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); // set return value GLMessage_DataType *rt = glmsg.mutable_returnvalue(); @@ -2447,7 +2753,9 @@ int GLTrace_glGetUniformLocation(GLuint program, const GLchar* name) { rt->set_type(GLMessage::DataType::INT); rt->add_intvalue(retValue); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); return retValue; @@ -2478,11 +2786,15 @@ void GLTrace_glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetVertexAttribfv(index, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -2511,11 +2823,15 @@ void GLTrace_glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetVertexAttribiv(index, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -2544,11 +2860,15 @@ void GLTrace_glGetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid** poin arg_pointer->add_intvalue((int)pointer); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetVertexAttribPointerv(index, pname, pointer); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -2571,11 +2891,15 @@ void GLTrace_glHint(GLenum target, GLenum mode) { arg_mode->add_intvalue((int)mode); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glHint(target, mode); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -2592,9 +2916,11 @@ GLboolean GLTrace_glIsBuffer(GLuint buffer) { arg_buffer->add_intvalue(buffer); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); GLboolean retValue = glContext->hooks->gl.glIsBuffer(buffer); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); // set return value GLMessage_DataType *rt = glmsg.mutable_returnvalue(); @@ -2602,7 +2928,9 @@ GLboolean GLTrace_glIsBuffer(GLuint buffer) { rt->set_type(GLMessage::DataType::BOOL); rt->add_boolvalue(retValue); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); return retValue; @@ -2621,9 +2949,11 @@ GLboolean GLTrace_glIsEnabled(GLenum cap) { arg_cap->add_intvalue((int)cap); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); GLboolean retValue = glContext->hooks->gl.glIsEnabled(cap); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); // set return value GLMessage_DataType *rt = glmsg.mutable_returnvalue(); @@ -2631,7 +2961,9 @@ GLboolean GLTrace_glIsEnabled(GLenum cap) { rt->set_type(GLMessage::DataType::BOOL); rt->add_boolvalue(retValue); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); return retValue; @@ -2650,9 +2982,11 @@ GLboolean GLTrace_glIsFramebuffer(GLuint framebuffer) { arg_framebuffer->add_intvalue(framebuffer); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); GLboolean retValue = glContext->hooks->gl.glIsFramebuffer(framebuffer); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); // set return value GLMessage_DataType *rt = glmsg.mutable_returnvalue(); @@ -2660,7 +2994,9 @@ GLboolean GLTrace_glIsFramebuffer(GLuint framebuffer) { rt->set_type(GLMessage::DataType::BOOL); rt->add_boolvalue(retValue); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); return retValue; @@ -2679,9 +3015,11 @@ GLboolean GLTrace_glIsProgram(GLuint program) { arg_program->add_intvalue(program); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); GLboolean retValue = glContext->hooks->gl.glIsProgram(program); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); // set return value GLMessage_DataType *rt = glmsg.mutable_returnvalue(); @@ -2689,7 +3027,9 @@ GLboolean GLTrace_glIsProgram(GLuint program) { rt->set_type(GLMessage::DataType::BOOL); rt->add_boolvalue(retValue); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); return retValue; @@ -2708,9 +3048,11 @@ GLboolean GLTrace_glIsRenderbuffer(GLuint renderbuffer) { arg_renderbuffer->add_intvalue(renderbuffer); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); GLboolean retValue = glContext->hooks->gl.glIsRenderbuffer(renderbuffer); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); // set return value GLMessage_DataType *rt = glmsg.mutable_returnvalue(); @@ -2718,7 +3060,9 @@ GLboolean GLTrace_glIsRenderbuffer(GLuint renderbuffer) { rt->set_type(GLMessage::DataType::BOOL); rt->add_boolvalue(retValue); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); return retValue; @@ -2737,9 +3081,11 @@ GLboolean GLTrace_glIsShader(GLuint shader) { arg_shader->add_intvalue(shader); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); GLboolean retValue = glContext->hooks->gl.glIsShader(shader); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); // set return value GLMessage_DataType *rt = glmsg.mutable_returnvalue(); @@ -2747,7 +3093,9 @@ GLboolean GLTrace_glIsShader(GLuint shader) { rt->set_type(GLMessage::DataType::BOOL); rt->add_boolvalue(retValue); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); return retValue; @@ -2766,9 +3114,11 @@ GLboolean GLTrace_glIsTexture(GLuint texture) { arg_texture->add_intvalue(texture); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); GLboolean retValue = glContext->hooks->gl.glIsTexture(texture); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); // set return value GLMessage_DataType *rt = glmsg.mutable_returnvalue(); @@ -2776,7 +3126,9 @@ GLboolean GLTrace_glIsTexture(GLuint texture) { rt->set_type(GLMessage::DataType::BOOL); rt->add_boolvalue(retValue); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); return retValue; @@ -2795,11 +3147,15 @@ void GLTrace_glLineWidth(GLfloat width) { arg_width->add_floatvalue(width); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glLineWidth(width); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -2816,11 +3172,15 @@ void GLTrace_glLinkProgram(GLuint program) { arg_program->add_intvalue(program); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glLinkProgram(program); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -2843,11 +3203,15 @@ void GLTrace_glPixelStorei(GLenum pname, GLint param) { arg_param->add_intvalue(param); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glPixelStorei(pname, param); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -2870,11 +3234,15 @@ void GLTrace_glPolygonOffset(GLfloat factor, GLfloat units) { arg_units->add_floatvalue(units); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glPolygonOffset(factor, units); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -2927,11 +3295,15 @@ void GLTrace_glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenu arg_pixels->add_intvalue((int)pixels); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glReadPixels(x, y, width, height, format, type, pixels); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -2942,11 +3314,15 @@ void GLTrace_glReleaseShaderCompiler(void) { glmsg.set_function(GLMessage::glReleaseShaderCompiler); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glReleaseShaderCompiler(); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -2981,11 +3357,15 @@ void GLTrace_glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei arg_height->add_intvalue(height); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glRenderbufferStorage(target, internalformat, width, height); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -3008,11 +3388,15 @@ void GLTrace_glSampleCoverage(GLclampf value, GLboolean invert) { arg_invert->add_boolvalue(invert); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glSampleCoverage(value, invert); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -3047,11 +3431,15 @@ void GLTrace_glScissor(GLint x, GLint y, GLsizei width, GLsizei height) { arg_height->add_intvalue(height); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glScissor(x, y, width, height); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -3092,11 +3480,15 @@ void GLTrace_glShaderBinary(GLsizei n, const GLuint* shaders, GLenum binaryforma arg_length->add_intvalue(length); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glShaderBinary(n, shaders, binaryformat, binary, length); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -3131,11 +3523,15 @@ void GLTrace_glShaderSource(GLuint shader, GLsizei count, const GLchar** string, arg_length->add_intvalue((int)length); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glShaderSource(shader, count, string, length); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -3164,11 +3560,15 @@ void GLTrace_glStencilFunc(GLenum func, GLint ref, GLuint mask) { arg_mask->add_intvalue(mask); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glStencilFunc(func, ref, mask); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -3203,11 +3603,15 @@ void GLTrace_glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint m arg_mask->add_intvalue(mask); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glStencilFuncSeparate(face, func, ref, mask); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -3224,11 +3628,15 @@ void GLTrace_glStencilMask(GLuint mask) { arg_mask->add_intvalue(mask); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glStencilMask(mask); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -3251,11 +3659,15 @@ void GLTrace_glStencilMaskSeparate(GLenum face, GLuint mask) { arg_mask->add_intvalue(mask); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glStencilMaskSeparate(face, mask); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -3284,11 +3696,15 @@ void GLTrace_glStencilOp(GLenum fail, GLenum zfail, GLenum zpass) { arg_zpass->add_intvalue((int)zpass); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glStencilOp(fail, zfail, zpass); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -3323,11 +3739,15 @@ void GLTrace_glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum arg_zpass->add_intvalue((int)zpass); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glStencilOpSeparate(face, fail, zfail, zpass); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -3392,11 +3812,15 @@ void GLTrace_glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsi arg_pixels->add_intvalue((int)pixels); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -3425,11 +3849,15 @@ void GLTrace_glTexParameterf(GLenum target, GLenum pname, GLfloat param) { arg_param->add_floatvalue(param); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glTexParameterf(target, pname, param); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -3458,11 +3886,15 @@ void GLTrace_glTexParameterfv(GLenum target, GLenum pname, const GLfloat* params arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glTexParameterfv(target, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -3491,11 +3923,15 @@ void GLTrace_glTexParameteri(GLenum target, GLenum pname, GLint param) { arg_param->add_intvalue(param); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glTexParameteri(target, pname, param); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -3524,11 +3960,15 @@ void GLTrace_glTexParameteriv(GLenum target, GLenum pname, const GLint* params) arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glTexParameteriv(target, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -3593,11 +4033,15 @@ void GLTrace_glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yo arg_pixels->add_intvalue((int)pixels); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -3620,11 +4064,15 @@ void GLTrace_glUniform1f(GLint location, GLfloat x) { arg_x->add_floatvalue(x); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glUniform1f(location, x); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -3653,11 +4101,15 @@ void GLTrace_glUniform1fv(GLint location, GLsizei count, const GLfloat* v) { arg_v->add_intvalue((int)v); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glUniform1fv(location, count, v); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -3680,11 +4132,15 @@ void GLTrace_glUniform1i(GLint location, GLint x) { arg_x->add_intvalue(x); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glUniform1i(location, x); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -3713,11 +4169,15 @@ void GLTrace_glUniform1iv(GLint location, GLsizei count, const GLint* v) { arg_v->add_intvalue((int)v); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glUniform1iv(location, count, v); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -3746,11 +4206,15 @@ void GLTrace_glUniform2f(GLint location, GLfloat x, GLfloat y) { arg_y->add_floatvalue(y); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glUniform2f(location, x, y); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -3779,11 +4243,15 @@ void GLTrace_glUniform2fv(GLint location, GLsizei count, const GLfloat* v) { arg_v->add_intvalue((int)v); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glUniform2fv(location, count, v); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -3812,11 +4280,15 @@ void GLTrace_glUniform2i(GLint location, GLint x, GLint y) { arg_y->add_intvalue(y); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glUniform2i(location, x, y); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -3845,11 +4317,15 @@ void GLTrace_glUniform2iv(GLint location, GLsizei count, const GLint* v) { arg_v->add_intvalue((int)v); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glUniform2iv(location, count, v); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -3884,11 +4360,15 @@ void GLTrace_glUniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z) { arg_z->add_floatvalue(z); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glUniform3f(location, x, y, z); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -3917,11 +4397,15 @@ void GLTrace_glUniform3fv(GLint location, GLsizei count, const GLfloat* v) { arg_v->add_intvalue((int)v); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glUniform3fv(location, count, v); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -3956,11 +4440,15 @@ void GLTrace_glUniform3i(GLint location, GLint x, GLint y, GLint z) { arg_z->add_intvalue(z); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glUniform3i(location, x, y, z); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -3989,11 +4477,15 @@ void GLTrace_glUniform3iv(GLint location, GLsizei count, const GLint* v) { arg_v->add_intvalue((int)v); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glUniform3iv(location, count, v); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -4034,11 +4526,15 @@ void GLTrace_glUniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloa arg_w->add_floatvalue(w); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glUniform4f(location, x, y, z, w); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -4067,11 +4563,15 @@ void GLTrace_glUniform4fv(GLint location, GLsizei count, const GLfloat* v) { arg_v->add_intvalue((int)v); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glUniform4fv(location, count, v); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -4112,11 +4612,15 @@ void GLTrace_glUniform4i(GLint location, GLint x, GLint y, GLint z, GLint w) { arg_w->add_intvalue(w); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glUniform4i(location, x, y, z, w); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -4145,11 +4649,15 @@ void GLTrace_glUniform4iv(GLint location, GLsizei count, const GLint* v) { arg_v->add_intvalue((int)v); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glUniform4iv(location, count, v); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -4184,11 +4692,15 @@ void GLTrace_glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpo arg_value->add_intvalue((int)value); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glUniformMatrix2fv(location, count, transpose, value); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -4223,11 +4735,15 @@ void GLTrace_glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpo arg_value->add_intvalue((int)value); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glUniformMatrix3fv(location, count, transpose, value); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -4262,11 +4778,15 @@ void GLTrace_glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpo arg_value->add_intvalue((int)value); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glUniformMatrix4fv(location, count, transpose, value); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -4283,11 +4803,15 @@ void GLTrace_glUseProgram(GLuint program) { arg_program->add_intvalue(program); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glUseProgram(program); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -4304,11 +4828,15 @@ void GLTrace_glValidateProgram(GLuint program) { arg_program->add_intvalue(program); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glValidateProgram(program); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -4331,11 +4859,15 @@ void GLTrace_glVertexAttrib1f(GLuint indx, GLfloat x) { arg_x->add_floatvalue(x); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glVertexAttrib1f(indx, x); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -4358,11 +4890,15 @@ void GLTrace_glVertexAttrib1fv(GLuint indx, const GLfloat* values) { arg_values->add_intvalue((int)values); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glVertexAttrib1fv(indx, values); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -4391,11 +4927,15 @@ void GLTrace_glVertexAttrib2f(GLuint indx, GLfloat x, GLfloat y) { arg_y->add_floatvalue(y); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glVertexAttrib2f(indx, x, y); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -4418,11 +4958,15 @@ void GLTrace_glVertexAttrib2fv(GLuint indx, const GLfloat* values) { arg_values->add_intvalue((int)values); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glVertexAttrib2fv(indx, values); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -4457,11 +5001,15 @@ void GLTrace_glVertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z) { arg_z->add_floatvalue(z); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glVertexAttrib3f(indx, x, y, z); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -4484,11 +5032,15 @@ void GLTrace_glVertexAttrib3fv(GLuint indx, const GLfloat* values) { arg_values->add_intvalue((int)values); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glVertexAttrib3fv(indx, values); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -4529,11 +5081,15 @@ void GLTrace_glVertexAttrib4f(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfl arg_w->add_floatvalue(w); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glVertexAttrib4f(indx, x, y, z, w); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -4556,11 +5112,15 @@ void GLTrace_glVertexAttrib4fv(GLuint indx, const GLfloat* values) { arg_values->add_intvalue((int)values); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glVertexAttrib4fv(indx, values); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -4607,11 +5167,15 @@ void GLTrace_glVertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboole arg_ptr->add_intvalue((int)ptr); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glVertexAttribPointer(indx, size, type, normalized, stride, ptr); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -4646,11 +5210,15 @@ void GLTrace_glViewport(GLint x, GLint y, GLsizei width, GLsizei height) { arg_height->add_intvalue(height); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glViewport(x, y, width, height); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -4676,11 +5244,15 @@ void GLTrace_glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image) { arg_image->add_intvalue((int)image); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glEGLImageTargetTexture2DOES(target, image); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -4703,11 +5275,15 @@ void GLTrace_glEGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES arg_image->add_intvalue((int)image); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glEGLImageTargetRenderbufferStorageOES(target, image); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -4748,11 +5324,15 @@ void GLTrace_glGetProgramBinaryOES(GLuint program, GLsizei bufSize, GLsizei *len arg_binary->add_intvalue((int)binary); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetProgramBinaryOES(program, bufSize, length, binaryFormat, binary); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -4787,11 +5367,15 @@ void GLTrace_glProgramBinaryOES(GLuint program, GLenum binaryFormat, const GLvoi arg_length->add_intvalue(length); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glProgramBinaryOES(program, binaryFormat, binary, length); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -4814,9 +5398,11 @@ void* GLTrace_glMapBufferOES(GLenum target, GLenum access) { arg_access->add_intvalue((int)access); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); void* retValue = glContext->hooks->gl.glMapBufferOES(target, access); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); // set return value GLMessage_DataType *rt = glmsg.mutable_returnvalue(); @@ -4824,7 +5410,9 @@ void* GLTrace_glMapBufferOES(GLenum target, GLenum access) { rt->set_type(GLMessage::DataType::INT); rt->add_intvalue((int)retValue); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); return retValue; @@ -4843,9 +5431,11 @@ GLboolean GLTrace_glUnmapBufferOES(GLenum target) { arg_target->add_intvalue((int)target); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); GLboolean retValue = glContext->hooks->gl.glUnmapBufferOES(target); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); // set return value GLMessage_DataType *rt = glmsg.mutable_returnvalue(); @@ -4853,7 +5443,9 @@ GLboolean GLTrace_glUnmapBufferOES(GLenum target) { rt->set_type(GLMessage::DataType::BOOL); rt->add_boolvalue(retValue); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); return retValue; @@ -4884,11 +5476,15 @@ void GLTrace_glGetBufferPointervOES(GLenum target, GLenum pname, GLvoid** params arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetBufferPointervOES(target, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -4959,11 +5555,15 @@ void GLTrace_glTexImage3DOES(GLenum target, GLint level, GLenum internalformat, arg_pixels->add_intvalue((int)pixels); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glTexImage3DOES(target, level, internalformat, width, height, depth, border, format, type, pixels); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -5040,11 +5640,15 @@ void GLTrace_glTexSubImage3DOES(GLenum target, GLint level, GLint xoffset, GLint arg_pixels->add_intvalue((int)pixels); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glTexSubImage3DOES(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -5109,11 +5713,15 @@ void GLTrace_glCopyTexSubImage3DOES(GLenum target, GLint level, GLint xoffset, G arg_height->add_intvalue(height); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glCopyTexSubImage3DOES(target, level, xoffset, yoffset, zoffset, x, y, width, height); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -5178,11 +5786,15 @@ void GLTrace_glCompressedTexImage3DOES(GLenum target, GLint level, GLenum intern arg_data->add_intvalue((int)data); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glCompressedTexImage3DOES(target, level, internalformat, width, height, depth, border, imageSize, data); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -5259,11 +5871,15 @@ void GLTrace_glCompressedTexSubImage3DOES(GLenum target, GLint level, GLint xoff arg_data->add_intvalue((int)data); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glCompressedTexSubImage3DOES(target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -5310,11 +5926,15 @@ void GLTrace_glFramebufferTexture3DOES(GLenum target, GLenum attachment, GLenum arg_zoffset->add_intvalue(zoffset); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glFramebufferTexture3DOES(target, attachment, textarget, texture, level, zoffset); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -5331,11 +5951,15 @@ void GLTrace_glBindVertexArrayOES(GLuint array) { arg_array->add_intvalue(array); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glBindVertexArrayOES(array); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -5358,11 +5982,15 @@ void GLTrace_glDeleteVertexArraysOES(GLsizei n, const GLuint *arrays) { arg_arrays->add_intvalue((int)arrays); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glDeleteVertexArraysOES(n, arrays); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -5385,11 +6013,15 @@ void GLTrace_glGenVertexArraysOES(GLsizei n, GLuint *arrays) { arg_arrays->add_intvalue((int)arrays); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGenVertexArraysOES(n, arrays); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -5406,9 +6038,11 @@ GLboolean GLTrace_glIsVertexArrayOES(GLuint array) { arg_array->add_intvalue(array); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); GLboolean retValue = glContext->hooks->gl.glIsVertexArrayOES(array); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); // set return value GLMessage_DataType *rt = glmsg.mutable_returnvalue(); @@ -5416,7 +6050,9 @@ GLboolean GLTrace_glIsVertexArrayOES(GLuint array) { rt->set_type(GLMessage::DataType::BOOL); rt->add_boolvalue(retValue); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); return retValue; @@ -5447,11 +6083,15 @@ void GLTrace_glGetPerfMonitorGroupsAMD(GLint *numGroups, GLsizei groupsSize, GLu arg_groups->add_intvalue((int)groups); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetPerfMonitorGroupsAMD(numGroups, groupsSize, groups); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -5492,11 +6132,15 @@ void GLTrace_glGetPerfMonitorCountersAMD(GLuint group, GLint *numCounters, GLint arg_counters->add_intvalue((int)counters); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetPerfMonitorCountersAMD(group, numCounters, maxActiveCounters, counterSize, counters); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -5531,11 +6175,15 @@ void GLTrace_glGetPerfMonitorGroupStringAMD(GLuint group, GLsizei bufSize, GLsiz arg_groupString->add_intvalue((int)groupString); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetPerfMonitorGroupStringAMD(group, bufSize, length, groupString); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -5576,11 +6224,15 @@ void GLTrace_glGetPerfMonitorCounterStringAMD(GLuint group, GLuint counter, GLsi arg_counterString->add_intvalue((int)counterString); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetPerfMonitorCounterStringAMD(group, counter, bufSize, length, counterString); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -5615,11 +6267,15 @@ void GLTrace_glGetPerfMonitorCounterInfoAMD(GLuint group, GLuint counter, GLenum arg_data->add_intvalue((int)data); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetPerfMonitorCounterInfoAMD(group, counter, pname, data); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -5642,11 +6298,15 @@ void GLTrace_glGenPerfMonitorsAMD(GLsizei n, GLuint *monitors) { arg_monitors->add_intvalue((int)monitors); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGenPerfMonitorsAMD(n, monitors); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -5669,11 +6329,15 @@ void GLTrace_glDeletePerfMonitorsAMD(GLsizei n, GLuint *monitors) { arg_monitors->add_intvalue((int)monitors); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glDeletePerfMonitorsAMD(n, monitors); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -5714,11 +6378,15 @@ void GLTrace_glSelectPerfMonitorCountersAMD(GLuint monitor, GLboolean enable, GL arg_countersList->add_intvalue((int)countersList); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glSelectPerfMonitorCountersAMD(monitor, enable, group, numCounters, countersList); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -5735,11 +6403,15 @@ void GLTrace_glBeginPerfMonitorAMD(GLuint monitor) { arg_monitor->add_intvalue(monitor); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glBeginPerfMonitorAMD(monitor); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -5756,11 +6428,15 @@ void GLTrace_glEndPerfMonitorAMD(GLuint monitor) { arg_monitor->add_intvalue(monitor); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glEndPerfMonitorAMD(monitor); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -5801,11 +6477,15 @@ void GLTrace_glGetPerfMonitorCounterDataAMD(GLuint monitor, GLenum pname, GLsize arg_bytesWritten->add_intvalue((int)bytesWritten); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetPerfMonitorCounterDataAMD(monitor, pname, dataSize, data, bytesWritten); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -5876,11 +6556,15 @@ void GLTrace_glBlitFramebufferANGLE(GLint srcX0, GLint srcY0, GLint srcX1, GLint arg_filter->add_intvalue((int)filter); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glBlitFramebufferANGLE(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -5921,11 +6605,15 @@ void GLTrace_glRenderbufferStorageMultisampleANGLE(GLenum target, GLsizei sample arg_height->add_intvalue(height); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glRenderbufferStorageMultisampleANGLE(target, samples, internalformat, width, height); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -5966,11 +6654,15 @@ void GLTrace_glRenderbufferStorageMultisampleAPPLE(GLenum target, GLsizei sample arg_height->add_intvalue(height); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glRenderbufferStorageMultisampleAPPLE(target, samples, internalformat, width, height); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -5981,11 +6673,15 @@ void GLTrace_glResolveMultisampleFramebufferAPPLE(void) { glmsg.set_function(GLMessage::glResolveMultisampleFramebufferAPPLE); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glResolveMultisampleFramebufferAPPLE(); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -6020,11 +6716,15 @@ void GLTrace_glLabelObjectEXT(GLenum type, GLuint object, GLsizei length, const arg_label->add_intvalue((int)label); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glLabelObjectEXT(type, object, length, label); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -6065,11 +6765,15 @@ void GLTrace_glGetObjectLabelEXT(GLenum type, GLuint object, GLsizei bufSize, GL arg_label->add_intvalue((int)label); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetObjectLabelEXT(type, object, bufSize, length, label); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -6092,11 +6796,15 @@ void GLTrace_glInsertEventMarkerEXT(GLsizei length, const GLchar *marker) { arg_marker->add_intvalue((int)marker); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glInsertEventMarkerEXT(length, marker); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -6119,11 +6827,15 @@ void GLTrace_glPushGroupMarkerEXT(GLsizei length, const GLchar *marker) { arg_marker->add_intvalue((int)marker); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glPushGroupMarkerEXT(length, marker); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -6134,11 +6846,15 @@ void GLTrace_glPopGroupMarkerEXT(void) { glmsg.set_function(GLMessage::glPopGroupMarkerEXT); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glPopGroupMarkerEXT(); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -6167,11 +6883,15 @@ void GLTrace_glDiscardFramebufferEXT(GLenum target, GLsizei numAttachments, cons arg_attachments->add_intvalue((int)attachments); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glDiscardFramebufferEXT(target, numAttachments, attachments); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -6212,11 +6932,15 @@ void GLTrace_glRenderbufferStorageMultisampleEXT(GLenum target, GLsizei samples, arg_height->add_intvalue(height); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glRenderbufferStorageMultisampleEXT(target, samples, internalformat, width, height); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -6263,11 +6987,15 @@ void GLTrace_glFramebufferTexture2DMultisampleEXT(GLenum target, GLenum attachme arg_samples->add_intvalue(samples); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glFramebufferTexture2DMultisampleEXT(target, attachment, textarget, texture, level, samples); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -6302,11 +7030,15 @@ void GLTrace_glMultiDrawArraysEXT(GLenum mode, GLint *first, GLsizei *count, GLs arg_primcount->add_intvalue(primcount); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glMultiDrawArraysEXT(mode, first, count, primcount); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -6347,11 +7079,15 @@ void GLTrace_glMultiDrawElementsEXT(GLenum mode, const GLsizei *count, GLenum ty arg_primcount->add_intvalue(primcount); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glMultiDrawElementsEXT(mode, count, type, indices, primcount); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -6374,11 +7110,15 @@ void GLTrace_glGenQueriesEXT(GLsizei n, GLuint *ids) { arg_ids->add_intvalue((int)ids); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGenQueriesEXT(n, ids); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -6401,11 +7141,15 @@ void GLTrace_glDeleteQueriesEXT(GLsizei n, const GLuint *ids) { arg_ids->add_intvalue((int)ids); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glDeleteQueriesEXT(n, ids); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -6422,9 +7166,11 @@ GLboolean GLTrace_glIsQueryEXT(GLuint id) { arg_id->add_intvalue(id); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); GLboolean retValue = glContext->hooks->gl.glIsQueryEXT(id); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); // set return value GLMessage_DataType *rt = glmsg.mutable_returnvalue(); @@ -6432,7 +7178,9 @@ GLboolean GLTrace_glIsQueryEXT(GLuint id) { rt->set_type(GLMessage::DataType::BOOL); rt->add_boolvalue(retValue); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); return retValue; @@ -6457,11 +7205,15 @@ void GLTrace_glBeginQueryEXT(GLenum target, GLuint id) { arg_id->add_intvalue(id); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glBeginQueryEXT(target, id); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -6478,11 +7230,15 @@ void GLTrace_glEndQueryEXT(GLenum target) { arg_target->add_intvalue((int)target); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glEndQueryEXT(target); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -6511,11 +7267,15 @@ void GLTrace_glGetQueryivEXT(GLenum target, GLenum pname, GLint *params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetQueryivEXT(target, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -6544,11 +7304,15 @@ void GLTrace_glGetQueryObjectuivEXT(GLuint id, GLenum pname, GLuint *params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetQueryObjectuivEXT(id, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -6559,9 +7323,11 @@ GLenum GLTrace_glGetGraphicsResetStatusEXT(void) { glmsg.set_function(GLMessage::glGetGraphicsResetStatusEXT); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); GLenum retValue = glContext->hooks->gl.glGetGraphicsResetStatusEXT(); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); // set return value GLMessage_DataType *rt = glmsg.mutable_returnvalue(); @@ -6569,7 +7335,9 @@ GLenum GLTrace_glGetGraphicsResetStatusEXT(void) { rt->set_type(GLMessage::DataType::ENUM); rt->add_intvalue((int)retValue); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); return retValue; @@ -6630,11 +7398,15 @@ void GLTrace_glReadnPixelsEXT(GLint x, GLint y, GLsizei width, GLsizei height, G arg_data->add_intvalue((int)data); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glReadnPixelsEXT(x, y, width, height, format, type, bufSize, data); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -6669,11 +7441,15 @@ void GLTrace_glGetnUniformfvEXT(GLuint program, GLint location, GLsizei bufSize, arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetnUniformfvEXT(program, location, bufSize, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -6708,11 +7484,15 @@ void GLTrace_glGetnUniformivEXT(GLuint program, GLint location, GLsizei bufSize, arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetnUniformivEXT(program, location, bufSize, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -6741,11 +7521,15 @@ void GLTrace_glUseProgramStagesEXT(GLuint pipeline, GLbitfield stages, GLuint pr arg_program->add_intvalue(program); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glUseProgramStagesEXT(pipeline, stages, program); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -6768,11 +7552,15 @@ void GLTrace_glActiveShaderProgramEXT(GLuint pipeline, GLuint program) { arg_program->add_intvalue(program); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glActiveShaderProgramEXT(pipeline, program); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -6801,9 +7589,11 @@ GLuint GLTrace_glCreateShaderProgramvEXT(GLenum type, GLsizei count, const GLcha arg_strings->add_intvalue((int)strings); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); GLuint retValue = glContext->hooks->gl.glCreateShaderProgramvEXT(type, count, strings); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); // set return value GLMessage_DataType *rt = glmsg.mutable_returnvalue(); @@ -6811,7 +7601,9 @@ GLuint GLTrace_glCreateShaderProgramvEXT(GLenum type, GLsizei count, const GLcha rt->set_type(GLMessage::DataType::INT); rt->add_intvalue(retValue); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); return retValue; @@ -6830,11 +7622,15 @@ void GLTrace_glBindProgramPipelineEXT(GLuint pipeline) { arg_pipeline->add_intvalue(pipeline); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glBindProgramPipelineEXT(pipeline); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -6857,11 +7653,15 @@ void GLTrace_glDeleteProgramPipelinesEXT(GLsizei n, const GLuint *pipelines) { arg_pipelines->add_intvalue((int)pipelines); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glDeleteProgramPipelinesEXT(n, pipelines); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -6884,11 +7684,15 @@ void GLTrace_glGenProgramPipelinesEXT(GLsizei n, GLuint *pipelines) { arg_pipelines->add_intvalue((int)pipelines); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGenProgramPipelinesEXT(n, pipelines); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -6905,9 +7709,11 @@ GLboolean GLTrace_glIsProgramPipelineEXT(GLuint pipeline) { arg_pipeline->add_intvalue(pipeline); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); GLboolean retValue = glContext->hooks->gl.glIsProgramPipelineEXT(pipeline); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); // set return value GLMessage_DataType *rt = glmsg.mutable_returnvalue(); @@ -6915,7 +7721,9 @@ GLboolean GLTrace_glIsProgramPipelineEXT(GLuint pipeline) { rt->set_type(GLMessage::DataType::BOOL); rt->add_boolvalue(retValue); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); return retValue; @@ -6946,11 +7754,15 @@ void GLTrace_glProgramParameteriEXT(GLuint program, GLenum pname, GLint value) { arg_value->add_intvalue(value); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glProgramParameteriEXT(program, pname, value); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -6979,11 +7791,15 @@ void GLTrace_glGetProgramPipelineivEXT(GLuint pipeline, GLenum pname, GLint *par arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetProgramPipelineivEXT(pipeline, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -7012,11 +7828,15 @@ void GLTrace_glProgramUniform1iEXT(GLuint program, GLint location, GLint x) { arg_x->add_intvalue(x); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glProgramUniform1iEXT(program, location, x); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -7051,11 +7871,15 @@ void GLTrace_glProgramUniform2iEXT(GLuint program, GLint location, GLint x, GLin arg_y->add_intvalue(y); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glProgramUniform2iEXT(program, location, x, y); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -7096,11 +7920,15 @@ void GLTrace_glProgramUniform3iEXT(GLuint program, GLint location, GLint x, GLin arg_z->add_intvalue(z); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glProgramUniform3iEXT(program, location, x, y, z); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -7147,11 +7975,15 @@ void GLTrace_glProgramUniform4iEXT(GLuint program, GLint location, GLint x, GLin arg_w->add_intvalue(w); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glProgramUniform4iEXT(program, location, x, y, z, w); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -7180,11 +8012,15 @@ void GLTrace_glProgramUniform1fEXT(GLuint program, GLint location, GLfloat x) { arg_x->add_floatvalue(x); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glProgramUniform1fEXT(program, location, x); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -7219,11 +8055,15 @@ void GLTrace_glProgramUniform2fEXT(GLuint program, GLint location, GLfloat x, GL arg_y->add_floatvalue(y); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glProgramUniform2fEXT(program, location, x, y); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -7264,11 +8104,15 @@ void GLTrace_glProgramUniform3fEXT(GLuint program, GLint location, GLfloat x, GL arg_z->add_floatvalue(z); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glProgramUniform3fEXT(program, location, x, y, z); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -7315,11 +8159,15 @@ void GLTrace_glProgramUniform4fEXT(GLuint program, GLint location, GLfloat x, GL arg_w->add_floatvalue(w); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glProgramUniform4fEXT(program, location, x, y, z, w); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -7354,11 +8202,15 @@ void GLTrace_glProgramUniform1ivEXT(GLuint program, GLint location, GLsizei coun arg_value->add_intvalue((int)value); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glProgramUniform1ivEXT(program, location, count, value); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -7393,11 +8245,15 @@ void GLTrace_glProgramUniform2ivEXT(GLuint program, GLint location, GLsizei coun arg_value->add_intvalue((int)value); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glProgramUniform2ivEXT(program, location, count, value); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -7432,11 +8288,15 @@ void GLTrace_glProgramUniform3ivEXT(GLuint program, GLint location, GLsizei coun arg_value->add_intvalue((int)value); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glProgramUniform3ivEXT(program, location, count, value); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -7471,11 +8331,15 @@ void GLTrace_glProgramUniform4ivEXT(GLuint program, GLint location, GLsizei coun arg_value->add_intvalue((int)value); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glProgramUniform4ivEXT(program, location, count, value); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -7510,11 +8374,15 @@ void GLTrace_glProgramUniform1fvEXT(GLuint program, GLint location, GLsizei coun arg_value->add_intvalue((int)value); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glProgramUniform1fvEXT(program, location, count, value); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -7549,11 +8417,15 @@ void GLTrace_glProgramUniform2fvEXT(GLuint program, GLint location, GLsizei coun arg_value->add_intvalue((int)value); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glProgramUniform2fvEXT(program, location, count, value); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -7588,11 +8460,15 @@ void GLTrace_glProgramUniform3fvEXT(GLuint program, GLint location, GLsizei coun arg_value->add_intvalue((int)value); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glProgramUniform3fvEXT(program, location, count, value); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -7627,11 +8503,15 @@ void GLTrace_glProgramUniform4fvEXT(GLuint program, GLint location, GLsizei coun arg_value->add_intvalue((int)value); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glProgramUniform4fvEXT(program, location, count, value); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -7672,11 +8552,15 @@ void GLTrace_glProgramUniformMatrix2fvEXT(GLuint program, GLint location, GLsize arg_value->add_intvalue((int)value); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glProgramUniformMatrix2fvEXT(program, location, count, transpose, value); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -7717,11 +8601,15 @@ void GLTrace_glProgramUniformMatrix3fvEXT(GLuint program, GLint location, GLsize arg_value->add_intvalue((int)value); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glProgramUniformMatrix3fvEXT(program, location, count, transpose, value); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -7762,11 +8650,15 @@ void GLTrace_glProgramUniformMatrix4fvEXT(GLuint program, GLint location, GLsize arg_value->add_intvalue((int)value); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glProgramUniformMatrix4fvEXT(program, location, count, transpose, value); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -7783,11 +8675,15 @@ void GLTrace_glValidateProgramPipelineEXT(GLuint pipeline) { arg_pipeline->add_intvalue(pipeline); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glValidateProgramPipelineEXT(pipeline); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -7822,11 +8718,15 @@ void GLTrace_glGetProgramPipelineInfoLogEXT(GLuint pipeline, GLsizei bufSize, GL arg_infoLog->add_intvalue((int)infoLog); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetProgramPipelineInfoLogEXT(pipeline, bufSize, length, infoLog); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -7861,11 +8761,15 @@ void GLTrace_glTexStorage1DEXT(GLenum target, GLsizei levels, GLenum internalfor arg_width->add_intvalue(width); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glTexStorage1DEXT(target, levels, internalformat, width); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -7906,11 +8810,15 @@ void GLTrace_glTexStorage2DEXT(GLenum target, GLsizei levels, GLenum internalfor arg_height->add_intvalue(height); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glTexStorage2DEXT(target, levels, internalformat, width, height); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -7957,11 +8865,15 @@ void GLTrace_glTexStorage3DEXT(GLenum target, GLsizei levels, GLenum internalfor arg_depth->add_intvalue(depth); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glTexStorage3DEXT(target, levels, internalformat, width, height, depth); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -8002,11 +8914,15 @@ void GLTrace_glTextureStorage1DEXT(GLuint texture, GLenum target, GLsizei levels arg_width->add_intvalue(width); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glTextureStorage1DEXT(texture, target, levels, internalformat, width); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -8053,11 +8969,15 @@ void GLTrace_glTextureStorage2DEXT(GLuint texture, GLenum target, GLsizei levels arg_height->add_intvalue(height); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glTextureStorage2DEXT(texture, target, levels, internalformat, width, height); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -8110,11 +9030,15 @@ void GLTrace_glTextureStorage3DEXT(GLuint texture, GLenum target, GLsizei levels arg_depth->add_intvalue(depth); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glTextureStorage3DEXT(texture, target, levels, internalformat, width, height, depth); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -8155,11 +9079,15 @@ void GLTrace_glRenderbufferStorageMultisampleIMG(GLenum target, GLsizei samples, arg_height->add_intvalue(height); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glRenderbufferStorageMultisampleIMG(target, samples, internalformat, width, height); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -8206,11 +9134,15 @@ void GLTrace_glFramebufferTexture2DMultisampleIMG(GLenum target, GLenum attachme arg_samples->add_intvalue(samples); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glFramebufferTexture2DMultisampleIMG(target, attachment, textarget, texture, level, samples); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -8227,11 +9159,15 @@ void GLTrace_glCoverageMaskNV(GLboolean mask) { arg_mask->add_boolvalue(mask); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glCoverageMaskNV(mask); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -8248,11 +9184,15 @@ void GLTrace_glCoverageOperationNV(GLenum operation) { arg_operation->add_intvalue((int)operation); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glCoverageOperationNV(operation); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -8275,11 +9215,15 @@ void GLTrace_glDrawBuffersNV(GLsizei n, const GLenum *bufs) { arg_bufs->add_intvalue((int)bufs); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glDrawBuffersNV(n, bufs); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -8302,11 +9246,15 @@ void GLTrace_glDeleteFencesNV(GLsizei n, const GLuint *fences) { arg_fences->add_intvalue((int)fences); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glDeleteFencesNV(n, fences); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -8329,11 +9277,15 @@ void GLTrace_glGenFencesNV(GLsizei n, GLuint *fences) { arg_fences->add_intvalue((int)fences); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGenFencesNV(n, fences); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -8350,9 +9302,11 @@ GLboolean GLTrace_glIsFenceNV(GLuint fence) { arg_fence->add_intvalue(fence); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); GLboolean retValue = glContext->hooks->gl.glIsFenceNV(fence); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); // set return value GLMessage_DataType *rt = glmsg.mutable_returnvalue(); @@ -8360,7 +9314,9 @@ GLboolean GLTrace_glIsFenceNV(GLuint fence) { rt->set_type(GLMessage::DataType::BOOL); rt->add_boolvalue(retValue); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); return retValue; @@ -8379,9 +9335,11 @@ GLboolean GLTrace_glTestFenceNV(GLuint fence) { arg_fence->add_intvalue(fence); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); GLboolean retValue = glContext->hooks->gl.glTestFenceNV(fence); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); // set return value GLMessage_DataType *rt = glmsg.mutable_returnvalue(); @@ -8389,7 +9347,9 @@ GLboolean GLTrace_glTestFenceNV(GLuint fence) { rt->set_type(GLMessage::DataType::BOOL); rt->add_boolvalue(retValue); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); return retValue; @@ -8420,11 +9380,15 @@ void GLTrace_glGetFenceivNV(GLuint fence, GLenum pname, GLint *params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetFenceivNV(fence, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -8441,11 +9405,15 @@ void GLTrace_glFinishFenceNV(GLuint fence) { arg_fence->add_intvalue(fence); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glFinishFenceNV(fence); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -8468,11 +9436,15 @@ void GLTrace_glSetFenceNV(GLuint fence, GLenum condition) { arg_condition->add_intvalue((int)condition); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glSetFenceNV(fence, condition); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -8489,11 +9461,15 @@ void GLTrace_glReadBufferNV(GLenum mode) { arg_mode->add_intvalue((int)mode); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glReadBufferNV(mode); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -8516,11 +9492,15 @@ void GLTrace_glAlphaFuncQCOM(GLenum func, GLclampf ref) { arg_ref->add_floatvalue(ref); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glAlphaFuncQCOM(func, ref); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -8549,11 +9529,15 @@ void GLTrace_glGetDriverControlsQCOM(GLint *num, GLsizei size, GLuint *driverCon arg_driverControls->add_intvalue((int)driverControls); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetDriverControlsQCOM(num, size, driverControls); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -8588,11 +9572,15 @@ void GLTrace_glGetDriverControlStringQCOM(GLuint driverControl, GLsizei bufSize, arg_driverControlString->add_intvalue((int)driverControlString); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetDriverControlStringQCOM(driverControl, bufSize, length, driverControlString); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -8609,11 +9597,15 @@ void GLTrace_glEnableDriverControlQCOM(GLuint driverControl) { arg_driverControl->add_intvalue(driverControl); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glEnableDriverControlQCOM(driverControl); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -8630,11 +9622,15 @@ void GLTrace_glDisableDriverControlQCOM(GLuint driverControl) { arg_driverControl->add_intvalue(driverControl); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glDisableDriverControlQCOM(driverControl); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -8663,11 +9659,15 @@ void GLTrace_glExtGetTexturesQCOM(GLuint *textures, GLint maxTextures, GLint *nu arg_numTextures->add_intvalue((int)numTextures); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glExtGetTexturesQCOM(textures, maxTextures, numTextures); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -8696,11 +9696,15 @@ void GLTrace_glExtGetBuffersQCOM(GLuint *buffers, GLint maxBuffers, GLint *numBu arg_numBuffers->add_intvalue((int)numBuffers); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glExtGetBuffersQCOM(buffers, maxBuffers, numBuffers); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -8729,11 +9733,15 @@ void GLTrace_glExtGetRenderbuffersQCOM(GLuint *renderbuffers, GLint maxRenderbuf arg_numRenderbuffers->add_intvalue((int)numRenderbuffers); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glExtGetRenderbuffersQCOM(renderbuffers, maxRenderbuffers, numRenderbuffers); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -8762,11 +9770,15 @@ void GLTrace_glExtGetFramebuffersQCOM(GLuint *framebuffers, GLint maxFramebuffer arg_numFramebuffers->add_intvalue((int)numFramebuffers); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glExtGetFramebuffersQCOM(framebuffers, maxFramebuffers, numFramebuffers); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -8807,11 +9819,15 @@ void GLTrace_glExtGetTexLevelParameterivQCOM(GLuint texture, GLenum face, GLint arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glExtGetTexLevelParameterivQCOM(texture, face, level, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -8840,11 +9856,15 @@ void GLTrace_glExtTexObjectStateOverrideiQCOM(GLenum target, GLenum pname, GLint arg_param->add_intvalue(param); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glExtTexObjectStateOverrideiQCOM(target, pname, param); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -8921,11 +9941,15 @@ void GLTrace_glExtGetTexSubImageQCOM(GLenum target, GLint level, GLint xoffset, arg_texels->add_intvalue((int)texels); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glExtGetTexSubImageQCOM(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, texels); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -8948,11 +9972,15 @@ void GLTrace_glExtGetBufferPointervQCOM(GLenum target, GLvoid **params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glExtGetBufferPointervQCOM(target, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -8981,11 +10009,15 @@ void GLTrace_glExtGetShadersQCOM(GLuint *shaders, GLint maxShaders, GLint *numSh arg_numShaders->add_intvalue((int)numShaders); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glExtGetShadersQCOM(shaders, maxShaders, numShaders); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -9014,11 +10046,15 @@ void GLTrace_glExtGetProgramsQCOM(GLuint *programs, GLint maxPrograms, GLint *nu arg_numPrograms->add_intvalue((int)numPrograms); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glExtGetProgramsQCOM(programs, maxPrograms, numPrograms); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -9035,9 +10071,11 @@ GLboolean GLTrace_glExtIsProgramBinaryQCOM(GLuint program) { arg_program->add_intvalue(program); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); GLboolean retValue = glContext->hooks->gl.glExtIsProgramBinaryQCOM(program); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); // set return value GLMessage_DataType *rt = glmsg.mutable_returnvalue(); @@ -9045,7 +10083,9 @@ GLboolean GLTrace_glExtIsProgramBinaryQCOM(GLuint program) { rt->set_type(GLMessage::DataType::BOOL); rt->add_boolvalue(retValue); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); return retValue; @@ -9082,11 +10122,15 @@ void GLTrace_glExtGetProgramBinarySourceQCOM(GLuint program, GLenum shadertype, arg_length->add_intvalue((int)length); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glExtGetProgramBinarySourceQCOM(program, shadertype, source, length); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -9127,11 +10171,15 @@ void GLTrace_glStartTilingQCOM(GLuint x, GLuint y, GLuint width, GLuint height, arg_preserveMask->add_intvalue(preserveMask); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glStartTilingQCOM(x, y, width, height, preserveMask); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -9148,11 +10196,15 @@ void GLTrace_glEndTilingQCOM(GLbitfield preserveMask) { arg_preserveMask->add_intvalue(preserveMask); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glEndTilingQCOM(preserveMask); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -9178,11 +10230,15 @@ void GLTrace_glAlphaFunc(GLenum func, GLclampf ref) { arg_ref->add_floatvalue(ref); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glAlphaFunc(func, ref); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -9205,11 +10261,15 @@ void GLTrace_glClipPlanef(GLenum plane, const GLfloat *equation) { arg_equation->add_intvalue((int)equation); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glClipPlanef(plane, equation); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -9244,11 +10304,15 @@ void GLTrace_glColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) arg_alpha->add_floatvalue(alpha); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glColor4f(red, green, blue, alpha); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -9271,11 +10335,15 @@ void GLTrace_glFogf(GLenum pname, GLfloat param) { arg_param->add_floatvalue(param); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glFogf(pname, param); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -9298,11 +10366,15 @@ void GLTrace_glFogfv(GLenum pname, const GLfloat *params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glFogfv(pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -9349,11 +10421,15 @@ void GLTrace_glFrustumf(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top arg_zFar->add_floatvalue(zFar); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glFrustumf(left, right, bottom, top, zNear, zFar); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -9376,11 +10452,15 @@ void GLTrace_glGetClipPlanef(GLenum pname, GLfloat eqn[4]) { arg_eqn->add_intvalue((int)eqn); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetClipPlanef(pname, eqn); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -9409,11 +10489,15 @@ void GLTrace_glGetLightfv(GLenum light, GLenum pname, GLfloat *params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetLightfv(light, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -9442,11 +10526,15 @@ void GLTrace_glGetMaterialfv(GLenum face, GLenum pname, GLfloat *params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetMaterialfv(face, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -9475,11 +10563,15 @@ void GLTrace_glGetTexEnvfv(GLenum env, GLenum pname, GLfloat *params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetTexEnvfv(env, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -9502,11 +10594,15 @@ void GLTrace_glLightModelf(GLenum pname, GLfloat param) { arg_param->add_floatvalue(param); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glLightModelf(pname, param); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -9529,11 +10625,15 @@ void GLTrace_glLightModelfv(GLenum pname, const GLfloat *params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glLightModelfv(pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -9562,11 +10662,15 @@ void GLTrace_glLightf(GLenum light, GLenum pname, GLfloat param) { arg_param->add_floatvalue(param); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glLightf(light, pname, param); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -9595,11 +10699,15 @@ void GLTrace_glLightfv(GLenum light, GLenum pname, const GLfloat *params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glLightfv(light, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -9616,11 +10724,15 @@ void GLTrace_glLoadMatrixf(const GLfloat *m) { arg_m->add_intvalue((int)m); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glLoadMatrixf(m); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -9649,11 +10761,15 @@ void GLTrace_glMaterialf(GLenum face, GLenum pname, GLfloat param) { arg_param->add_floatvalue(param); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glMaterialf(face, pname, param); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -9682,11 +10798,15 @@ void GLTrace_glMaterialfv(GLenum face, GLenum pname, const GLfloat *params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glMaterialfv(face, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -9703,11 +10823,15 @@ void GLTrace_glMultMatrixf(const GLfloat *m) { arg_m->add_intvalue((int)m); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glMultMatrixf(m); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -9748,11 +10872,15 @@ void GLTrace_glMultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, G arg_q->add_floatvalue(q); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glMultiTexCoord4f(target, s, t, r, q); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -9781,11 +10909,15 @@ void GLTrace_glNormal3f(GLfloat nx, GLfloat ny, GLfloat nz) { arg_nz->add_floatvalue(nz); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glNormal3f(nx, ny, nz); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -9832,11 +10964,15 @@ void GLTrace_glOrthof(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, arg_zFar->add_floatvalue(zFar); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glOrthof(left, right, bottom, top, zNear, zFar); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -9859,11 +10995,15 @@ void GLTrace_glPointParameterf(GLenum pname, GLfloat param) { arg_param->add_floatvalue(param); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glPointParameterf(pname, param); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -9886,11 +11026,15 @@ void GLTrace_glPointParameterfv(GLenum pname, const GLfloat *params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glPointParameterfv(pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -9907,11 +11051,15 @@ void GLTrace_glPointSize(GLfloat size) { arg_size->add_floatvalue(size); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glPointSize(size); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -9946,11 +11094,15 @@ void GLTrace_glRotatef(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) { arg_z->add_floatvalue(z); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glRotatef(angle, x, y, z); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -9979,11 +11131,15 @@ void GLTrace_glScalef(GLfloat x, GLfloat y, GLfloat z) { arg_z->add_floatvalue(z); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glScalef(x, y, z); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -10012,11 +11168,15 @@ void GLTrace_glTexEnvf(GLenum target, GLenum pname, GLfloat param) { arg_param->add_floatvalue(param); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glTexEnvf(target, pname, param); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -10045,11 +11205,15 @@ void GLTrace_glTexEnvfv(GLenum target, GLenum pname, const GLfloat *params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glTexEnvfv(target, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -10078,11 +11242,15 @@ void GLTrace_glTranslatef(GLfloat x, GLfloat y, GLfloat z) { arg_z->add_floatvalue(z); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glTranslatef(x, y, z); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -10105,11 +11273,15 @@ void GLTrace_glAlphaFuncx(GLenum func, GLclampx ref) { arg_ref->add_intvalue(ref); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glAlphaFuncx(func, ref); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -10144,11 +11316,15 @@ void GLTrace_glClearColorx(GLclampx red, GLclampx green, GLclampx blue, GLclampx arg_alpha->add_intvalue(alpha); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glClearColorx(red, green, blue, alpha); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -10165,11 +11341,15 @@ void GLTrace_glClearDepthx(GLclampx depth) { arg_depth->add_intvalue(depth); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glClearDepthx(depth); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -10186,11 +11366,15 @@ void GLTrace_glClientActiveTexture(GLenum texture) { arg_texture->add_intvalue((int)texture); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glClientActiveTexture(texture); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -10213,11 +11397,15 @@ void GLTrace_glClipPlanex(GLenum plane, const GLfixed *equation) { arg_equation->add_intvalue((int)equation); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glClipPlanex(plane, equation); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -10252,11 +11440,15 @@ void GLTrace_glColor4ub(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha) arg_alpha->add_intvalue((int)alpha); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glColor4ub(red, green, blue, alpha); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -10291,11 +11483,15 @@ void GLTrace_glColor4x(GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha) arg_alpha->add_intvalue(alpha); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glColor4x(red, green, blue, alpha); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -10330,11 +11526,15 @@ void GLTrace_glColorPointer(GLint size, GLenum type, GLsizei stride, const GLvoi arg_pointer->add_intvalue((int)pointer); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glColorPointer(size, type, stride, pointer); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -10357,11 +11557,15 @@ void GLTrace_glDepthRangex(GLclampx zNear, GLclampx zFar) { arg_zFar->add_intvalue(zFar); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glDepthRangex(zNear, zFar); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -10378,11 +11582,15 @@ void GLTrace_glDisableClientState(GLenum array) { arg_array->add_intvalue((int)array); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glDisableClientState(array); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -10399,11 +11607,15 @@ void GLTrace_glEnableClientState(GLenum array) { arg_array->add_intvalue((int)array); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glEnableClientState(array); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -10426,11 +11638,15 @@ void GLTrace_glFogx(GLenum pname, GLfixed param) { arg_param->add_intvalue(param); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glFogx(pname, param); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -10453,11 +11669,15 @@ void GLTrace_glFogxv(GLenum pname, const GLfixed *params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glFogxv(pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -10504,11 +11724,15 @@ void GLTrace_glFrustumx(GLfixed left, GLfixed right, GLfixed bottom, GLfixed top arg_zFar->add_intvalue(zFar); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glFrustumx(left, right, bottom, top, zNear, zFar); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -10531,11 +11755,15 @@ void GLTrace_glGetClipPlanex(GLenum pname, GLfixed eqn[4]) { arg_eqn->add_intvalue((int)eqn); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetClipPlanex(pname, eqn); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -10558,11 +11786,15 @@ void GLTrace_glGetFixedv(GLenum pname, GLfixed *params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetFixedv(pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -10591,11 +11823,15 @@ void GLTrace_glGetLightxv(GLenum light, GLenum pname, GLfixed *params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetLightxv(light, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -10624,11 +11860,15 @@ void GLTrace_glGetMaterialxv(GLenum face, GLenum pname, GLfixed *params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetMaterialxv(face, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -10651,11 +11891,15 @@ void GLTrace_glGetPointerv(GLenum pname, GLvoid **params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetPointerv(pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -10684,11 +11928,15 @@ void GLTrace_glGetTexEnviv(GLenum env, GLenum pname, GLint *params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetTexEnviv(env, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -10717,11 +11965,15 @@ void GLTrace_glGetTexEnvxv(GLenum env, GLenum pname, GLfixed *params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetTexEnvxv(env, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -10750,11 +12002,15 @@ void GLTrace_glGetTexParameterxv(GLenum target, GLenum pname, GLfixed *params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetTexParameterxv(target, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -10777,11 +12033,15 @@ void GLTrace_glLightModelx(GLenum pname, GLfixed param) { arg_param->add_intvalue(param); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glLightModelx(pname, param); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -10804,11 +12064,15 @@ void GLTrace_glLightModelxv(GLenum pname, const GLfixed *params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glLightModelxv(pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -10837,11 +12101,15 @@ void GLTrace_glLightx(GLenum light, GLenum pname, GLfixed param) { arg_param->add_intvalue(param); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glLightx(light, pname, param); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -10870,11 +12138,15 @@ void GLTrace_glLightxv(GLenum light, GLenum pname, const GLfixed *params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glLightxv(light, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -10891,11 +12163,15 @@ void GLTrace_glLineWidthx(GLfixed width) { arg_width->add_intvalue(width); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glLineWidthx(width); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -10906,11 +12182,15 @@ void GLTrace_glLoadIdentity(void) { glmsg.set_function(GLMessage::glLoadIdentity); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glLoadIdentity(); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -10927,11 +12207,15 @@ void GLTrace_glLoadMatrixx(const GLfixed *m) { arg_m->add_intvalue((int)m); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glLoadMatrixx(m); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -10948,11 +12232,15 @@ void GLTrace_glLogicOp(GLenum opcode) { arg_opcode->add_intvalue((int)opcode); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glLogicOp(opcode); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -10981,11 +12269,15 @@ void GLTrace_glMaterialx(GLenum face, GLenum pname, GLfixed param) { arg_param->add_intvalue(param); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glMaterialx(face, pname, param); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -11014,11 +12306,15 @@ void GLTrace_glMaterialxv(GLenum face, GLenum pname, const GLfixed *params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glMaterialxv(face, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -11035,11 +12331,15 @@ void GLTrace_glMatrixMode(GLenum mode) { arg_mode->add_intvalue((int)mode); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glMatrixMode(mode); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -11056,11 +12356,15 @@ void GLTrace_glMultMatrixx(const GLfixed *m) { arg_m->add_intvalue((int)m); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glMultMatrixx(m); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -11101,11 +12405,15 @@ void GLTrace_glMultiTexCoord4x(GLenum target, GLfixed s, GLfixed t, GLfixed r, G arg_q->add_intvalue(q); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glMultiTexCoord4x(target, s, t, r, q); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -11134,11 +12442,15 @@ void GLTrace_glNormal3x(GLfixed nx, GLfixed ny, GLfixed nz) { arg_nz->add_intvalue(nz); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glNormal3x(nx, ny, nz); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -11167,11 +12479,15 @@ void GLTrace_glNormalPointer(GLenum type, GLsizei stride, const GLvoid *pointer) arg_pointer->add_intvalue((int)pointer); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glNormalPointer(type, stride, pointer); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -11218,11 +12534,15 @@ void GLTrace_glOrthox(GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, arg_zFar->add_intvalue(zFar); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glOrthox(left, right, bottom, top, zNear, zFar); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -11245,11 +12565,15 @@ void GLTrace_glPointParameterx(GLenum pname, GLfixed param) { arg_param->add_intvalue(param); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glPointParameterx(pname, param); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -11272,11 +12596,15 @@ void GLTrace_glPointParameterxv(GLenum pname, const GLfixed *params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glPointParameterxv(pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -11293,11 +12621,15 @@ void GLTrace_glPointSizex(GLfixed size) { arg_size->add_intvalue(size); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glPointSizex(size); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -11320,11 +12652,15 @@ void GLTrace_glPolygonOffsetx(GLfixed factor, GLfixed units) { arg_units->add_intvalue(units); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glPolygonOffsetx(factor, units); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -11335,11 +12671,15 @@ void GLTrace_glPopMatrix(void) { glmsg.set_function(GLMessage::glPopMatrix); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glPopMatrix(); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -11350,11 +12690,15 @@ void GLTrace_glPushMatrix(void) { glmsg.set_function(GLMessage::glPushMatrix); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glPushMatrix(); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -11389,11 +12733,15 @@ void GLTrace_glRotatex(GLfixed angle, GLfixed x, GLfixed y, GLfixed z) { arg_z->add_intvalue(z); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glRotatex(angle, x, y, z); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -11416,11 +12764,15 @@ void GLTrace_glSampleCoveragex(GLclampx value, GLboolean invert) { arg_invert->add_boolvalue(invert); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glSampleCoveragex(value, invert); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -11449,11 +12801,15 @@ void GLTrace_glScalex(GLfixed x, GLfixed y, GLfixed z) { arg_z->add_intvalue(z); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glScalex(x, y, z); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -11470,11 +12826,15 @@ void GLTrace_glShadeModel(GLenum mode) { arg_mode->add_intvalue((int)mode); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glShadeModel(mode); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -11509,11 +12869,15 @@ void GLTrace_glTexCoordPointer(GLint size, GLenum type, GLsizei stride, const GL arg_pointer->add_intvalue((int)pointer); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glTexCoordPointer(size, type, stride, pointer); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -11542,11 +12906,15 @@ void GLTrace_glTexEnvi(GLenum target, GLenum pname, GLint param) { arg_param->add_intvalue(param); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glTexEnvi(target, pname, param); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -11575,11 +12943,15 @@ void GLTrace_glTexEnvx(GLenum target, GLenum pname, GLfixed param) { arg_param->add_intvalue(param); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glTexEnvx(target, pname, param); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -11608,11 +12980,15 @@ void GLTrace_glTexEnviv(GLenum target, GLenum pname, const GLint *params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glTexEnviv(target, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -11641,11 +13017,15 @@ void GLTrace_glTexEnvxv(GLenum target, GLenum pname, const GLfixed *params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glTexEnvxv(target, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -11674,11 +13054,15 @@ void GLTrace_glTexParameterx(GLenum target, GLenum pname, GLfixed param) { arg_param->add_intvalue(param); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glTexParameterx(target, pname, param); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -11707,11 +13091,15 @@ void GLTrace_glTexParameterxv(GLenum target, GLenum pname, const GLfixed *params arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glTexParameterxv(target, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -11740,11 +13128,15 @@ void GLTrace_glTranslatex(GLfixed x, GLfixed y, GLfixed z) { arg_z->add_intvalue(z); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glTranslatex(x, y, z); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -11779,11 +13171,15 @@ void GLTrace_glVertexPointer(GLint size, GLenum type, GLsizei stride, const GLvo arg_pointer->add_intvalue((int)pointer); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glVertexPointer(size, type, stride, pointer); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -11812,11 +13208,15 @@ void GLTrace_glPointSizePointerOES(GLenum type, GLsizei stride, const GLvoid *po arg_pointer->add_intvalue((int)pointer); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glPointSizePointerOES(type, stride, pointer); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -11842,11 +13242,15 @@ void GLTrace_glBlendEquationSeparateOES(GLenum modeRGB, GLenum modeAlpha) { arg_modeAlpha->add_intvalue((int)modeAlpha); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glBlendEquationSeparateOES(modeRGB, modeAlpha); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -11881,11 +13285,15 @@ void GLTrace_glBlendFuncSeparateOES(GLenum srcRGB, GLenum dstRGB, GLenum srcAlph arg_dstAlpha->add_intvalue((int)dstAlpha); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glBlendFuncSeparateOES(srcRGB, dstRGB, srcAlpha, dstAlpha); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -11902,11 +13310,15 @@ void GLTrace_glBlendEquationOES(GLenum mode) { arg_mode->add_intvalue((int)mode); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glBlendEquationOES(mode); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -11947,11 +13359,15 @@ void GLTrace_glDrawTexsOES(GLshort x, GLshort y, GLshort z, GLshort width, GLsho arg_height->add_intvalue(height); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glDrawTexsOES(x, y, z, width, height); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -11992,11 +13408,15 @@ void GLTrace_glDrawTexiOES(GLint x, GLint y, GLint z, GLint width, GLint height) arg_height->add_intvalue(height); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glDrawTexiOES(x, y, z, width, height); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -12037,11 +13457,15 @@ void GLTrace_glDrawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed width, GLfix arg_height->add_intvalue(height); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glDrawTexxOES(x, y, z, width, height); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -12058,11 +13482,15 @@ void GLTrace_glDrawTexsvOES(const GLshort *coords) { arg_coords->add_intvalue((int)coords); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glDrawTexsvOES(coords); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -12079,11 +13507,15 @@ void GLTrace_glDrawTexivOES(const GLint *coords) { arg_coords->add_intvalue((int)coords); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glDrawTexivOES(coords); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -12100,11 +13532,15 @@ void GLTrace_glDrawTexxvOES(const GLfixed *coords) { arg_coords->add_intvalue((int)coords); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glDrawTexxvOES(coords); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -12145,11 +13581,15 @@ void GLTrace_glDrawTexfOES(GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLflo arg_height->add_floatvalue(height); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glDrawTexfOES(x, y, z, width, height); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -12166,11 +13606,15 @@ void GLTrace_glDrawTexfvOES(const GLfloat *coords) { arg_coords->add_intvalue((int)coords); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glDrawTexfvOES(coords); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -12193,11 +13637,15 @@ void GLTrace_glAlphaFuncxOES(GLenum func, GLclampx ref) { arg_ref->add_intvalue(ref); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glAlphaFuncxOES(func, ref); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -12232,11 +13680,15 @@ void GLTrace_glClearColorxOES(GLclampx red, GLclampx green, GLclampx blue, GLcla arg_alpha->add_intvalue(alpha); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glClearColorxOES(red, green, blue, alpha); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -12253,11 +13705,15 @@ void GLTrace_glClearDepthxOES(GLclampx depth) { arg_depth->add_intvalue(depth); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glClearDepthxOES(depth); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -12280,11 +13736,15 @@ void GLTrace_glClipPlanexOES(GLenum plane, const GLfixed *equation) { arg_equation->add_intvalue((int)equation); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glClipPlanexOES(plane, equation); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -12319,11 +13779,15 @@ void GLTrace_glColor4xOES(GLfixed red, GLfixed green, GLfixed blue, GLfixed alph arg_alpha->add_intvalue(alpha); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glColor4xOES(red, green, blue, alpha); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -12346,11 +13810,15 @@ void GLTrace_glDepthRangexOES(GLclampx zNear, GLclampx zFar) { arg_zFar->add_intvalue(zFar); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glDepthRangexOES(zNear, zFar); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -12373,11 +13841,15 @@ void GLTrace_glFogxOES(GLenum pname, GLfixed param) { arg_param->add_intvalue(param); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glFogxOES(pname, param); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -12400,11 +13872,15 @@ void GLTrace_glFogxvOES(GLenum pname, const GLfixed *params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glFogxvOES(pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -12451,11 +13927,15 @@ void GLTrace_glFrustumxOES(GLfixed left, GLfixed right, GLfixed bottom, GLfixed arg_zFar->add_intvalue(zFar); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glFrustumxOES(left, right, bottom, top, zNear, zFar); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -12478,11 +13958,15 @@ void GLTrace_glGetClipPlanexOES(GLenum pname, GLfixed eqn[4]) { arg_eqn->add_intvalue((int)eqn); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetClipPlanexOES(pname, eqn); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -12505,11 +13989,15 @@ void GLTrace_glGetFixedvOES(GLenum pname, GLfixed *params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetFixedvOES(pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -12538,11 +14026,15 @@ void GLTrace_glGetLightxvOES(GLenum light, GLenum pname, GLfixed *params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetLightxvOES(light, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -12571,11 +14063,15 @@ void GLTrace_glGetMaterialxvOES(GLenum face, GLenum pname, GLfixed *params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetMaterialxvOES(face, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -12604,11 +14100,15 @@ void GLTrace_glGetTexEnvxvOES(GLenum env, GLenum pname, GLfixed *params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetTexEnvxvOES(env, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -12637,11 +14137,15 @@ void GLTrace_glGetTexParameterxvOES(GLenum target, GLenum pname, GLfixed *params arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetTexParameterxvOES(target, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -12664,11 +14168,15 @@ void GLTrace_glLightModelxOES(GLenum pname, GLfixed param) { arg_param->add_intvalue(param); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glLightModelxOES(pname, param); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -12691,11 +14199,15 @@ void GLTrace_glLightModelxvOES(GLenum pname, const GLfixed *params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glLightModelxvOES(pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -12724,11 +14236,15 @@ void GLTrace_glLightxOES(GLenum light, GLenum pname, GLfixed param) { arg_param->add_intvalue(param); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glLightxOES(light, pname, param); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -12757,11 +14273,15 @@ void GLTrace_glLightxvOES(GLenum light, GLenum pname, const GLfixed *params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glLightxvOES(light, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -12778,11 +14298,15 @@ void GLTrace_glLineWidthxOES(GLfixed width) { arg_width->add_intvalue(width); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glLineWidthxOES(width); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -12799,11 +14323,15 @@ void GLTrace_glLoadMatrixxOES(const GLfixed *m) { arg_m->add_intvalue((int)m); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glLoadMatrixxOES(m); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -12832,11 +14360,15 @@ void GLTrace_glMaterialxOES(GLenum face, GLenum pname, GLfixed param) { arg_param->add_intvalue(param); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glMaterialxOES(face, pname, param); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -12865,11 +14397,15 @@ void GLTrace_glMaterialxvOES(GLenum face, GLenum pname, const GLfixed *params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glMaterialxvOES(face, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -12886,11 +14422,15 @@ void GLTrace_glMultMatrixxOES(const GLfixed *m) { arg_m->add_intvalue((int)m); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glMultMatrixxOES(m); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -12931,11 +14471,15 @@ void GLTrace_glMultiTexCoord4xOES(GLenum target, GLfixed s, GLfixed t, GLfixed r arg_q->add_intvalue(q); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glMultiTexCoord4xOES(target, s, t, r, q); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -12964,11 +14508,15 @@ void GLTrace_glNormal3xOES(GLfixed nx, GLfixed ny, GLfixed nz) { arg_nz->add_intvalue(nz); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glNormal3xOES(nx, ny, nz); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -13015,11 +14563,15 @@ void GLTrace_glOrthoxOES(GLfixed left, GLfixed right, GLfixed bottom, GLfixed to arg_zFar->add_intvalue(zFar); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glOrthoxOES(left, right, bottom, top, zNear, zFar); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -13042,11 +14594,15 @@ void GLTrace_glPointParameterxOES(GLenum pname, GLfixed param) { arg_param->add_intvalue(param); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glPointParameterxOES(pname, param); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -13069,11 +14625,15 @@ void GLTrace_glPointParameterxvOES(GLenum pname, const GLfixed *params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glPointParameterxvOES(pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -13090,11 +14650,15 @@ void GLTrace_glPointSizexOES(GLfixed size) { arg_size->add_intvalue(size); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glPointSizexOES(size); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -13117,11 +14681,15 @@ void GLTrace_glPolygonOffsetxOES(GLfixed factor, GLfixed units) { arg_units->add_intvalue(units); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glPolygonOffsetxOES(factor, units); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -13156,11 +14724,15 @@ void GLTrace_glRotatexOES(GLfixed angle, GLfixed x, GLfixed y, GLfixed z) { arg_z->add_intvalue(z); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glRotatexOES(angle, x, y, z); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -13183,11 +14755,15 @@ void GLTrace_glSampleCoveragexOES(GLclampx value, GLboolean invert) { arg_invert->add_boolvalue(invert); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glSampleCoveragexOES(value, invert); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -13216,11 +14792,15 @@ void GLTrace_glScalexOES(GLfixed x, GLfixed y, GLfixed z) { arg_z->add_intvalue(z); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glScalexOES(x, y, z); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -13249,11 +14829,15 @@ void GLTrace_glTexEnvxOES(GLenum target, GLenum pname, GLfixed param) { arg_param->add_intvalue(param); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glTexEnvxOES(target, pname, param); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -13282,11 +14866,15 @@ void GLTrace_glTexEnvxvOES(GLenum target, GLenum pname, const GLfixed *params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glTexEnvxvOES(target, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -13315,11 +14903,15 @@ void GLTrace_glTexParameterxOES(GLenum target, GLenum pname, GLfixed param) { arg_param->add_intvalue(param); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glTexParameterxOES(target, pname, param); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -13348,11 +14940,15 @@ void GLTrace_glTexParameterxvOES(GLenum target, GLenum pname, const GLfixed *par arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glTexParameterxvOES(target, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -13381,11 +14977,15 @@ void GLTrace_glTranslatexOES(GLfixed x, GLfixed y, GLfixed z) { arg_z->add_intvalue(z); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glTranslatexOES(x, y, z); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -13402,9 +15002,11 @@ GLboolean GLTrace_glIsRenderbufferOES(GLuint renderbuffer) { arg_renderbuffer->add_intvalue(renderbuffer); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); GLboolean retValue = glContext->hooks->gl.glIsRenderbufferOES(renderbuffer); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); // set return value GLMessage_DataType *rt = glmsg.mutable_returnvalue(); @@ -13412,7 +15014,9 @@ GLboolean GLTrace_glIsRenderbufferOES(GLuint renderbuffer) { rt->set_type(GLMessage::DataType::BOOL); rt->add_boolvalue(retValue); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); return retValue; @@ -13437,11 +15041,15 @@ void GLTrace_glBindRenderbufferOES(GLenum target, GLuint renderbuffer) { arg_renderbuffer->add_intvalue(renderbuffer); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glBindRenderbufferOES(target, renderbuffer); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -13464,11 +15072,15 @@ void GLTrace_glDeleteRenderbuffersOES(GLsizei n, const GLuint* renderbuffers) { arg_renderbuffers->add_intvalue((int)renderbuffers); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glDeleteRenderbuffersOES(n, renderbuffers); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -13491,11 +15103,15 @@ void GLTrace_glGenRenderbuffersOES(GLsizei n, GLuint* renderbuffers) { arg_renderbuffers->add_intvalue((int)renderbuffers); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGenRenderbuffersOES(n, renderbuffers); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -13530,11 +15146,15 @@ void GLTrace_glRenderbufferStorageOES(GLenum target, GLenum internalformat, GLsi arg_height->add_intvalue(height); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glRenderbufferStorageOES(target, internalformat, width, height); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -13563,11 +15183,15 @@ void GLTrace_glGetRenderbufferParameterivOES(GLenum target, GLenum pname, GLint* arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetRenderbufferParameterivOES(target, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -13584,9 +15208,11 @@ GLboolean GLTrace_glIsFramebufferOES(GLuint framebuffer) { arg_framebuffer->add_intvalue(framebuffer); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); GLboolean retValue = glContext->hooks->gl.glIsFramebufferOES(framebuffer); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); // set return value GLMessage_DataType *rt = glmsg.mutable_returnvalue(); @@ -13594,7 +15220,9 @@ GLboolean GLTrace_glIsFramebufferOES(GLuint framebuffer) { rt->set_type(GLMessage::DataType::BOOL); rt->add_boolvalue(retValue); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); return retValue; @@ -13619,11 +15247,15 @@ void GLTrace_glBindFramebufferOES(GLenum target, GLuint framebuffer) { arg_framebuffer->add_intvalue(framebuffer); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glBindFramebufferOES(target, framebuffer); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -13646,11 +15278,15 @@ void GLTrace_glDeleteFramebuffersOES(GLsizei n, const GLuint* framebuffers) { arg_framebuffers->add_intvalue((int)framebuffers); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glDeleteFramebuffersOES(n, framebuffers); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -13673,11 +15309,15 @@ void GLTrace_glGenFramebuffersOES(GLsizei n, GLuint* framebuffers) { arg_framebuffers->add_intvalue((int)framebuffers); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGenFramebuffersOES(n, framebuffers); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -13694,9 +15334,11 @@ GLenum GLTrace_glCheckFramebufferStatusOES(GLenum target) { arg_target->add_intvalue((int)target); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); GLenum retValue = glContext->hooks->gl.glCheckFramebufferStatusOES(target); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); // set return value GLMessage_DataType *rt = glmsg.mutable_returnvalue(); @@ -13704,7 +15346,9 @@ GLenum GLTrace_glCheckFramebufferStatusOES(GLenum target) { rt->set_type(GLMessage::DataType::ENUM); rt->add_intvalue((int)retValue); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); return retValue; @@ -13741,11 +15385,15 @@ void GLTrace_glFramebufferRenderbufferOES(GLenum target, GLenum attachment, GLen arg_renderbuffer->add_intvalue(renderbuffer); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glFramebufferRenderbufferOES(target, attachment, renderbuffertarget, renderbuffer); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -13786,11 +15434,15 @@ void GLTrace_glFramebufferTexture2DOES(GLenum target, GLenum attachment, GLenum arg_level->add_intvalue(level); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glFramebufferTexture2DOES(target, attachment, textarget, texture, level); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -13825,11 +15477,15 @@ void GLTrace_glGetFramebufferAttachmentParameterivOES(GLenum target, GLenum atta arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetFramebufferAttachmentParameterivOES(target, attachment, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -13846,11 +15502,15 @@ void GLTrace_glGenerateMipmapOES(GLenum target) { arg_target->add_intvalue((int)target); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGenerateMipmapOES(target); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -13867,11 +15527,15 @@ void GLTrace_glCurrentPaletteMatrixOES(GLuint matrixpaletteindex) { arg_matrixpaletteindex->add_intvalue(matrixpaletteindex); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glCurrentPaletteMatrixOES(matrixpaletteindex); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -13882,11 +15546,15 @@ void GLTrace_glLoadPaletteFromModelViewMatrixOES(void) { glmsg.set_function(GLMessage::glLoadPaletteFromModelViewMatrixOES); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glLoadPaletteFromModelViewMatrixOES(); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -13921,11 +15589,15 @@ void GLTrace_glMatrixIndexPointerOES(GLint size, GLenum type, GLsizei stride, co arg_pointer->add_intvalue((int)pointer); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glMatrixIndexPointerOES(size, type, stride, pointer); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -13960,11 +15632,15 @@ void GLTrace_glWeightPointerOES(GLint size, GLenum type, GLsizei stride, const G arg_pointer->add_intvalue((int)pointer); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glWeightPointerOES(size, type, stride, pointer); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -13987,9 +15663,11 @@ GLbitfield GLTrace_glQueryMatrixxOES(GLfixed mantissa[16], GLint exponent[16]) { arg_exponent->add_intvalue((int)exponent); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); GLbitfield retValue = glContext->hooks->gl.glQueryMatrixxOES(mantissa, exponent); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); // set return value GLMessage_DataType *rt = glmsg.mutable_returnvalue(); @@ -13997,7 +15675,9 @@ GLbitfield GLTrace_glQueryMatrixxOES(GLfixed mantissa[16], GLint exponent[16]) { rt->set_type(GLMessage::DataType::INT); rt->add_intvalue(retValue); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); return retValue; @@ -14022,11 +15702,15 @@ void GLTrace_glDepthRangefOES(GLclampf zNear, GLclampf zFar) { arg_zFar->add_floatvalue(zFar); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glDepthRangefOES(zNear, zFar); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -14073,11 +15757,15 @@ void GLTrace_glFrustumfOES(GLfloat left, GLfloat right, GLfloat bottom, GLfloat arg_zFar->add_floatvalue(zFar); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glFrustumfOES(left, right, bottom, top, zNear, zFar); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -14124,11 +15812,15 @@ void GLTrace_glOrthofOES(GLfloat left, GLfloat right, GLfloat bottom, GLfloat to arg_zFar->add_floatvalue(zFar); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glOrthofOES(left, right, bottom, top, zNear, zFar); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -14151,11 +15843,15 @@ void GLTrace_glClipPlanefOES(GLenum plane, const GLfloat *equation) { arg_equation->add_intvalue((int)equation); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glClipPlanefOES(plane, equation); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -14178,11 +15874,15 @@ void GLTrace_glGetClipPlanefOES(GLenum pname, GLfloat eqn[4]) { arg_eqn->add_intvalue((int)eqn); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetClipPlanefOES(pname, eqn); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -14199,11 +15899,15 @@ void GLTrace_glClearDepthfOES(GLclampf depth) { arg_depth->add_floatvalue(depth); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glClearDepthfOES(depth); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -14232,11 +15936,15 @@ void GLTrace_glTexGenfOES(GLenum coord, GLenum pname, GLfloat param) { arg_param->add_floatvalue(param); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glTexGenfOES(coord, pname, param); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -14265,11 +15973,15 @@ void GLTrace_glTexGenfvOES(GLenum coord, GLenum pname, const GLfloat *params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glTexGenfvOES(coord, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -14298,11 +16010,15 @@ void GLTrace_glTexGeniOES(GLenum coord, GLenum pname, GLint param) { arg_param->add_intvalue(param); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glTexGeniOES(coord, pname, param); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -14331,11 +16047,15 @@ void GLTrace_glTexGenivOES(GLenum coord, GLenum pname, const GLint *params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glTexGenivOES(coord, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -14364,11 +16084,15 @@ void GLTrace_glTexGenxOES(GLenum coord, GLenum pname, GLfixed param) { arg_param->add_intvalue(param); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glTexGenxOES(coord, pname, param); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -14397,11 +16121,15 @@ void GLTrace_glTexGenxvOES(GLenum coord, GLenum pname, const GLfixed *params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glTexGenxvOES(coord, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -14430,11 +16158,15 @@ void GLTrace_glGetTexGenfvOES(GLenum coord, GLenum pname, GLfloat *params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetTexGenfvOES(coord, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -14463,11 +16195,15 @@ void GLTrace_glGetTexGenivOES(GLenum coord, GLenum pname, GLint *params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetTexGenivOES(coord, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -14496,11 +16232,15 @@ void GLTrace_glGetTexGenxvOES(GLenum coord, GLenum pname, GLfixed *params) { arg_params->add_intvalue((int)params); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glGetTexGenxvOES(coord, pname, params); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -14523,11 +16263,15 @@ void GLTrace_glClipPlanefIMG(GLenum p, const GLfloat *eqn) { arg_eqn->add_intvalue((int)eqn); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glClipPlanefIMG(p, eqn); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } @@ -14550,11 +16294,15 @@ void GLTrace_glClipPlanexIMG(GLenum p, const GLfixed *eqn) { arg_eqn->add_intvalue((int)eqn); // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); glContext->hooks->gl.glClipPlanexIMG(p, eqn); - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); } diff --git a/opengl/libs/GLES_trace/src/gltrace_fixup.cpp b/opengl/libs/GLES_trace/src/gltrace_fixup.cpp index 871b5dc720b8..6c4feb5a56d7 100644 --- a/opengl/libs/GLES_trace/src/gltrace_fixup.cpp +++ b/opengl/libs/GLES_trace/src/gltrace_fixup.cpp @@ -15,9 +15,13 @@ */ #include <cutils/log.h> +#include <GLES/gl.h> +#include <GLES/glext.h> #include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> #include "gltrace.pb.h" +#include "gltrace_api.h" #include "gltrace_context.h" #include "gltrace_fixup.h" @@ -198,6 +202,20 @@ void fixup_glShaderSource(GLMessage *glmsg) { arg_strpp->add_charvalue(src); } +void fixup_glUniformGenericInteger(int argIndex, int nIntegers, GLMessage *glmsg) { + /* void glUniform?iv(GLint location, GLsizei count, const GLint *value); */ + GLMessage_DataType *arg_values = glmsg->mutable_args(argIndex); + GLint *src = (GLint*)arg_values->intvalue(0); + + arg_values->set_type(GLMessage::DataType::INT); + arg_values->set_isarray(true); + arg_values->clear_intvalue(); + + for (int i = 0; i < nIntegers; i++) { + arg_values->add_intvalue(*src++); + } +} + void fixup_glUniformGeneric(int argIndex, int nFloats, GLMessage *glmsg) { GLMessage_DataType *arg_values = glmsg->mutable_args(argIndex); GLfloat *src = (GLfloat*)arg_values->intvalue(0); @@ -223,6 +241,10 @@ void fixup_GenericIntArray(int argIndex, int nInts, GLMessage *glmsg) { GLMessage_DataType *arg_intarray = glmsg->mutable_args(argIndex); GLint *intp = (GLint *)arg_intarray->intvalue(0); + if (intp == NULL) { + return; + } + arg_intarray->set_type(GLMessage::DataType::INT); arg_intarray->set_isarray(true); arg_intarray->clear_intvalue(); @@ -232,6 +254,15 @@ void fixup_GenericIntArray(int argIndex, int nInts, GLMessage *glmsg) { } } +void fixup_GenericEnumArray(int argIndex, int nEnums, GLMessage *glmsg) { + // fixup as if they were ints + fixup_GenericIntArray(argIndex, nEnums, glmsg); + + // and then set the data type to be enum + GLMessage_DataType *arg_enumarray = glmsg->mutable_args(argIndex); + arg_enumarray->set_type(GLMessage::DataType::ENUM); +} + void fixup_glGenGeneric(GLMessage *glmsg) { /* void glGen*(GLsizei n, GLuint * buffers); */ GLMessage_DataType arg_n = glmsg->args(0); @@ -270,13 +301,94 @@ void fixup_glGetFloatv(GLMessage *glmsg) { arg_params->add_floatvalue(*src); } -void fixupGLMessage(GLTraceContext *context, nsecs_t start, nsecs_t end, GLMessage *glmsg) { +void fixup_glLinkProgram(GLMessage *glmsg) { + /* void glLinkProgram(GLuint program); */ + GLuint program = glmsg->args(0).intvalue(0); + + /* We don't have to fixup this call, but as soon as a program is linked, + we obtain information about all active attributes and uniforms to + pass on to the debugger. Note that in order to pass this info to + the debugger, all we need to do is call the trace versions of the + necessary calls. */ + + GLint n, maxNameLength; + GLchar *name; + GLint size; + GLenum type; + + // obtain info regarding active attributes + GLTrace_glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &n); + GLTrace_glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxNameLength); + + name = (GLchar *) malloc(maxNameLength); + for (int i = 0; i < n; i++) { + GLTrace_glGetActiveAttrib(program, i, maxNameLength, NULL, &size, &type, name); + } + free(name); + + // obtain info regarding active uniforms + GLTrace_glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &n); + GLTrace_glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxNameLength); + + name = (GLchar *) malloc(maxNameLength); + for (int i = 0; i < n; i++) { + GLTrace_glGetActiveUniform(program, i, maxNameLength, NULL, &size, &type, name); + } + free(name); +} + +/** Given a glGetActive[Uniform|Attrib] call, obtain the location + * of the variable in the call. + */ +int getShaderVariableLocation(GLTraceContext *context, GLMessage *glmsg) { + GLMessage_Function func = glmsg->function(); + if (func != GLMessage::glGetActiveAttrib && func != GLMessage::glGetActiveUniform) { + return -1; + } + + int program = glmsg->args(0).intvalue(0); + GLchar *name = (GLchar*) glmsg->args(6).intvalue(0); + + if (func == GLMessage::glGetActiveAttrib) { + return context->hooks->gl.glGetAttribLocation(program, name); + } else { + return context->hooks->gl.glGetUniformLocation(program, name); + } +} + +void fixup_glGetActiveAttribOrUniform(GLMessage *glmsg, int location) { + /* void glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, + GLsizei* length, GLint* size, GLenum* type, GLchar* name); */ + /* void glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, + GLsizei* length, GLint* size, GLenum* type, GLchar* name) */ + + fixup_GenericIntArray(3, 1, glmsg); // length + fixup_GenericIntArray(4, 1, glmsg); // size + fixup_GenericEnumArray(5, 1, glmsg); // type + fixup_CStringPtr(6, glmsg); // name + + // The index argument in the glGetActive[Attrib|Uniform] functions + // does not correspond to the actual location index as used in + // glUniform*() or glVertexAttrib*() to actually upload the data. + // In order to make things simpler for the debugger, we also pass + // a hidden location argument that stores the actual location. + // append the location value to the end of the argument list + GLMessage_DataType *arg_location = glmsg->add_args(); + arg_location->set_isarray(false); + arg_location->set_type(GLMessage::DataType::INT); + arg_location->add_intvalue(location); +} + +void fixupGLMessage(GLTraceContext *context, nsecs_t wallStart, nsecs_t wallEnd, + nsecs_t threadStart, nsecs_t threadEnd, + GLMessage *glmsg) { // for all messages, set the current context id glmsg->set_context_id(context->getId()); // set start time and duration - glmsg->set_start_time(start); - glmsg->set_duration((unsigned)(end - start)); + glmsg->set_start_time(wallStart); + glmsg->set_duration((unsigned)(wallEnd - wallStart)); + glmsg->set_threadtime((unsigned)(threadEnd - threadStart)); // do any custom message dependent processing switch (glmsg->function()) { @@ -292,6 +404,19 @@ void fixupGLMessage(GLTraceContext *context, nsecs_t start, nsecs_t end, GLMessa case GLMessage::glGenTextures: /* void glGenTextures(GLsizei n, GLuint *textures); */ fixup_glGenGeneric(glmsg); break; + case GLMessage::glLinkProgram: /* void glLinkProgram(GLuint program); */ + fixup_glLinkProgram(glmsg); + break; + case GLMessage::glGetActiveAttrib: + fixup_glGetActiveAttribOrUniform(glmsg, getShaderVariableLocation(context, glmsg)); + break; + case GLMessage::glGetActiveUniform: + fixup_glGetActiveAttribOrUniform(glmsg, getShaderVariableLocation(context, glmsg)); + break; + case GLMessage::glBindAttribLocation: + /* void glBindAttribLocation(GLuint program, GLuint index, const GLchar* name); */ + fixup_CStringPtr(2, glmsg); + break; case GLMessage::glGetAttribLocation: case GLMessage::glGetUniformLocation: /* int glGetAttribLocation(GLuint program, const GLchar* name) */ @@ -331,6 +456,38 @@ void fixupGLMessage(GLTraceContext *context, nsecs_t start, nsecs_t end, GLMessa case GLMessage::glShaderSource: fixup_glShaderSource(glmsg); break; + case GLMessage::glUniform1iv: + /* void glUniform1iv(GLint location, GLsizei count, const GLint *value); */ + fixup_glUniformGenericInteger(2, 1, glmsg); + break; + case GLMessage::glUniform2iv: + /* void glUniform2iv(GLint location, GLsizei count, const GLint *value); */ + fixup_glUniformGenericInteger(2, 2, glmsg); + break; + case GLMessage::glUniform3iv: + /* void glUniform3iv(GLint location, GLsizei count, const GLint *value); */ + fixup_glUniformGenericInteger(2, 3, glmsg); + break; + case GLMessage::glUniform4iv: + /* void glUniform4iv(GLint location, GLsizei count, const GLint *value); */ + fixup_glUniformGenericInteger(2, 4, glmsg); + break; + case GLMessage::glUniform1fv: + /* void glUniform1fv(GLint location, GLsizei count, const GLfloat *value); */ + fixup_glUniformGeneric(2, 1, glmsg); + break; + case GLMessage::glUniform2fv: + /* void glUniform2fv(GLint location, GLsizei count, const GLfloat *value); */ + fixup_glUniformGeneric(2, 2, glmsg); + break; + case GLMessage::glUniform3fv: + /* void glUniform3fv(GLint location, GLsizei count, const GLfloat *value); */ + fixup_glUniformGeneric(2, 3, glmsg); + break; + case GLMessage::glUniform4fv: + /* void glUniform4fv(GLint location, GLsizei count, const GLfloat *value); */ + fixup_glUniformGeneric(2, 4, glmsg); + break; case GLMessage::glUniformMatrix2fv: /* void glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) */ diff --git a/opengl/libs/GLES_trace/src/gltrace_fixup.h b/opengl/libs/GLES_trace/src/gltrace_fixup.h index 64f75458dfe4..f63b0569036e 100644 --- a/opengl/libs/GLES_trace/src/gltrace_fixup.h +++ b/opengl/libs/GLES_trace/src/gltrace_fixup.h @@ -25,7 +25,9 @@ namespace android { namespace gltrace { -void fixupGLMessage(GLTraceContext *curContext, nsecs_t start, nsecs_t end, GLMessage *message); +void fixupGLMessage(GLTraceContext *curContext, nsecs_t wallStart, nsecs_t wallEnd, + nsecs_t threadStart, nsecs_t threadEnd, + GLMessage *message); void fixup_addFBContents(GLTraceContext *curContext, GLMessage *message, FBBinding fbToRead); }; diff --git a/opengl/libs/GLES_trace/tools/genapi.py b/opengl/libs/GLES_trace/tools/genapi.py index 557e4076dba3..e1660be1aa3b 100755 --- a/opengl/libs/GLES_trace/tools/genapi.py +++ b/opengl/libs/GLES_trace/tools/genapi.py @@ -162,13 +162,15 @@ TRACE_CALL_TEMPLATE = pyratemp.Template( <!--(end)--> // call function - nsecs_t start_time = systemTime(); + nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC); + nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD); <!--(if retType != "void")--> $!retType!$ retValue = glContext->hooks->gl.$!callsite!$; <!--(else)--> glContext->hooks->gl.$!callsite!$; <!--(end)--> - nsecs_t end_time = systemTime(); + nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD); + nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC); <!--(if retType != "void")--> // set return value @@ -178,7 +180,9 @@ TRACE_CALL_TEMPLATE = pyratemp.Template( rt->$!retDataType.getProtobufCall()!$retValue); <!--(end)--> - fixupGLMessage(glContext, start_time, end_time, &glmsg); + fixupGLMessage(glContext, wallStartTime, wallEndTime, + threadStartTime, threadEndTime, + &glmsg); glContext->traceGLMessage(&glmsg); <!--(if retType != "void")--> diff --git a/opengl/libs/egl_impl.h b/opengl/libs/egl_impl.h index 8ff51eca4b7a..cb0e908d3140 100644 --- a/opengl/libs/egl_impl.h +++ b/opengl/libs/egl_impl.h @@ -30,7 +30,6 @@ namespace android { // ---------------------------------------------------------------------------- EGLAPI const GLubyte * egl_get_string_for_current_context(GLenum name); -EGLAPI EGLImageKHR egl_get_image_for_current_context(EGLImageKHR image); // ---------------------------------------------------------------------------- }; // namespace android diff --git a/opengl/libs/tools/glapigen b/opengl/libs/tools/glapigen index 9be40cf67d48..4d8334f90f0c 100755 --- a/opengl/libs/tools/glapigen +++ b/opengl/libs/tools/glapigen @@ -37,12 +37,6 @@ while (my $line = <>) { #printf("%s", $line); my $prefix = ""; - if ($name eq "glEGLImageTargetTexture2DOES") { - $prefix = "__"; - } - if ($name eq "glEGLImageTargetRenderbufferStorageOES") { - $prefix = "__"; - } if ($name eq "glGetString") { $prefix = "__"; } diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml index 3beaac998b75..3a8e3fc6fcff 100644 --- a/packages/SettingsProvider/res/values/defaults.xml +++ b/packages/SettingsProvider/res/values/defaults.xml @@ -148,4 +148,7 @@ <!-- Development settings --> <bool name="def_stay_on_while_plugged_in">false</bool> + <!-- Number of retries for connecting to DHCP. + Value here is the same as WifiStateMachine.DEFAULT_MAX_DHCP_RETRIES --> + <integer name="def_max_dhcp_retries">9</integer> </resources> diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java index 882aa6624a28..330a1899a0b0 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java @@ -1602,6 +1602,9 @@ public class DatabaseHelper extends SQLiteOpenHelper { loadBooleanSetting(stmt, Settings.Secure.NETSTATS_ENABLED, R.bool.def_netstats_enabled); + + loadIntegerSetting(stmt, Settings.Secure.WIFI_MAX_DHCP_RETRY_COUNT, + R.integer.def_max_dhcp_retries); } finally { if (stmt != null) stmt.close(); } diff --git a/packages/SystemUI/res/layout-land/status_bar_recent_item.xml b/packages/SystemUI/res/layout-land/status_bar_recent_item.xml index 2d76455d0024..aa2786174ef4 100644 --- a/packages/SystemUI/res/layout-land/status_bar_recent_item.xml +++ b/packages/SystemUI/res/layout-land/status_bar_recent_item.xml @@ -58,6 +58,7 @@ android:maxHeight="@dimen/status_bar_recents_app_icon_max_height" android:scaleType="centerInside" android:adjustViewBounds="true" + android:visibility="invisible" /> <TextView android:id="@+id/app_label" diff --git a/packages/SystemUI/res/layout-port/status_bar_recent_item.xml b/packages/SystemUI/res/layout-port/status_bar_recent_item.xml index b653fcd8143a..bc389f967127 100644 --- a/packages/SystemUI/res/layout-port/status_bar_recent_item.xml +++ b/packages/SystemUI/res/layout-port/status_bar_recent_item.xml @@ -81,6 +81,7 @@ android:maxHeight="@dimen/status_bar_recents_app_icon_max_height" android:scaleType="centerInside" android:adjustViewBounds="true" + android:visibility="invisible" /> <TextView android:id="@+id/app_description" diff --git a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml index cb26db00a54b..333fcdafdead 100644 --- a/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml +++ b/packages/SystemUI/res/layout-sw600dp/status_bar_recent_item.xml @@ -65,6 +65,7 @@ android:maxHeight="@dimen/status_bar_recents_app_icon_max_height" android:scaleType="centerInside" android:adjustViewBounds="true" + android:visibility="invisible" /> diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java index 14ce266c63db..cd8bd4ecd3be 100644 --- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java +++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java @@ -236,6 +236,10 @@ public class SwipeHelper { public void onAnimationEnd(Animator animation) { mCallback.onChildDismissed(view); animView.setLayerType(View.LAYER_TYPE_NONE, null); + // Restore the alpha/translation parameters to what they were before swiping + // (for when these items are recycled) + animView.setAlpha(1f); + setTranslation(animView, 0f); } }); anim.addUpdateListener(new AnimatorUpdateListener() { diff --git a/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java b/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java index ad38a11a2a3c..dc2f0be40542 100644 --- a/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java +++ b/packages/SystemUI/src/com/android/systemui/recent/Choreographer.java @@ -134,6 +134,9 @@ import android.view.View; void jumpTo(boolean appearing) { mContentView.setTranslationY(appearing ? 0 : mPanelHeight); + if (mScrimView.getBackground() != null) { + mScrimView.getBackground().setAlpha(appearing ? 255 : 0); + } } public void setPanelHeight(int h) { diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java index 4145fc46c04c..92f4ca96a2e4 100644 --- a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java +++ b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java @@ -16,12 +16,6 @@ package com.android.systemui.recent; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - import android.app.ActivityManager; import android.content.ComponentName; import android.content.Context; @@ -36,15 +30,17 @@ import android.graphics.drawable.Drawable; import android.os.AsyncTask; import android.os.Handler; import android.os.Process; -import android.os.SystemClock; -import android.util.DisplayMetrics; import android.util.Log; -import android.util.LruCache; import com.android.systemui.R; import com.android.systemui.statusbar.phone.PhoneStatusBar; import com.android.systemui.statusbar.tablet.TabletStatusBar; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; + public class RecentTasksLoader { static final String TAG = "RecentTasksLoader"; static final boolean DEBUG = TabletStatusBar.DEBUG || PhoneStatusBar.DEBUG || false; @@ -55,11 +51,14 @@ public class RecentTasksLoader { private Context mContext; private RecentsPanelView mRecentsPanel; - private AsyncTask<Void, Integer, Void> mThumbnailLoader; + private AsyncTask<Void, ArrayList<TaskDescription>, Void> mTaskLoader; + private AsyncTask<Void, TaskDescription, Void> mThumbnailLoader; private final Handler mHandler; private int mIconDpi; private Bitmap mDefaultThumbnailBackground; + private Bitmap mDefaultIconBackground; + private int mNumTasksInFirstScreenful; public RecentTasksLoader(Context context) { mContext = context; @@ -76,12 +75,20 @@ public class RecentTasksLoader { mIconDpi = res.getDisplayMetrics().densityDpi; } + // Render default icon (just a blank image) + int defaultIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.app_icon_size); + int iconSize = (int) (defaultIconSize * mIconDpi / res.getDisplayMetrics().densityDpi); + mDefaultIconBackground = Bitmap.createBitmap(iconSize, iconSize, Bitmap.Config.ARGB_8888); + // Render the default thumbnail background - int width = (int) res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_width); - int height = (int) res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_height); + int thumbnailWidth = + (int) res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_width); + int thumbnailHeight = + (int) res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_height); int color = res.getColor(R.drawable.status_bar_recents_app_thumbnail_background); - mDefaultThumbnailBackground = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + mDefaultThumbnailBackground = + Bitmap.createBitmap(thumbnailWidth, thumbnailHeight, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(mDefaultThumbnailBackground); c.drawColor(color); @@ -95,12 +102,17 @@ public class RecentTasksLoader { public void setRecentsPanel(RecentsPanelView recentsPanel) { mRecentsPanel = recentsPanel; + mNumTasksInFirstScreenful = mRecentsPanel.numItemsInOneScreenful(); } public Bitmap getDefaultThumbnail() { return mDefaultThumbnailBackground; } + public Bitmap getDefaultIcon() { + return mDefaultIconBackground; + } + // Create an TaskDescription, returning null if the title or icon is null, or if it's the // home activity TaskDescription createTaskDescription(int taskId, int persistentTaskId, Intent baseIntent, @@ -114,6 +126,12 @@ public class RecentTasksLoader { homeInfo = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME) .resolveActivityInfo(pm, 0); } + // Don't load the current home activity. + if (homeInfo != null + && homeInfo.packageName.equals(intent.getComponent().getPackageName()) + && homeInfo.name.equals(intent.getComponent().getClassName())) { + return null; + } intent.setFlags((intent.getFlags()&~Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) | Intent.FLAG_ACTIVITY_NEW_TASK); @@ -121,9 +139,8 @@ public class RecentTasksLoader { if (resolveInfo != null) { final ActivityInfo info = resolveInfo.activityInfo; final String title = info.loadLabel(pm).toString(); - Drawable icon = getFullResIcon(resolveInfo, pm); - if (title != null && title.length() > 0 && icon != null) { + if (title != null && title.length() > 0) { if (DEBUG) Log.v(TAG, "creating activity desc for id=" + persistentTaskId + ", label=" + title); @@ -131,14 +148,6 @@ public class RecentTasksLoader { persistentTaskId, resolveInfo, baseIntent, info.packageName, description); item.setLabel(title); - item.setIcon(icon); - - // Don't load the current home activity. - if (homeInfo != null - && homeInfo.packageName.equals(intent.getComponent().getPackageName()) - && homeInfo.name.equals(intent.getComponent().getClassName())) { - return null; - } return item; } else { @@ -148,10 +157,12 @@ public class RecentTasksLoader { return null; } - void loadThumbnail(TaskDescription td) { + void loadThumbnailAndIcon(TaskDescription td) { final ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); + final PackageManager pm = mContext.getPackageManager(); ActivityManager.TaskThumbnails thumbs = am.getTaskThumbnails(td.persistentTaskId); + Drawable icon = getFullResIcon(td.resolveInfo, pm); if (DEBUG) Log.v(TAG, "Loaded bitmap for task " + td + ": " + thumbs.mainThumbnail); @@ -161,6 +172,10 @@ public class RecentTasksLoader { } else { td.setThumbnail(mDefaultThumbnailBackground); } + if (icon != null) { + td.setIcon(icon); + } + td.setLoaded(true); } } @@ -194,111 +209,149 @@ public class RecentTasksLoader { return getFullResDefaultActivityIcon(); } - public void cancelLoadingThumbnails() { + public void cancelLoadingThumbnailsAndIcons() { + if (mTaskLoader != null) { + mTaskLoader.cancel(false); + mTaskLoader = null; + } if (mThumbnailLoader != null) { mThumbnailLoader.cancel(false); mThumbnailLoader = null; } } - // return a snapshot of the current list of recent apps - ArrayList<TaskDescription> getRecentTasks() { - cancelLoadingThumbnails(); - - ArrayList<TaskDescription> tasks = new ArrayList<TaskDescription>(); - final PackageManager pm = mContext.getPackageManager(); - final ActivityManager am = (ActivityManager) + public void loadTasksInBackground() { + // cancel all previous loading of tasks and thumbnails + cancelLoadingThumbnailsAndIcons(); + final LinkedBlockingQueue<TaskDescription> tasksWaitingForThumbnails = + new LinkedBlockingQueue<TaskDescription>(); + final ArrayList<TaskDescription> taskDescriptionsWaitingToLoad = + new ArrayList<TaskDescription>(); + mTaskLoader = new AsyncTask<Void, ArrayList<TaskDescription>, Void>() { + @Override + protected void onProgressUpdate(ArrayList<TaskDescription>... values) { + if (!isCancelled()) { + ArrayList<TaskDescription> newTasks = values[0]; + // do a callback to RecentsPanelView to let it know we have more values + // how do we let it know we're all done? just always call back twice + mRecentsPanel.onTasksLoaded(newTasks); + } + } + @Override + protected Void doInBackground(Void... params) { + // We load in two stages: first, we update progress with just the first screenful + // of items. Then, we update with the rest of the items + final int origPri = Process.getThreadPriority(Process.myTid()); + Process.setThreadPriority(Process.THREAD_GROUP_BG_NONINTERACTIVE); + final PackageManager pm = mContext.getPackageManager(); + final ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); - final List<ActivityManager.RecentTaskInfo> recentTasks = - am.getRecentTasks(MAX_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE); + final List<ActivityManager.RecentTaskInfo> recentTasks = + am.getRecentTasks(MAX_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE); + int numTasks = recentTasks.size(); + ActivityInfo homeInfo = new Intent(Intent.ACTION_MAIN) + .addCategory(Intent.CATEGORY_HOME).resolveActivityInfo(pm, 0); - ActivityInfo homeInfo = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME) - .resolveActivityInfo(pm, 0); + boolean firstScreenful = true; + ArrayList<TaskDescription> tasks = new ArrayList<TaskDescription>(); - HashSet<Integer> recentTasksToKeepInCache = new HashSet<Integer>(); - int numTasks = recentTasks.size(); + // skip the first task - assume it's either the home screen or the current activity. + final int first = 1; + for (int i = first, index = 0; i < numTasks && (index < MAX_TASKS); ++i) { + if (isCancelled()) { + break; + } + final ActivityManager.RecentTaskInfo recentInfo = recentTasks.get(i); + TaskDescription item = createTaskDescription(recentInfo.id, + recentInfo.persistentId, recentInfo.baseIntent, + recentInfo.origActivity, recentInfo.description, homeInfo); + + if (item != null) { + while (true) { + try { + tasksWaitingForThumbnails.put(item); + break; + } catch (InterruptedException e) { + } + } + tasks.add(item); + if (firstScreenful && tasks.size() == mNumTasksInFirstScreenful) { + publishProgress(tasks); + tasks = new ArrayList<TaskDescription>(); + firstScreenful = false; + //break; + } + ++index; + } + } - // skip the first task - assume it's either the home screen or the current activity. - final int first = 1; - recentTasksToKeepInCache.add(recentTasks.get(0).persistentId); - for (int i = first, index = 0; i < numTasks && (index < MAX_TASKS); ++i) { - final ActivityManager.RecentTaskInfo recentInfo = recentTasks.get(i); + if (!isCancelled()) { + publishProgress(tasks); + if (firstScreenful) { + // always should publish two updates + publishProgress(new ArrayList<TaskDescription>()); + } + } - TaskDescription item = createTaskDescription(recentInfo.id, - recentInfo.persistentId, recentInfo.baseIntent, - recentInfo.origActivity, recentInfo.description, homeInfo); + while (true) { + try { + tasksWaitingForThumbnails.put(new TaskDescription()); + break; + } catch (InterruptedException e) { + } + } - if (item != null) { - tasks.add(item); - ++index; + Process.setThreadPriority(origPri); + return null; } - } - - // when we're not using the TaskDescription cache, we load the thumbnails in the - // background - loadThumbnailsInBackground(new ArrayList<TaskDescription>(tasks)); - return tasks; + }; + mTaskLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + loadThumbnailsAndIconsInBackground(tasksWaitingForThumbnails); } - private void loadThumbnailsInBackground(final ArrayList<TaskDescription> descriptions) { - if (descriptions.size() > 0) { - if (DEBUG) Log.v(TAG, "Showing " + descriptions.size() + " tasks"); - loadThumbnail(descriptions.get(0)); - if (descriptions.size() > 1) { - mThumbnailLoader = new AsyncTask<Void, Integer, Void>() { - @Override - protected void onProgressUpdate(Integer... values) { - final TaskDescription td = descriptions.get(values[0]); - if (!isCancelled()) { - mRecentsPanel.onTaskThumbnailLoaded(td); - } - // This is to prevent the loader thread from getting ahead - // of our UI updates. - mHandler.post(new Runnable() { - @Override public void run() { - synchronized (td) { - td.notifyAll(); - } - } - }); + private void loadThumbnailsAndIconsInBackground( + final BlockingQueue<TaskDescription> tasksWaitingForThumbnails) { + // continually read items from tasksWaitingForThumbnails and load + // thumbnails and icons for them. finish thread when cancelled or there + // is a null item in tasksWaitingForThumbnails + mThumbnailLoader = new AsyncTask<Void, TaskDescription, Void>() { + @Override + protected void onProgressUpdate(TaskDescription... values) { + if (!isCancelled()) { + TaskDescription td = values[0]; + mRecentsPanel.onTaskThumbnailLoaded(td); + } + } + @Override + protected Void doInBackground(Void... params) { + final int origPri = Process.getThreadPriority(Process.myTid()); + Process.setThreadPriority(Process.THREAD_GROUP_BG_NONINTERACTIVE); + + while (true) { + if (isCancelled()) { + break; } - - @Override - protected Void doInBackground(Void... params) { - final int origPri = Process.getThreadPriority(Process.myTid()); - Process.setThreadPriority(Process.THREAD_GROUP_BG_NONINTERACTIVE); - long nextTime = SystemClock.uptimeMillis(); - for (int i=1; i<descriptions.size(); i++) { - TaskDescription td = descriptions.get(i); - loadThumbnail(td); - long now = SystemClock.uptimeMillis(); - nextTime += 0; - if (nextTime > now) { - try { - Thread.sleep(nextTime-now); - } catch (InterruptedException e) { - } - } - - if (isCancelled()) { - break; - } - synchronized (td) { - publishProgress(i); - try { - td.wait(500); - } catch (InterruptedException e) { - } - } + TaskDescription td = null; + while (td == null) { + try { + td = tasksWaitingForThumbnails.take(); + } catch (InterruptedException e) { } - Process.setThreadPriority(origPri); - return null; } - }; - mThumbnailLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + if (td.isNull()) { + break; + } + loadThumbnailAndIcon(td); + synchronized(td) { + publishProgress(td); + } + } + + Process.setThreadPriority(origPri); + return null; } - } + }; + mThumbnailLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } - } diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java index f971d2d50632..4718a1719dcb 100644 --- a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java +++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java @@ -22,11 +22,18 @@ import android.content.res.Configuration; import android.database.DataSetObserver; import android.graphics.Canvas; import android.util.AttributeSet; +import android.util.DisplayMetrics; +import android.util.FloatMath; import android.util.Log; import android.view.MotionEvent; import android.view.View; -import android.view.ViewConfiguration; +import android.view.View.MeasureSpec; +import android.view.View.OnClickListener; +import android.view.View.OnLongClickListener; import android.view.View.OnTouchListener; +import android.view.ViewConfiguration; +import android.view.ViewTreeObserver; +import android.view.ViewTreeObserver.OnGlobalLayoutListener; import android.widget.HorizontalScrollView; import android.widget.LinearLayout; @@ -34,6 +41,8 @@ import com.android.systemui.R; import com.android.systemui.SwipeHelper; import com.android.systemui.recent.RecentsPanelView.TaskDescriptionAdapter; +import java.util.ArrayList; + public class RecentsHorizontalScrollView extends HorizontalScrollView implements SwipeHelper.Callback { private static final String TAG = RecentsPanelView.TAG; @@ -44,6 +53,8 @@ public class RecentsHorizontalScrollView extends HorizontalScrollView protected int mLastScrollPosition; private SwipeHelper mSwipeHelper; private RecentsScrollViewPerformanceHelper mPerformanceHelper; + private ArrayList<View> mRecycledViews; + private int mNumItemsInOneScreenful; public RecentsHorizontalScrollView(Context context, AttributeSet attrs) { super(context, attrs, 0); @@ -51,6 +62,7 @@ public class RecentsHorizontalScrollView extends HorizontalScrollView float pagingTouchSlop = ViewConfiguration.get(mContext).getScaledPagingTouchSlop(); mSwipeHelper = new SwipeHelper(SwipeHelper.Y, this, densityScale, pagingTouchSlop); mPerformanceHelper = RecentsScrollViewPerformanceHelper.create(context, attrs, this, false); + mRecycledViews = new ArrayList<View>(); } private int scrollPositionOfMostRecent() { @@ -58,9 +70,23 @@ public class RecentsHorizontalScrollView extends HorizontalScrollView } private void update() { + for (int i = 0; i < mLinearLayout.getChildCount(); i++) { + View v = mLinearLayout.getChildAt(i); + mRecycledViews.add(v); + mAdapter.recycleView(v); + } + LayoutTransition transitioner = getLayoutTransition(); + setLayoutTransition(null); + mLinearLayout.removeAllViews(); for (int i = 0; i < mAdapter.getCount(); i++) { - final View view = mAdapter.getView(i, null, mLinearLayout); + View old = null; + if (mRecycledViews.size() != 0) { + old = mRecycledViews.remove(mRecycledViews.size() - 1); + old.setVisibility(VISIBLE); + } + + final View view = mAdapter.getView(i, old, mLinearLayout); if (mPerformanceHelper != null) { mPerformanceHelper.addViewCallback(view); @@ -87,7 +113,8 @@ public class RecentsHorizontalScrollView extends HorizontalScrollView } }; - final View thumbnailView = view.findViewById(R.id.app_thumbnail); + RecentsPanelView.ViewHolder holder = (RecentsPanelView.ViewHolder) view.getTag(); + final View thumbnailView = holder.thumbnailView; OnLongClickListener longClickListener = new OnLongClickListener() { public boolean onLongClick(View v) { final View anchorView = view.findViewById(R.id.app_description); @@ -107,13 +134,21 @@ public class RecentsHorizontalScrollView extends HorizontalScrollView appTitle.setOnTouchListener(noOpListener); mLinearLayout.addView(view); } + setLayoutTransition(transitioner); + // Scroll to end after layout. - post(new Runnable() { - public void run() { - mLastScrollPosition = scrollPositionOfMostRecent(); - scrollTo(mLastScrollPosition, 0); - } - }); + final ViewTreeObserver observer = getViewTreeObserver(); + + final OnGlobalLayoutListener updateScroll = new OnGlobalLayoutListener() { + public void onGlobalLayout() { + mLastScrollPosition = scrollPositionOfMostRecent(); + scrollTo(mLastScrollPosition, 0); + if (observer.isAlive()) { + observer.removeOnGlobalLayoutListener(this); + } + } + }; + observer.addOnGlobalLayoutListener(updateScroll); } @Override @@ -142,8 +177,10 @@ public class RecentsHorizontalScrollView extends HorizontalScrollView } public void onChildDismissed(View v) { + mRecycledViews.add(v); mLinearLayout.removeView(v); mCallback.handleSwipe(v); + v.setActivated(false); } public void onBeginDrag(View v) { @@ -315,6 +352,24 @@ public class RecentsHorizontalScrollView extends HorizontalScrollView update(); } }); + DisplayMetrics dm = getResources().getDisplayMetrics(); + int childWidthMeasureSpec = + MeasureSpec.makeMeasureSpec(dm.widthPixels, MeasureSpec.AT_MOST); + int childheightMeasureSpec = + MeasureSpec.makeMeasureSpec(dm.heightPixels, MeasureSpec.AT_MOST); + View child = mAdapter.createView(mLinearLayout); + child.measure(childWidthMeasureSpec, childheightMeasureSpec); + mNumItemsInOneScreenful = + (int) FloatMath.ceil(dm.widthPixels / (float) child.getMeasuredWidth()); + mRecycledViews.add(child); + + for (int i = 0; i < mNumItemsInOneScreenful - 1; i++) { + mRecycledViews.add(mAdapter.createView(mLinearLayout)); + } + } + + public int numItemsInOneScreenful() { + return mNumItemsInOneScreenful; } @Override diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java index a10e363ec27c..78967203e889 100644 --- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java @@ -27,6 +27,7 @@ import android.graphics.Bitmap; import android.graphics.Matrix; import android.graphics.Shader.TileMode; import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; import android.net.Uri; import android.provider.Settings; import android.util.AttributeSet; @@ -36,18 +37,18 @@ import android.view.LayoutInflater; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; -import android.view.ViewConfiguration; import android.view.ViewGroup; +import android.view.ViewRootImpl; import android.view.accessibility.AccessibilityEvent; import android.view.animation.AnimationUtils; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.BaseAdapter; +import android.widget.FrameLayout; import android.widget.HorizontalScrollView; import android.widget.ImageView; import android.widget.ImageView.ScaleType; import android.widget.PopupMenu; -import android.widget.RelativeLayout; import android.widget.ScrollView; import android.widget.TextView; @@ -59,7 +60,7 @@ import com.android.systemui.statusbar.tablet.TabletStatusBar; import java.util.ArrayList; -public class RecentsPanelView extends RelativeLayout implements OnItemClickListener, RecentsCallback, +public class RecentsPanelView extends FrameLayout implements OnItemClickListener, RecentsCallback, StatusBarPanel, Animator.AnimatorListener, View.OnTouchListener { static final String TAG = "RecentsPanelView"; static final boolean DEBUG = TabletStatusBar.DEBUG || PhoneStatusBar.DEBUG || false; @@ -71,6 +72,10 @@ public class RecentsPanelView extends RelativeLayout implements OnItemClickListe private StatusBarTouchProxy mStatusBarTouchProxy; private boolean mShowing; + private boolean mWaitingToShow; + private boolean mWaitingToShowAnimated; + private boolean mReadyToShow; + private int mNumItemsWaitingForThumbnailsAndIcons; private Choreographer mChoreo; OnRecentsPanelVisibilityChangedListener mVisibilityChangedListener; @@ -104,6 +109,7 @@ public class RecentsPanelView extends RelativeLayout implements OnItemClickListe TextView labelView; TextView descriptionView; TaskDescription taskDescription; + boolean loadedThumbnailAndIcon; } /* package */ final class TaskDescriptionAdapter extends BaseAdapter { @@ -125,42 +131,82 @@ public class RecentsPanelView extends RelativeLayout implements OnItemClickListe return position; // we just need something unique for this position } - public View getView(int position, View convertView, ViewGroup parent) { - ViewHolder holder; - if (convertView == null) { - convertView = mInflater.inflate(R.layout.status_bar_recent_item, parent, false); - holder = new ViewHolder(); - holder.thumbnailView = convertView.findViewById(R.id.app_thumbnail); - holder.thumbnailViewImage = (ImageView) convertView.findViewById( - R.id.app_thumbnail_image); - // If we set the default thumbnail now, we avoid an onLayout when we update - // the thumbnail later (if they both have the same dimensions) + public View createView(ViewGroup parent) { + View convertView = mInflater.inflate(R.layout.status_bar_recent_item, parent, false); + ViewHolder holder = new ViewHolder(); + holder.thumbnailView = convertView.findViewById(R.id.app_thumbnail); + holder.thumbnailViewImage = + (ImageView) convertView.findViewById(R.id.app_thumbnail_image); + // If we set the default thumbnail now, we avoid an onLayout when we update + // the thumbnail later (if they both have the same dimensions) + if (mRecentTasksLoader != null) { updateThumbnail(holder, mRecentTasksLoader.getDefaultThumbnail(), false, false); + } + holder.iconView = (ImageView) convertView.findViewById(R.id.app_icon); + if (mRecentTasksLoader != null) { + holder.iconView.setImageBitmap(mRecentTasksLoader.getDefaultIcon()); + } + holder.labelView = (TextView) convertView.findViewById(R.id.app_label); + holder.descriptionView = (TextView) convertView.findViewById(R.id.app_description); - holder.iconView = (ImageView) convertView.findViewById(R.id.app_icon); - holder.labelView = (TextView) convertView.findViewById(R.id.app_label); - holder.descriptionView = (TextView) convertView.findViewById(R.id.app_description); + convertView.setTag(holder); + return convertView; + } - convertView.setTag(holder); - } else { - holder = (ViewHolder) convertView.getTag(); + public View getView(int position, View convertView, ViewGroup parent) { + if (convertView == null) { + convertView = createView(parent); } + ViewHolder holder = (ViewHolder) convertView.getTag(); // index is reverse since most recent appears at the bottom... final int index = mRecentTaskDescriptions.size() - position - 1; final TaskDescription td = mRecentTaskDescriptions.get(index); - holder.iconView.setImageDrawable(td.getIcon()); + holder.labelView.setText(td.getLabel()); holder.thumbnailView.setContentDescription(td.getLabel()); - updateThumbnail(holder, td.getThumbnail(), true, false); + holder.loadedThumbnailAndIcon = td.isLoaded(); + if (td.isLoaded()) { + updateThumbnail(holder, td.getThumbnail(), true, false); + updateIcon(holder, td.getIcon(), true, false); + mNumItemsWaitingForThumbnailsAndIcons--; + } holder.thumbnailView.setTag(td); holder.thumbnailView.setOnLongClickListener(new OnLongClickDelegate(convertView)); holder.taskDescription = td; - return convertView; } + + public void recycleView(View v) { + ViewHolder holder = (ViewHolder) v.getTag(); + updateThumbnail(holder, mRecentTasksLoader.getDefaultThumbnail(), false, false); + holder.iconView.setImageBitmap(mRecentTasksLoader.getDefaultIcon()); + holder.iconView.setVisibility(INVISIBLE); + holder.labelView.setText(null); + holder.thumbnailView.setContentDescription(null); + holder.thumbnailView.setTag(null); + holder.thumbnailView.setOnLongClickListener(null); + holder.thumbnailView.setVisibility(INVISIBLE); + holder.taskDescription = null; + holder.loadedThumbnailAndIcon = false; + } + } + + public int numItemsInOneScreenful() { + if (mRecentsContainer instanceof RecentsHorizontalScrollView){ + RecentsHorizontalScrollView scrollView + = (RecentsHorizontalScrollView) mRecentsContainer; + return scrollView.numItemsInOneScreenful(); + } else if (mRecentsContainer instanceof RecentsVerticalScrollView){ + RecentsVerticalScrollView scrollView + = (RecentsVerticalScrollView) mRecentsContainer; + return scrollView.numItemsInOneScreenful(); + } + else { + throw new IllegalArgumentException("missing Recents[Horizontal]ScrollView"); + } } @Override @@ -192,15 +238,32 @@ public class RecentsPanelView extends RelativeLayout implements OnItemClickListe } public void show(boolean show, boolean animate) { - show(show, animate, null); + if (show) { + refreshRecentTasksList(null, true); + mWaitingToShow = true; + mWaitingToShowAnimated = animate; + showIfReady(); + } else { + show(show, animate, null, false); + } + } + + private void showIfReady() { + // mWaitingToShow = there was a touch up on the recents button + // mReadyToShow = we've created views for the first screenful of items + if (mWaitingToShow && mReadyToShow) { // && mNumItemsWaitingForThumbnailsAndIcons <= 0 + show(true, mWaitingToShowAnimated, null, false); + } } public void show(boolean show, boolean animate, - ArrayList<TaskDescription> recentTaskDescriptions) { + ArrayList<TaskDescription> recentTaskDescriptions, boolean firstScreenful) { + // For now, disable animations. We may want to re-enable in the future + animate = false; if (show) { // Need to update list of recent apps before we set visibility so this view's // content description is updated before it gets focus for TalkBack mode - refreshRecentTasksList(recentTaskDescriptions); + refreshRecentTasksList(recentTaskDescriptions, firstScreenful); // if there are no apps, either bring up a "No recent apps" message, or just // quit early @@ -209,19 +272,24 @@ public class RecentsPanelView extends RelativeLayout implements OnItemClickListe mRecentsNoApps.setVisibility(noApps ? View.VISIBLE : View.INVISIBLE); } else { if (noApps) { - if (DEBUG) Log.v(TAG, "Nothing to show"); + if (DEBUG) Log.v(TAG, "Nothing to show"); // Need to set recent tasks to dirty so that next time we load, we // refresh the list of tasks - mRecentTasksLoader.cancelLoadingThumbnails(); + mRecentTasksLoader.cancelLoadingThumbnailsAndIcons(); mRecentTasksDirty = true; + + mWaitingToShow = false; + mReadyToShow = false; return; } } } else { // Need to set recent tasks to dirty so that next time we load, we // refresh the list of tasks - mRecentTasksLoader.cancelLoadingThumbnails(); + mRecentTasksLoader.cancelLoadingThumbnailsAndIcons(); mRecentTasksDirty = true; + mWaitingToShow = false; + mReadyToShow = false; } if (animate) { if (mShowing != show) { @@ -385,7 +453,6 @@ public class RecentsPanelView extends RelativeLayout implements OnItemClickListe throw new IllegalArgumentException("missing Recents[Horizontal]ScrollView"); } - mRecentsScrim = findViewById(R.id.recents_bg_protect); mRecentsNoApps = findViewById(R.id.recents_no_apps); mChoreo = new Choreographer(this, mRecentsScrim, mRecentsContainer, mRecentsNoApps, this); @@ -425,6 +492,20 @@ public class RecentsPanelView extends RelativeLayout implements OnItemClickListe } } + + private void updateIcon(ViewHolder h, Drawable icon, boolean show, boolean anim) { + if (icon != null) { + h.iconView.setImageDrawable(icon); + if (show && h.iconView.getVisibility() != View.VISIBLE) { + if (anim) { + h.iconView.setAnimation( + AnimationUtils.loadAnimation(mContext, R.anim.recent_appear)); + } + h.iconView.setVisibility(View.VISIBLE); + } + } + } + private void updateThumbnail(ViewHolder h, Bitmap thumbnail, boolean show, boolean anim) { if (thumbnail != null) { // Should remove the default image in the frame @@ -458,31 +539,36 @@ public class RecentsPanelView extends RelativeLayout implements OnItemClickListe } } - void onTaskThumbnailLoaded(TaskDescription ad) { - synchronized (ad) { + void onTaskThumbnailLoaded(TaskDescription td) { + synchronized (td) { if (mRecentsContainer != null) { ViewGroup container = mRecentsContainer; if (container instanceof HorizontalScrollView || container instanceof ScrollView) { - container = (ViewGroup)container.findViewById( + container = (ViewGroup) container.findViewById( R.id.recents_linear_layout); } // Look for a view showing this thumbnail, to update. - for (int i=0; i<container.getChildCount(); i++) { + for (int i=0; i < container.getChildCount(); i++) { View v = container.getChildAt(i); if (v.getTag() instanceof ViewHolder) { ViewHolder h = (ViewHolder)v.getTag(); - if (h.taskDescription == ad) { + if (!h.loadedThumbnailAndIcon && h.taskDescription == td) { // only fade in the thumbnail if recents is already visible-- we // show it immediately otherwise - boolean animateShow = mShowing && - mRecentsContainer.getAlpha() > ViewConfiguration.ALPHA_THRESHOLD; - updateThumbnail(h, ad.getThumbnail(), true, animateShow); + //boolean animateShow = mShowing && + // mRecentsContainer.getAlpha() > ViewConfiguration.ALPHA_THRESHOLD; + boolean animateShow = false; + updateIcon(h, td.getIcon(), true, animateShow); + updateThumbnail(h, td.getThumbnail(), true, animateShow); + h.loadedThumbnailAndIcon = true; + mNumItemsWaitingForThumbnailsAndIcons--; } } } } - } + } + showIfReady(); } // additional optimization when we have sofware system buttons - start loading the recent @@ -516,7 +602,7 @@ public class RecentsPanelView extends RelativeLayout implements OnItemClickListe public void clearRecentTasksList() { // Clear memory used by screenshots if (mRecentTaskDescriptions != null) { - mRecentTasksLoader.cancelLoadingThumbnails(); + mRecentTasksLoader.cancelLoadingThumbnailsAndIcons(); mRecentTaskDescriptions.clear(); mListAdapter.notifyDataSetInvalidated(); mRecentTasksDirty = true; @@ -524,26 +610,50 @@ public class RecentsPanelView extends RelativeLayout implements OnItemClickListe } public void refreshRecentTasksList() { - refreshRecentTasksList(null); + refreshRecentTasksList(null, false); } - private void refreshRecentTasksList(ArrayList<TaskDescription> recentTasksList) { + private void refreshRecentTasksList( + ArrayList<TaskDescription> recentTasksList, boolean firstScreenful) { if (mRecentTasksDirty) { if (recentTasksList != null) { - mRecentTaskDescriptions = recentTasksList; + mFirstScreenful = true; + onTasksLoaded(recentTasksList); } else { - mRecentTaskDescriptions = mRecentTasksLoader.getRecentTasks(); + mFirstScreenful = true; + mRecentTasksLoader.loadTasksInBackground(); } - mListAdapter.notifyDataSetInvalidated(); - updateUiElements(getResources().getConfiguration()); mRecentTasksDirty = false; } } + boolean mFirstScreenful; + public void onTasksLoaded(ArrayList<TaskDescription> tasks) { + if (!mFirstScreenful && tasks.size() == 0) { + return; + } + mNumItemsWaitingForThumbnailsAndIcons = + mFirstScreenful ? tasks.size() : mRecentTaskDescriptions.size(); + if (mRecentTaskDescriptions == null) { + mRecentTaskDescriptions = new ArrayList(tasks); + } else { + mRecentTaskDescriptions.addAll(tasks); + } + mListAdapter.notifyDataSetInvalidated(); + updateUiElements(getResources().getConfiguration()); + mReadyToShow = true; + mFirstScreenful = false; + showIfReady(); + } + public ArrayList<TaskDescription> getRecentTasksList() { return mRecentTaskDescriptions; } + public boolean getFirstScreenful() { + return mFirstScreenful; + } + private void updateUiElements(Configuration config) { final int items = mRecentTaskDescriptions.size(); diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java index dc13092c2c3d..0605c4c039a2 100644 --- a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java +++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java @@ -22,10 +22,18 @@ import android.content.res.Configuration; import android.database.DataSetObserver; import android.graphics.Canvas; import android.util.AttributeSet; +import android.util.DisplayMetrics; +import android.util.FloatMath; import android.util.Log; import android.view.MotionEvent; import android.view.View; +import android.view.View.MeasureSpec; +import android.view.View.OnClickListener; +import android.view.View.OnLongClickListener; +import android.view.View.OnTouchListener; import android.view.ViewConfiguration; +import android.view.ViewTreeObserver; +import android.view.ViewTreeObserver.OnGlobalLayoutListener; import android.widget.LinearLayout; import android.widget.ScrollView; @@ -33,6 +41,8 @@ import com.android.systemui.R; import com.android.systemui.SwipeHelper; import com.android.systemui.recent.RecentsPanelView.TaskDescriptionAdapter; +import java.util.ArrayList; + public class RecentsVerticalScrollView extends ScrollView implements SwipeHelper.Callback { private static final String TAG = RecentsPanelView.TAG; private static final boolean DEBUG = RecentsPanelView.DEBUG; @@ -42,6 +52,8 @@ public class RecentsVerticalScrollView extends ScrollView implements SwipeHelper protected int mLastScrollPosition; private SwipeHelper mSwipeHelper; private RecentsScrollViewPerformanceHelper mPerformanceHelper; + private ArrayList<View> mRecycledViews; + private int mNumItemsInOneScreenful; public RecentsVerticalScrollView(Context context, AttributeSet attrs) { super(context, attrs, 0); @@ -50,6 +62,7 @@ public class RecentsVerticalScrollView extends ScrollView implements SwipeHelper mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, pagingTouchSlop); mPerformanceHelper = RecentsScrollViewPerformanceHelper.create(context, attrs, this, true); + mRecycledViews = new ArrayList<View>(); } private int scrollPositionOfMostRecent() { @@ -57,77 +70,91 @@ public class RecentsVerticalScrollView extends ScrollView implements SwipeHelper } private void update() { + for (int i = 0; i < mLinearLayout.getChildCount(); i++) { + View v = mLinearLayout.getChildAt(i); + mRecycledViews.add(v); + mAdapter.recycleView(v); + } + LayoutTransition transitioner = getLayoutTransition(); + setLayoutTransition(null); + mLinearLayout.removeAllViews(); // Once we can clear the data associated with individual item views, // we can get rid of the removeAllViews() and the code below will // recycle them. for (int i = 0; i < mAdapter.getCount(); i++) { View old = null; - if (i < mLinearLayout.getChildCount()) { - old = mLinearLayout.getChildAt(i); - old.setVisibility(View.VISIBLE); + if (mRecycledViews.size() != 0) { + old = mRecycledViews.remove(mRecycledViews.size() - 1); + old.setVisibility(VISIBLE); } + final View view = mAdapter.getView(i, old, mLinearLayout); if (mPerformanceHelper != null) { mPerformanceHelper.addViewCallback(view); } - if (old == null) { - OnTouchListener noOpListener = new OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - return true; - } - }; + OnTouchListener noOpListener = new OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + return true; + } + }; - view.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - mCallback.dismiss(); - } - }); - // We don't want a click sound when we dimiss recents - view.setSoundEffectsEnabled(false); + view.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + mCallback.dismiss(); + } + }); + // We don't want a click sound when we dimiss recents + view.setSoundEffectsEnabled(false); - OnClickListener launchAppListener = new OnClickListener() { - public void onClick(View v) { - mCallback.handleOnClick(view); - } - }; - - final View thumbnailView = view.findViewById(R.id.app_thumbnail); - OnLongClickListener longClickListener = new OnLongClickListener() { - public boolean onLongClick(View v) { - final View anchorView = view.findViewById(R.id.app_description); - mCallback.handleLongPress(view, anchorView, thumbnailView); - return true; - } - }; - thumbnailView.setClickable(true); - thumbnailView.setOnClickListener(launchAppListener); - thumbnailView.setOnLongClickListener(longClickListener); - - // We don't want to dismiss recents if a user clicks on the app title - // (we also don't want to launch the app either, though, because the - // app title is a small target and doesn't have great click feedback) - final View appTitle = view.findViewById(R.id.app_label); - appTitle.setContentDescription(" "); - appTitle.setOnTouchListener(noOpListener); - final View calloutLine = view.findViewById(R.id.recents_callout_line); - calloutLine.setOnTouchListener(noOpListener); - mLinearLayout.addView(view); - } - } - for (int i = mAdapter.getCount(); i < mLinearLayout.getChildCount(); i++) { - mLinearLayout.getChildAt(i).setVisibility(View.GONE); + OnClickListener launchAppListener = new OnClickListener() { + public void onClick(View v) { + mCallback.handleOnClick(view); + } + }; + + RecentsPanelView.ViewHolder holder = (RecentsPanelView.ViewHolder) view.getTag(); + final View thumbnailView = holder.thumbnailView; + OnLongClickListener longClickListener = new OnLongClickListener() { + public boolean onLongClick(View v) { + final View anchorView = view.findViewById(R.id.app_description); + mCallback.handleLongPress(view, anchorView, thumbnailView); + return true; + } + }; + thumbnailView.setClickable(true); + thumbnailView.setOnClickListener(launchAppListener); + thumbnailView.setOnLongClickListener(longClickListener); + + // We don't want to dismiss recents if a user clicks on the app title + // (we also don't want to launch the app either, though, because the + // app title is a small target and doesn't have great click feedback) + final View appTitle = view.findViewById(R.id.app_label); + appTitle.setContentDescription(" "); + appTitle.setOnTouchListener(noOpListener); + final View calloutLine = view.findViewById(R.id.recents_callout_line); + calloutLine.setOnTouchListener(noOpListener); + + mLinearLayout.addView(view); } + setLayoutTransition(transitioner); + // Scroll to end after layout. - post(new Runnable() { - public void run() { - mLastScrollPosition = scrollPositionOfMostRecent(); - scrollTo(0, mLastScrollPosition); - } - }); + final ViewTreeObserver observer = getViewTreeObserver(); + + final OnGlobalLayoutListener updateScroll = new OnGlobalLayoutListener() { + public void onGlobalLayout() { + mLastScrollPosition = scrollPositionOfMostRecent(); + scrollTo(0, mLastScrollPosition); + if (observer.isAlive()) { + observer.removeOnGlobalLayoutListener(this); + } + } + }; + observer.addOnGlobalLayoutListener(updateScroll); } @Override @@ -156,8 +183,10 @@ public class RecentsVerticalScrollView extends ScrollView implements SwipeHelper } public void onChildDismissed(View v) { + mRecycledViews.add(v); mLinearLayout.removeView(v); mCallback.handleSwipe(v); + v.setActivated(false); } public void onBeginDrag(View v) { @@ -330,6 +359,25 @@ public class RecentsVerticalScrollView extends ScrollView implements SwipeHelper update(); } }); + + DisplayMetrics dm = getResources().getDisplayMetrics(); + int childWidthMeasureSpec = + MeasureSpec.makeMeasureSpec(dm.widthPixels, MeasureSpec.AT_MOST); + int childheightMeasureSpec = + MeasureSpec.makeMeasureSpec(dm.heightPixels, MeasureSpec.AT_MOST); + View child = mAdapter.createView(mLinearLayout); + child.measure(childWidthMeasureSpec, childheightMeasureSpec); + mNumItemsInOneScreenful = + (int) FloatMath.ceil(dm.heightPixels / (float) child.getMeasuredHeight()); + mRecycledViews.add(child); + + for (int i = 0; i < mNumItemsInOneScreenful - 1; i++) { + mRecycledViews.add(mAdapter.createView(mLinearLayout)); + } + } + + public int numItemsInOneScreenful() { + return mNumItemsInOneScreenful; } @Override diff --git a/packages/SystemUI/src/com/android/systemui/recent/TaskDescription.java b/packages/SystemUI/src/com/android/systemui/recent/TaskDescription.java index dcfd6d8feb1c..7e979b723bda 100644 --- a/packages/SystemUI/src/com/android/systemui/recent/TaskDescription.java +++ b/packages/SystemUI/src/com/android/systemui/recent/TaskDescription.java @@ -32,6 +32,7 @@ public final class TaskDescription { private Bitmap mThumbnail; // generated by Activity.onCreateThumbnail() private Drawable mIcon; // application package icon private CharSequence mLabel; // application package label + private boolean mLoaded; public TaskDescription(int _taskId, int _persistentTaskId, ResolveInfo _resolveInfo, Intent _intent, @@ -45,6 +46,28 @@ public final class TaskDescription { packageName = _packageName; } + public TaskDescription() { + resolveInfo = null; + intent = null; + taskId = -1; + persistentTaskId = -1; + + description = null; + packageName = null; + } + + public void setLoaded(boolean loaded) { + mLoaded = loaded; + } + + public boolean isLoaded() { + return mLoaded; + } + + public boolean isNull() { + return resolveInfo == null; + } + // mark all these as locked? public CharSequence getLabel() { return mLabel; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index 5a1e3f440edd..b3cef9063e39 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -393,7 +393,7 @@ public class PhoneStatusBar extends StatusBar { } lp.gravity = Gravity.BOTTOM | Gravity.LEFT; lp.setTitle("RecentsPanel"); - lp.windowAnimations = R.style.Animation_RecentPanel; + lp.windowAnimations = com.android.internal.R.style.Animation_RecentApplications; lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING; return lp; @@ -403,11 +403,13 @@ public class PhoneStatusBar extends StatusBar { // Recents Panel boolean visible = false; ArrayList<TaskDescription> recentTasksList = null; + boolean firstScreenful = false; if (mRecentsPanel != null) { visible = mRecentsPanel.isShowing(); WindowManagerImpl.getDefault().removeView(mRecentsPanel); if (visible) { recentTasksList = mRecentsPanel.getRecentTasksList(); + firstScreenful = mRecentsPanel.getFirstScreenful(); } } @@ -425,7 +427,7 @@ public class PhoneStatusBar extends StatusBar { WindowManagerImpl.getDefault().addView(mRecentsPanel, lp); mRecentsPanel.setBar(this); if (visible) { - mRecentsPanel.show(true, false, recentTasksList); + mRecentsPanel.show(true, false, recentTasksList, firstScreenful); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java index d787e105c2f8..c59290cc2453 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java @@ -88,6 +88,7 @@ public class NetworkController extends BroadcastReceiver { int mLastSignalLevel; boolean mShowPhoneRSSIForData = false; boolean mShowAtLeastThreeGees = false; + boolean mAlwaysShowCdmaRssi = false; String mContentDescriptionPhoneSignal; String mContentDescriptionWifi; @@ -156,7 +157,7 @@ public class NetworkController extends BroadcastReceiver { IBatteryStats mBatteryStats; public interface SignalCluster { - void setWifiIndicators(boolean visible, int strengthIcon, int activityIcon, + void setWifiIndicators(boolean visible, int strengthIcon, int activityIcon, String contentDescription); void setMobileDataIndicators(boolean visible, int strengthIcon, int activityIcon, int typeIcon, String contentDescription, String typeContentDescription); @@ -176,6 +177,8 @@ public class NetworkController extends BroadcastReceiver { mShowPhoneRSSIForData = res.getBoolean(R.bool.config_showPhoneRSSIForData); mShowAtLeastThreeGees = res.getBoolean(R.bool.config_showMin3G); + mAlwaysShowCdmaRssi = res.getBoolean( + com.android.internal.R.bool.config_alwaysUseCdmaRssi); // set up the default wifi icon, used when no radios have ever appeared updateWifiIcons(); @@ -287,7 +290,7 @@ public class NetworkController extends BroadcastReceiver { // wimax is special cluster.setMobileDataIndicators( true, - mWimaxIconId, + mAlwaysShowCdmaRssi ? mPhoneSignalIconId : mWimaxIconId, mMobileActivityIconId, mDataTypeIconId, mContentDescriptionWimax, @@ -351,7 +354,7 @@ public class NetworkController extends BroadcastReceiver { @Override public void onSignalStrengthsChanged(SignalStrength signalStrength) { if (DEBUG) { - Slog.d(TAG, "onSignalStrengthsChanged signalStrength=" + signalStrength + + Slog.d(TAG, "onSignalStrengthsChanged signalStrength=" + signalStrength + ((signalStrength == null) ? "" : (" level=" + signalStrength.getLevel()))); } mSignalStrength = signalStrength; @@ -469,7 +472,15 @@ public class NetworkController extends BroadcastReceiver { } else { int iconLevel; int[] iconList; - mLastSignalLevel = iconLevel = mSignalStrength.getLevel(); + if (isCdma() && mAlwaysShowCdmaRssi) { + mLastSignalLevel = iconLevel = mSignalStrength.getCdmaLevel(); + if(DEBUG) Slog.d(TAG, "mAlwaysShowCdmaRssi=" + mAlwaysShowCdmaRssi + + " set to cdmaLevel=" + mSignalStrength.getCdmaLevel() + + " instead of level=" + mSignalStrength.getLevel()); + } else { + mLastSignalLevel = iconLevel = mSignalStrength.getLevel(); + } + if (isCdma()) { if (isCdmaEri()) { iconList = TelephonyIcons.TELEPHONY_SIGNAL_STRENGTH_ROAMING[mInetCondition]; @@ -487,7 +498,6 @@ public class NetworkController extends BroadcastReceiver { mPhoneSignalIconId = iconList[iconLevel]; mContentDescriptionPhoneSignal = mContext.getString( AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[iconLevel]); - mDataSignalIconId = TelephonyIcons.DATA_SIGNAL_STRENGTH[mInetCondition][iconLevel]; } } @@ -914,7 +924,7 @@ public class NetworkController extends BroadcastReceiver { mobileLabel = ""; } } else { - mobileLabel + mobileLabel = context.getString(R.string.status_bar_settings_signal_meter_disconnected); } @@ -1190,7 +1200,7 @@ public class NetworkController extends BroadcastReceiver { v.setText(wifiLabel); } } - + // mobile label N = mMobileLabelViews.size(); for (int i=0; i<N; i++) { diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk index 157405a2168c..22fa7520ee1a 100644 --- a/services/audioflinger/Android.mk +++ b/services/audioflinger/Android.mk @@ -7,6 +7,7 @@ LOCAL_SRC_FILES:= \ AudioMixer.cpp.arm \ AudioResampler.cpp.arm \ AudioPolicyService.cpp \ + AudioBufferProvider.cpp \ ServiceUtilities.cpp # AudioResamplerSinc.cpp.arm # AudioResamplerCubic.cpp.arm @@ -17,6 +18,7 @@ LOCAL_C_INCLUDES := \ LOCAL_SHARED_LIBRARIES := \ libaudioutils \ + libcommon_time_client \ libcutils \ libutils \ libbinder \ diff --git a/services/audioflinger/AudioBufferProvider.cpp b/services/audioflinger/AudioBufferProvider.cpp new file mode 100644 index 000000000000..678fd58b4e47 --- /dev/null +++ b/services/audioflinger/AudioBufferProvider.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#undef __STRICT_ANSI__ +#define __STDINT_LIMITS +#define __STDC_LIMIT_MACROS +#include <stdint.h> + +#include "AudioBufferProvider.h" + +namespace android { + +const int64_t AudioBufferProvider::kInvalidPTS = INT64_MAX; + +}; // namespace android diff --git a/services/audioflinger/AudioBufferProvider.h b/services/audioflinger/AudioBufferProvider.h index 81c5c3959930..62ad6bd727b8 100644 --- a/services/audioflinger/AudioBufferProvider.h +++ b/services/audioflinger/AudioBufferProvider.h @@ -38,8 +38,15 @@ public: }; virtual ~AudioBufferProvider() {} - - virtual status_t getNextBuffer(Buffer* buffer) = 0; + + // value representing an invalid presentation timestamp + static const int64_t kInvalidPTS; + + // pts is the local time when the next sample yielded by getNextBuffer + // will be rendered. + // Pass kInvalidPTS if the PTS is unknown or not applicable. + virtual status_t getNextBuffer(Buffer* buffer, int64_t pts) = 0; + virtual void releaseBuffer(Buffer* buffer) = 0; }; diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index 5c964b232330..2e2834c3c7f6 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -1,4 +1,4 @@ -/* //device/include/server/AudioFlinger/AudioFlinger.cpp +/* ** ** Copyright 2007, The Android Open Source Project ** @@ -61,6 +61,9 @@ #include <powermanager/PowerManager.h> // #define DEBUG_CPU_USAGE 10 // log statistics every n wall clock seconds +#include <common_time/cc_helper.h> +#include <common_time/local_clock.h> + // ---------------------------------------------------------------------------- @@ -69,7 +72,6 @@ namespace android { static const char kDeadlockedString[] = "AudioFlinger may be deadlocked\n"; static const char kHardwareLockedString[] = "Hardware lock is taken\n"; -//static const nsecs_t kStandbyTimeInNsecs = seconds(3); static const float MAX_GAIN = 4096.0f; static const uint32_t MAX_GAIN_INT = 0x1000; @@ -99,6 +101,7 @@ static const uint32_t kMinThreadSleepTimeUs = 5000; // maximum divider applied to the active sleep time in the mixer thread loop static const uint32_t kMaxThreadSleepTimeShift = 2; +nsecs_t AudioFlinger::mStandbyTimeInNsecs = kDefaultStandbyTimeInNsecs; // ---------------------------------------------------------------------------- @@ -147,11 +150,14 @@ static const char * const audio_interfaces[] = { AudioFlinger::AudioFlinger() : BnAudioFlinger(), - mPrimaryHardwareDev(NULL), - mHardwareStatus(AUDIO_HW_IDLE), // see also onFirstRef() - mMasterVolume(1.0f), mMasterMute(false), mNextUniqueId(1), - mMode(AUDIO_MODE_INVALID), - mBtNrecIsOff(false) + mPrimaryHardwareDev(NULL), + mHardwareStatus(AUDIO_HW_IDLE), // see also onFirstRef() + mMasterVolume(1.0f), + mMasterVolumeSupportLvl(MVS_NONE), + mMasterMute(false), + mNextUniqueId(1), + mMode(AUDIO_MODE_INVALID), + mBtNrecIsOff(false) { } @@ -162,6 +168,18 @@ void AudioFlinger::onFirstRef() Mutex::Autolock _l(mLock); /* TODO: move all this work into an Init() function */ + char val_str[PROPERTY_VALUE_MAX] = { 0 }; + if (property_get("ro.audio.flinger_standbytime_ms", val_str, NULL) >= 0) { + uint32_t int_val; + if (1 == sscanf(val_str, "%u", &int_val)) { + mStandbyTimeInNsecs = milliseconds(int_val); + ALOGI("Using %u mSec as standby time.", int_val); + } else { + mStandbyTimeInNsecs = kDefaultStandbyTimeInNsecs; + ALOGI("Using default %u mSec as standby time.", + (uint32_t)(mStandbyTimeInNsecs / 1000000)); + } + } for (size_t i = 0; i < ARRAY_SIZE(audio_interfaces); i++) { const hw_module_t *mod; @@ -193,6 +211,32 @@ void AudioFlinger::onFirstRef() AutoMutex lock(mHardwareLock); + // Determine the level of master volume support the primary audio HAL has, + // and set the initial master volume at the same time. + float initialVolume = 1.0; + mMasterVolumeSupportLvl = MVS_NONE; + if (0 == mPrimaryHardwareDev->init_check(mPrimaryHardwareDev)) { + audio_hw_device_t *dev = mPrimaryHardwareDev; + + mHardwareStatus = AUDIO_HW_GET_MASTER_VOLUME; + if ((NULL != dev->get_master_volume) && + (NO_ERROR == dev->get_master_volume(dev, &initialVolume))) { + mMasterVolumeSupportLvl = MVS_FULL; + } else { + mMasterVolumeSupportLvl = MVS_SETONLY; + initialVolume = 1.0; + } + + mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME; + if ((NULL == dev->set_master_volume) || + (NO_ERROR != dev->set_master_volume(dev, initialVolume))) { + mMasterVolumeSupportLvl = MVS_NONE; + } + mHardwareStatus = AUDIO_HW_INIT; + } + + // Set the mode for each audio HAL, and try to set the initial volume (if + // supported) for all of the non-primary audio HALs. for (size_t i = 0; i < mAudioHwDevs.size(); i++) { audio_hw_device_t *dev = mAudioHwDevs[i]; @@ -203,11 +247,22 @@ void AudioFlinger::onFirstRef() mMode = AUDIO_MODE_NORMAL; // assigned multiple times with same value mHardwareStatus = AUDIO_HW_SET_MODE; dev->set_mode(dev, mMode); - mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME; - dev->set_master_volume(dev, 1.0f); - mHardwareStatus = AUDIO_HW_IDLE; + + if ((dev != mPrimaryHardwareDev) && + (NULL != dev->set_master_volume)) { + mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME; + dev->set_master_volume(dev, initialVolume); + } + + mHardwareStatus = AUDIO_HW_INIT; } } + + mMasterVolumeSW = (MVS_NONE == mMasterVolumeSupportLvl) + ? initialVolume + : 1.0; + mMasterVolume = initialVolume; + mHardwareStatus = AUDIO_HW_IDLE; } AudioFlinger::~AudioFlinger() @@ -273,7 +328,10 @@ status_t AudioFlinger::dumpInternals(int fd, const Vector<String16>& args) String8 result; hardware_call_state hardwareStatus = mHardwareStatus; - snprintf(buffer, SIZE, "Hardware status: %d\n", hardwareStatus); + snprintf(buffer, SIZE, "Hardware status: %d\n" + "Standby Time mSec: %u\n", + hardwareStatus, + (uint32_t)(mStandbyTimeInNsecs / 1000000)); result.append(buffer); write(fd, result.string(), result.size()); return NO_ERROR; @@ -377,6 +435,7 @@ sp<IAudioTrack> AudioFlinger::createTrack( uint32_t flags, const sp<IMemory>& sharedBuffer, audio_io_handle_t output, + bool isTimed, int *sessionId, status_t *status) { @@ -435,7 +494,7 @@ sp<IAudioTrack> AudioFlinger::createTrack( ALOGV("createTrack() lSessionId: %d", lSessionId); track = thread->createTrack_l(client, streamType, sampleRate, format, - channelMask, frameCount, sharedBuffer, lSessionId, &lStatus); + channelMask, frameCount, sharedBuffer, lSessionId, isTimed, &lStatus); // move effect chain to this output thread if an effect on same session was waiting // for a track to be created @@ -528,20 +587,29 @@ status_t AudioFlinger::setMasterVolume(float value) return PERMISSION_DENIED; } + float swmv = value; + // when hw supports master volume, don't scale in sw mixer - { // scope for the lock - AutoMutex lock(mHardwareLock); - mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME; - if (mPrimaryHardwareDev->set_master_volume(mPrimaryHardwareDev, value) == NO_ERROR) { - value = 1.0f; + if (MVS_NONE != mMasterVolumeSupportLvl) { + for (size_t i = 0; i < mAudioHwDevs.size(); i++) { + AutoMutex lock(mHardwareLock); + audio_hw_device_t *dev = mAudioHwDevs[i]; + + mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME; + if (NULL != dev->set_master_volume) { + dev->set_master_volume(dev, value); + } + mHardwareStatus = AUDIO_HW_IDLE; } - mHardwareStatus = AUDIO_HW_IDLE; + + swmv = 1.0; } Mutex::Autolock _l(mLock); - mMasterVolume = value; - for (uint32_t i = 0; i < mPlaybackThreads.size(); i++) - mPlaybackThreads.valueAt(i)->setMasterVolume(value); + mMasterVolume = value; + mMasterVolumeSW = swmv; + for (size_t i = 0; i < mPlaybackThreads.size(); i++) + mPlaybackThreads.valueAt(i)->setMasterVolume(swmv); return NO_ERROR; } @@ -572,7 +640,7 @@ status_t AudioFlinger::setMode(audio_mode_t mode) if (NO_ERROR == ret) { Mutex::Autolock _l(mLock); mMode = mode; - for (uint32_t i = 0; i < mPlaybackThreads.size(); i++) + for (size_t i = 0; i < mPlaybackThreads.size(); i++) mPlaybackThreads.valueAt(i)->setMode(mode); } @@ -621,8 +689,9 @@ status_t AudioFlinger::setMasterMute(bool muted) } Mutex::Autolock _l(mLock); + // This is an optimization, so PlaybackThread doesn't have to look at the one from AudioFlinger mMasterMute = muted; - for (uint32_t i = 0; i < mPlaybackThreads.size(); i++) + for (size_t i = 0; i < mPlaybackThreads.size(); i++) mPlaybackThreads.valueAt(i)->setMasterMute(muted); return NO_ERROR; @@ -634,12 +703,36 @@ float AudioFlinger::masterVolume() const return masterVolume_l(); } +float AudioFlinger::masterVolumeSW() const +{ + Mutex::Autolock _l(mLock); + return masterVolumeSW_l(); +} + bool AudioFlinger::masterMute() const { Mutex::Autolock _l(mLock); return masterMute_l(); } +float AudioFlinger::masterVolume_l() const +{ + if (MVS_FULL == mMasterVolumeSupportLvl) { + float ret_val; + AutoMutex lock(mHardwareLock); + + mHardwareStatus = AUDIO_HW_GET_MASTER_VOLUME; + assert(NULL != mPrimaryHardwareDev); + assert(NULL != mPrimaryHardwareDev->get_master_volume); + + mPrimaryHardwareDev->get_master_volume(mPrimaryHardwareDev, &ret_val); + mHardwareStatus = AUDIO_HW_IDLE; + return ret_val; + } + + return mMasterVolume; +} + status_t AudioFlinger::setStreamVolume(audio_stream_type_t stream, float value, audio_io_handle_t output) { @@ -665,7 +758,7 @@ status_t AudioFlinger::setStreamVolume(audio_stream_type_t stream, float value, mStreamTypes[stream].volume = value; if (thread == NULL) { - for (uint32_t i = 0; i < mPlaybackThreads.size(); i++) { + for (size_t i = 0; i < mPlaybackThreads.size(); i++) { mPlaybackThreads.valueAt(i)->setStreamVolume(stream, value); } } else { @@ -711,7 +804,7 @@ float AudioFlinger::streamVolume(audio_stream_type_t stream, audio_io_handle_t o } volume = thread->streamVolume(stream); } else { - volume = mStreamTypes[stream].volume; + volume = streamVolume_l(stream); } return volume; @@ -723,7 +816,8 @@ bool AudioFlinger::streamMute(audio_stream_type_t stream) const return true; } - return mStreamTypes[stream].mute; + AutoMutex lock(mLock); + return streamMute_l(stream); } status_t AudioFlinger::setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs) @@ -812,7 +906,7 @@ String8 AudioFlinger::getParameters(audio_io_handle_t ioHandle, const String8& k for (size_t i = 0; i < mAudioHwDevs.size(); i++) { audio_hw_device_t *dev = mAudioHwDevs[i]; char *s = dev->get_parameters(dev, keys.string()); - out_s8 += String8(s); + out_s8 += String8(s ? s : ""); free(s); } return out_s8; @@ -928,7 +1022,7 @@ void AudioFlinger::removeNotificationClient(pid_t pid) { Mutex::Autolock _l(mLock); - int index = mNotificationClients.indexOfKey(pid); + ssize_t index = mNotificationClients.indexOfKey(pid); if (index >= 0) { sp <NotificationClient> client = mNotificationClients.valueFor(pid); ALOGV("removeNotificationClient() %p, pid %d", client.get(), pid); @@ -936,9 +1030,9 @@ void AudioFlinger::removeNotificationClient(pid_t pid) } ALOGV("%d died, releasing its sessions", pid); - int num = mAudioSessionRefs.size(); + size_t num = mAudioSessionRefs.size(); bool removed = false; - for (int i = 0; i< num; i++) { + for (size_t i = 0; i< num; ) { AudioSessionRef *ref = mAudioSessionRefs.itemAt(i); ALOGV(" pid %d @ %d", ref->pid, i); if (ref->pid == pid) { @@ -946,8 +1040,9 @@ void AudioFlinger::removeNotificationClient(pid_t pid) mAudioSessionRefs.removeAt(i); delete ref; removed = true; - i--; num--; + } else { + i++; } } if (removed) { @@ -1238,7 +1333,7 @@ void AudioFlinger::ThreadBase::setEffectSuspended_l( void AudioFlinger::ThreadBase::checkSuspendOnAddEffectChain_l(const sp<EffectChain>& chain) { - int index = mSuspendedSessions.indexOfKey(chain->sessionId()); + ssize_t index = mSuspendedSessions.indexOfKey(chain->sessionId()); if (index < 0) { return; } @@ -1264,7 +1359,7 @@ void AudioFlinger::ThreadBase::updateSuspendedSessions_l(const effect_uuid_t *ty bool suspend, int sessionId) { - int index = mSuspendedSessions.indexOfKey(sessionId); + ssize_t index = mSuspendedSessions.indexOfKey(sessionId); KeyedVector <int, sp<SuspendedSessionDesc> > sessionEffects; @@ -1364,7 +1459,7 @@ AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinge mOutput(output), // Assumes constructor is called by AudioFlinger with it's mLock held, // but it would be safer to explicitly pass initial masterVolume as parameter - mMasterVolume(audioFlinger->masterVolume_l()), + mMasterVolume(audioFlinger->masterVolumeSW_l()), mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mInWrite(false) { snprintf(mName, kNameLength, "AudioOut_%d", id); @@ -1375,11 +1470,13 @@ AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinge // There is no AUDIO_STREAM_MIN, and ++ operator does not compile for (audio_stream_type_t stream = (audio_stream_type_t) 0; stream < AUDIO_STREAM_CNT; stream = (audio_stream_type_t) (stream + 1)) { - mStreamTypes[stream].volume = mAudioFlinger->streamVolumeInternal(stream); - mStreamTypes[stream].mute = mAudioFlinger->streamMute(stream); + mStreamTypes[stream].volume = mAudioFlinger->streamVolume_l(stream); + mStreamTypes[stream].mute = mAudioFlinger->streamMute_l(stream); // initialized by stream_type_t default constructor // mStreamTypes[stream].valid = true; } + // mStreamTypes[AUDIO_STREAM_CNT] exists but isn't explicitly initialized here, + // because mAudioFlinger doesn't have one to copy from } AudioFlinger::PlaybackThread::~PlaybackThread() @@ -1480,6 +1577,7 @@ sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTra int frameCount, const sp<IMemory>& sharedBuffer, int sessionId, + bool isTimed, status_t *status) { sp<Track> track; @@ -1530,9 +1628,14 @@ sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTra } } - track = new Track(this, client, streamType, sampleRate, format, - channelMask, frameCount, sharedBuffer, sessionId); - if (track->getCblk() == NULL || track->name() < 0) { + if (!isTimed) { + track = new Track(this, client, streamType, sampleRate, format, + channelMask, frameCount, sharedBuffer, sessionId); + } else { + track = TimedTrack::create(this, client, streamType, sampleRate, format, + channelMask, frameCount, sharedBuffer, sessionId); + } + if (track == NULL || track->getCblk() == NULL || track->name() < 0) { lStatus = NO_MEMORY; goto Exit; } @@ -1573,40 +1676,36 @@ uint32_t AudioFlinger::PlaybackThread::latency() const } } -status_t AudioFlinger::PlaybackThread::setMasterVolume(float value) +void AudioFlinger::PlaybackThread::setMasterVolume(float value) { + Mutex::Autolock _l(mLock); mMasterVolume = value; - return NO_ERROR; } -status_t AudioFlinger::PlaybackThread::setMasterMute(bool muted) +void AudioFlinger::PlaybackThread::setMasterMute(bool muted) { - mMasterMute = muted; - return NO_ERROR; + Mutex::Autolock _l(mLock); + setMasterMute_l(muted); } -status_t AudioFlinger::PlaybackThread::setStreamVolume(audio_stream_type_t stream, float value) +void AudioFlinger::PlaybackThread::setStreamVolume(audio_stream_type_t stream, float value) { + Mutex::Autolock _l(mLock); mStreamTypes[stream].volume = value; - return NO_ERROR; } -status_t AudioFlinger::PlaybackThread::setStreamMute(audio_stream_type_t stream, bool muted) +void AudioFlinger::PlaybackThread::setStreamMute(audio_stream_type_t stream, bool muted) { + Mutex::Autolock _l(mLock); mStreamTypes[stream].mute = muted; - return NO_ERROR; } float AudioFlinger::PlaybackThread::streamVolume(audio_stream_type_t stream) const { + Mutex::Autolock _l(mLock); return mStreamTypes[stream].volume; } -bool AudioFlinger::PlaybackThread::streamMute(audio_stream_type_t stream) const -{ - return mStreamTypes[stream].mute; -} - // addTrack_l() must be called with ThreadBase::mLock held status_t AudioFlinger::PlaybackThread::addTrack_l(const sp<Track>& track) { @@ -1936,11 +2035,11 @@ bool AudioFlinger::MixerThread::threadLoop() property_get("ro.audio.silent", value, "0"); if (atoi(value)) { ALOGD("Silence is golden"); - setMasterMute(true); + setMasterMute_l(true); } } - standbyTime = systemTime() + kStandbyTimeInNsecs; + standbyTime = systemTime() + mStandbyTimeInNsecs; sleepTime = idleSleepTime; sleepTimeShift = 0; continue; @@ -1956,8 +2055,21 @@ bool AudioFlinger::MixerThread::threadLoop() } if (CC_LIKELY(mixerStatus == MIXER_TRACKS_READY)) { + // obtain the presentation timestamp of the next output buffer + int64_t pts; + status_t status = INVALID_OPERATION; + + if (NULL != mOutput->stream->get_next_write_timestamp) { + status = mOutput->stream->get_next_write_timestamp( + mOutput->stream, &pts); + } + + if (status != NO_ERROR) { + pts = AudioBufferProvider::kInvalidPTS; + } + // mix buffers... - mAudioMixer->process(); + mAudioMixer->process(pts); // increase sleep time progressively when application underrun condition clears. // Only increase sleep time if the mixer is ready for two consecutive times to avoid // that a steady state of alternating ready/not ready conditions keeps the sleep time @@ -1966,7 +2078,7 @@ bool AudioFlinger::MixerThread::threadLoop() sleepTimeShift--; } sleepTime = 0; - standbyTime = systemTime() + kStandbyTimeInNsecs; + standbyTime = systemTime() + mStandbyTimeInNsecs; //TODO: delay standby when effects have a tail } else { // If no tracks are ready, sleep once for the duration of an output @@ -2113,7 +2225,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac ALOG_ASSERT(minFrames <= cblk->frameCount); } } - if ((cblk->framesReady() >= minFrames) && track->isReady() && + if ((track->framesReady() >= minFrames) && track->isReady() && !track->isPaused() && !track->isTerminated()) { //ALOGV("track %d u=%08x, s=%08x [OK] on thread %p", name, cblk->user, cblk->server, this); @@ -2183,7 +2295,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac uint16_t sendLevel = cblk->getSendLevel_U4_12(); // send level comes from shared memory and so may be corrupt - if (sendLevel >= MAX_GAIN_INT) { + if (sendLevel > MAX_GAIN_INT) { ALOGV("Track send level out of range: %04X", sendLevel); sendLevel = MAX_GAIN_INT; } @@ -2204,25 +2316,21 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac } // Convert volumes from 8.24 to 4.12 format - int16_t left, right, aux; // This additional clamping is needed in case chain->setVolume_l() overshot - uint32_t v_clamped = (vl + (1 << 11)) >> 12; - if (v_clamped > MAX_GAIN_INT) v_clamped = MAX_GAIN_INT; - left = int16_t(v_clamped); - v_clamped = (vr + (1 << 11)) >> 12; - if (v_clamped > MAX_GAIN_INT) v_clamped = MAX_GAIN_INT; - right = int16_t(v_clamped); + vl = (vl + (1 << 11)) >> 12; + if (vl > MAX_GAIN_INT) vl = MAX_GAIN_INT; + vr = (vr + (1 << 11)) >> 12; + if (vr > MAX_GAIN_INT) vr = MAX_GAIN_INT; - if (va > MAX_GAIN_INT) va = MAX_GAIN_INT; - aux = int16_t(va); + if (va > MAX_GAIN_INT) va = MAX_GAIN_INT; // va is uint32_t, so no need to check for - // XXX: these things DON'T need to be done each time mAudioMixer->setBufferProvider(name, track); mAudioMixer->enable(name); - mAudioMixer->setParameter(name, param, AudioMixer::VOLUME0, (void *)left); - mAudioMixer->setParameter(name, param, AudioMixer::VOLUME1, (void *)right); - mAudioMixer->setParameter(name, param, AudioMixer::AUXLEVEL, (void *)aux); + mAudioMixer->setParameter(name, param, AudioMixer::VOLUME0, (void *)vl); + mAudioMixer->setParameter(name, param, AudioMixer::VOLUME1, (void *)vr); + mAudioMixer->setParameter(name, param, AudioMixer::AUXLEVEL, (void *)va); mAudioMixer->setParameter( name, AudioMixer::TRACK, @@ -2576,7 +2684,6 @@ bool AudioFlinger::DirectOutputThread::threadLoop() sp<Track> trackToRemove; sp<Track> activeTrack; nsecs_t standbyTime = systemTime(); - int8_t *curBuf; size_t mixBufferSize = mFrameCount*mFrameSize; uint32_t activeSleepTime = activeSleepTimeUs(); uint32_t idleSleepTime = idleSleepTimeUs(); @@ -2637,7 +2744,7 @@ bool AudioFlinger::DirectOutputThread::threadLoop() property_get("ro.audio.silent", value, "0"); if (atoi(value)) { ALOGD("Silence is golden"); - setMasterMute(true); + setMasterMute_l(true); } } @@ -2780,11 +2887,12 @@ bool AudioFlinger::DirectOutputThread::threadLoop() if (CC_LIKELY(mixerStatus == MIXER_TRACKS_READY)) { AudioBufferProvider::Buffer buffer; size_t frameCount = mFrameCount; - curBuf = (int8_t *)mMixBuffer; + int8_t *curBuf = (int8_t *)mMixBuffer; // output audio to hardware while (frameCount) { buffer.frameCount = frameCount; - activeTrack->getNextBuffer(&buffer); + activeTrack->getNextBuffer(&buffer, + AudioBufferProvider::kInvalidPTS); if (CC_UNLIKELY(buffer.raw == NULL)) { memset(curBuf, 0, frameCount * mFrameSize); break; @@ -3033,11 +3141,11 @@ bool AudioFlinger::DuplicatingThread::threadLoop() property_get("ro.audio.silent", value, "0"); if (atoi(value)) { ALOGD("Silence is golden"); - setMasterMute(true); + setMasterMute_l(true); } } - standbyTime = systemTime() + kStandbyTimeInNsecs; + standbyTime = systemTime() + mStandbyTimeInNsecs; sleepTime = idleSleepTime; continue; } @@ -3054,7 +3162,7 @@ bool AudioFlinger::DuplicatingThread::threadLoop() if (CC_LIKELY(mixerStatus == MIXER_TRACKS_READY)) { // mix buffers... if (outputsReady(outputTracks)) { - mAudioMixer->process(); + mAudioMixer->process(AudioBufferProvider::kInvalidPTS); } else { memset(mMixBuffer, 0, mixBufferSize); } @@ -3091,7 +3199,7 @@ bool AudioFlinger::DuplicatingThread::threadLoop() // enable changes in effect chain unlockEffectChains(effectChains); - standbyTime = systemTime() + kStandbyTimeInNsecs; + standbyTime = systemTime() + mStandbyTimeInNsecs; for (size_t i = 0; i < outputTracks.size(); i++) { outputTracks[i]->write(mMixBuffer, writeFrames); } @@ -3121,6 +3229,7 @@ bool AudioFlinger::DuplicatingThread::threadLoop() void AudioFlinger::DuplicatingThread::addOutputTrack(MixerThread *thread) { + // FIXME explain this formula int frameCount = (3 * mFrameCount * mSampleRate) / thread->sampleRate(); OutputTrack *outputTrack = new OutputTrack((ThreadBase *)thread, this, @@ -3140,7 +3249,7 @@ void AudioFlinger::DuplicatingThread::removeOutputTrack(MixerThread *thread) { Mutex::Autolock _l(mLock); for (size_t i = 0; i < mOutputTracks.size(); i++) { - if (mOutputTracks[i]->thread() == (ThreadBase *)thread) { + if (mOutputTracks[i]->thread() == thread) { mOutputTracks[i]->destroy(); mOutputTracks.removeAt(i); updateWaitTime(); @@ -3392,7 +3501,7 @@ void AudioFlinger::PlaybackThread::Track::destroy() { // NOTE: destroyTrack_l() can remove a strong reference to this Track // by removing it from mTracks vector, so there is a risk that this Tracks's - // desctructor is called. As the destructor needs to lock mLock, + // destructor is called. As the destructor needs to lock mLock, // we must acquire a strong reference on this Track before locking mLock // here so that the destructor is called only when exiting this function. // On the other hand, as long as Track::destroy() is only called by @@ -3441,7 +3550,8 @@ void AudioFlinger::PlaybackThread::Track::dump(char* buffer, size_t size) (int)mAuxBuffer); } -status_t AudioFlinger::PlaybackThread::Track::getNextBuffer(AudioBufferProvider::Buffer* buffer) +status_t AudioFlinger::PlaybackThread::Track::getNextBuffer( + AudioBufferProvider::Buffer* buffer, int64_t pts) { audio_track_cblk_t* cblk = this->cblk(); uint32_t framesReady; @@ -3482,10 +3592,14 @@ getNextBuffer_exit: return NOT_ENOUGH_DATA; } +uint32_t AudioFlinger::PlaybackThread::Track::framesReady() const{ + return mCblk->framesReady(); +} + bool AudioFlinger::PlaybackThread::Track::isReady() const { if (mFillingUpStatus != FS_FILLING || isStopped() || isPausing()) return true; - if (mCblk->framesReady() >= mCblk->frameCount || + if (framesReady() >= mCblk->frameCount || (mCblk->flags & CBLK_FORCEREADY_MSK)) { mFillingUpStatus = FS_FILLED; android_atomic_and(~CBLK_FORCEREADY_MSK, &mCblk->flags); @@ -3494,11 +3608,11 @@ bool AudioFlinger::PlaybackThread::Track::isReady() const { return false; } -status_t AudioFlinger::PlaybackThread::Track::start() +status_t AudioFlinger::PlaybackThread::Track::start(pid_t tid) { status_t status = NO_ERROR; - ALOGV("start(%d), calling pid %d session %d", - mName, IPCThreadState::self()->getCallingPid(), mSessionId); + ALOGV("start(%d), calling pid %d session %d tid %d", + mName, IPCThreadState::self()->getCallingPid(), mSessionId, tid); sp<ThreadBase> thread = mThread.promote(); if (thread != 0) { Mutex::Autolock _l(thread->mLock); @@ -3642,6 +3756,406 @@ void AudioFlinger::PlaybackThread::Track::setAuxBuffer(int EffectId, int32_t *bu mAuxBuffer = buffer; } +// timed audio tracks + +sp<AudioFlinger::PlaybackThread::TimedTrack> +AudioFlinger::PlaybackThread::TimedTrack::create( + const wp<ThreadBase>& thread, + const sp<Client>& client, + audio_stream_type_t streamType, + uint32_t sampleRate, + audio_format_t format, + uint32_t channelMask, + int frameCount, + const sp<IMemory>& sharedBuffer, + int sessionId) { + if (!client->reserveTimedTrack()) + return NULL; + + sp<TimedTrack> track = new TimedTrack( + thread, client, streamType, sampleRate, format, channelMask, frameCount, + sharedBuffer, sessionId); + + if (track == NULL) { + client->releaseTimedTrack(); + return NULL; + } + + return track; +} + +AudioFlinger::PlaybackThread::TimedTrack::TimedTrack( + const wp<ThreadBase>& thread, + const sp<Client>& client, + audio_stream_type_t streamType, + uint32_t sampleRate, + audio_format_t format, + uint32_t channelMask, + int frameCount, + const sp<IMemory>& sharedBuffer, + int sessionId) + : Track(thread, client, streamType, sampleRate, format, channelMask, + frameCount, sharedBuffer, sessionId), + mTimedSilenceBuffer(NULL), + mTimedSilenceBufferSize(0), + mTimedAudioOutputOnTime(false), + mMediaTimeTransformValid(false) +{ + LocalClock lc; + mLocalTimeFreq = lc.getLocalFreq(); + + mLocalTimeToSampleTransform.a_zero = 0; + mLocalTimeToSampleTransform.b_zero = 0; + mLocalTimeToSampleTransform.a_to_b_numer = sampleRate; + mLocalTimeToSampleTransform.a_to_b_denom = mLocalTimeFreq; + LinearTransform::reduce(&mLocalTimeToSampleTransform.a_to_b_numer, + &mLocalTimeToSampleTransform.a_to_b_denom); +} + +AudioFlinger::PlaybackThread::TimedTrack::~TimedTrack() { + mClient->releaseTimedTrack(); + delete [] mTimedSilenceBuffer; +} + +status_t AudioFlinger::PlaybackThread::TimedTrack::allocateTimedBuffer( + size_t size, sp<IMemory>* buffer) { + + Mutex::Autolock _l(mTimedBufferQueueLock); + + trimTimedBufferQueue_l(); + + // lazily initialize the shared memory heap for timed buffers + if (mTimedMemoryDealer == NULL) { + const int kTimedBufferHeapSize = 512 << 10; + + mTimedMemoryDealer = new MemoryDealer(kTimedBufferHeapSize, + "AudioFlingerTimed"); + if (mTimedMemoryDealer == NULL) + return NO_MEMORY; + } + + sp<IMemory> newBuffer = mTimedMemoryDealer->allocate(size); + if (newBuffer == NULL) { + newBuffer = mTimedMemoryDealer->allocate(size); + if (newBuffer == NULL) + return NO_MEMORY; + } + + *buffer = newBuffer; + return NO_ERROR; +} + +// caller must hold mTimedBufferQueueLock +void AudioFlinger::PlaybackThread::TimedTrack::trimTimedBufferQueue_l() { + int64_t mediaTimeNow; + { + Mutex::Autolock mttLock(mMediaTimeTransformLock); + if (!mMediaTimeTransformValid) + return; + + int64_t targetTimeNow; + status_t res = (mMediaTimeTransformTarget == TimedAudioTrack::COMMON_TIME) + ? mCCHelper.getCommonTime(&targetTimeNow) + : mCCHelper.getLocalTime(&targetTimeNow); + + if (OK != res) + return; + + if (!mMediaTimeTransform.doReverseTransform(targetTimeNow, + &mediaTimeNow)) { + return; + } + } + + size_t trimIndex; + for (trimIndex = 0; trimIndex < mTimedBufferQueue.size(); trimIndex++) { + if (mTimedBufferQueue[trimIndex].pts() > mediaTimeNow) + break; + } + + if (trimIndex) { + mTimedBufferQueue.removeItemsAt(0, trimIndex); + } +} + +status_t AudioFlinger::PlaybackThread::TimedTrack::queueTimedBuffer( + const sp<IMemory>& buffer, int64_t pts) { + + { + Mutex::Autolock mttLock(mMediaTimeTransformLock); + if (!mMediaTimeTransformValid) + return INVALID_OPERATION; + } + + Mutex::Autolock _l(mTimedBufferQueueLock); + + mTimedBufferQueue.add(TimedBuffer(buffer, pts)); + + return NO_ERROR; +} + +status_t AudioFlinger::PlaybackThread::TimedTrack::setMediaTimeTransform( + const LinearTransform& xform, TimedAudioTrack::TargetTimeline target) { + + ALOGV("%s az=%lld bz=%lld n=%d d=%u tgt=%d", __PRETTY_FUNCTION__, + xform.a_zero, xform.b_zero, xform.a_to_b_numer, xform.a_to_b_denom, + target); + + if (!(target == TimedAudioTrack::LOCAL_TIME || + target == TimedAudioTrack::COMMON_TIME)) { + return BAD_VALUE; + } + + Mutex::Autolock lock(mMediaTimeTransformLock); + mMediaTimeTransform = xform; + mMediaTimeTransformTarget = target; + mMediaTimeTransformValid = true; + + return NO_ERROR; +} + +#define min(a, b) ((a) < (b) ? (a) : (b)) + +// implementation of getNextBuffer for tracks whose buffers have timestamps +status_t AudioFlinger::PlaybackThread::TimedTrack::getNextBuffer( + AudioBufferProvider::Buffer* buffer, int64_t pts) +{ + if (pts == AudioBufferProvider::kInvalidPTS) { + buffer->raw = 0; + buffer->frameCount = 0; + return INVALID_OPERATION; + } + + // get ahold of the output stream that these samples will be written to + sp<ThreadBase> thread = mThread.promote(); + if (thread == NULL) { + buffer->raw = 0; + buffer->frameCount = 0; + return INVALID_OPERATION; + } + PlaybackThread* playbackThread = static_cast<PlaybackThread*>(thread.get()); + + Mutex::Autolock _l(mTimedBufferQueueLock); + + while (true) { + + // if we have no timed buffers, then fail + if (mTimedBufferQueue.isEmpty()) { + buffer->raw = 0; + buffer->frameCount = 0; + return NOT_ENOUGH_DATA; + } + + TimedBuffer& head = mTimedBufferQueue.editItemAt(0); + + // calculate the PTS of the head of the timed buffer queue expressed in + // local time + int64_t headLocalPTS; + { + Mutex::Autolock mttLock(mMediaTimeTransformLock); + + assert(mMediaTimeTransformValid); + + if (mMediaTimeTransform.a_to_b_denom == 0) { + // the transform represents a pause, so yield silence + timedYieldSilence(buffer->frameCount, buffer); + return NO_ERROR; + } + + int64_t transformedPTS; + if (!mMediaTimeTransform.doForwardTransform(head.pts(), + &transformedPTS)) { + // the transform failed. this shouldn't happen, but if it does + // then just drop this buffer + ALOGW("timedGetNextBuffer transform failed"); + buffer->raw = 0; + buffer->frameCount = 0; + mTimedBufferQueue.removeAt(0); + return NO_ERROR; + } + + if (mMediaTimeTransformTarget == TimedAudioTrack::COMMON_TIME) { + if (OK != mCCHelper.commonTimeToLocalTime(transformedPTS, + &headLocalPTS)) { + buffer->raw = 0; + buffer->frameCount = 0; + return INVALID_OPERATION; + } + } else { + headLocalPTS = transformedPTS; + } + } + + // adjust the head buffer's PTS to reflect the portion of the head buffer + // that has already been consumed + int64_t effectivePTS = headLocalPTS + + ((head.position() / mCblk->frameSize) * mLocalTimeFreq / sampleRate()); + + // Calculate the delta in samples between the head of the input buffer + // queue and the start of the next output buffer that will be written. + // If the transformation fails because of over or underflow, it means + // that the sample's position in the output stream is so far out of + // whack that it should just be dropped. + int64_t sampleDelta; + if (llabs(effectivePTS - pts) >= (static_cast<int64_t>(1) << 31)) { + ALOGV("*** head buffer is too far from PTS: dropped buffer"); + mTimedBufferQueue.removeAt(0); + continue; + } + if (!mLocalTimeToSampleTransform.doForwardTransform( + (effectivePTS - pts) << 32, &sampleDelta)) { + ALOGV("*** too late during sample rate transform: dropped buffer"); + mTimedBufferQueue.removeAt(0); + continue; + } + + ALOGV("*** %s head.pts=%lld head.pos=%d pts=%lld sampleDelta=[%d.%08x]", + __PRETTY_FUNCTION__, head.pts(), head.position(), pts, + static_cast<int32_t>((sampleDelta >= 0 ? 0 : 1) + (sampleDelta >> 32)), + static_cast<uint32_t>(sampleDelta & 0xFFFFFFFF)); + + // if the delta between the ideal placement for the next input sample and + // the current output position is within this threshold, then we will + // concatenate the next input samples to the previous output + const int64_t kSampleContinuityThreshold = + (static_cast<int64_t>(sampleRate()) << 32) / 10; + + // if this is the first buffer of audio that we're emitting from this track + // then it should be almost exactly on time. + const int64_t kSampleStartupThreshold = 1LL << 32; + + if ((mTimedAudioOutputOnTime && llabs(sampleDelta) <= kSampleContinuityThreshold) || + (!mTimedAudioOutputOnTime && llabs(sampleDelta) <= kSampleStartupThreshold)) { + // the next input is close enough to being on time, so concatenate it + // with the last output + timedYieldSamples(buffer); + + ALOGV("*** on time: head.pos=%d frameCount=%u", head.position(), buffer->frameCount); + return NO_ERROR; + } else if (sampleDelta > 0) { + // the gap between the current output position and the proper start of + // the next input sample is too big, so fill it with silence + uint32_t framesUntilNextInput = (sampleDelta + 0x80000000) >> 32; + + timedYieldSilence(framesUntilNextInput, buffer); + ALOGV("*** silence: frameCount=%u", buffer->frameCount); + return NO_ERROR; + } else { + // the next input sample is late + uint32_t lateFrames = static_cast<uint32_t>(-((sampleDelta + 0x80000000) >> 32)); + size_t onTimeSamplePosition = + head.position() + lateFrames * mCblk->frameSize; + + if (onTimeSamplePosition > head.buffer()->size()) { + // all the remaining samples in the head are too late, so + // drop it and move on + ALOGV("*** too late: dropped buffer"); + mTimedBufferQueue.removeAt(0); + continue; + } else { + // skip over the late samples + head.setPosition(onTimeSamplePosition); + + // yield the available samples + timedYieldSamples(buffer); + + ALOGV("*** late: head.pos=%d frameCount=%u", head.position(), buffer->frameCount); + return NO_ERROR; + } + } + } +} + +// Yield samples from the timed buffer queue head up to the given output +// buffer's capacity. +// +// Caller must hold mTimedBufferQueueLock +void AudioFlinger::PlaybackThread::TimedTrack::timedYieldSamples( + AudioBufferProvider::Buffer* buffer) { + + const TimedBuffer& head = mTimedBufferQueue[0]; + + buffer->raw = (static_cast<uint8_t*>(head.buffer()->pointer()) + + head.position()); + + uint32_t framesLeftInHead = ((head.buffer()->size() - head.position()) / + mCblk->frameSize); + size_t framesRequested = buffer->frameCount; + buffer->frameCount = min(framesLeftInHead, framesRequested); + + mTimedAudioOutputOnTime = true; +} + +// Yield samples of silence up to the given output buffer's capacity +// +// Caller must hold mTimedBufferQueueLock +void AudioFlinger::PlaybackThread::TimedTrack::timedYieldSilence( + uint32_t numFrames, AudioBufferProvider::Buffer* buffer) { + + // lazily allocate a buffer filled with silence + if (mTimedSilenceBufferSize < numFrames * mCblk->frameSize) { + delete [] mTimedSilenceBuffer; + mTimedSilenceBufferSize = numFrames * mCblk->frameSize; + mTimedSilenceBuffer = new uint8_t[mTimedSilenceBufferSize]; + memset(mTimedSilenceBuffer, 0, mTimedSilenceBufferSize); + } + + buffer->raw = mTimedSilenceBuffer; + size_t framesRequested = buffer->frameCount; + buffer->frameCount = min(numFrames, framesRequested); + + mTimedAudioOutputOnTime = false; +} + +void AudioFlinger::PlaybackThread::TimedTrack::releaseBuffer( + AudioBufferProvider::Buffer* buffer) { + + Mutex::Autolock _l(mTimedBufferQueueLock); + + // If the buffer which was just released is part of the buffer at the head + // of the queue, be sure to update the amt of the buffer which has been + // consumed. If the buffer being returned is not part of the head of the + // queue, its either because the buffer is part of the silence buffer, or + // because the head of the timed queue was trimmed after the mixer called + // getNextBuffer but before the mixer called releaseBuffer. + if ((buffer->raw != mTimedSilenceBuffer) && mTimedBufferQueue.size()) { + TimedBuffer& head = mTimedBufferQueue.editItemAt(0); + + void* start = head.buffer()->pointer(); + void* end = head.buffer()->pointer() + head.buffer()->size(); + + if ((buffer->raw >= start) && (buffer->raw <= end)) { + head.setPosition(head.position() + + (buffer->frameCount * mCblk->frameSize)); + if (static_cast<size_t>(head.position()) >= head.buffer()->size()) { + mTimedBufferQueue.removeAt(0); + } + } + } + + buffer->raw = 0; + buffer->frameCount = 0; +} + +uint32_t AudioFlinger::PlaybackThread::TimedTrack::framesReady() const { + Mutex::Autolock _l(mTimedBufferQueueLock); + + uint32_t frames = 0; + for (size_t i = 0; i < mTimedBufferQueue.size(); i++) { + const TimedBuffer& tb = mTimedBufferQueue[i]; + frames += (tb.buffer()->size() - tb.position()) / mCblk->frameSize; + } + + return frames; +} + +AudioFlinger::PlaybackThread::TimedTrack::TimedBuffer::TimedBuffer() + : mPTS(0), mPosition(0) {} + +AudioFlinger::PlaybackThread::TimedTrack::TimedBuffer::TimedBuffer( + const sp<IMemory>& buffer, int64_t pts) + : mBuffer(buffer), mPTS(pts), mPosition(0) {} + // ---------------------------------------------------------------------------- // RecordTrack constructor must be called with AudioFlinger::mLock held @@ -3678,7 +4192,7 @@ AudioFlinger::RecordThread::RecordTrack::~RecordTrack() } } -status_t AudioFlinger::RecordThread::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer) +status_t AudioFlinger::RecordThread::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer, int64_t pts) { audio_track_cblk_t* cblk = this->cblk(); uint32_t framesAvail; @@ -3717,12 +4231,12 @@ getNextBuffer_exit: return NOT_ENOUGH_DATA; } -status_t AudioFlinger::RecordThread::RecordTrack::start() +status_t AudioFlinger::RecordThread::RecordTrack::start(pid_t tid) { sp<ThreadBase> thread = mThread.promote(); if (thread != 0) { RecordThread *recordThread = (RecordThread *)thread.get(); - return recordThread->start(this); + return recordThread->start(this, tid); } else { return BAD_VALUE; } @@ -3789,9 +4303,9 @@ AudioFlinger::PlaybackThread::OutputTrack::~OutputTrack() clearBufferQueue(); } -status_t AudioFlinger::PlaybackThread::OutputTrack::start() +status_t AudioFlinger::PlaybackThread::OutputTrack::start(pid_t tid) { - status_t status = Track::start(); + status_t status = Track::start(tid); if (status != NO_ERROR) { return status; } @@ -3821,7 +4335,7 @@ bool AudioFlinger::PlaybackThread::OutputTrack::write(int16_t* data, uint32_t fr uint32_t waitTimeLeftMs = mSourceThread->waitTimeMs(); if (!mActive && frames != 0) { - start(); + start(0); sp<ThreadBase> thread = mThread.promote(); if (thread != 0) { MixerThread *mixerThread = (MixerThread *)thread.get(); @@ -3983,10 +4497,9 @@ status_t AudioFlinger::PlaybackThread::OutputTrack::obtainBuffer(AudioBufferProv void AudioFlinger::PlaybackThread::OutputTrack::clearBufferQueue() { size_t size = mBufferQueue.size(); - Buffer *pBuffer; for (size_t i = 0; i < size; i++) { - pBuffer = mBufferQueue.itemAt(i); + Buffer *pBuffer = mBufferQueue.itemAt(i); delete [] pBuffer->mBuffer; delete pBuffer; } @@ -3998,8 +4511,10 @@ void AudioFlinger::PlaybackThread::OutputTrack::clearBufferQueue() AudioFlinger::Client::Client(const sp<AudioFlinger>& audioFlinger, pid_t pid) : RefBase(), mAudioFlinger(audioFlinger), + // FIXME should be a "k" constant not hard-coded, in .h or ro. property, see 4 lines below mMemoryDealer(new MemoryDealer(1024*1024, "AudioFlinger::Client")), - mPid(pid) + mPid(pid), + mTimedTrackCount(0) { // 1 MB of address space is good for 32 tracks, 8 buffers each, 4 KB/buffer } @@ -4015,6 +4530,31 @@ sp<MemoryDealer> AudioFlinger::Client::heap() const return mMemoryDealer; } +// Reserve one of the limited slots for a timed audio track associated +// with this client +bool AudioFlinger::Client::reserveTimedTrack() +{ + const int kMaxTimedTracksPerClient = 4; + + Mutex::Autolock _l(mTimedTrackLock); + + if (mTimedTrackCount >= kMaxTimedTracksPerClient) { + ALOGW("can not create timed track - pid %d has exceeded the limit", + mPid); + return false; + } + + mTimedTrackCount++; + return true; +} + +// Release a slot for a timed audio track +void AudioFlinger::Client::releaseTimedTrack() +{ + Mutex::Autolock _l(mTimedTrackLock); + mTimedTrackCount--; +} + // ---------------------------------------------------------------------------- AudioFlinger::NotificationClient::NotificationClient(const sp<AudioFlinger>& audioFlinger, @@ -4031,9 +4571,7 @@ AudioFlinger::NotificationClient::~NotificationClient() void AudioFlinger::NotificationClient::binderDied(const wp<IBinder>& who) { sp<NotificationClient> keep(this); - { - mAudioFlinger->removeNotificationClient(mPid); - } + mAudioFlinger->removeNotificationClient(mPid); } // ---------------------------------------------------------------------------- @@ -4056,8 +4594,8 @@ sp<IMemory> AudioFlinger::TrackHandle::getCblk() const { return mTrack->getCblk(); } -status_t AudioFlinger::TrackHandle::start() { - return mTrack->start(); +status_t AudioFlinger::TrackHandle::start(pid_t tid) { + return mTrack->start(tid); } void AudioFlinger::TrackHandle::stop() { @@ -4081,6 +4619,38 @@ status_t AudioFlinger::TrackHandle::attachAuxEffect(int EffectId) return mTrack->attachAuxEffect(EffectId); } +status_t AudioFlinger::TrackHandle::allocateTimedBuffer(size_t size, + sp<IMemory>* buffer) { + if (!mTrack->isTimedTrack()) + return INVALID_OPERATION; + + PlaybackThread::TimedTrack* tt = + reinterpret_cast<PlaybackThread::TimedTrack*>(mTrack.get()); + return tt->allocateTimedBuffer(size, buffer); +} + +status_t AudioFlinger::TrackHandle::queueTimedBuffer(const sp<IMemory>& buffer, + int64_t pts) { + if (!mTrack->isTimedTrack()) + return INVALID_OPERATION; + + PlaybackThread::TimedTrack* tt = + reinterpret_cast<PlaybackThread::TimedTrack*>(mTrack.get()); + return tt->queueTimedBuffer(buffer, pts); +} + +status_t AudioFlinger::TrackHandle::setMediaTimeTransform( + const LinearTransform& xform, int target) { + + if (!mTrack->isTimedTrack()) + return INVALID_OPERATION; + + PlaybackThread::TimedTrack* tt = + reinterpret_cast<PlaybackThread::TimedTrack*>(mTrack.get()); + return tt->setMediaTimeTransform( + xform, static_cast<TimedAudioTrack::TargetTimeline>(target)); +} + status_t AudioFlinger::TrackHandle::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { @@ -4179,9 +4749,9 @@ sp<IMemory> AudioFlinger::RecordHandle::getCblk() const { return mRecordTrack->getCblk(); } -status_t AudioFlinger::RecordHandle::start() { +status_t AudioFlinger::RecordHandle::start(pid_t tid) { ALOGV("RecordHandle::start()"); - return mRecordTrack->start(); + return mRecordTrack->start(tid); } void AudioFlinger::RecordHandle::stop() { @@ -4310,7 +4880,8 @@ bool AudioFlinger::RecordThread::threadLoop() } buffer.frameCount = mFrameCount; - if (CC_LIKELY(mActiveTrack->getNextBuffer(&buffer) == NO_ERROR)) { + if (CC_LIKELY(mActiveTrack->getNextBuffer( + &buffer, AudioBufferProvider::kInvalidPTS) == NO_ERROR)) { size_t framesOut = buffer.frameCount; if (mResampler == NULL) { // no resampling @@ -4473,9 +5044,9 @@ Exit: return track; } -status_t AudioFlinger::RecordThread::start(RecordThread::RecordTrack* recordTrack) +status_t AudioFlinger::RecordThread::start(RecordThread::RecordTrack* recordTrack, pid_t tid) { - ALOGV("RecordThread::start"); + ALOGV("RecordThread::start tid=%d", tid); sp <ThreadBase> strongMe = this; status_t status = NO_ERROR; { @@ -4588,7 +5159,7 @@ status_t AudioFlinger::RecordThread::dump(int fd, const Vector<String16>& args) return NO_ERROR; } -status_t AudioFlinger::RecordThread::getNextBuffer(AudioBufferProvider::Buffer* buffer) +status_t AudioFlinger::RecordThread::getNextBuffer(AudioBufferProvider::Buffer* buffer, int64_t pts) { size_t framesReq = buffer->frameCount; size_t framesReady = mFrameCount - mRsmpInIndex; @@ -4659,7 +5230,7 @@ bool AudioFlinger::RecordThread::checkForNewParameters_l() } if (param.getInt(String8(AudioParameter::keyFrameCount), value) == NO_ERROR) { // do not accept frame count changes if tracks are open as the track buffer - // size depends on frame count and correct behavior would not be garantied + // size depends on frame count and correct behavior would not be guaranteed // if frame count is changed after track creation if (mActiveTrack != 0) { status = INVALID_OPERATION; @@ -4976,8 +5547,7 @@ status_t AudioFlinger::closeOutput(audio_io_handle_t output) } } } - void *param2 = NULL; - audioConfigChanged_l(AudioSystem::OUTPUT_CLOSED, output, param2); + audioConfigChanged_l(AudioSystem::OUTPUT_CLOSED, output, NULL); mPlaybackThreads.removeItem(output); } thread->exit(); @@ -5121,8 +5691,7 @@ status_t AudioFlinger::closeInput(audio_io_handle_t input) } ALOGV("closeInput() %d", input); - void *param2 = NULL; - audioConfigChanged_l(AudioSystem::INPUT_CLOSED, input, param2); + audioConfigChanged_l(AudioSystem::INPUT_CLOSED, input, NULL); mRecordThreads.removeItem(input); } thread->exit(); @@ -5154,8 +5723,7 @@ status_t AudioFlinger::setStreamOutput(audio_stream_type_t stream, audio_io_hand for (size_t i = 0; i < mPlaybackThreads.size(); i++) { PlaybackThread *thread = mPlaybackThreads.valueAt(i).get(); - if (thread != dstThread && - thread->type() != ThreadBase::DIRECT) { + if (thread != dstThread && thread->type() != ThreadBase::DIRECT) { MixerThread *srcThread = (MixerThread *)thread; srcThread->setStreamValid(stream, false); srcThread->invalidateTracks(stream); @@ -5176,8 +5744,8 @@ void AudioFlinger::acquireAudioSessionId(int audioSession) Mutex::Autolock _l(mLock); pid_t caller = IPCThreadState::self()->getCallingPid(); ALOGV("acquiring %d from %d", audioSession, caller); - int num = mAudioSessionRefs.size(); - for (int i = 0; i< num; i++) { + size_t num = mAudioSessionRefs.size(); + for (size_t i = 0; i< num; i++) { AudioSessionRef *ref = mAudioSessionRefs.editItemAt(i); if (ref->sessionid == audioSession && ref->pid == caller) { ref->cnt++; @@ -5194,8 +5762,8 @@ void AudioFlinger::releaseAudioSessionId(int audioSession) Mutex::Autolock _l(mLock); pid_t caller = IPCThreadState::self()->getCallingPid(); ALOGV("releasing %d from %d", audioSession, caller); - int num = mAudioSessionRefs.size(); - for (int i = 0; i< num; i++) { + size_t num = mAudioSessionRefs.size(); + for (size_t i = 0; i< num; i++) { AudioSessionRef *ref = mAudioSessionRefs.itemAt(i); if (ref->sessionid == audioSession && ref->pid == caller) { ref->cnt--; @@ -5278,33 +5846,20 @@ void AudioFlinger::purgeStaleEffects_l() { // checkPlaybackThread_l() must be called with AudioFlinger::mLock held AudioFlinger::PlaybackThread *AudioFlinger::checkPlaybackThread_l(audio_io_handle_t output) const { - PlaybackThread *thread = NULL; - if (mPlaybackThreads.indexOfKey(output) >= 0) { - thread = (PlaybackThread *)mPlaybackThreads.valueFor(output).get(); - } - return thread; + return mPlaybackThreads.valueFor(output).get(); } // checkMixerThread_l() must be called with AudioFlinger::mLock held AudioFlinger::MixerThread *AudioFlinger::checkMixerThread_l(audio_io_handle_t output) const { PlaybackThread *thread = checkPlaybackThread_l(output); - if (thread != NULL) { - if (thread->type() == ThreadBase::DIRECT) { - thread = NULL; - } - } - return (MixerThread *)thread; + return thread != NULL && thread->type() != ThreadBase::DIRECT ? (MixerThread *) thread : NULL; } // checkRecordThread_l() must be called with AudioFlinger::mLock held AudioFlinger::RecordThread *AudioFlinger::checkRecordThread_l(audio_io_handle_t input) const { - RecordThread *thread = NULL; - if (mRecordThreads.indexOfKey(input) >= 0) { - thread = (RecordThread *)mRecordThreads.valueFor(input).get(); - } - return thread; + return mRecordThreads.valueFor(input).get(); } uint32_t AudioFlinger::nextUniqueId() @@ -5667,10 +6222,7 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::ThreadBase::createEffect_l( goto Exit; } // Only Pre processor effects are allowed on input threads and only on input threads - if ((mType == RECORD && - (desc->flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_PRE_PROC) || - (mType != RECORD && - (desc->flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC)) { + if ((mType == RECORD) != ((desc->flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC)) { ALOGW("createEffect_l() effect %s (flags %08x) created on wrong thread type %d", desc->name, desc->flags, mType); lStatus = BAD_VALUE; @@ -6107,7 +6659,6 @@ status_t AudioFlinger::EffectModule::addHandle(const sp<EffectHandle>& handle) status_t status; Mutex::Autolock _l(mLock); - // First handle in mHandles has highest priority and controls the effect module int priority = handle->priority(); size_t size = mHandles.size(); sp<EffectHandle> h; @@ -7177,12 +7728,12 @@ status_t AudioFlinger::EffectChain::addEffect_l(const sp<EffectModule>& effect) // Reject insertion if an effect with EFFECT_FLAG_INSERT_EXCLUSIVE is // already present - int size = (int)mEffects.size(); - int idx_insert = size; - int idx_insert_first = -1; - int idx_insert_last = -1; + size_t size = mEffects.size(); + size_t idx_insert = size; + ssize_t idx_insert_first = -1; + ssize_t idx_insert_last = -1; - for (int i = 0; i < size; i++) { + for (size_t i = 0; i < size; i++) { effect_descriptor_t d = mEffects[i]->desc(); uint32_t iMode = d.flags & EFFECT_FLAG_TYPE_MASK; uint32_t iPref = d.flags & EFFECT_FLAG_INSERT_MASK; @@ -7251,11 +7802,10 @@ status_t AudioFlinger::EffectChain::addEffect_l(const sp<EffectModule>& effect) size_t AudioFlinger::EffectChain::removeEffect_l(const sp<EffectModule>& effect) { Mutex::Autolock _l(mLock); - int size = (int)mEffects.size(); - int i; + size_t size = mEffects.size(); uint32_t type = effect->desc().flags & EFFECT_FLAG_TYPE_MASK; - for (i = 0; i < size; i++) { + for (size_t i = 0; i < size; i++) { if (effect == mEffects[i]) { // calling stop here will remove pre-processing effect from the audio HAL. // This is safe as we hold the EffectChain mutex which guarantees that we are not in @@ -7402,7 +7952,7 @@ void AudioFlinger::EffectChain::setEffectSuspended_l( sp<SuspendedEffectDesc> desc; // use effect type UUID timelow as key as there is no real risk of identical // timeLow fields among effect type UUIDs. - int index = mSuspendedEffects.indexOfKey(type->timeLow); + ssize_t index = mSuspendedEffects.indexOfKey(type->timeLow); if (suspend) { if (index >= 0) { desc = mSuspendedEffects.valueAt(index); @@ -7452,7 +8002,7 @@ void AudioFlinger::EffectChain::setEffectSuspendedAll_l(bool suspend) { sp<SuspendedEffectDesc> desc; - int index = mSuspendedEffects.indexOfKey((int)kKeyForSuspendAll); + ssize_t index = mSuspendedEffects.indexOfKey((int)kKeyForSuspendAll); if (suspend) { if (index >= 0) { desc = mSuspendedEffects.valueAt(index); @@ -7534,7 +8084,7 @@ sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectIfEnabled( void AudioFlinger::EffectChain::checkSuspendOnEffectEnabled(const sp<EffectModule>& effect, bool enabled) { - int index = mSuspendedEffects.indexOfKey(effect->desc().type.timeLow); + ssize_t index = mSuspendedEffects.indexOfKey(effect->desc().type.timeLow); if (enabled) { if (index < 0) { // if the effect is not suspend check if all effects are suspended diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h index fdcd9166e209..50712cf1fa8a 100644 --- a/services/audioflinger/AudioFlinger.h +++ b/services/audioflinger/AudioFlinger.h @@ -1,4 +1,4 @@ -/* //device/include/server/AudioFlinger/AudioFlinger.h +/* ** ** Copyright 2007, The Android Open Source Project ** @@ -22,11 +22,14 @@ #include <sys/types.h> #include <limits.h> +#include <common_time/cc_helper.h> + #include <media/IAudioFlinger.h> #include <media/IAudioFlingerClient.h> #include <media/IAudioTrack.h> #include <media/IAudioRecord.h> #include <media/AudioSystem.h> +#include <media/AudioTrack.h> #include <utils/Atomic.h> #include <utils/Errors.h> @@ -55,7 +58,7 @@ class AudioResampler; // ---------------------------------------------------------------------------- -static const nsecs_t kStandbyTimeInNsecs = seconds(3); +static const nsecs_t kDefaultStandbyTimeInNsecs = seconds(3); class AudioFlinger : public BinderService<AudioFlinger>, @@ -78,6 +81,7 @@ public: uint32_t flags, const sp<IMemory>& sharedBuffer, audio_io_handle_t output, + bool isTimed, int *sessionId, status_t *status); @@ -102,6 +106,7 @@ public: virtual status_t setMasterMute(bool muted); virtual float masterVolume() const; + virtual float masterVolumeSW() const; virtual bool masterMute() const; virtual status_t setStreamVolume(audio_stream_type_t stream, float value, @@ -206,6 +211,8 @@ private: audio_hw_device_t* findSuitableHwDev_l(uint32_t devices); void purgeStaleEffects_l(); + static nsecs_t mStandbyTimeInNsecs; + // Internal dump utilites. status_t dumpPermissionDenial(int fd, const Vector<String16>& args); status_t dumpClients(int fd, const Vector<String16>& args); @@ -220,12 +227,18 @@ private: pid_t pid() const { return mPid; } sp<AudioFlinger> audioFlinger() const { return mAudioFlinger; } + bool reserveTimedTrack(); + void releaseTimedTrack(); + private: Client(const Client&); Client& operator = (const Client&); const sp<AudioFlinger> mAudioFlinger; const sp<MemoryDealer> mMemoryDealer; const pid_t mPid; + + Mutex mTimedTrackLock; + int mTimedTrackCount; }; // --- Notification Client --- @@ -290,6 +303,8 @@ private: enum track_state { IDLE, TERMINATED, + // These are order-sensitive; do not change order without reviewing the impact. + // In particular there are assumptions about > STOPPED. STOPPED, RESUMING, ACTIVE, @@ -314,7 +329,7 @@ private: int sessionId); virtual ~TrackBase(); - virtual status_t start() = 0; + virtual status_t start(pid_t tid) = 0; virtual void stop() = 0; sp<IMemory> getCblk() const { return mCblkMemory; } audio_track_cblk_t* cblk() const { return mCblk; } @@ -331,7 +346,9 @@ private: TrackBase(const TrackBase&); TrackBase& operator = (const TrackBase&); - virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer) = 0; + virtual status_t getNextBuffer( + AudioBufferProvider::Buffer* buffer, + int64_t pts) = 0; virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer); audio_format_t format() const { @@ -586,7 +603,7 @@ private: virtual ~Track(); void dump(char* buffer, size_t size); - virtual status_t start(); + virtual status_t start(pid_t tid); virtual void stop(); void pause(); @@ -607,7 +624,6 @@ private: int16_t *mainBuffer() const { return mMainBuffer; } int auxEffectId() const { return mAuxEffectId; } - protected: friend class ThreadBase; friend class TrackHandle; @@ -618,7 +634,11 @@ private: Track(const Track&); Track& operator = (const Track&); - virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer); + virtual status_t getNextBuffer( + AudioBufferProvider::Buffer* buffer, + int64_t pts); + virtual uint32_t framesReady() const; + bool isMuted() const { return mMute; } bool isPausing() const { return mState == PAUSING; @@ -634,6 +654,8 @@ private: return (mStreamType == AUDIO_STREAM_CNT); } + virtual bool isTimedTrack() const { return false; } + // we don't really need a lock for these volatile bool mMute; // FILLED state is used for suppressing volume ramp at begin of playing @@ -650,6 +672,79 @@ private: bool mHasVolumeController; }; // end of Track + class TimedTrack : public Track { + public: + static sp<TimedTrack> create(const wp<ThreadBase>& thread, + const sp<Client>& client, + audio_stream_type_t streamType, + uint32_t sampleRate, + audio_format_t format, + uint32_t channelMask, + int frameCount, + const sp<IMemory>& sharedBuffer, + int sessionId); + ~TimedTrack(); + + class TimedBuffer { + public: + TimedBuffer(); + TimedBuffer(const sp<IMemory>& buffer, int64_t pts); + const sp<IMemory>& buffer() const { return mBuffer; } + int64_t pts() const { return mPTS; } + int position() const { return mPosition; } + void setPosition(int pos) { mPosition = pos; } + private: + sp<IMemory> mBuffer; + int64_t mPTS; + int mPosition; + }; + + virtual bool isTimedTrack() const { return true; } + + virtual uint32_t framesReady() const; + + virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer, + int64_t pts); + virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer); + void timedYieldSamples(AudioBufferProvider::Buffer* buffer); + void timedYieldSilence(uint32_t numFrames, + AudioBufferProvider::Buffer* buffer); + + status_t allocateTimedBuffer(size_t size, + sp<IMemory>* buffer); + status_t queueTimedBuffer(const sp<IMemory>& buffer, + int64_t pts); + status_t setMediaTimeTransform(const LinearTransform& xform, + TimedAudioTrack::TargetTimeline target); + void trimTimedBufferQueue_l(); + + private: + TimedTrack(const wp<ThreadBase>& thread, + const sp<Client>& client, + audio_stream_type_t streamType, + uint32_t sampleRate, + audio_format_t format, + uint32_t channelMask, + int frameCount, + const sp<IMemory>& sharedBuffer, + int sessionId); + + uint64_t mLocalTimeFreq; + LinearTransform mLocalTimeToSampleTransform; + sp<MemoryDealer> mTimedMemoryDealer; + Vector<TimedBuffer> mTimedBufferQueue; + uint8_t* mTimedSilenceBuffer; + uint32_t mTimedSilenceBufferSize; + mutable Mutex mTimedBufferQueueLock; + bool mTimedAudioOutputOnTime; + CCHelper mCCHelper; + + Mutex mMediaTimeTransformLock; + LinearTransform mMediaTimeTransform; + bool mMediaTimeTransformValid; + TimedAudioTrack::TargetTimeline mMediaTimeTransformTarget; + }; + // playback track class OutputTrack : public Track { @@ -668,10 +763,10 @@ private: int frameCount); virtual ~OutputTrack(); - virtual status_t start(); + virtual status_t start(pid_t tid); virtual void stop(); bool write(int16_t* data, uint32_t frames); - bool bufferQueueEmpty() const { return (mBufferQueue.size() == 0) ? true : false; } + bool bufferQueueEmpty() const { return mBufferQueue.size() == 0; } bool isActive() const { return mActive; } const wp<ThreadBase>& thread() const { return mThread; } @@ -707,17 +802,13 @@ private: virtual uint32_t latency() const; - virtual status_t setMasterVolume(float value); - virtual status_t setMasterMute(bool muted); - - virtual float masterVolume() const { return mMasterVolume; } - virtual bool masterMute() const { return mMasterMute; } + void setMasterVolume(float value); + void setMasterMute(bool muted); - virtual status_t setStreamVolume(audio_stream_type_t stream, float value); - virtual status_t setStreamMute(audio_stream_type_t stream, bool muted); + void setStreamVolume(audio_stream_type_t stream, float value); + void setStreamMute(audio_stream_type_t stream, bool muted); - virtual float streamVolume(audio_stream_type_t stream) const; - virtual bool streamMute(audio_stream_type_t stream) const; + float streamVolume(audio_stream_type_t stream) const; sp<Track> createTrack_l( const sp<AudioFlinger::Client>& client, @@ -728,6 +819,7 @@ private: int frameCount, const sp<IMemory>& sharedBuffer, int sessionId, + bool isTimed, status_t *status); AudioStreamOut* getOutput() const; @@ -760,7 +852,11 @@ private: int mSuspended; int mBytesWritten; private: + // mMasterMute is in both PlaybackThread and in AudioFlinger. When a + // PlaybackThread needs to find out if master-muted, it checks it's local + // copy rather than the one in AudioFlinger. This optimization saves a lock. bool mMasterMute; + void setMasterMute_l(bool muted) { mMasterMute = muted; } protected: SortedVector< wp<Track> > mActiveTracks; @@ -853,6 +949,8 @@ private: private: void applyVolume(uint16_t leftVol, uint16_t rightVol, bool ramp); + // volumes last sent to audio HAL with stream->set_volume() + // FIXME use standard representation and names float mLeftVolFloat; float mRightVolFloat; uint16_t mLeftVolShort; @@ -884,7 +982,11 @@ private: PlaybackThread *checkPlaybackThread_l(audio_io_handle_t output) const; MixerThread *checkMixerThread_l(audio_io_handle_t output) const; RecordThread *checkRecordThread_l(audio_io_handle_t input) const; - float streamVolumeInternal(audio_stream_type_t stream) const + // no range check, AudioFlinger::mLock held + bool streamMute_l(audio_stream_type_t stream) const + { return mStreamTypes[stream].mute; } + // no range check, doesn't check per-thread stream volume, AudioFlinger::mLock held + float streamVolume_l(audio_stream_type_t stream) const { return mStreamTypes[stream].volume; } void audioConfigChanged_l(int event, audio_io_handle_t ioHandle, void *param2); @@ -892,25 +994,32 @@ private: uint32_t nextUniqueId(); status_t moveEffectChain_l(int sessionId, - AudioFlinger::PlaybackThread *srcThread, - AudioFlinger::PlaybackThread *dstThread, + PlaybackThread *srcThread, + PlaybackThread *dstThread, bool reRegister); PlaybackThread *primaryPlaybackThread_l(); uint32_t primaryOutputDevice_l(); friend class AudioBuffer; + // server side of the client's IAudioTrack class TrackHandle : public android::BnAudioTrack { public: TrackHandle(const sp<PlaybackThread::Track>& track); virtual ~TrackHandle(); virtual sp<IMemory> getCblk() const; - virtual status_t start(); + virtual status_t start(pid_t tid); virtual void stop(); virtual void flush(); virtual void mute(bool); virtual void pause(); virtual status_t attachAuxEffect(int effectId); + virtual status_t allocateTimedBuffer(size_t size, + sp<IMemory>* buffer); + virtual status_t queueTimedBuffer(const sp<IMemory>& buffer, + int64_t pts); + virtual status_t setMediaTimeTransform(const LinearTransform& xform, + int target); virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags); private: @@ -943,7 +1052,7 @@ private: int sessionId); virtual ~RecordTrack(); - virtual status_t start(); + virtual status_t start(pid_t tid); virtual void stop(); bool overflow() { bool tmp = mOverflow; mOverflow = false; return tmp; } @@ -958,7 +1067,9 @@ private: RecordTrack(const RecordTrack&); RecordTrack& operator = (const RecordTrack&); - virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer); + virtual status_t getNextBuffer( + AudioBufferProvider::Buffer* buffer, + int64_t pts); bool mOverflow; }; @@ -988,13 +1099,15 @@ private: status_t *status); status_t start(RecordTrack* recordTrack); + status_t start(RecordTrack* recordTrack, pid_t tid); void stop(RecordTrack* recordTrack); status_t dump(int fd, const Vector<String16>& args); AudioStreamIn* getInput() const; AudioStreamIn* clearInput(); virtual audio_stream_t* stream(); - virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer); + virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer, + int64_t pts); virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer); virtual bool checkForNewParameters_l(); virtual String8 getParameters(const String8& keys); @@ -1023,12 +1136,13 @@ private: ssize_t mBytesRead; }; + // server side of the client's IAudioRecord class RecordHandle : public android::BnAudioRecord { public: RecordHandle(const sp<RecordThread::RecordTrack>& recordTrack); virtual ~RecordHandle(); virtual sp<IMemory> getCblk() const; - virtual status_t start(); + virtual status_t start(pid_t tid); virtual void stop(); virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags); @@ -1151,6 +1265,7 @@ mutable Mutex mLock; // mutex for process, commands and handl status_t mStatus; // initialization status effect_state mState; // current activation state Vector< wp<EffectHandle> > mHandles; // list of client handles + // First handle in mHandles has highest priority and controls the effect module uint32_t mMaxDisableWaitCnt; // maximum grace period before forcing an effect off after // sending disable command. uint32_t mDisableWaitCnt; // current process() calls count during disable period. @@ -1376,6 +1491,7 @@ mutable Mutex mLock; // mutex for process, commands and handl hwDev(dev), stream(in) {} }; + // for mAudioSessionRefs only struct AudioSessionRef { // FIXME rename parameter names when fields get "m" prefix AudioSessionRef(int sessionid_, pid_t pid_) : @@ -1388,6 +1504,28 @@ mutable Mutex mLock; // mutex for process, commands and handl friend class RecordThread; friend class PlaybackThread; + enum master_volume_support { + // MVS_NONE: + // Audio HAL has no support for master volume, either setting or + // getting. All master volume control must be implemented in SW by the + // AudioFlinger mixing core. + MVS_NONE, + + // MVS_SETONLY: + // Audio HAL has support for setting master volume, but not for getting + // master volume (original HAL design did not include a getter). + // AudioFlinger needs to keep track of the last set master volume in + // addition to needing to set an initial, default, master volume at HAL + // load time. + MVS_SETONLY, + + // MVS_FULL: + // Audio HAL has support both for setting and getting master volume. + // AudioFlinger should send all set and get master volume requests + // directly to the HAL. + MVS_FULL, + }; + mutable Mutex mLock; DefaultKeyedVector< pid_t, wp<Client> > mClients; // see ~Client() @@ -1416,6 +1554,7 @@ mutable Mutex mLock; // mutex for process, commands and handl AUDIO_SET_VOICE_VOLUME, AUDIO_SET_PARAMETER, AUDIO_HW_GET_INPUT_BUFFER_SIZE, + AUDIO_HW_GET_MASTER_VOLUME, }; mutable hardware_call_state mHardwareStatus; // for dump only @@ -1426,18 +1565,22 @@ mutable Mutex mLock; // mutex for process, commands and handl // both are protected by mLock float mMasterVolume; + float mMasterVolumeSW; + master_volume_support mMasterVolumeSupportLvl; bool mMasterMute; DefaultKeyedVector< audio_io_handle_t, sp<RecordThread> > mRecordThreads; DefaultKeyedVector< pid_t, sp<NotificationClient> > mNotificationClients; - volatile int32_t mNextUniqueId; + volatile int32_t mNextUniqueId; // updated by android_atomic_inc audio_mode_t mMode; bool mBtNrecIsOff; + // protected by mLock Vector<AudioSessionRef*> mAudioSessionRefs; - float masterVolume_l() const { return mMasterVolume; } + float masterVolume_l() const; + float masterVolumeSW_l() const { return mMasterVolumeSW; } bool masterMute_l() const { return mMasterMute; } private: diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp index 191520a33a54..020d62afd99b 100644 --- a/services/audioflinger/AudioMixer.cpp +++ b/services/audioflinger/AudioMixer.cpp @@ -1,4 +1,4 @@ -/* //device/include/server/AudioFlinger/AudioMixer.cpp +/* ** ** Copyright 2007, The Android Open Source Project ** @@ -33,6 +33,8 @@ #include <system/audio.h> #include <audio_utils/primitives.h> +#include <common_time/local_clock.h> +#include <common_time/cc_helper.h> #include "AudioMixer.h" @@ -45,6 +47,9 @@ AudioMixer::AudioMixer(size_t frameCount, uint32_t sampleRate) { // AudioMixer is not yet capable of multi-channel beyond stereo assert(2 == MAX_NUM_CHANNELS); + + LocalClock lc; + mState.enabledTracks= 0; mState.needsChanged = 0; mState.frameCount = frameCount; @@ -80,6 +85,7 @@ AudioMixer::AudioMixer(size_t frameCount, uint32_t sampleRate) t->sampleRate = mSampleRate; t->mainBuffer = NULL; t->auxBuffer = NULL; + t->localTimeFreq = lc.getLocalFreq(); t++; } } @@ -251,6 +257,7 @@ void AudioMixer::setParameter(int name, int target, int param, void *value) } break; case AUXLEVEL: + //assert(0 <= valueInt && valueInt <= MAX_GAIN_INT); if (track.auxLevel != valueInt) { ALOGV("setParameter(VOLUME, AUXLEVEL: %04x)", valueInt); track.prevAuxLevel = track.auxLevel << 16; @@ -289,6 +296,7 @@ bool AudioMixer::track_t::setResampler(uint32_t value, uint32_t devSampleRate) if (resampler == NULL) { resampler = AudioResampler::create( format, channelCount, devSampleRate); + resampler->setLocalTimeFreq(localTimeFreq); } return true; } @@ -333,13 +341,13 @@ void AudioMixer::setBufferProvider(int name, AudioBufferProvider* buffer) -void AudioMixer::process() +void AudioMixer::process(int64_t pts) { - mState.hook(&mState); + mState.hook(&mState, pts); } -void AudioMixer::process__validate(state_t* state) +void AudioMixer::process__validate(state_t* state, int64_t pts) { ALOGW_IF(!state->needsChanged, "in process__validate() but nothing's invalid"); @@ -443,7 +451,7 @@ void AudioMixer::process__validate(state_t* state) countActiveTracks, state->enabledTracks, all16BitsStereoNoResample, resampling, volumeRamp); - state->hook(state); + state->hook(state, pts); // Now that the volume ramp has been done, set optimal state and // track hooks for subsequent mixer process @@ -549,7 +557,7 @@ void AudioMixer::volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, i } t->prevVolume[0] = vl; t->prevVolume[1] = vr; - t->adjustVolumeRamp((aux != NULL)); + t->adjustVolumeRamp(aux != NULL); } void AudioMixer::volumeStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux) @@ -558,7 +566,7 @@ void AudioMixer::volumeStereo(track_t* t, int32_t* out, size_t frameCount, int32 const int16_t vr = t->volume[1]; if (CC_UNLIKELY(aux != NULL)) { - const int16_t va = (int16_t)t->auxLevel; + const int16_t va = t->auxLevel; do { int16_t l = (int16_t)(*temp++ >> 12); int16_t r = (int16_t)(*temp++ >> 12); @@ -757,7 +765,7 @@ void AudioMixer::track__16BitsMono(track_t* t, int32_t* out, size_t frameCount, } // no-op case -void AudioMixer::process__nop(state_t* state) +void AudioMixer::process__nop(state_t* state, int64_t pts) { uint32_t e0 = state->enabledTracks; size_t bufSize = state->frameCount * sizeof(int16_t) * MAX_NUM_CHANNELS; @@ -787,7 +795,9 @@ void AudioMixer::process__nop(state_t* state) size_t outFrames = state->frameCount; while (outFrames) { t1.buffer.frameCount = outFrames; - t1.bufferProvider->getNextBuffer(&t1.buffer); + int64_t outputPTS = calculateOutputPTS( + t1, pts, state->frameCount - outFrames); + t1.bufferProvider->getNextBuffer(&t1.buffer, outputPTS); if (t1.buffer.raw == NULL) break; outFrames -= t1.buffer.frameCount; t1.bufferProvider->releaseBuffer(&t1.buffer); @@ -797,7 +807,7 @@ void AudioMixer::process__nop(state_t* state) } // generic code without resampling -void AudioMixer::process__genericNoResampling(state_t* state) +void AudioMixer::process__genericNoResampling(state_t* state, int64_t pts) { int32_t outTemp[BLOCKSIZE * MAX_NUM_CHANNELS] __attribute__((aligned(32))); @@ -809,7 +819,7 @@ void AudioMixer::process__genericNoResampling(state_t* state) e0 &= ~(1<<i); track_t& t = state->tracks[i]; t.buffer.frameCount = state->frameCount; - t.bufferProvider->getNextBuffer(&t.buffer); + t.bufferProvider->getNextBuffer(&t.buffer, pts); t.frameCount = t.buffer.frameCount; t.in = t.buffer.raw; // t.in == NULL can happen if the track was flushed just after having @@ -853,7 +863,7 @@ void AudioMixer::process__genericNoResampling(state_t* state) while (outFrames) { size_t inFrames = (t.frameCount > outFrames)?outFrames:t.frameCount; if (inFrames) { - (t.hook)(&t, outTemp + (BLOCKSIZE-outFrames)*MAX_NUM_CHANNELS, inFrames, state->resampleTemp, aux); + t.hook(&t, outTemp + (BLOCKSIZE-outFrames)*MAX_NUM_CHANNELS, inFrames, state->resampleTemp, aux); t.frameCount -= inFrames; outFrames -= inFrames; if (CC_UNLIKELY(aux != NULL)) { @@ -863,7 +873,9 @@ void AudioMixer::process__genericNoResampling(state_t* state) if (t.frameCount == 0 && outFrames) { t.bufferProvider->releaseBuffer(&t.buffer); t.buffer.frameCount = (state->frameCount - numFrames) - (BLOCKSIZE - outFrames); - t.bufferProvider->getNextBuffer(&t.buffer); + int64_t outputPTS = calculateOutputPTS( + t, pts, numFrames + (BLOCKSIZE - outFrames)); + t.bufferProvider->getNextBuffer(&t.buffer, outputPTS); t.in = t.buffer.raw; if (t.in == NULL) { enabledTracks &= ~(1<<i); @@ -892,7 +904,7 @@ void AudioMixer::process__genericNoResampling(state_t* state) // generic code with resampling -void AudioMixer::process__genericResampling(state_t* state) +void AudioMixer::process__genericResampling(state_t* state, int64_t pts) { // this const just means that local variable outTemp doesn't change int32_t* const outTemp = state->outputTemp; @@ -932,14 +944,16 @@ void AudioMixer::process__genericResampling(state_t* state) // acquire/release the buffers because it's done by // the resampler. if ((t.needs & NEEDS_RESAMPLE__MASK) == NEEDS_RESAMPLE_ENABLED) { - (t.hook)(&t, outTemp, numFrames, state->resampleTemp, aux); + t.resampler->setPTS(pts); + t.hook(&t, outTemp, numFrames, state->resampleTemp, aux); } else { size_t outFrames = 0; while (outFrames < numFrames) { t.buffer.frameCount = numFrames - outFrames; - t.bufferProvider->getNextBuffer(&t.buffer); + int64_t outputPTS = calculateOutputPTS(t, pts, outFrames); + t.bufferProvider->getNextBuffer(&t.buffer, outputPTS); t.in = t.buffer.raw; // t.in == NULL can happen if the track was flushed just after having // been enabled for mixing. @@ -948,7 +962,7 @@ void AudioMixer::process__genericResampling(state_t* state) if (CC_UNLIKELY(aux != NULL)) { aux += outFrames; } - (t.hook)(&t, outTemp + outFrames*MAX_NUM_CHANNELS, t.buffer.frameCount, state->resampleTemp, aux); + t.hook(&t, outTemp + outFrames*MAX_NUM_CHANNELS, t.buffer.frameCount, state->resampleTemp, aux); outFrames += t.buffer.frameCount; t.bufferProvider->releaseBuffer(&t.buffer); } @@ -959,9 +973,15 @@ void AudioMixer::process__genericResampling(state_t* state) } // one track, 16 bits stereo without resampling is the most common case -void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state) +void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state, + int64_t pts) { + // This method is only called when state->enabledTracks has exactly + // one bit set. The asserts below would verify this, but are commented out + // since the whole point of this method is to optimize performance. + //assert(0 != state->enabledTracks); const int i = 31 - __builtin_clz(state->enabledTracks); + //assert((1 << i) == state->enabledTracks); const track_t& t = state->tracks[i]; AudioBufferProvider::Buffer& b(t.buffer); @@ -974,7 +994,8 @@ void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state) const uint32_t vrl = t.volumeRL; while (numFrames) { b.frameCount = numFrames; - t.bufferProvider->getNextBuffer(&b); + int64_t outputPTS = calculateOutputPTS(t, pts, out - t.mainBuffer); + t.bufferProvider->getNextBuffer(&b, outputPTS); const int16_t *in = b.i16; // in == NULL can happen if the track was flushed just after having @@ -1018,7 +1039,8 @@ void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state) // 2 tracks is also a common case // NEVER used in current implementation of process__validate() // only use if the 2 tracks have the same output buffer -void AudioMixer::process__TwoTracks16BitsStereoNoResampling(state_t* state) +void AudioMixer::process__TwoTracks16BitsStereoNoResampling(state_t* state, + int64_t pts) { int i; uint32_t en = state->enabledTracks; @@ -1052,7 +1074,9 @@ void AudioMixer::process__TwoTracks16BitsStereoNoResampling(state_t* state) if (frameCount0 == 0) { b0.frameCount = numFrames; - t0.bufferProvider->getNextBuffer(&b0); + int64_t outputPTS = calculateOutputPTS(t0, pts, + out - t0.mainBuffer); + t0.bufferProvider->getNextBuffer(&b0, outputPTS); if (b0.i16 == NULL) { if (buff == NULL) { buff = new int16_t[MAX_NUM_CHANNELS * state->frameCount]; @@ -1066,7 +1090,9 @@ void AudioMixer::process__TwoTracks16BitsStereoNoResampling(state_t* state) } if (frameCount1 == 0) { b1.frameCount = numFrames; - t1.bufferProvider->getNextBuffer(&b1); + int64_t outputPTS = calculateOutputPTS(t1, pts, + out - t0.mainBuffer); + t1.bufferProvider->getNextBuffer(&b1, outputPTS); if (b1.i16 == NULL) { if (buff == NULL) { buff = new int16_t[MAX_NUM_CHANNELS * state->frameCount]; @@ -1112,5 +1138,14 @@ void AudioMixer::process__TwoTracks16BitsStereoNoResampling(state_t* state) } #endif +int64_t AudioMixer::calculateOutputPTS(const track_t& t, int64_t basePTS, + int outputFrameIndex) +{ + if (AudioBufferProvider::kInvalidPTS == basePTS) + return AudioBufferProvider::kInvalidPTS; + + return basePTS + ((outputFrameIndex * t.localTimeFreq) / t.sampleRate); +} + // ---------------------------------------------------------------------------- }; // namespace android diff --git a/services/audioflinger/AudioMixer.h b/services/audioflinger/AudioMixer.h index c709686f6825..b2102123646e 100644 --- a/services/audioflinger/AudioMixer.h +++ b/services/audioflinger/AudioMixer.h @@ -1,4 +1,4 @@ -/* //device/include/server/AudioFlinger/AudioMixer.h +/* ** ** Copyright 2007, The Android Open Source Project ** @@ -79,7 +79,7 @@ public: void setParameter(int name, int target, int param, void *value); void setBufferProvider(int name, AudioBufferProvider* bufferProvider); - void process(); + void process(int64_t pts); uint32_t trackNames() const { return mTrackNames; } @@ -114,7 +114,6 @@ private: struct state_t; struct track_t; - typedef void (*mix_t)(state_t* state); typedef void (*hook_t)(track_t* t, int32_t* output, size_t numOutFrames, int32_t* temp, int32_t* aux); static const int BLOCKSIZE = 16; // 4 cache lines @@ -128,30 +127,46 @@ private: int32_t prevVolume[MAX_NUM_CHANNELS]; + // 16-byte boundary + int32_t volumeInc[MAX_NUM_CHANNELS]; - int32_t auxLevel; int32_t auxInc; int32_t prevAuxLevel; + // 16-byte boundary + + int16_t auxLevel; // 0 <= auxLevel <= MAX_GAIN_INT, but signed for mul performance uint16_t frameCount; - uint8_t channelCount : 4; - uint8_t enabled : 1; - uint8_t reserved0 : 3; - uint8_t format; - uint32_t channelMask; + uint8_t channelCount; // 1 or 2, redundant with (needs & NEEDS_CHANNEL_COUNT__MASK) + uint8_t format; // always 16 + uint16_t enabled; // actually bool + uint32_t channelMask; // currently under-used AudioBufferProvider* bufferProvider; - mutable AudioBufferProvider::Buffer buffer; + + // 16-byte boundary + + mutable AudioBufferProvider::Buffer buffer; // 8 bytes hook_t hook; const void* in; // current location in buffer + // 16-byte boundary + AudioResampler* resampler; uint32_t sampleRate; int32_t* mainBuffer; int32_t* auxBuffer; + // 16-byte boundary + + uint64_t localTimeFreq; + + int64_t padding; + + // 16-byte boundary + bool setResampler(uint32_t sampleRate, uint32_t devSampleRate); bool doesResample() const { return resampler != NULL; } void resetResampler() { if (resampler != NULL) resampler->reset(); } @@ -165,7 +180,7 @@ private: uint32_t enabledTracks; uint32_t needsChanged; size_t frameCount; - mix_t hook; + void (*hook)(state_t* state, int64_t pts); // one of process__*, never NULL int32_t *outputTemp; int32_t *resampleTemp; int32_t reserved[2]; @@ -187,14 +202,19 @@ private: static void volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux); static void volumeStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux); - static void process__validate(state_t* state); - static void process__nop(state_t* state); - static void process__genericNoResampling(state_t* state); - static void process__genericResampling(state_t* state); - static void process__OneTrack16BitsStereoNoResampling(state_t* state); + static void process__validate(state_t* state, int64_t pts); + static void process__nop(state_t* state, int64_t pts); + static void process__genericNoResampling(state_t* state, int64_t pts); + static void process__genericResampling(state_t* state, int64_t pts); + static void process__OneTrack16BitsStereoNoResampling(state_t* state, + int64_t pts); #if 0 - static void process__TwoTracks16BitsStereoNoResampling(state_t* state); + static void process__TwoTracks16BitsStereoNoResampling(state_t* state, + int64_t pts); #endif + + static int64_t calculateOutputPTS(const track_t& t, int64_t basePTS, + int outputFrameIndex); }; // ---------------------------------------------------------------------------- diff --git a/services/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp index 21b5811ac374..987b039f820c 100644 --- a/services/audioflinger/AudioPolicyService.cpp +++ b/services/audioflinger/AudioPolicyService.cpp @@ -116,19 +116,7 @@ AudioPolicyService::~AudioPolicyService() // release audio pre processing resources for (size_t i = 0; i < mInputSources.size(); i++) { - InputSourceDesc *source = mInputSources.valueAt(i); - Vector <EffectDesc *> effects = source->mEffects; - for (size_t j = 0; j < effects.size(); j++) { - delete effects[j]->mName; - Vector <effect_param_t *> params = effects[j]->mParams; - for (size_t k = 0; k < params.size(); k++) { - delete params[k]; - } - params.clear(); - delete effects[j]; - } - effects.clear(); - delete source; + delete mInputSources.valueAt(i); } mInputSources.clear(); @@ -616,8 +604,7 @@ void AudioPolicyService::setPreProcessorEnabled(InputDesc *inputDesc, bool enabl { Vector<sp<AudioEffect> > fxVector = inputDesc->mEffects; for (size_t i = 0; i < fxVector.size(); i++) { - sp<AudioEffect> fx = fxVector.itemAt(i); - fx->setEnabled(enabled); + fxVector.itemAt(i)->setEnabled(enabled); } } @@ -768,7 +755,7 @@ status_t AudioPolicyService::AudioCommandThread::dump(int fd) snprintf(buffer, SIZE, "- Commands:\n"); result = String8(buffer); result.append(" Command Time Wait pParam\n"); - for (int i = 0; i < (int)mAudioCommands.size(); i++) { + for (size_t i = 0; i < mAudioCommands.size(); i++) { mAudioCommands[i]->dump(buffer, SIZE); result.append(buffer); } @@ -902,7 +889,7 @@ status_t AudioPolicyService::AudioCommandThread::voiceVolumeCommand(float volume // insertCommand_l() must be called with mLock held void AudioPolicyService::AudioCommandThread::insertCommand_l(AudioCommand *command, int delayMs) { - ssize_t i; + ssize_t i; // not size_t because i will count down to -1 Vector <AudioCommand *> removedCommands; command->mTime = systemTime() + milliseconds(delayMs); @@ -1243,7 +1230,7 @@ AudioPolicyService::InputSourceDesc *AudioPolicyService::loadInputSource( node = node->next; continue; } - EffectDesc *effect = new EffectDesc(*effects[i]); + EffectDesc *effect = new EffectDesc(*effects[i]); // deep copy loadEffectParameters(node, effect->mParams); ALOGV("loadInputSource() adding effect %s uuid %08x", effect->mName, effect->mUuid.timeLow); source->mEffects.add(effect); @@ -1294,11 +1281,7 @@ AudioPolicyService::EffectDesc *AudioPolicyService::loadEffect(cnode *root) ALOGW("loadEffect() invalid uuid %s", node->value); return NULL; } - EffectDesc *effect = new EffectDesc(); - effect->mName = strdup(root->name); - memcpy(&effect->mUuid, &uuid, sizeof(effect_uuid_t)); - - return effect; + return new EffectDesc(root->name, uuid); } status_t AudioPolicyService::loadEffects(cnode *root, Vector <EffectDesc *>& effects) diff --git a/services/audioflinger/AudioPolicyService.h b/services/audioflinger/AudioPolicyService.h index fdaf57644e40..679fd30df02a 100644 --- a/services/audioflinger/AudioPolicyService.h +++ b/services/audioflinger/AudioPolicyService.h @@ -233,8 +233,33 @@ private: class EffectDesc { public: - EffectDesc() {} - virtual ~EffectDesc() {} + EffectDesc(const char *name, const effect_uuid_t& uuid) : + mName(strdup(name)), + mUuid(uuid) { } + EffectDesc(const EffectDesc& orig) : + mName(strdup(orig.mName)), + mUuid(orig.mUuid) { + // deep copy mParams + for (size_t k = 0; k < orig.mParams.size(); k++) { + effect_param_t *origParam = orig.mParams[k]; + // psize and vsize are rounded up to an int boundary for allocation + size_t origSize = sizeof(effect_param_t) + + ((origParam->psize + 3) & ~3) + + ((origParam->vsize + 3) & ~3); + effect_param_t *dupParam = (effect_param_t *) malloc(origSize); + memcpy(dupParam, origParam, origSize); + // This works because the param buffer allocation is also done by + // multiples of 4 bytes originally. In theory we should memcpy only + // the actual param size, that is without rounding vsize. + mParams.add(dupParam); + } + } + /*virtual*/ ~EffectDesc() { + free(mName); + for (size_t k = 0; k < mParams.size(); k++) { + free(mParams[k]); + } + } char *mName; effect_uuid_t mUuid; Vector <effect_param_t *> mParams; @@ -243,7 +268,11 @@ private: class InputSourceDesc { public: InputSourceDesc() {} - virtual ~InputSourceDesc() {} + /*virtual*/ ~InputSourceDesc() { + for (size_t j = 0; j < mEffects.size(); j++) { + delete mEffects[j]; + } + } Vector <EffectDesc *> mEffects; }; diff --git a/services/audioflinger/AudioResampler.cpp b/services/audioflinger/AudioResampler.cpp index 9486b9c9efe0..398ba0b6004d 100644 --- a/services/audioflinger/AudioResampler.cpp +++ b/services/audioflinger/AudioResampler.cpp @@ -122,7 +122,8 @@ AudioResampler::AudioResampler(int bitDepth, int inChannelCount, int32_t sampleRate) : mBitDepth(bitDepth), mChannelCount(inChannelCount), mSampleRate(sampleRate), mInSampleRate(sampleRate), mInputIndex(0), - mPhaseFraction(0) { + mPhaseFraction(0), mLocalTimeFreq(0), + mPTS(AudioBufferProvider::kInvalidPTS) { // sanity check on format if ((bitDepth != 16) ||(inChannelCount < 1) || (inChannelCount > 2)) { ALOGE("Unsupported sample format, %d bits, %d channels", bitDepth, @@ -150,6 +151,23 @@ void AudioResampler::setVolume(int16_t left, int16_t right) { mVolume[1] = right; } +void AudioResampler::setLocalTimeFreq(uint64_t freq) { + mLocalTimeFreq = freq; +} + +void AudioResampler::setPTS(int64_t pts) { + mPTS = pts; +} + +int64_t AudioResampler::calculateOutputPTS(int outputFrameIndex) { + + if (mPTS == AudioBufferProvider::kInvalidPTS) { + return AudioBufferProvider::kInvalidPTS; + } else { + return mPTS + ((outputFrameIndex * mLocalTimeFreq) / mSampleRate); + } +} + void AudioResampler::reset() { mInputIndex = 0; mPhaseFraction = 0; @@ -196,7 +214,8 @@ void AudioResamplerOrder1::resampleStereo16(int32_t* out, size_t outFrameCount, // buffer is empty, fetch a new one while (mBuffer.frameCount == 0) { mBuffer.frameCount = inFrameCount; - provider->getNextBuffer(&mBuffer); + provider->getNextBuffer(&mBuffer, + calculateOutputPTS(outputIndex / 2)); if (mBuffer.raw == NULL) { goto resampleStereo16_exit; } @@ -290,7 +309,8 @@ void AudioResamplerOrder1::resampleMono16(int32_t* out, size_t outFrameCount, // buffer is empty, fetch a new one while (mBuffer.frameCount == 0) { mBuffer.frameCount = inFrameCount; - provider->getNextBuffer(&mBuffer); + provider->getNextBuffer(&mBuffer, + calculateOutputPTS(outputIndex / 2)); if (mBuffer.raw == NULL) { mInputIndex = inputIndex; mPhaseFraction = phaseFraction; diff --git a/services/audioflinger/AudioResampler.h b/services/audioflinger/AudioResampler.h index c23016e02ca5..9deb7963d215 100644 --- a/services/audioflinger/AudioResampler.h +++ b/services/audioflinger/AudioResampler.h @@ -49,6 +49,10 @@ public: virtual void init() = 0; virtual void setSampleRate(int32_t inSampleRate); virtual void setVolume(int16_t left, int16_t right); + virtual void setLocalTimeFreq(uint64_t freq); + + // set the PTS of the next buffer output by the resampler + virtual void setPTS(int64_t pts); virtual void resample(int32_t* out, size_t outFrameCount, AudioBufferProvider* provider) = 0; @@ -72,6 +76,8 @@ protected: AudioResampler(const AudioResampler&); AudioResampler& operator=(const AudioResampler&); + int64_t calculateOutputPTS(int outputFrameIndex); + const int32_t mBitDepth; const int32_t mChannelCount; const int32_t mSampleRate; @@ -85,6 +91,8 @@ protected: size_t mInputIndex; int32_t mPhaseIncrement; uint32_t mPhaseFraction; + uint64_t mLocalTimeFreq; + int64_t mPTS; }; // ---------------------------------------------------------------------------- diff --git a/services/audioflinger/AudioResamplerCubic.cpp b/services/audioflinger/AudioResamplerCubic.cpp index c0e760e643ce..18e59e93ee2e 100644 --- a/services/audioflinger/AudioResamplerCubic.cpp +++ b/services/audioflinger/AudioResamplerCubic.cpp @@ -65,7 +65,7 @@ void AudioResamplerCubic::resampleStereo16(int32_t* out, size_t outFrameCount, // fetch first buffer if (mBuffer.frameCount == 0) { mBuffer.frameCount = inFrameCount; - provider->getNextBuffer(&mBuffer); + provider->getNextBuffer(&mBuffer, mPTS); if (mBuffer.raw == NULL) return; // ALOGW("New buffer: offset=%p, frames=%dn", mBuffer.raw, mBuffer.frameCount); @@ -95,7 +95,8 @@ void AudioResamplerCubic::resampleStereo16(int32_t* out, size_t outFrameCount, inputIndex = 0; provider->releaseBuffer(&mBuffer); mBuffer.frameCount = inFrameCount; - provider->getNextBuffer(&mBuffer); + provider->getNextBuffer(&mBuffer, + calculateOutputPTS(outputIndex / 2)); if (mBuffer.raw == NULL) goto save_state; // ugly, but efficient in = mBuffer.i16; @@ -130,7 +131,7 @@ void AudioResamplerCubic::resampleMono16(int32_t* out, size_t outFrameCount, // fetch first buffer if (mBuffer.frameCount == 0) { mBuffer.frameCount = inFrameCount; - provider->getNextBuffer(&mBuffer); + provider->getNextBuffer(&mBuffer, mPTS); if (mBuffer.raw == NULL) return; // ALOGW("New buffer: offset=%p, frames=%d", mBuffer.raw, mBuffer.frameCount); @@ -160,7 +161,8 @@ void AudioResamplerCubic::resampleMono16(int32_t* out, size_t outFrameCount, inputIndex = 0; provider->releaseBuffer(&mBuffer); mBuffer.frameCount = inFrameCount; - provider->getNextBuffer(&mBuffer); + provider->getNextBuffer(&mBuffer, + calculateOutputPTS(outputIndex / 2)); if (mBuffer.raw == NULL) goto save_state; // ugly, but efficient // ALOGW("New buffer: offset=%p, frames=%dn", mBuffer.raw, mBuffer.frameCount); @@ -181,4 +183,3 @@ save_state: // ---------------------------------------------------------------------------- } ; // namespace android - diff --git a/services/audioflinger/AudioResamplerSinc.cpp b/services/audioflinger/AudioResamplerSinc.cpp index 7a27b810afd0..d373c08385b0 100644 --- a/services/audioflinger/AudioResamplerSinc.cpp +++ b/services/audioflinger/AudioResamplerSinc.cpp @@ -203,7 +203,8 @@ void AudioResamplerSinc::resample(int32_t* out, size_t outFrameCount, // buffer is empty, fetch a new one while (mBuffer.frameCount == 0) { mBuffer.frameCount = inFrameCount; - provider->getNextBuffer(&mBuffer); + provider->getNextBuffer(&mBuffer, + calculateOutputPTS(outputIndex / 2)); if (mBuffer.raw == NULL) { goto resample_exit; } @@ -354,4 +355,3 @@ void AudioResamplerSinc::interpolate( // ---------------------------------------------------------------------------- }; // namespace android - diff --git a/services/common_time/Android.mk b/services/common_time/Android.mk new file mode 100644 index 000000000000..e534d4987c45 --- /dev/null +++ b/services/common_time/Android.mk @@ -0,0 +1,34 @@ +LOCAL_PATH:= $(call my-dir) + +# +# common_time_service +# + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + common_clock_service.cpp \ + common_time_config_service.cpp \ + common_time_server.cpp \ + common_time_server_api.cpp \ + common_time_server_packets.cpp \ + clock_recovery.cpp \ + common_clock.cpp \ + main.cpp + +# Uncomment to enable vesbose logging and debug service. +#TIME_SERVICE_DEBUG=true +ifeq ($(TIME_SERVICE_DEBUG), true) +LOCAL_SRC_FILES += diag_thread.cpp +LOCAL_CFLAGS += -DTIME_SERVICE_DEBUG +endif + +LOCAL_SHARED_LIBRARIES := \ + libbinder \ + libcommon_time_client \ + libutils + +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE := common_time + +include $(BUILD_EXECUTABLE) diff --git a/services/common_time/clock_recovery.cpp b/services/common_time/clock_recovery.cpp new file mode 100644 index 000000000000..6c98d32a7109 --- /dev/null +++ b/services/common_time/clock_recovery.cpp @@ -0,0 +1,321 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * A service that exchanges time synchronization information between + * a master that defines a timeline and clients that follow the timeline. + */ + +#define __STDC_LIMIT_MACROS +#define LOG_TAG "common_time" +#include <utils/Log.h> +#include <stdint.h> + +#include <common_time/local_clock.h> +#include <assert.h> + +#include "clock_recovery.h" +#include "common_clock.h" +#ifdef TIME_SERVICE_DEBUG +#include "diag_thread.h" +#endif + +// Define log macro so we can make LOGV into LOGE when we are exclusively +// debugging this code. +#ifdef TIME_SERVICE_DEBUG +#define LOG_TS ALOGE +#else +#define LOG_TS ALOGV +#endif + +namespace android { + +ClockRecoveryLoop::ClockRecoveryLoop(LocalClock* local_clock, + CommonClock* common_clock) { + assert(NULL != local_clock); + assert(NULL != common_clock); + + local_clock_ = local_clock; + common_clock_ = common_clock; + + local_clock_can_slew_ = local_clock_->initCheck() && + (local_clock_->setLocalSlew(0) == OK); + + reset(true, true); + +#ifdef TIME_SERVICE_DEBUG + diag_thread_ = new DiagThread(common_clock_, local_clock_); + if (diag_thread_ != NULL) { + status_t res = diag_thread_->startWorkThread(); + if (res != OK) + ALOGW("Failed to start A@H clock recovery diagnostic thread."); + } else + ALOGW("Failed to allocate diagnostic thread."); +#endif +} + +ClockRecoveryLoop::~ClockRecoveryLoop() { +#ifdef TIME_SERVICE_DEBUG + diag_thread_->stopWorkThread(); +#endif +} + +// Constants. +const float ClockRecoveryLoop::dT = 1.0; +const float ClockRecoveryLoop::Kc = 1.0f; +const float ClockRecoveryLoop::Ti = 15.0f; +const float ClockRecoveryLoop::Tf = 0.05; +const float ClockRecoveryLoop::bias_Fc = 0.01; +const float ClockRecoveryLoop::bias_RC = (dT / (2 * 3.14159f * bias_Fc)); +const float ClockRecoveryLoop::bias_Alpha = (dT / (bias_RC + dT)); +const int64_t ClockRecoveryLoop::panic_thresh_ = 50000; +const int64_t ClockRecoveryLoop::control_thresh_ = 10000; +const float ClockRecoveryLoop::COmin = -100.0f; +const float ClockRecoveryLoop::COmax = 100.0f; + +void ClockRecoveryLoop::reset(bool position, bool frequency) { + Mutex::Autolock lock(&lock_); + reset_l(position, frequency); +} + +uint32_t ClockRecoveryLoop::findMinRTTNdx(DisciplineDataPoint* data, + uint32_t count) { + uint32_t min_rtt = 0; + for (uint32_t i = 1; i < count; ++i) + if (data[min_rtt].rtt > data[i].rtt) + min_rtt = i; + + return min_rtt; +} + +bool ClockRecoveryLoop::pushDisciplineEvent(int64_t local_time, + int64_t nominal_common_time, + int64_t rtt) { + Mutex::Autolock lock(&lock_); + + int64_t local_common_time = 0; + common_clock_->localToCommon(local_time, &local_common_time); + int64_t raw_delta = nominal_common_time - local_common_time; + +#ifdef TIME_SERVICE_DEBUG + ALOGE("local=%lld, common=%lld, delta=%lld, rtt=%lld\n", + local_common_time, nominal_common_time, + raw_delta, rtt); +#endif + + // If we have not defined a basis for common time, then we need to use these + // initial points to do so. In order to avoid significant initial error + // from a particularly bad startup data point, we collect the first N data + // points and choose the best of them before moving on. + if (!common_clock_->isValid()) { + if (startup_filter_wr_ < kStartupFilterSize) { + DisciplineDataPoint& d = startup_filter_data_[startup_filter_wr_]; + d.local_time = local_time; + d.nominal_common_time = nominal_common_time; + d.rtt = rtt; + startup_filter_wr_++; + } + + if (startup_filter_wr_ == kStartupFilterSize) { + uint32_t min_rtt = findMinRTTNdx(startup_filter_data_, + kStartupFilterSize); + + common_clock_->setBasis( + startup_filter_data_[min_rtt].local_time, + startup_filter_data_[min_rtt].nominal_common_time); + } + + return true; + } + + int64_t observed_common; + int64_t delta; + float delta_f, dCO; + int32_t correction_cur; + + if (OK != common_clock_->localToCommon(local_time, &observed_common)) { + // Since we just checked to make certain that this conversion was valid, + // and no one else in the system should be messing with it, if this + // conversion is suddenly invalid, it is a good reason to panic. + ALOGE("Failed to convert local time to common time in %s:%d", + __PRETTY_FUNCTION__, __LINE__); + return false; + } + + // Implement a filter which should match NTP filtering behavior when a + // client is associated with only one peer of lower stratum. Basically, + // always use the best of the N last data points, where best is defined as + // lowest round trip time. NTP uses an N of 8; we use a value of 6. + // + // TODO(johngro) : experiment with other filter strategies. The goal here + // is to mitigate the effects of high RTT data points which typically have + // large asymmetries in the TX/RX legs. Downside of the existing NTP + // approach (particularly because of the PID controller we are using to + // produce the control signal from the filtered data) are that the rate at + // which discipline events are actually acted upon becomes irregular and can + // become drawn out (the time between actionable event can go way up). If + // the system receives a strong high quality data point, the proportional + // component of the controller can produce a strong correction which is left + // in place for too long causing overshoot. In addition, the integral + // component of the system currently is an approximation based on the + // assumption of a more or less homogeneous sampling of the error. Its + // unclear what the effect of undermining this assumption would be right + // now. + + // Two ideas which come to mind immediately would be to... + // 1) Keep a history of more data points (32 or so) and ignore data points + // whose RTT is more than a certain number of standard deviations outside + // of the norm. + // 2) Eliminate the PID controller portion of this system entirely. + // Instead, move to a system which uses a very wide filter (128 data + // points or more) with a sum-of-least-squares line fitting approach to + // tracking the long term drift. This would take the place of the I + // component in the current PID controller. Also use a much more narrow + // outlier-rejector filter (as described in #1) to drive a short term + // correction factor similar to the P component of the PID controller. + assert(filter_wr_ < kFilterSize); + filter_data_[filter_wr_].local_time = local_time; + filter_data_[filter_wr_].observed_common_time = observed_common; + filter_data_[filter_wr_].nominal_common_time = nominal_common_time; + filter_data_[filter_wr_].rtt = rtt; + filter_data_[filter_wr_].point_used = false; + uint32_t current_point = filter_wr_; + filter_wr_ = (filter_wr_ + 1) % kFilterSize; + if (!filter_wr_) + filter_full_ = true; + + uint32_t scan_end = filter_full_ ? kFilterSize : filter_wr_; + uint32_t min_rtt = findMinRTTNdx(filter_data_, scan_end); + // We only use packets with low RTTs for control. If the packet RTT + // is less than the panic threshold, we can probably eat the jitter with the + // control loop. Otherwise, take the packet only if it better than all + // of the packets we have in the history. That way we try to track + // something, even if it is noisy. + if (current_point == min_rtt || rtt < control_thresh_) { + delta_f = delta = nominal_common_time - observed_common; + + // Compute the error then clamp to the panic threshold. If we ever + // exceed this amt of error, its time to panic and reset the system. + // Given that the error in the measurement of the error could be as + // high as the RTT of the data point, we don't actually panic until + // the implied error (delta) is greater than the absolute panic + // threashold plus the RTT. IOW - we don't panic until we are + // absoluely sure that our best case sync is worse than the absolute + // panic threshold. + int64_t effective_panic_thresh = panic_thresh_ + rtt; + if ((delta > effective_panic_thresh) || + (delta < -effective_panic_thresh)) { + // PANIC!!! + reset_l(false, true); + return false; + } + + } else { + // We do not have a good packet to look at, but we also do not want to + // free-run the clock at some crazy slew rate. So we guess the + // trajectory of the clock based on the last controller output and the + // estimated bias of our clock against the master. + // The net effect of this is that CO == CObias after some extended + // period of no feedback. + delta_f = last_delta_f_ - dT*(CO - CObias); + delta = delta_f; + } + + // Velocity form PI control equation. + dCO = Kc * (1.0f + dT/Ti) * delta_f - Kc * last_delta_f_; + CO += dCO * Tf; // Filter CO by applying gain <1 here. + + // Save error terms for later. + last_delta_f_ = delta_f; + last_delta_ = delta; + + // Clamp CO to +/- 100ppm. + if (CO < COmin) + CO = COmin; + else if (CO > COmax) + CO = COmax; + + // Update the controller bias. + CObias = bias_Alpha * CO + (1.0f - bias_Alpha) * lastCObias; + lastCObias = CObias; + + // Convert PPM to 16-bit int range. Add some guard band (-0.01) so we + // don't get fp weirdness. + correction_cur = CO * 327.66; + + // If there was a change in the amt of correction to use, update the + // system. + if (correction_cur_ != correction_cur) { + correction_cur_ = correction_cur; + applySlew(); + } + + LOG_TS("clock_loop %lld %f %f %f %d\n", raw_delta, delta_f, CO, CObias, correction_cur); + +#ifdef TIME_SERVICE_DEBUG + diag_thread_->pushDisciplineEvent( + local_time, + observed_common, + nominal_common_time, + correction_cur, + rtt); +#endif + + return true; +} + +int32_t ClockRecoveryLoop::getLastErrorEstimate() { + Mutex::Autolock lock(&lock_); + + if (last_delta_valid_) + return last_delta_; + else + return ICommonClock::kErrorEstimateUnknown; +} + +void ClockRecoveryLoop::reset_l(bool position, bool frequency) { + assert(NULL != common_clock_); + + if (position) { + common_clock_->resetBasis(); + startup_filter_wr_ = 0; + } + + if (frequency) { + last_delta_valid_ = false; + last_delta_ = 0; + last_delta_f_ = 0.0; + correction_cur_ = 0x0; + CO = 0.0f; + lastCObias = CObias = 0.0f; + applySlew(); + } + + filter_wr_ = 0; + filter_full_ = false; +} + +void ClockRecoveryLoop::applySlew() { + if (local_clock_can_slew_) { + local_clock_->setLocalSlew(correction_cur_); + } else { + // The SW clock recovery implemented by the common clock class expects + // values expressed in PPM. CO is in ppm. + common_clock_->setSlew(local_clock_->getLocalTime(), CO); + } +} + +} // namespace android diff --git a/services/common_time/clock_recovery.h b/services/common_time/clock_recovery.h new file mode 100644 index 000000000000..b7362be33b14 --- /dev/null +++ b/services/common_time/clock_recovery.h @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __CLOCK_RECOVERY_H__ +#define __CLOCK_RECOVERY_H__ + +#include <stdint.h> +#include <common_time/ICommonClock.h> +#include <utils/LinearTransform.h> +#include <utils/threads.h> + +#ifdef TIME_SERVICE_DEBUG +#include "diag_thread.h" +#endif + +namespace android { + +class CommonClock; +class LocalClock; + +class ClockRecoveryLoop { + public: + ClockRecoveryLoop(LocalClock* local_clock, CommonClock* common_clock); + ~ClockRecoveryLoop(); + + void reset(bool position, bool frequency); + bool pushDisciplineEvent(int64_t local_time, + int64_t nominal_common_time, + int64_t data_point_rtt); + int32_t getLastErrorEstimate(); + + private: + + // Tuned using the "Good Gain" method. + // See: + // http://techteach.no/publications/books/dynamics_and_control/tuning_pid_controller.pdf + + // Controller period (1Hz for now). + static const float dT; + + // Controller gain, positive and unitless. Larger values converge faster, + // but can cause instability. + static const float Kc; + + // Integral reset time. Smaller values cause loop to track faster, but can + // also cause instability. + static const float Ti; + + // Controller output filter time constant. Range (0-1). Smaller values make + // output smoother, but slow convergence. + static const float Tf; + + // Low-pass filter for bias tracker. + static const float bias_Fc; // HZ + static const float bias_RC; // Computed in constructor. + static const float bias_Alpha; // Computed inconstructor. + + // The maximum allowed error (as indicated by a pushDisciplineEvent) before + // we panic. + static const int64_t panic_thresh_; + + // The maximum allowed error rtt time for packets to be used for control + // feedback, unless the packet is the best in recent memory. + static const int64_t control_thresh_; + + typedef struct { + int64_t local_time; + int64_t observed_common_time; + int64_t nominal_common_time; + int64_t rtt; + bool point_used; + } DisciplineDataPoint; + + static uint32_t findMinRTTNdx(DisciplineDataPoint* data, uint32_t count); + + void reset_l(bool position, bool frequency); + void applySlew(); + + // The local clock HW abstraction we use as the basis for common time. + LocalClock* local_clock_; + bool local_clock_can_slew_; + + // The common clock we end up controlling along with the lock used to + // serialize operations. + CommonClock* common_clock_; + Mutex lock_; + + // parameters maintained while running and reset during a reset + // of the frequency correction. + bool last_delta_valid_; + int32_t last_delta_; + float last_delta_f_; + int32_t integrated_error_; + int32_t correction_cur_; + + // Contoller Output. + float CO; + + // Bias tracking for trajectory estimation. + float CObias; + float lastCObias; + + // Controller output bounds. The controller will not try to + // slew faster that +/-100ppm offset from center per interation. + static const float COmin; + static const float COmax; + + // State kept for filtering the discipline data. + static const uint32_t kFilterSize = 16; + DisciplineDataPoint filter_data_[kFilterSize]; + uint32_t filter_wr_; + bool filter_full_; + + static const uint32_t kStartupFilterSize = 4; + DisciplineDataPoint startup_filter_data_[kStartupFilterSize]; + uint32_t startup_filter_wr_; + +#ifdef TIME_SERVICE_DEBUG + sp<DiagThread> diag_thread_; +#endif +}; + +} // namespace android + +#endif // __CLOCK_RECOVERY_H__ diff --git a/services/common_time/common_clock.cpp b/services/common_time/common_clock.cpp new file mode 100644 index 000000000000..c9eb3884440d --- /dev/null +++ b/services/common_time/common_clock.cpp @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define __STDC_LIMIT_MACROS + +#define LOG_TAG "common_time" +#include <utils/Log.h> + +#include <stdint.h> + +#include <utils/Errors.h> +#include <utils/LinearTransform.h> + +#include "common_clock.h" + +namespace android { + +CommonClock::CommonClock() { + cur_slew_ = 0; + cur_trans_valid_ = false; + + cur_trans_.a_zero = 0; + cur_trans_.b_zero = 0; + cur_trans_.a_to_b_numer = local_to_common_freq_numer_ = 1; + cur_trans_.a_to_b_denom = local_to_common_freq_denom_ = 1; + duration_trans_ = cur_trans_; +} + +bool CommonClock::init(uint64_t local_freq) { + Mutex::Autolock lock(&lock_); + + if (!local_freq) + return false; + + uint64_t numer = kCommonFreq; + uint64_t denom = local_freq; + + LinearTransform::reduce(&numer, &denom); + if ((numer > UINT32_MAX) || (denom > UINT32_MAX)) { + ALOGE("Overflow in CommonClock::init while trying to reduce %lld/%lld", + kCommonFreq, local_freq); + return false; + } + + cur_trans_.a_to_b_numer = local_to_common_freq_numer_ = + static_cast<uint32_t>(numer); + cur_trans_.a_to_b_denom = local_to_common_freq_denom_ = + static_cast<uint32_t>(denom); + duration_trans_ = cur_trans_; + + return true; +} + +status_t CommonClock::localToCommon(int64_t local, int64_t *common_out) const { + Mutex::Autolock lock(&lock_); + + if (!cur_trans_valid_) + return INVALID_OPERATION; + + if (!cur_trans_.doForwardTransform(local, common_out)) + return INVALID_OPERATION; + + return OK; +} + +status_t CommonClock::commonToLocal(int64_t common, int64_t *local_out) const { + Mutex::Autolock lock(&lock_); + + if (!cur_trans_valid_) + return INVALID_OPERATION; + + if (!cur_trans_.doReverseTransform(common, local_out)) + return INVALID_OPERATION; + + return OK; +} + +int64_t CommonClock::localDurationToCommonDuration(int64_t localDur) const { + int64_t ret; + duration_trans_.doForwardTransform(localDur, &ret); + return ret; +} + +void CommonClock::setBasis(int64_t local, int64_t common) { + Mutex::Autolock lock(&lock_); + + cur_trans_.a_zero = local; + cur_trans_.b_zero = common; + cur_trans_valid_ = true; +} + +void CommonClock::resetBasis() { + Mutex::Autolock lock(&lock_); + + cur_trans_.a_zero = 0; + cur_trans_.b_zero = 0; + cur_trans_valid_ = false; +} + +status_t CommonClock::setSlew(int64_t change_time, int32_t ppm) { + Mutex::Autolock lock(&lock_); + + int64_t new_local_basis; + int64_t new_common_basis; + + if (cur_trans_valid_) { + new_local_basis = change_time; + if (!cur_trans_.doForwardTransform(change_time, &new_common_basis)) { + ALOGE("Overflow when attempting to set slew rate to %d", ppm); + return INVALID_OPERATION; + } + } else { + new_local_basis = 0; + new_common_basis = 0; + } + + cur_slew_ = ppm; + uint32_t n1 = local_to_common_freq_numer_; + uint32_t n2 = 1000000 + cur_slew_; + + uint32_t d1 = local_to_common_freq_denom_; + uint32_t d2 = 1000000; + + // n1/d1 has already been reduced, no need to do so here. + LinearTransform::reduce(&n1, &d2); + LinearTransform::reduce(&n2, &d1); + LinearTransform::reduce(&n2, &d2); + + cur_trans_.a_zero = new_local_basis; + cur_trans_.b_zero = new_common_basis; + cur_trans_.a_to_b_numer = n1 * n2; + cur_trans_.a_to_b_denom = d1 * d2; + + return OK; +} + +} // namespace android diff --git a/services/common_time/common_clock.h b/services/common_time/common_clock.h new file mode 100644 index 000000000000..b786fdceba5f --- /dev/null +++ b/services/common_time/common_clock.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __COMMON_CLOCK_H__ +#define __COMMON_CLOCK_H__ + +#include <stdint.h> + +#include <utils/Errors.h> +#include <utils/LinearTransform.h> +#include <utils/threads.h> + +namespace android { + +class CommonClock { + public: + CommonClock(); + + bool init(uint64_t local_freq); + + status_t localToCommon(int64_t local, int64_t *common_out) const; + status_t commonToLocal(int64_t common, int64_t *local_out) const; + int64_t localDurationToCommonDuration(int64_t localDur) const; + uint64_t getCommonFreq() const { return kCommonFreq; } + bool isValid() const { return cur_trans_valid_; } + status_t setSlew(int64_t change_time, int32_t ppm); + void setBasis(int64_t local, int64_t common); + void resetBasis(); + private: + mutable Mutex lock_; + + int32_t cur_slew_; + uint32_t local_to_common_freq_numer_; + uint32_t local_to_common_freq_denom_; + + LinearTransform duration_trans_; + LinearTransform cur_trans_; + bool cur_trans_valid_; + + static const uint64_t kCommonFreq = 1000000ull; +}; + +} // namespace android +#endif // __COMMON_CLOCK_H__ diff --git a/services/common_time/common_clock_service.cpp b/services/common_time/common_clock_service.cpp new file mode 100644 index 000000000000..9ca6f3523084 --- /dev/null +++ b/services/common_time/common_clock_service.cpp @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <common_time/local_clock.h> +#include <utils/String8.h> + +#include "common_clock_service.h" +#include "common_clock.h" +#include "common_time_server.h" + +namespace android { + +sp<CommonClockService> CommonClockService::instantiate( + CommonTimeServer& timeServer) { + sp<CommonClockService> tcc = new CommonClockService(timeServer); + if (tcc == NULL) + return NULL; + + defaultServiceManager()->addService(ICommonClock::kServiceName, tcc); + return tcc; +} + +status_t CommonClockService::dump(int fd, const Vector<String16>& args) { + Mutex::Autolock lock(mRegistrationLock); + return mTimeServer.dumpClockInterface(fd, args, mListeners.size()); +} + +status_t CommonClockService::isCommonTimeValid(bool* valid, + uint32_t* timelineID) { + return mTimeServer.isCommonTimeValid(valid, timelineID); +} + +status_t CommonClockService::commonTimeToLocalTime(int64_t commonTime, + int64_t* localTime) { + return mTimeServer.getCommonClock().commonToLocal(commonTime, localTime); +} + +status_t CommonClockService::localTimeToCommonTime(int64_t localTime, + int64_t* commonTime) { + return mTimeServer.getCommonClock().localToCommon(localTime, commonTime); +} + +status_t CommonClockService::getCommonTime(int64_t* commonTime) { + return localTimeToCommonTime(mTimeServer.getLocalClock().getLocalTime(), commonTime); +} + +status_t CommonClockService::getCommonFreq(uint64_t* freq) { + *freq = mTimeServer.getCommonClock().getCommonFreq(); + return OK; +} + +status_t CommonClockService::getLocalTime(int64_t* localTime) { + *localTime = mTimeServer.getLocalClock().getLocalTime(); + return OK; +} + +status_t CommonClockService::getLocalFreq(uint64_t* freq) { + *freq = mTimeServer.getLocalClock().getLocalFreq(); + return OK; +} + +status_t CommonClockService::getEstimatedError(int32_t* estimate) { + *estimate = mTimeServer.getEstimatedError(); + return OK; +} + +status_t CommonClockService::getTimelineID(uint64_t* id) { + *id = mTimeServer.getTimelineID(); + return OK; +} + +status_t CommonClockService::getState(State* state) { + *state = mTimeServer.getState(); + return OK; +} + +status_t CommonClockService::getMasterAddr(struct sockaddr_storage* addr) { + return mTimeServer.getMasterAddr(addr); +} + +status_t CommonClockService::registerListener( + const sp<ICommonClockListener>& listener) { + Mutex::Autolock lock(mRegistrationLock); + + { // scoping for autolock pattern + Mutex::Autolock lock(mCallbackLock); + // check whether this is a duplicate + for (size_t i = 0; i < mListeners.size(); i++) { + if (mListeners[i]->asBinder() == listener->asBinder()) + return ALREADY_EXISTS; + } + } + + mListeners.add(listener); + mTimeServer.reevaluateAutoDisableState(0 != mListeners.size()); + return listener->asBinder()->linkToDeath(this); +} + +status_t CommonClockService::unregisterListener( + const sp<ICommonClockListener>& listener) { + Mutex::Autolock lock(mRegistrationLock); + status_t ret_val = NAME_NOT_FOUND; + + { // scoping for autolock pattern + Mutex::Autolock lock(mCallbackLock); + for (size_t i = 0; i < mListeners.size(); i++) { + if (mListeners[i]->asBinder() == listener->asBinder()) { + mListeners[i]->asBinder()->unlinkToDeath(this); + mListeners.removeAt(i); + ret_val = OK; + break; + } + } + } + + mTimeServer.reevaluateAutoDisableState(0 != mListeners.size()); + return ret_val; +} + +void CommonClockService::binderDied(const wp<IBinder>& who) { + Mutex::Autolock lock(mRegistrationLock); + + { // scoping for autolock pattern + Mutex::Autolock lock(mCallbackLock); + for (size_t i = 0; i < mListeners.size(); i++) { + if (mListeners[i]->asBinder() == who) { + mListeners.removeAt(i); + break; + } + } + } + + mTimeServer.reevaluateAutoDisableState(0 != mListeners.size()); +} + +void CommonClockService::notifyOnTimelineChanged(uint64_t timelineID) { + Mutex::Autolock lock(mCallbackLock); + + for (size_t i = 0; i < mListeners.size(); i++) { + mListeners[i]->onTimelineChanged(timelineID); + } +} + +}; // namespace android diff --git a/services/common_time/common_clock_service.h b/services/common_time/common_clock_service.h new file mode 100644 index 000000000000..a65e398d276f --- /dev/null +++ b/services/common_time/common_clock_service.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <common_time/ICommonClock.h> + +#ifndef ANDROID_COMMON_CLOCK_SERVICE_H +#define ANDROID_COMMON_CLOCK_SERVICE_H + +namespace android { + +class CommonTimeServer; + +class CommonClockService : public BnCommonClock, + public android::IBinder::DeathRecipient { + public: + static sp<CommonClockService> instantiate(CommonTimeServer& timeServer); + + virtual status_t dump(int fd, const Vector<String16>& args); + + virtual status_t isCommonTimeValid(bool* valid, uint32_t *timelineID); + virtual status_t commonTimeToLocalTime(int64_t common_time, + int64_t* local_time); + virtual status_t localTimeToCommonTime(int64_t local_time, + int64_t* common_time); + virtual status_t getCommonTime(int64_t* common_time); + virtual status_t getCommonFreq(uint64_t* freq); + virtual status_t getLocalTime(int64_t* local_time); + virtual status_t getLocalFreq(uint64_t* freq); + virtual status_t getEstimatedError(int32_t* estimate); + virtual status_t getTimelineID(uint64_t* id); + virtual status_t getState(ICommonClock::State* state); + virtual status_t getMasterAddr(struct sockaddr_storage* addr); + + virtual status_t registerListener( + const sp<ICommonClockListener>& listener); + virtual status_t unregisterListener( + const sp<ICommonClockListener>& listener); + + void notifyOnTimelineChanged(uint64_t timelineID); + + private: + CommonClockService(CommonTimeServer& timeServer) + : mTimeServer(timeServer) { }; + + virtual void binderDied(const wp<IBinder>& who); + + CommonTimeServer& mTimeServer; + + // locks used to synchronize access to the list of registered listeners. + // The callback lock is held whenever the list is used to perform callbacks + // or while the list is being modified. The registration lock used to + // serialize access across registerListener, unregisterListener, and + // binderDied. + // + // The reason for two locks is that registerListener, unregisterListener, + // and binderDied each call into the core service and obtain the core + // service thread lock when they call reevaluateAutoDisableState. The core + // service thread obtains the main thread lock whenever its thread is + // running, and sometimes needs to call notifyOnTimelineChanged which then + // obtains the callback lock. If callers of registration functions were + // holding the callback lock when they called into the core service, we + // would have a classic A/B, B/A ordering deadlock. To avoid this, the + // registration functions hold the registration lock for the duration of + // their call, but hold the callback lock only while they mutate the list. + // This way, the list's size cannot change (because of the registration + // lock) during the call into reevaluateAutoDisableState, but the core work + // thread can still safely call notifyOnTimelineChanged while holding the + // main thread lock. + Mutex mCallbackLock; + Mutex mRegistrationLock; + + Vector<sp<ICommonClockListener> > mListeners; +}; + +}; // namespace android + +#endif // ANDROID_COMMON_CLOCK_SERVICE_H diff --git a/services/common_time/common_time_config_service.cpp b/services/common_time/common_time_config_service.cpp new file mode 100644 index 000000000000..958561818423 --- /dev/null +++ b/services/common_time/common_time_config_service.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <utils/String8.h> + +#include "common_time_config_service.h" +#include "common_time_server.h" + +namespace android { + +sp<CommonTimeConfigService> CommonTimeConfigService::instantiate( + CommonTimeServer& timeServer) { + sp<CommonTimeConfigService> ctcs = new CommonTimeConfigService(timeServer); + if (ctcs == NULL) + return NULL; + + defaultServiceManager()->addService(ICommonTimeConfig::kServiceName, ctcs); + return ctcs; +} + +status_t CommonTimeConfigService::dump(int fd, const Vector<String16>& args) { + return mTimeServer.dumpConfigInterface(fd, args); +} + +status_t CommonTimeConfigService::getMasterElectionPriority(uint8_t *priority) { + return mTimeServer.getMasterElectionPriority(priority); +} + +status_t CommonTimeConfigService::setMasterElectionPriority(uint8_t priority) { + return mTimeServer.setMasterElectionPriority(priority); +} + +status_t CommonTimeConfigService::getMasterElectionEndpoint( + struct sockaddr_storage *addr) { + return mTimeServer.getMasterElectionEndpoint(addr); +} + +status_t CommonTimeConfigService::setMasterElectionEndpoint( + const struct sockaddr_storage *addr) { + return mTimeServer.setMasterElectionEndpoint(addr); +} + +status_t CommonTimeConfigService::getMasterElectionGroupId(uint64_t *id) { + return mTimeServer.getMasterElectionGroupId(id); +} + +status_t CommonTimeConfigService::setMasterElectionGroupId(uint64_t id) { + return mTimeServer.setMasterElectionGroupId(id); +} + +status_t CommonTimeConfigService::getInterfaceBinding(String16& ifaceName) { + String8 tmp; + status_t ret = mTimeServer.getInterfaceBinding(tmp); + ifaceName = String16(tmp); + return ret; +} + +status_t CommonTimeConfigService::setInterfaceBinding(const String16& ifaceName) { + String8 tmp(ifaceName); + return mTimeServer.setInterfaceBinding(tmp); +} + +status_t CommonTimeConfigService::getMasterAnnounceInterval(int *interval) { + return mTimeServer.getMasterAnnounceInterval(interval); +} + +status_t CommonTimeConfigService::setMasterAnnounceInterval(int interval) { + return mTimeServer.setMasterAnnounceInterval(interval); +} + +status_t CommonTimeConfigService::getClientSyncInterval(int *interval) { + return mTimeServer.getClientSyncInterval(interval); +} + +status_t CommonTimeConfigService::setClientSyncInterval(int interval) { + return mTimeServer.setClientSyncInterval(interval); +} + +status_t CommonTimeConfigService::getPanicThreshold(int *threshold) { + return mTimeServer.getPanicThreshold(threshold); +} + +status_t CommonTimeConfigService::setPanicThreshold(int threshold) { + return mTimeServer.setPanicThreshold(threshold); +} + +status_t CommonTimeConfigService::getAutoDisable(bool *autoDisable) { + return mTimeServer.getAutoDisable(autoDisable); +} + +status_t CommonTimeConfigService::setAutoDisable(bool autoDisable) { + return mTimeServer.setAutoDisable(autoDisable); +} + +status_t CommonTimeConfigService::forceNetworklessMasterMode() { + return mTimeServer.forceNetworklessMasterMode(); +} + +}; // namespace android diff --git a/services/common_time/common_time_config_service.h b/services/common_time/common_time_config_service.h new file mode 100644 index 000000000000..8283c24e0f4c --- /dev/null +++ b/services/common_time/common_time_config_service.h @@ -0,0 +1,59 @@ +/* * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <common_time/ICommonTimeConfig.h> + +#ifndef ANDROID_COMMON_TIME_CONFIG_SERVICE_H +#define ANDROID_COMMON_TIME_CONFIG_SERVICE_H + +namespace android { + +class String16; +class CommonTimeServer; + +class CommonTimeConfigService : public BnCommonTimeConfig { + public: + static sp<CommonTimeConfigService> instantiate(CommonTimeServer& timeServer); + + virtual status_t dump(int fd, const Vector<String16>& args); + + virtual status_t getMasterElectionPriority(uint8_t *priority); + virtual status_t setMasterElectionPriority(uint8_t priority); + virtual status_t getMasterElectionEndpoint(struct sockaddr_storage *addr); + virtual status_t setMasterElectionEndpoint(const struct sockaddr_storage *addr); + virtual status_t getMasterElectionGroupId(uint64_t *id); + virtual status_t setMasterElectionGroupId(uint64_t id); + virtual status_t getInterfaceBinding(String16& ifaceName); + virtual status_t setInterfaceBinding(const String16& ifaceName); + virtual status_t getMasterAnnounceInterval(int *interval); + virtual status_t setMasterAnnounceInterval(int interval); + virtual status_t getClientSyncInterval(int *interval); + virtual status_t setClientSyncInterval(int interval); + virtual status_t getPanicThreshold(int *threshold); + virtual status_t setPanicThreshold(int threshold); + virtual status_t getAutoDisable(bool *autoDisable); + virtual status_t setAutoDisable(bool autoDisable); + virtual status_t forceNetworklessMasterMode(); + + private: + CommonTimeConfigService(CommonTimeServer& timeServer) + : mTimeServer(timeServer) { } + CommonTimeServer& mTimeServer; + +}; + +}; // namespace android + +#endif // ANDROID_COMMON_TIME_CONFIG_SERVICE_H diff --git a/services/common_time/common_time_server.cpp b/services/common_time/common_time_server.cpp new file mode 100644 index 000000000000..ef7fa1682575 --- /dev/null +++ b/services/common_time/common_time_server.cpp @@ -0,0 +1,1380 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * A service that exchanges time synchronization information between + * a master that defines a timeline and clients that follow the timeline. + */ + +#define LOG_TAG "common_time" +#include <utils/Log.h> + +#include <arpa/inet.h> +#include <assert.h> +#include <fcntl.h> +#include <linux/if_ether.h> +#include <net/if.h> +#include <net/if_arp.h> +#include <netinet/ip.h> +#include <poll.h> +#include <stdio.h> +#include <sys/eventfd.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/socket.h> + +#include <common_time/local_clock.h> +#include <binder/IPCThreadState.h> +#include <binder/ProcessState.h> +#include <utils/Timers.h> + +#include "common_clock_service.h" +#include "common_time_config_service.h" +#include "common_time_server.h" +#include "common_time_server_packets.h" +#include "clock_recovery.h" +#include "common_clock.h" + +#define MAX_INT ((int)0x7FFFFFFF) + +namespace android { + +const char* CommonTimeServer::kDefaultMasterElectionAddr = "239.195.128.88"; +const uint16_t CommonTimeServer::kDefaultMasterElectionPort = 8887; +const uint64_t CommonTimeServer::kDefaultSyncGroupID = 0; +const uint8_t CommonTimeServer::kDefaultMasterPriority = 1; +const uint32_t CommonTimeServer::kDefaultMasterAnnounceIntervalMs = 10000; +const uint32_t CommonTimeServer::kDefaultSyncRequestIntervalMs = 1000; +const uint32_t CommonTimeServer::kDefaultPanicThresholdUsec = 50000; +const bool CommonTimeServer::kDefaultAutoDisable = true; +const int CommonTimeServer::kSetupRetryTimeoutMs = 30000; +const int64_t CommonTimeServer::kNoGoodDataPanicThresholdUsec = 600000000ll; +const uint32_t CommonTimeServer::kRTTDiscardPanicThreshMultiplier = 5; + +// timeout value representing an infinite timeout +const int CommonTimeServer::kInfiniteTimeout = -1; + +/*** Initial state constants ***/ + +// number of WhoIsMaster attempts sent before giving up +const int CommonTimeServer::kInitial_NumWhoIsMasterRetries = 6; + +// timeout used when waiting for a response to a WhoIsMaster request +const int CommonTimeServer::kInitial_WhoIsMasterTimeoutMs = 500; + +/*** Client state constants ***/ + +// number of sync requests that can fail before a client assumes its master +// is dead +const int CommonTimeServer::kClient_NumSyncRequestRetries = 5; + +/*** Master state constants ***/ + +/*** Ronin state constants ***/ + +// number of WhoIsMaster attempts sent before declaring ourselves master +const int CommonTimeServer::kRonin_NumWhoIsMasterRetries = 4; + +// timeout used when waiting for a response to a WhoIsMaster request +const int CommonTimeServer::kRonin_WhoIsMasterTimeoutMs = 500; + +/*** WaitForElection state constants ***/ + +// how long do we wait for an announcement from a master before +// trying another election? +const int CommonTimeServer::kWaitForElection_TimeoutMs = 5000; + +CommonTimeServer::CommonTimeServer() + : Thread(false) + , mState(ICommonClock::STATE_INITIAL) + , mClockRecovery(&mLocalClock, &mCommonClock) + , mSocket(-1) + , mLastPacketRxLocalTime(0) + , mTimelineID(ICommonClock::kInvalidTimelineID) + , mClockSynced(false) + , mCommonClockHasClients(false) + , mInitial_WhoIsMasterRequestTimeouts(0) + , mClient_MasterDeviceID(0) + , mClient_MasterDevicePriority(0) + , mRonin_WhoIsMasterRequestTimeouts(0) { + // zero out sync stats + resetSyncStats(); + + // Setup the master election endpoint to use the default. + struct sockaddr_in* meep = + reinterpret_cast<struct sockaddr_in*>(&mMasterElectionEP); + memset(&mMasterElectionEP, 0, sizeof(mMasterElectionEP)); + inet_aton(kDefaultMasterElectionAddr, &meep->sin_addr); + meep->sin_family = AF_INET; + meep->sin_port = htons(kDefaultMasterElectionPort); + + // Zero out the master endpoint. + memset(&mMasterEP, 0, sizeof(mMasterEP)); + mMasterEPValid = false; + mBindIfaceValid = false; + setForceLowPriority(false); + + // Set all remaining configuration parameters to their defaults. + mDeviceID = 0; + mSyncGroupID = kDefaultSyncGroupID; + mMasterPriority = kDefaultMasterPriority; + mMasterAnnounceIntervalMs = kDefaultMasterAnnounceIntervalMs; + mSyncRequestIntervalMs = kDefaultSyncRequestIntervalMs; + mPanicThresholdUsec = kDefaultPanicThresholdUsec; + mAutoDisable = kDefaultAutoDisable; + + // Create the eventfd we will use to signal our thread to wake up when + // needed. + mWakeupThreadFD = eventfd(0, EFD_NONBLOCK); + + // seed the random number generator (used to generated timeline IDs) + srand48(static_cast<unsigned int>(systemTime())); +} + +CommonTimeServer::~CommonTimeServer() { + shutdownThread(); + + // No need to grab the lock here. We are in the destructor; if the the user + // has a thread in any of the APIs while the destructor is being called, + // there is a threading problem a the application level we cannot reasonably + // do anything about. + cleanupSocket_l(); + + if (mWakeupThreadFD >= 0) { + close(mWakeupThreadFD); + mWakeupThreadFD = -1; + } +} + +bool CommonTimeServer::startServices() { + // start the ICommonClock service + mICommonClock = CommonClockService::instantiate(*this); + if (mICommonClock == NULL) + return false; + + // start the ICommonTimeConfig service + mICommonTimeConfig = CommonTimeConfigService::instantiate(*this); + if (mICommonTimeConfig == NULL) + return false; + + return true; +} + +bool CommonTimeServer::threadLoop() { + // Register our service interfaces. + if (!startServices()) + return false; + + // Hold the lock while we are in the main thread loop. It will release the + // lock when it blocks, and hold the lock at all other times. + mLock.lock(); + runStateMachine_l(); + mLock.unlock(); + + IPCThreadState::self()->stopProcess(); + return false; +} + +bool CommonTimeServer::runStateMachine_l() { + if (!mLocalClock.initCheck()) + return false; + + if (!mCommonClock.init(mLocalClock.getLocalFreq())) + return false; + + // Enter the initial state. + becomeInitial("startup"); + + // run the state machine + while (!exitPending()) { + struct pollfd pfds[2]; + int rc; + int eventCnt = 0; + int64_t wakeupTime; + + // We are always interested in our wakeup FD. + pfds[eventCnt].fd = mWakeupThreadFD; + pfds[eventCnt].events = POLLIN; + pfds[eventCnt].revents = 0; + eventCnt++; + + // If we have a valid socket, then we are interested in what it has to + // say as well. + if (mSocket >= 0) { + pfds[eventCnt].fd = mSocket; + pfds[eventCnt].events = POLLIN; + pfds[eventCnt].revents = 0; + eventCnt++; + } + + // Note, we were holding mLock when this function was called. We + // release it only while we are blocking and hold it at all other times. + mLock.unlock(); + rc = poll(pfds, eventCnt, mCurTimeout.msecTillTimeout()); + wakeupTime = mLocalClock.getLocalTime(); + mLock.lock(); + + // Is it time to shutdown? If so, don't hesitate... just do it. + if (exitPending()) + break; + + // Did the poll fail? This should never happen and is fatal if it does. + if (rc < 0) { + ALOGE("%s:%d poll failed", __PRETTY_FUNCTION__, __LINE__); + return false; + } + + if (rc == 0) + mCurTimeout.setTimeout(kInfiniteTimeout); + + // Were we woken up on purpose? If so, clear the eventfd with a read. + if (pfds[0].revents) + clearPendingWakeupEvents_l(); + + // Is out bind address dirty? If so, clean up our socket (if any). + // Alternatively, do we have an active socket but should be auto + // disabled? If so, release the socket and enter the proper sync state. + bool droppedSocket = false; + if (mBindIfaceDirty || ((mSocket >= 0) && shouldAutoDisable())) { + cleanupSocket_l(); + mBindIfaceDirty = false; + droppedSocket = true; + } + + // Do we not have a socket but should have one? If so, try to set one + // up. + if ((mSocket < 0) && mBindIfaceValid && !shouldAutoDisable()) { + if (setupSocket_l()) { + // Success! We are now joining a new network (either coming + // from no network, or coming from a potentially different + // network). Force our priority to be lower so that we defer to + // any other masters which may already be on the network we are + // joining. Later, when we enter either the client or the + // master state, we will clear this flag and go back to our + // normal election priority. + setForceLowPriority(true); + switch (mState) { + // If we were in initial (whether we had a immediately + // before this network or not) we want to simply reset the + // system and start again. Forcing a transition from + // INITIAL to INITIAL should do the job. + case CommonClockService::STATE_INITIAL: + becomeInitial("bound interface"); + break; + + // If we were in the master state, then either we were the + // master in a no-network situation, or we were the master + // of a different network and have moved to a new interface. + // In either case, immediately send out a master + // announcement at low priority. + case CommonClockService::STATE_MASTER: + sendMasterAnnouncement(); + break; + + // If we were in any other state (CLIENT, RONIN, or + // WAIT_FOR_ELECTION) then we must be moving from one + // network to another. We have lost our old master; + // transition to RONIN in an attempt to find a new master. + // If there are none out there, we will just assume + // responsibility for the timeline we used to be a client + // of. + default: + becomeRonin("bound interface"); + break; + } + } else { + // That's odd... we failed to set up our socket. This could be + // due to some transient network change which will work itself + // out shortly; schedule a retry attempt in the near future. + mCurTimeout.setTimeout(kSetupRetryTimeoutMs); + } + + // One way or the other, we don't have any data to process at this + // point (since we just tried to bulid a new socket). Loop back + // around and wait for the next thing to do. + continue; + } else if (droppedSocket) { + // We just lost our socket, and for whatever reason (either no + // config, or auto disable engaged) we are not supposed to rebuild + // one at this time. We are not going to rebuild our socket until + // something about our config/auto-disabled status changes, so we + // are basically in network-less mode. If we are already in either + // INITIAL or MASTER, just stay there until something changes. If + // we are in any other state (CLIENT, RONIN or WAIT_FOR_ELECTION), + // then transition to either INITIAL or MASTER depending on whether + // or not our timeline is valid. + ALOGI("Entering networkless mode interface is %s, " + "shouldAutoDisable = %s", + mBindIfaceValid ? "valid" : "invalid", + shouldAutoDisable() ? "true" : "false"); + if ((mState != ICommonClock::STATE_INITIAL) && + (mState != ICommonClock::STATE_MASTER)) { + if (mTimelineID == ICommonClock::kInvalidTimelineID) + becomeInitial("network-less mode"); + else + becomeMaster("network-less mode"); + } + + continue; + } + + // Did we wakeup with no signalled events across all of our FDs? If so, + // we must have hit our timeout. + if (rc == 0) { + if (!handleTimeout()) + ALOGE("handleTimeout failed"); + continue; + } + + // Does our socket have data for us (assuming we still have one, we + // may have RXed a packet at the same time as a config change telling us + // to shut our socket down)? If so, process its data. + if ((mSocket >= 0) && (eventCnt > 1) && (pfds[1].revents)) { + mLastPacketRxLocalTime = wakeupTime; + if (!handlePacket()) + ALOGE("handlePacket failed"); + } + } + + cleanupSocket_l(); + return true; +} + +void CommonTimeServer::clearPendingWakeupEvents_l() { + int64_t tmp; + read(mWakeupThreadFD, &tmp, sizeof(tmp)); +} + +void CommonTimeServer::wakeupThread_l() { + int64_t tmp = 1; + write(mWakeupThreadFD, &tmp, sizeof(tmp)); +} + +void CommonTimeServer::cleanupSocket_l() { + if (mSocket >= 0) { + close(mSocket); + mSocket = -1; + } +} + +void CommonTimeServer::shutdownThread() { + // Flag the work thread for shutdown. + this->requestExit(); + + // Signal the thread in case its sleeping. + mLock.lock(); + wakeupThread_l(); + mLock.unlock(); + + // Wait for the thread to exit. + this->join(); +} + +bool CommonTimeServer::setupSocket_l() { + int rc; + bool ret_val = false; + struct sockaddr_in* ipv4_addr = NULL; + char masterElectionEPStr[64]; + const int one = 1; + + // This should never be needed, but if we happened to have an old socket + // lying around, be sure to not leak it before proceeding. + cleanupSocket_l(); + + // If we don't have a valid endpoint to bind to, then how did we get here in + // the first place? Regardless, we know that we are going to fail to bind, + // so don't even try. + if (!mBindIfaceValid) + return false; + + sockaddrToString(mMasterElectionEP, true, masterElectionEPStr, + sizeof(masterElectionEPStr)); + ALOGI("Building socket :: bind = %s master election = %s", + mBindIface.string(), masterElectionEPStr); + + // TODO: add proper support for IPv6. Right now, we block IPv6 addresses at + // the configuration interface level. + if (AF_INET != mMasterElectionEP.ss_family) { + ALOGW("TODO: add proper IPv6 support"); + goto bailout; + } + + // open a UDP socket for the timeline serivce + mSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (mSocket < 0) { + ALOGE("Failed to create socket (errno = %d)", errno); + goto bailout; + } + + // Bind to the selected interface using Linux's spiffy SO_BINDTODEVICE. + struct ifreq ifr; + memset(&ifr, 0, sizeof(ifr)); + snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", mBindIface.string()); + ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = 0; + rc = setsockopt(mSocket, SOL_SOCKET, SO_BINDTODEVICE, + (void *)&ifr, sizeof(ifr)); + if (rc) { + ALOGE("Failed to bind socket at to interface %s (errno = %d)", + ifr.ifr_name, errno); + goto bailout; + } + + // Bind our socket to INADDR_ANY and the master election port. The + // interface binding we made using SO_BINDTODEVICE should limit us to + // traffic only on the interface we are interested in. We need to bind to + // INADDR_ANY and the specific master election port in order to be able to + // receive both unicast traffic and master election multicast traffic with + // just a single socket. + struct sockaddr_in bindAddr; + ipv4_addr = reinterpret_cast<struct sockaddr_in*>(&mMasterElectionEP); + memcpy(&bindAddr, ipv4_addr, sizeof(bindAddr)); + bindAddr.sin_addr.s_addr = INADDR_ANY; + rc = bind(mSocket, + reinterpret_cast<const sockaddr *>(&bindAddr), + sizeof(bindAddr)); + if (rc) { + ALOGE("Failed to bind socket to port %hu (errno = %d)", + ntohs(bindAddr.sin_port), errno); + goto bailout; + } + + if (0xE0000000 == (ntohl(ipv4_addr->sin_addr.s_addr) & 0xF0000000)) { + // If our master election endpoint is a multicast address, be sure to join + // the multicast group. + struct ip_mreq mreq; + mreq.imr_multiaddr = ipv4_addr->sin_addr; + mreq.imr_interface.s_addr = htonl(INADDR_ANY); + rc = setsockopt(mSocket, IPPROTO_IP, IP_ADD_MEMBERSHIP, + &mreq, sizeof(mreq)); + if (rc == -1) { + ALOGE("Failed to join multicast group at %s. (errno = %d)", + masterElectionEPStr, errno); + goto bailout; + } + + // disable loopback of multicast packets + const int zero = 0; + rc = setsockopt(mSocket, IPPROTO_IP, IP_MULTICAST_LOOP, + &zero, sizeof(zero)); + if (rc == -1) { + ALOGE("Failed to disable multicast loopback (errno = %d)", errno); + goto bailout; + } + } else + if (ntohl(ipv4_addr->sin_addr.s_addr) != 0xFFFFFFFF) { + // If the master election address is neither broadcast, nor multicast, + // then we are misconfigured. The config API layer should prevent this + // from ever happening. + goto bailout; + } + + // Set the TTL of sent packets to 1. (Time protocol sync should never leave + // the local subnet) + rc = setsockopt(mSocket, IPPROTO_IP, IP_TTL, &one, sizeof(one)); + if (rc == -1) { + ALOGE("Failed to set TTL to %d (errno = %d)", one, errno); + goto bailout; + } + + // get the device's unique ID + if (!assignDeviceID()) + goto bailout; + + ret_val = true; + +bailout: + if (!ret_val) + cleanupSocket_l(); + return ret_val; +} + +// generate a unique device ID that can be used for arbitration +bool CommonTimeServer::assignDeviceID() { + if (!mBindIfaceValid) + return false; + + struct ifreq ifr; + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_addr.sa_family = AF_INET; + strlcpy(ifr.ifr_name, mBindIface.string(), IFNAMSIZ); + + int rc = ioctl(mSocket, SIOCGIFHWADDR, &ifr); + if (rc) { + ALOGE("%s:%d ioctl failed", __PRETTY_FUNCTION__, __LINE__); + return false; + } + + if (ifr.ifr_addr.sa_family != ARPHRD_ETHER) { + ALOGE("%s:%d got non-Ethernet address", __PRETTY_FUNCTION__, __LINE__); + return false; + } + + mDeviceID = 0; + for (int i = 0; i < ETH_ALEN; i++) { + mDeviceID = (mDeviceID << 8) | ifr.ifr_hwaddr.sa_data[i]; + } + + return true; +} + +// generate a new timeline ID +void CommonTimeServer::assignTimelineID() { + do { + mTimelineID = (static_cast<uint64_t>(lrand48()) << 32) + | static_cast<uint64_t>(lrand48()); + } while (mTimelineID == ICommonClock::kInvalidTimelineID); +} + +// Select a preference between the device IDs of two potential masters. +// Returns true if the first ID wins, or false if the second ID wins. +bool CommonTimeServer::arbitrateMaster( + uint64_t deviceID1, uint8_t devicePrio1, + uint64_t deviceID2, uint8_t devicePrio2) { + return ((devicePrio1 > devicePrio2) || + ((devicePrio1 == devicePrio2) && (deviceID1 > deviceID2))); +} + +bool CommonTimeServer::handlePacket() { + uint8_t buf[256]; + struct sockaddr_storage srcAddr; + socklen_t srcAddrLen = sizeof(srcAddr); + + ssize_t recvBytes = recvfrom( + mSocket, buf, sizeof(buf), 0, + reinterpret_cast<const sockaddr *>(&srcAddr), &srcAddrLen); + + if (recvBytes < 0) { + ALOGE("%s:%d recvfrom failed", __PRETTY_FUNCTION__, __LINE__); + return false; + } + + UniversalTimeServicePacket pkt; + recvBytes = pkt.deserializePacket(buf, recvBytes, mSyncGroupID); + if (recvBytes < 0) + return false; + + bool result; + switch (pkt.packetType) { + case TIME_PACKET_WHO_IS_MASTER_REQUEST: + result = handleWhoIsMasterRequest(&pkt.p.who_is_master_request, + srcAddr); + break; + + case TIME_PACKET_WHO_IS_MASTER_RESPONSE: + result = handleWhoIsMasterResponse(&pkt.p.who_is_master_response, + srcAddr); + break; + + case TIME_PACKET_SYNC_REQUEST: + result = handleSyncRequest(&pkt.p.sync_request, srcAddr); + break; + + case TIME_PACKET_SYNC_RESPONSE: + result = handleSyncResponse(&pkt.p.sync_response, srcAddr); + break; + + case TIME_PACKET_MASTER_ANNOUNCEMENT: + result = handleMasterAnnouncement(&pkt.p.master_announcement, + srcAddr); + break; + + default: { + ALOGD("%s:%d unknown packet type(%d)", + __PRETTY_FUNCTION__, __LINE__, pkt.packetType); + result = false; + } break; + } + + return result; +} + +bool CommonTimeServer::handleTimeout() { + // If we have no socket, then this must be a timeout to retry socket setup. + if (mSocket < 0) + return true; + + switch (mState) { + case ICommonClock::STATE_INITIAL: + return handleTimeoutInitial(); + case ICommonClock::STATE_CLIENT: + return handleTimeoutClient(); + case ICommonClock::STATE_MASTER: + return handleTimeoutMaster(); + case ICommonClock::STATE_RONIN: + return handleTimeoutRonin(); + case ICommonClock::STATE_WAIT_FOR_ELECTION: + return handleTimeoutWaitForElection(); + } + + return false; +} + +bool CommonTimeServer::handleTimeoutInitial() { + if (++mInitial_WhoIsMasterRequestTimeouts == + kInitial_NumWhoIsMasterRetries) { + // none of our attempts to discover a master succeeded, so make + // this device the master + return becomeMaster("initial timeout"); + } else { + // retry the WhoIsMaster request + return sendWhoIsMasterRequest(); + } +} + +bool CommonTimeServer::handleTimeoutClient() { + if (shouldPanicNotGettingGoodData()) + return becomeInitial("timeout panic, no good data"); + + if (mClient_SyncRequestPending) { + mClient_SyncRequestPending = false; + + if (++mClient_SyncRequestTimeouts < kClient_NumSyncRequestRetries) { + // a sync request has timed out, so retry + return sendSyncRequest(); + } else { + // The master has failed to respond to a sync request for too many + // times in a row. Assume the master is dead and start electing + // a new master. + return becomeRonin("master not responding"); + } + } else { + // initiate the next sync request + return sendSyncRequest(); + } +} + +bool CommonTimeServer::handleTimeoutMaster() { + // send another announcement from the master + return sendMasterAnnouncement(); +} + +bool CommonTimeServer::handleTimeoutRonin() { + if (++mRonin_WhoIsMasterRequestTimeouts == kRonin_NumWhoIsMasterRetries) { + // no other master is out there, so we won the election + return becomeMaster("no better masters detected"); + } else { + return sendWhoIsMasterRequest(); + } +} + +bool CommonTimeServer::handleTimeoutWaitForElection() { + return becomeRonin("timeout waiting for election conclusion"); +} + +bool CommonTimeServer::handleWhoIsMasterRequest( + const WhoIsMasterRequestPacket* request, + const sockaddr_storage& srcAddr) { + if (mState == ICommonClock::STATE_MASTER) { + // is this request related to this master's timeline? + if (request->timelineID != ICommonClock::kInvalidTimelineID && + request->timelineID != mTimelineID) + return true; + + WhoIsMasterResponsePacket pkt; + pkt.initHeader(mTimelineID, mSyncGroupID); + pkt.deviceID = mDeviceID; + pkt.devicePriority = effectivePriority(); + + uint8_t buf[256]; + ssize_t bufSz = pkt.serializePacket(buf, sizeof(buf)); + if (bufSz < 0) + return false; + + ssize_t sendBytes = sendto( + mSocket, buf, bufSz, 0, + reinterpret_cast<const sockaddr *>(&srcAddr), + sizeof(srcAddr)); + if (sendBytes == -1) { + ALOGE("%s:%d sendto failed", __PRETTY_FUNCTION__, __LINE__); + return false; + } + } else if (mState == ICommonClock::STATE_RONIN) { + // if we hear a WhoIsMaster request from another device following + // the same timeline and that device wins arbitration, then we will stop + // trying to elect ourselves master and will instead wait for an + // announcement from the election winner + if (request->timelineID != mTimelineID) + return true; + + if (arbitrateMaster(request->senderDeviceID, + request->senderDevicePriority, + mDeviceID, + effectivePriority())) + return becomeWaitForElection("would lose election"); + + return true; + } else if (mState == ICommonClock::STATE_INITIAL) { + // If a group of devices booted simultaneously (e.g. after a power + // outage) and all of them are in the initial state and there is no + // master, then each device may time out and declare itself master at + // the same time. To avoid this, listen for + // WhoIsMaster(InvalidTimeline) requests from peers. If we would lose + // arbitration against that peer, reset our timeout count so that the + // peer has a chance to become master before we time out. + if (request->timelineID == ICommonClock::kInvalidTimelineID && + arbitrateMaster(request->senderDeviceID, + request->senderDevicePriority, + mDeviceID, + effectivePriority())) { + mInitial_WhoIsMasterRequestTimeouts = 0; + } + } + + return true; +} + +bool CommonTimeServer::handleWhoIsMasterResponse( + const WhoIsMasterResponsePacket* response, + const sockaddr_storage& srcAddr) { + if (mState == ICommonClock::STATE_INITIAL || mState == ICommonClock::STATE_RONIN) { + return becomeClient(srcAddr, + response->deviceID, + response->devicePriority, + response->timelineID, + "heard whois response"); + } else if (mState == ICommonClock::STATE_CLIENT) { + // if we get multiple responses because there are multiple devices + // who believe that they are master, then follow the master that + // wins arbitration + if (arbitrateMaster(response->deviceID, + response->devicePriority, + mClient_MasterDeviceID, + mClient_MasterDevicePriority)) { + return becomeClient(srcAddr, + response->deviceID, + response->devicePriority, + response->timelineID, + "heard whois response"); + } + } + + return true; +} + +bool CommonTimeServer::handleSyncRequest(const SyncRequestPacket* request, + const sockaddr_storage& srcAddr) { + SyncResponsePacket pkt; + pkt.initHeader(mTimelineID, mSyncGroupID); + + if ((mState == ICommonClock::STATE_MASTER) && + (mTimelineID == request->timelineID)) { + int64_t rxLocalTime = mLastPacketRxLocalTime; + int64_t rxCommonTime; + + // If we are master on an actual network and have actual clients, then + // we are no longer low priority. + setForceLowPriority(false); + + if (OK != mCommonClock.localToCommon(rxLocalTime, &rxCommonTime)) { + return false; + } + + int64_t txLocalTime = mLocalClock.getLocalTime();; + int64_t txCommonTime; + if (OK != mCommonClock.localToCommon(txLocalTime, &txCommonTime)) { + return false; + } + + pkt.nak = 0; + pkt.clientTxLocalTime = request->clientTxLocalTime; + pkt.masterRxCommonTime = rxCommonTime; + pkt.masterTxCommonTime = txCommonTime; + } else { + pkt.nak = 1; + pkt.clientTxLocalTime = 0; + pkt.masterRxCommonTime = 0; + pkt.masterTxCommonTime = 0; + } + + uint8_t buf[256]; + ssize_t bufSz = pkt.serializePacket(buf, sizeof(buf)); + if (bufSz < 0) + return false; + + ssize_t sendBytes = sendto( + mSocket, &buf, bufSz, 0, + reinterpret_cast<const sockaddr *>(&srcAddr), + sizeof(srcAddr)); + if (sendBytes == -1) { + ALOGE("%s:%d sendto failed", __PRETTY_FUNCTION__, __LINE__); + return false; + } + + return true; +} + +bool CommonTimeServer::handleSyncResponse( + const SyncResponsePacket* response, + const sockaddr_storage& srcAddr) { + if (mState != ICommonClock::STATE_CLIENT) + return true; + + assert(mMasterEPValid); + if (!sockaddrMatch(srcAddr, mMasterEP, true)) { + char srcEP[64], expectedEP[64]; + sockaddrToString(srcAddr, true, srcEP, sizeof(srcEP)); + sockaddrToString(mMasterEP, true, expectedEP, sizeof(expectedEP)); + ALOGI("Dropping sync response from unexpected address." + " Expected %s Got %s", expectedEP, srcEP); + return true; + } + + if (response->nak) { + // if our master is no longer accepting requests, then we need to find + // a new master + return becomeRonin("master NAK'ed"); + } + + mClient_SyncRequestPending = 0; + mClient_SyncRequestTimeouts = 0; + mClient_PacketRTTLog.logRX(response->clientTxLocalTime, + mLastPacketRxLocalTime); + + bool result; + if (!(mClient_SyncRespsRXedFromCurMaster++)) { + // the first request/response exchange between a client and a master + // may take unusually long due to ARP, so discard it. + result = true; + } else { + int64_t clientTxLocalTime = response->clientTxLocalTime; + int64_t clientRxLocalTime = mLastPacketRxLocalTime; + int64_t masterTxCommonTime = response->masterTxCommonTime; + int64_t masterRxCommonTime = response->masterRxCommonTime; + + int64_t rtt = (clientRxLocalTime - clientTxLocalTime); + int64_t avgLocal = (clientTxLocalTime + clientRxLocalTime) >> 1; + int64_t avgCommon = (masterTxCommonTime + masterRxCommonTime) >> 1; + + // if the RTT of the packet is significantly larger than the panic + // threshold, we should simply discard it. Its better to do nothing + // than to take cues from a packet like that. + int rttCommon = mCommonClock.localDurationToCommonDuration(rtt); + if (rttCommon > (static_cast<int64_t>(mPanicThresholdUsec) * + kRTTDiscardPanicThreshMultiplier)) { + ALOGV("Dropping sync response with RTT of %lld uSec", rttCommon); + mClient_ExpiredSyncRespsRXedFromCurMaster++; + if (shouldPanicNotGettingGoodData()) + return becomeInitial("RX panic, no good data"); + } else { + result = mClockRecovery.pushDisciplineEvent(avgLocal, avgCommon, rttCommon); + mClient_LastGoodSyncRX = clientRxLocalTime; + + if (result) { + // indicate to listeners that we've synced to the common timeline + notifyClockSync(); + } else { + ALOGE("Panic! Observed clock sync error is too high to tolerate," + " resetting state machine and starting over."); + notifyClockSyncLoss(); + return becomeInitial("panic"); + } + } + } + + mCurTimeout.setTimeout(mSyncRequestIntervalMs); + return result; +} + +bool CommonTimeServer::handleMasterAnnouncement( + const MasterAnnouncementPacket* packet, + const sockaddr_storage& srcAddr) { + uint64_t newDeviceID = packet->deviceID; + uint8_t newDevicePrio = packet->devicePriority; + uint64_t newTimelineID = packet->timelineID; + + if (mState == ICommonClock::STATE_INITIAL || + mState == ICommonClock::STATE_RONIN || + mState == ICommonClock::STATE_WAIT_FOR_ELECTION) { + // if we aren't currently following a master, then start following + // this new master + return becomeClient(srcAddr, + newDeviceID, + newDevicePrio, + newTimelineID, + "heard master announcement"); + } else if (mState == ICommonClock::STATE_CLIENT) { + // if the new master wins arbitration against our current master, + // then become a client of the new master + if (arbitrateMaster(newDeviceID, + newDevicePrio, + mClient_MasterDeviceID, + mClient_MasterDevicePriority)) + return becomeClient(srcAddr, + newDeviceID, + newDevicePrio, + newTimelineID, + "heard master announcement"); + } else if (mState == ICommonClock::STATE_MASTER) { + // two masters are competing - if the new one wins arbitration, then + // cease acting as master + if (arbitrateMaster(newDeviceID, newDevicePrio, + mDeviceID, effectivePriority())) + return becomeClient(srcAddr, newDeviceID, + newDevicePrio, newTimelineID, + "heard master announcement"); + } + + return true; +} + +bool CommonTimeServer::sendWhoIsMasterRequest() { + assert(mState == ICommonClock::STATE_INITIAL || mState == ICommonClock::STATE_RONIN); + + // If we have no socket, then we must be in the unconfigured initial state. + // Don't report any errors, just don't try to send the initial who-is-master + // query. Eventually, our network will either become configured, or we will + // be forced into network-less master mode by higher level code. + if (mSocket < 0) { + assert(mState == ICommonClock::STATE_INITIAL); + return true; + } + + bool ret = false; + WhoIsMasterRequestPacket pkt; + pkt.initHeader(mSyncGroupID); + pkt.senderDeviceID = mDeviceID; + pkt.senderDevicePriority = effectivePriority(); + + uint8_t buf[256]; + ssize_t bufSz = pkt.serializePacket(buf, sizeof(buf)); + if (bufSz >= 0) { + ssize_t sendBytes = sendto( + mSocket, buf, bufSz, 0, + reinterpret_cast<const sockaddr *>(&mMasterElectionEP), + sizeof(mMasterElectionEP)); + if (sendBytes < 0) + ALOGE("WhoIsMaster sendto failed (errno %d)", errno); + ret = true; + } + + if (mState == ICommonClock::STATE_INITIAL) { + mCurTimeout.setTimeout(kInitial_WhoIsMasterTimeoutMs); + } else { + mCurTimeout.setTimeout(kRonin_WhoIsMasterTimeoutMs); + } + + return ret; +} + +bool CommonTimeServer::sendSyncRequest() { + // If we are sending sync requests, then we must be in the client state and + // we must have a socket (when we have no network, we are only supposed to + // be in INITIAL or MASTER) + assert(mState == ICommonClock::STATE_CLIENT); + assert(mSocket >= 0); + + bool ret = false; + SyncRequestPacket pkt; + pkt.initHeader(mTimelineID, mSyncGroupID); + pkt.clientTxLocalTime = mLocalClock.getLocalTime(); + + if (!mClient_FirstSyncTX) + mClient_FirstSyncTX = pkt.clientTxLocalTime; + + mClient_PacketRTTLog.logTX(pkt.clientTxLocalTime); + + uint8_t buf[256]; + ssize_t bufSz = pkt.serializePacket(buf, sizeof(buf)); + if (bufSz >= 0) { + ssize_t sendBytes = sendto( + mSocket, buf, bufSz, 0, + reinterpret_cast<const sockaddr *>(&mMasterEP), + sizeof(mMasterEP)); + if (sendBytes < 0) + ALOGE("SyncRequest sendto failed (errno %d)", errno); + ret = true; + } + + mClient_SyncsSentToCurMaster++; + mCurTimeout.setTimeout(mSyncRequestIntervalMs); + mClient_SyncRequestPending = true; + + return ret; +} + +bool CommonTimeServer::sendMasterAnnouncement() { + bool ret = false; + assert(mState == ICommonClock::STATE_MASTER); + + // If we are being asked to send a master announcement, but we have no + // socket, we must be in network-less master mode. Don't bother to send the + // announcement, and don't bother to schedule a timeout. When the network + // comes up, the work thread will get poked and start the process of + // figuring out who the current master should be. + if (mSocket < 0) { + mCurTimeout.setTimeout(kInfiniteTimeout); + return true; + } + + MasterAnnouncementPacket pkt; + pkt.initHeader(mTimelineID, mSyncGroupID); + pkt.deviceID = mDeviceID; + pkt.devicePriority = effectivePriority(); + + uint8_t buf[256]; + ssize_t bufSz = pkt.serializePacket(buf, sizeof(buf)); + if (bufSz >= 0) { + ssize_t sendBytes = sendto( + mSocket, buf, bufSz, 0, + reinterpret_cast<const sockaddr *>(&mMasterElectionEP), + sizeof(mMasterElectionEP)); + if (sendBytes < 0) + ALOGE("MasterAnnouncement sendto failed (errno %d)", errno); + ret = true; + } + + mCurTimeout.setTimeout(mMasterAnnounceIntervalMs); + return ret; +} + +bool CommonTimeServer::becomeClient(const sockaddr_storage& masterEP, + uint64_t masterDeviceID, + uint8_t masterDevicePriority, + uint64_t timelineID, + const char* cause) { + char newEPStr[64], oldEPStr[64]; + sockaddrToString(masterEP, true, newEPStr, sizeof(newEPStr)); + sockaddrToString(mMasterEP, mMasterEPValid, oldEPStr, sizeof(oldEPStr)); + + ALOGI("%s --> CLIENT (%s) :%s" + " OldMaster: %02x-%014llx::%016llx::%s" + " NewMaster: %02x-%014llx::%016llx::%s", + stateToString(mState), cause, + (mTimelineID != timelineID) ? " (new timeline)" : "", + mClient_MasterDevicePriority, mClient_MasterDeviceID, + mTimelineID, oldEPStr, + masterDevicePriority, masterDeviceID, + timelineID, newEPStr); + + if (mTimelineID != timelineID) { + // start following a new timeline + mTimelineID = timelineID; + mClockRecovery.reset(true, true); + notifyClockSyncLoss(); + } else { + // start following a new master on the existing timeline + mClockRecovery.reset(false, true); + } + + mMasterEP = masterEP; + mMasterEPValid = true; + setForceLowPriority(false); + + mClient_MasterDeviceID = masterDeviceID; + mClient_MasterDevicePriority = masterDevicePriority; + resetSyncStats(); + + setState(ICommonClock::STATE_CLIENT); + + // add some jitter to when the various clients send their requests + // in order to reduce the likelihood that a group of clients overload + // the master after receiving a master announcement + usleep((lrand48() % 100) * 1000); + + return sendSyncRequest(); +} + +bool CommonTimeServer::becomeMaster(const char* cause) { + uint64_t oldTimelineID = mTimelineID; + if (mTimelineID == ICommonClock::kInvalidTimelineID) { + // this device has not been following any existing timeline, + // so it will create a new timeline and declare itself master + assert(!mCommonClock.isValid()); + + // set the common time basis + mCommonClock.setBasis(mLocalClock.getLocalTime(), 0); + + // assign an arbitrary timeline iD + assignTimelineID(); + + // notify listeners that we've created a common timeline + notifyClockSync(); + } + + ALOGI("%s --> MASTER (%s) : %s timeline %016llx", + stateToString(mState), cause, + (oldTimelineID == mTimelineID) ? "taking ownership of" + : "creating new", + mTimelineID); + + memset(&mMasterEP, 0, sizeof(mMasterEP)); + mMasterEPValid = false; + setForceLowPriority(false); + mClient_MasterDevicePriority = effectivePriority(); + mClient_MasterDeviceID = mDeviceID; + mClockRecovery.reset(false, true); + resetSyncStats(); + + setState(ICommonClock::STATE_MASTER); + return sendMasterAnnouncement(); +} + +bool CommonTimeServer::becomeRonin(const char* cause) { + // If we were the client of a given timeline, but had never received even a + // single time sync packet, then we transition back to Initial instead of + // Ronin. If we transition to Ronin and end up becoming the new Master, we + // will be unable to service requests for other clients because we never + // actually knew what time it was. By going to initial, we ensure that + // other clients who know what time it is, but would lose master arbitration + // in the Ronin case, will step up and become the proper new master of the + // old timeline. + + char oldEPStr[64]; + sockaddrToString(mMasterEP, mMasterEPValid, oldEPStr, sizeof(oldEPStr)); + memset(&mMasterEP, 0, sizeof(mMasterEP)); + mMasterEPValid = false; + + if (mCommonClock.isValid()) { + ALOGI("%s --> RONIN (%s) : lost track of previously valid timeline " + "%02x-%014llx::%016llx::%s (%d TXed %d RXed %d RXExpired)", + stateToString(mState), cause, + mClient_MasterDevicePriority, mClient_MasterDeviceID, + mTimelineID, oldEPStr, + mClient_SyncsSentToCurMaster, + mClient_SyncRespsRXedFromCurMaster, + mClient_ExpiredSyncRespsRXedFromCurMaster); + + mRonin_WhoIsMasterRequestTimeouts = 0; + setState(ICommonClock::STATE_RONIN); + return sendWhoIsMasterRequest(); + } else { + ALOGI("%s --> INITIAL (%s) : never synced timeline " + "%02x-%014llx::%016llx::%s (%d TXed %d RXed %d RXExpired)", + stateToString(mState), cause, + mClient_MasterDevicePriority, mClient_MasterDeviceID, + mTimelineID, oldEPStr, + mClient_SyncsSentToCurMaster, + mClient_SyncRespsRXedFromCurMaster, + mClient_ExpiredSyncRespsRXedFromCurMaster); + + return becomeInitial("ronin, no timeline"); + } +} + +bool CommonTimeServer::becomeWaitForElection(const char* cause) { + ALOGI("%s --> WAIT_FOR_ELECTION (%s) : dropping out of election," + " waiting %d mSec for completion.", + stateToString(mState), cause, kWaitForElection_TimeoutMs); + + setState(ICommonClock::STATE_WAIT_FOR_ELECTION); + mCurTimeout.setTimeout(kWaitForElection_TimeoutMs); + return true; +} + +bool CommonTimeServer::becomeInitial(const char* cause) { + ALOGI("Entering INITIAL (%s), total reset.", cause); + + setState(ICommonClock::STATE_INITIAL); + + // reset clock recovery + mClockRecovery.reset(true, true); + + // reset internal state bookkeeping. + mCurTimeout.setTimeout(kInfiniteTimeout); + memset(&mMasterEP, 0, sizeof(mMasterEP)); + mMasterEPValid = false; + mLastPacketRxLocalTime = 0; + mTimelineID = ICommonClock::kInvalidTimelineID; + mClockSynced = false; + mInitial_WhoIsMasterRequestTimeouts = 0; + mClient_MasterDeviceID = 0; + mClient_MasterDevicePriority = 0; + mRonin_WhoIsMasterRequestTimeouts = 0; + resetSyncStats(); + + // send the first request to discover the master + return sendWhoIsMasterRequest(); +} + +void CommonTimeServer::notifyClockSync() { + if (!mClockSynced) { + mClockSynced = true; + mICommonClock->notifyOnTimelineChanged(mTimelineID); + } +} + +void CommonTimeServer::notifyClockSyncLoss() { + if (mClockSynced) { + mClockSynced = false; + mICommonClock->notifyOnTimelineChanged( + ICommonClock::kInvalidTimelineID); + } +} + +void CommonTimeServer::setState(ICommonClock::State s) { + mState = s; +} + +const char* CommonTimeServer::stateToString(ICommonClock::State s) { + switch(s) { + case ICommonClock::STATE_INITIAL: + return "INITIAL"; + case ICommonClock::STATE_CLIENT: + return "CLIENT"; + case ICommonClock::STATE_MASTER: + return "MASTER"; + case ICommonClock::STATE_RONIN: + return "RONIN"; + case ICommonClock::STATE_WAIT_FOR_ELECTION: + return "WAIT_FOR_ELECTION"; + default: + return "unknown"; + } +} + +void CommonTimeServer::sockaddrToString(const sockaddr_storage& addr, + bool addrValid, + char* buf, size_t bufLen) { + if (!bufLen || !buf) + return; + + if (addrValid) { + switch (addr.ss_family) { + case AF_INET: { + const struct sockaddr_in* sa = + reinterpret_cast<const struct sockaddr_in*>(&addr); + unsigned long a = ntohl(sa->sin_addr.s_addr); + uint16_t p = ntohs(sa->sin_port); + snprintf(buf, bufLen, "%lu.%lu.%lu.%lu:%hu", + ((a >> 24) & 0xFF), ((a >> 16) & 0xFF), + ((a >> 8) & 0xFF), (a & 0xFF), p); + } break; + + case AF_INET6: { + const struct sockaddr_in6* sa = + reinterpret_cast<const struct sockaddr_in6*>(&addr); + const uint8_t* a = sa->sin6_addr.s6_addr; + uint16_t p = ntohs(sa->sin6_port); + snprintf(buf, bufLen, + "%02X%02X:%02X%02X:%02X%02X:%02X%02X:" + "%02X%02X:%02X%02X:%02X%02X:%02X%02X port %hd", + a[0], a[1], a[ 2], a[ 3], a[ 4], a[ 5], a[ 6], a[ 7], + a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15], + p); + } break; + + default: + snprintf(buf, bufLen, + "<unknown sockaddr family %d>", addr.ss_family); + break; + } + } else { + snprintf(buf, bufLen, "<none>"); + } + + buf[bufLen - 1] = 0; +} + +bool CommonTimeServer::sockaddrMatch(const sockaddr_storage& a1, + const sockaddr_storage& a2, + bool matchAddressOnly) { + if (a1.ss_family != a2.ss_family) + return false; + + switch (a1.ss_family) { + case AF_INET: { + const struct sockaddr_in* sa1 = + reinterpret_cast<const struct sockaddr_in*>(&a1); + const struct sockaddr_in* sa2 = + reinterpret_cast<const struct sockaddr_in*>(&a2); + + if (sa1->sin_addr.s_addr != sa2->sin_addr.s_addr) + return false; + + return (matchAddressOnly || (sa1->sin_port == sa2->sin_port)); + } break; + + case AF_INET6: { + const struct sockaddr_in6* sa1 = + reinterpret_cast<const struct sockaddr_in6*>(&a1); + const struct sockaddr_in6* sa2 = + reinterpret_cast<const struct sockaddr_in6*>(&a2); + + if (memcmp(&sa1->sin6_addr, &sa2->sin6_addr, sizeof(sa2->sin6_addr))) + return false; + + return (matchAddressOnly || (sa1->sin6_port == sa2->sin6_port)); + } break; + + // Huh? We don't deal in non-IPv[46] addresses. Not sure how we got + // here, but we don't know how to comapre these addresses and simply + // default to a no-match decision. + default: return false; + } +} + +void CommonTimeServer::TimeoutHelper::setTimeout(int msec) { + mTimeoutValid = (msec >= 0); + if (mTimeoutValid) + mEndTime = systemTime() + + (static_cast<nsecs_t>(msec) * 1000000); +} + +int CommonTimeServer::TimeoutHelper::msecTillTimeout() { + if (!mTimeoutValid) + return kInfiniteTimeout; + + nsecs_t now = systemTime(); + if (now >= mEndTime) + return 0; + + uint64_t deltaMsec = (((mEndTime - now) + 999999) / 1000000); + + if (deltaMsec > static_cast<uint64_t>(MAX_INT)) + return MAX_INT; + + return static_cast<int>(deltaMsec); +} + +bool CommonTimeServer::shouldPanicNotGettingGoodData() { + if (mClient_FirstSyncTX) { + int64_t now = mLocalClock.getLocalTime(); + int64_t delta = now - (mClient_LastGoodSyncRX + ? mClient_LastGoodSyncRX + : mClient_FirstSyncTX); + int64_t deltaUsec = mCommonClock.localDurationToCommonDuration(delta); + + if (deltaUsec >= kNoGoodDataPanicThresholdUsec) + return true; + } + + return false; +} + +void CommonTimeServer::PacketRTTLog::logTX(int64_t txTime) { + txTimes[wrPtr] = txTime; + rxTimes[wrPtr] = 0; + wrPtr = (wrPtr + 1) % RTT_LOG_SIZE; + if (!wrPtr) + logFull = true; +} + +void CommonTimeServer::PacketRTTLog::logRX(int64_t txTime, int64_t rxTime) { + if (!logFull && !wrPtr) + return; + + uint32_t i = logFull ? wrPtr : 0; + do { + if (txTimes[i] == txTime) { + rxTimes[i] = rxTime; + break; + } + i = (i + 1) % RTT_LOG_SIZE; + } while (i != wrPtr); +} + +} // namespace android diff --git a/services/common_time/common_time_server.h b/services/common_time/common_time_server.h new file mode 100644 index 000000000000..a0f549f6d8f9 --- /dev/null +++ b/services/common_time/common_time_server.h @@ -0,0 +1,330 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_COMMON_TIME_SERVER_H +#define ANDROID_COMMON_TIME_SERVER_H + +#include <arpa/inet.h> +#include <stdint.h> +#include <linux/socket.h> + +#include <common_time/ICommonClock.h> +#include <common_time/local_clock.h> +#include <utils/String8.h> + +#include "clock_recovery.h" +#include "common_clock.h" +#include "common_time_server_packets.h" + +#define RTT_LOG_SIZE 30 + +namespace android { + +class CommonClockService; +class CommonTimeConfigService; + +/***** time service implementation *****/ + +class CommonTimeServer : public Thread { + public: + CommonTimeServer(); + ~CommonTimeServer(); + + bool startServices(); + + // Common Clock API methods + CommonClock& getCommonClock() { return mCommonClock; } + LocalClock& getLocalClock() { return mLocalClock; } + uint64_t getTimelineID(); + int32_t getEstimatedError(); + ICommonClock::State getState(); + status_t getMasterAddr(struct sockaddr_storage* addr); + status_t isCommonTimeValid(bool* valid, uint32_t* timelineID); + + // Config API methods + status_t getMasterElectionPriority(uint8_t *priority); + status_t setMasterElectionPriority(uint8_t priority); + status_t getMasterElectionEndpoint(struct sockaddr_storage *addr); + status_t setMasterElectionEndpoint(const struct sockaddr_storage *addr); + status_t getMasterElectionGroupId(uint64_t *id); + status_t setMasterElectionGroupId(uint64_t id); + status_t getInterfaceBinding(String8& ifaceName); + status_t setInterfaceBinding(const String8& ifaceName); + status_t getMasterAnnounceInterval(int *interval); + status_t setMasterAnnounceInterval(int interval); + status_t getClientSyncInterval(int *interval); + status_t setClientSyncInterval(int interval); + status_t getPanicThreshold(int *threshold); + status_t setPanicThreshold(int threshold); + status_t getAutoDisable(bool *autoDisable); + status_t setAutoDisable(bool autoDisable); + status_t forceNetworklessMasterMode(); + + // Method used by the CommonClockService to notify the core service about + // changes in the number of active common clock clients. + void reevaluateAutoDisableState(bool commonClockHasClients); + + status_t dumpClockInterface(int fd, const Vector<String16>& args, + size_t activeClients); + status_t dumpConfigInterface(int fd, const Vector<String16>& args); + + private: + class PacketRTTLog { + public: + PacketRTTLog() { + resetLog(); + } + + void resetLog() { + wrPtr = 0; + logFull = 0; + } + + void logTX(int64_t txTime); + void logRX(int64_t txTime, int64_t rxTime); + void dumpLog(int fd, const CommonClock& cclk); + + private: + uint32_t wrPtr; + bool logFull; + int64_t txTimes[RTT_LOG_SIZE]; + int64_t rxTimes[RTT_LOG_SIZE]; + }; + + class TimeoutHelper { + public: + TimeoutHelper() : mTimeoutValid(false) { } + + void setTimeout(int msec); + int msecTillTimeout(); + + private: + bool mTimeoutValid; + nsecs_t mEndTime; + }; + + bool threadLoop(); + + bool runStateMachine_l(); + bool setupSocket_l(); + + void assignTimelineID(); + bool assignDeviceID(); + + static bool arbitrateMaster(uint64_t deviceID1, uint8_t devicePrio1, + uint64_t deviceID2, uint8_t devicePrio2); + + bool handlePacket(); + bool handleWhoIsMasterRequest (const WhoIsMasterRequestPacket* request, + const sockaddr_storage& srcAddr); + bool handleWhoIsMasterResponse(const WhoIsMasterResponsePacket* response, + const sockaddr_storage& srcAddr); + bool handleSyncRequest (const SyncRequestPacket* request, + const sockaddr_storage& srcAddr); + bool handleSyncResponse (const SyncResponsePacket* response, + const sockaddr_storage& srcAddr); + bool handleMasterAnnouncement (const MasterAnnouncementPacket* packet, + const sockaddr_storage& srcAddr); + + bool handleTimeout(); + bool handleTimeoutInitial(); + bool handleTimeoutClient(); + bool handleTimeoutMaster(); + bool handleTimeoutRonin(); + bool handleTimeoutWaitForElection(); + + bool sendWhoIsMasterRequest(); + bool sendSyncRequest(); + bool sendMasterAnnouncement(); + + bool becomeClient(const sockaddr_storage& masterAddr, + uint64_t masterDeviceID, + uint8_t masterDevicePriority, + uint64_t timelineID, + const char* cause); + bool becomeMaster(const char* cause); + bool becomeRonin(const char* cause); + bool becomeWaitForElection(const char* cause); + bool becomeInitial(const char* cause); + + void notifyClockSync(); + void notifyClockSyncLoss(); + + ICommonClock::State mState; + void setState(ICommonClock::State s); + + void clearPendingWakeupEvents_l(); + void wakeupThread_l(); + void cleanupSocket_l(); + void shutdownThread(); + + inline uint8_t effectivePriority() const { + return (mMasterPriority & 0x7F) | + (mForceLowPriority ? 0x00 : 0x80); + } + + inline bool shouldAutoDisable() const { + return (mAutoDisable && !mCommonClockHasClients); + } + + inline void resetSyncStats() { + mClient_SyncRequestPending = false; + mClient_SyncRequestTimeouts = 0; + mClient_SyncsSentToCurMaster = 0; + mClient_SyncRespsRXedFromCurMaster = 0; + mClient_ExpiredSyncRespsRXedFromCurMaster = 0; + mClient_FirstSyncTX = 0; + mClient_LastGoodSyncRX = 0; + mClient_PacketRTTLog.resetLog(); + } + + bool shouldPanicNotGettingGoodData(); + + // Helper to keep track of the state machine's current timeout + TimeoutHelper mCurTimeout; + + // common clock, local clock abstraction, and clock recovery loop + CommonClock mCommonClock; + LocalClock mLocalClock; + ClockRecoveryLoop mClockRecovery; + + // implementation of ICommonClock + sp<CommonClockService> mICommonClock; + + // implementation of ICommonTimeConfig + sp<CommonTimeConfigService> mICommonTimeConfig; + + // UDP socket for the time sync protocol + int mSocket; + + // eventfd used to wakeup the work thread in response to configuration + // changes. + int mWakeupThreadFD; + + // timestamp captured when a packet is received + int64_t mLastPacketRxLocalTime; + + // ID of the timeline that this device is following + uint64_t mTimelineID; + + // flag for whether the clock has been synced to a timeline + bool mClockSynced; + + // flag used to indicate that clients should be considered to be lower + // priority than all of their peers during elections. This flag is set and + // cleared by the state machine. It is set when the client joins a new + // network. If the client had been a master in the old network (or an + // isolated master with no network connectivity) it should defer to any + // masters which may already be on the network. It will be cleared whenever + // the state machine transitions to the master state. + bool mForceLowPriority; + inline void setForceLowPriority(bool val) { + mForceLowPriority = val; + if (mState == ICommonClock::STATE_MASTER) + mClient_MasterDevicePriority = effectivePriority(); + } + + // Lock to synchronize access to internal state and configuration. + Mutex mLock; + + // Flag updated by the common clock service to indicate that it does or does + // not currently have registered clients. When the the auto disable flag is + // cleared on the common time service, the service will participate in + // network synchronization whenever it has a valid network interface to bind + // to. When the auto disable flag is set on the common time service, it + // will only participate in network synchronization when it has both a valid + // interface AND currently active common clock clients. + bool mCommonClockHasClients; + + // Configuration info + struct sockaddr_storage mMasterElectionEP; // Endpoint over which we conduct master election + String8 mBindIface; // Endpoint for the service to bind to. + bool mBindIfaceValid; // whether or not the bind Iface is valid. + bool mBindIfaceDirty; // whether or not the bind Iface is valid. + struct sockaddr_storage mMasterEP; // Endpoint of our current master (if any) + bool mMasterEPValid; + uint64_t mDeviceID; // unique ID of this device + uint64_t mSyncGroupID; // synchronization group ID of this device. + uint8_t mMasterPriority; // Priority of this device in master election. + uint32_t mMasterAnnounceIntervalMs; + uint32_t mSyncRequestIntervalMs; + uint32_t mPanicThresholdUsec; + bool mAutoDisable; + + // Config defaults. + static const char* kDefaultMasterElectionAddr; + static const uint16_t kDefaultMasterElectionPort; + static const uint64_t kDefaultSyncGroupID; + static const uint8_t kDefaultMasterPriority; + static const uint32_t kDefaultMasterAnnounceIntervalMs; + static const uint32_t kDefaultSyncRequestIntervalMs; + static const uint32_t kDefaultPanicThresholdUsec; + static const bool kDefaultAutoDisable; + + // Priority mask and shift fields. + static const uint64_t kDeviceIDMask; + static const uint8_t kDevicePriorityMask; + static const uint8_t kDevicePriorityHiLowBit; + static const uint32_t kDevicePriorityShift; + + // Unconfgurable constants + static const int kSetupRetryTimeoutMs; + static const int64_t kNoGoodDataPanicThresholdUsec; + static const uint32_t kRTTDiscardPanicThreshMultiplier; + + /*** status while in the Initial state ***/ + int mInitial_WhoIsMasterRequestTimeouts; + static const int kInitial_NumWhoIsMasterRetries; + static const int kInitial_WhoIsMasterTimeoutMs; + + /*** status while in the Client state ***/ + uint64_t mClient_MasterDeviceID; + uint8_t mClient_MasterDevicePriority; + bool mClient_SyncRequestPending; + int mClient_SyncRequestTimeouts; + uint32_t mClient_SyncsSentToCurMaster; + uint32_t mClient_SyncRespsRXedFromCurMaster; + uint32_t mClient_ExpiredSyncRespsRXedFromCurMaster; + int64_t mClient_FirstSyncTX; + int64_t mClient_LastGoodSyncRX; + PacketRTTLog mClient_PacketRTTLog; + static const int kClient_NumSyncRequestRetries; + + + /*** status while in the Master state ***/ + static const uint32_t kDefaultMaster_AnnouncementIntervalMs; + + /*** status while in the Ronin state ***/ + int mRonin_WhoIsMasterRequestTimeouts; + static const int kRonin_NumWhoIsMasterRetries; + static const int kRonin_WhoIsMasterTimeoutMs; + + /*** status while in the WaitForElection state ***/ + static const int kWaitForElection_TimeoutMs; + + static const int kInfiniteTimeout; + + static const char* stateToString(ICommonClock::State s); + static void sockaddrToString(const sockaddr_storage& addr, bool addrValid, + char* buf, size_t bufLen); + static bool sockaddrMatch(const sockaddr_storage& a1, + const sockaddr_storage& a2, + bool matchAddressOnly); +}; + +} // namespace android + +#endif // ANDROID_COMMON_TIME_SERVER_H diff --git a/services/common_time/common_time_server_api.cpp b/services/common_time/common_time_server_api.cpp new file mode 100644 index 000000000000..fb8c2615e1c0 --- /dev/null +++ b/services/common_time/common_time_server_api.cpp @@ -0,0 +1,435 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * A service that exchanges time synchronization information between + * a master that defines a timeline and clients that follow the timeline. + */ + +#define LOG_TAG "common_time" +#include <utils/Log.h> + +#include <binder/IServiceManager.h> +#include <binder/IPCThreadState.h> + +#include "common_time_server.h" + +namespace android { + +// +// Clock API +// +uint64_t CommonTimeServer::getTimelineID() { + AutoMutex _lock(&mLock); + return mTimelineID; +} + +ICommonClock::State CommonTimeServer::getState() { + AutoMutex _lock(&mLock); + return mState; +} + +status_t CommonTimeServer::getMasterAddr(struct sockaddr_storage* addr) { + AutoMutex _lock(&mLock); + if (mMasterEPValid) { + memcpy(addr, &mMasterEP, sizeof(*addr)); + return OK; + } + + return UNKNOWN_ERROR; +} + +int32_t CommonTimeServer::getEstimatedError() { + AutoMutex _lock(&mLock); + + if (ICommonClock::STATE_MASTER == mState) + return 0; + + if (!mClockSynced) + return ICommonClock::kErrorEstimateUnknown; + + return mClockRecovery.getLastErrorEstimate(); +} + +status_t CommonTimeServer::isCommonTimeValid(bool* valid, + uint32_t* timelineID) { + AutoMutex _lock(&mLock); + *valid = mCommonClock.isValid(); + *timelineID = mTimelineID; + return OK; +} + +// +// Config API +// +status_t CommonTimeServer::getMasterElectionPriority(uint8_t *priority) { + AutoMutex _lock(&mLock); + *priority = mMasterPriority; + return OK; +} + +status_t CommonTimeServer::setMasterElectionPriority(uint8_t priority) { + AutoMutex _lock(&mLock); + + if (priority > 0x7F) + return BAD_VALUE; + + mMasterPriority = priority; + return OK; +} + +status_t CommonTimeServer::getMasterElectionEndpoint( + struct sockaddr_storage *addr) { + AutoMutex _lock(&mLock); + memcpy(addr, &mMasterElectionEP, sizeof(*addr)); + return OK; +} + +status_t CommonTimeServer::setMasterElectionEndpoint( + const struct sockaddr_storage *addr) { + AutoMutex _lock(&mLock); + + if (!addr) + return BAD_VALUE; + + // TODO: add proper support for IPv6 + if (addr->ss_family != AF_INET) + return BAD_VALUE; + + // Only multicast and broadcast endpoints with explicit ports are allowed. + uint16_t ipv4Port = ntohs( + reinterpret_cast<const struct sockaddr_in*>(addr)->sin_port); + if (!ipv4Port) + return BAD_VALUE; + + uint32_t ipv4Addr = ntohl( + reinterpret_cast<const struct sockaddr_in*>(addr)->sin_addr.s_addr); + if ((ipv4Addr != 0xFFFFFFFF) && (0xE0000000 != (ipv4Addr & 0xF0000000))) + return BAD_VALUE; + + memcpy(&mMasterElectionEP, addr, sizeof(mMasterElectionEP)); + + // Force a rebind in order to change election enpoints. + mBindIfaceDirty = true; + wakeupThread_l(); + return OK; +} + +status_t CommonTimeServer::getMasterElectionGroupId(uint64_t *id) { + AutoMutex _lock(&mLock); + *id = mSyncGroupID; + return OK; +} + +status_t CommonTimeServer::setMasterElectionGroupId(uint64_t id) { + AutoMutex _lock(&mLock); + mSyncGroupID = id; + return OK; +} + +status_t CommonTimeServer::getInterfaceBinding(String8& ifaceName) { + AutoMutex _lock(&mLock); + if (!mBindIfaceValid) + return INVALID_OPERATION; + ifaceName = mBindIface; + return OK; +} + +status_t CommonTimeServer::setInterfaceBinding(const String8& ifaceName) { + AutoMutex _lock(&mLock); + + mBindIfaceDirty = true; + if (ifaceName.size()) { + mBindIfaceValid = true; + mBindIface = ifaceName; + } else { + mBindIfaceValid = false; + mBindIface.clear(); + } + + wakeupThread_l(); + return OK; +} + +status_t CommonTimeServer::getMasterAnnounceInterval(int *interval) { + AutoMutex _lock(&mLock); + *interval = mMasterAnnounceIntervalMs; + return OK; +} + +status_t CommonTimeServer::setMasterAnnounceInterval(int interval) { + AutoMutex _lock(&mLock); + + if (interval > (6 *3600000)) // Max interval is once every 6 hrs + return BAD_VALUE; + + if (interval < 500) // Min interval is once per 0.5 seconds + return BAD_VALUE; + + mMasterAnnounceIntervalMs = interval; + if (ICommonClock::STATE_MASTER == mState) { + int pendingTimeout = mCurTimeout.msecTillTimeout(); + if ((kInfiniteTimeout == pendingTimeout) || + (pendingTimeout > interval)) { + mCurTimeout.setTimeout(mMasterAnnounceIntervalMs); + wakeupThread_l(); + } + } + + return OK; +} + +status_t CommonTimeServer::getClientSyncInterval(int *interval) { + AutoMutex _lock(&mLock); + *interval = mSyncRequestIntervalMs; + return OK; +} + +status_t CommonTimeServer::setClientSyncInterval(int interval) { + AutoMutex _lock(&mLock); + + if (interval > (3600000)) // Max interval is once every 60 min + return BAD_VALUE; + + if (interval < 250) // Min interval is once per 0.25 seconds + return BAD_VALUE; + + mSyncRequestIntervalMs = interval; + if (ICommonClock::STATE_CLIENT == mState) { + int pendingTimeout = mCurTimeout.msecTillTimeout(); + if ((kInfiniteTimeout == pendingTimeout) || + (pendingTimeout > interval)) { + mCurTimeout.setTimeout(mSyncRequestIntervalMs); + wakeupThread_l(); + } + } + + return OK; +} + +status_t CommonTimeServer::getPanicThreshold(int *threshold) { + AutoMutex _lock(&mLock); + *threshold = mPanicThresholdUsec; + return OK; +} + +status_t CommonTimeServer::setPanicThreshold(int threshold) { + AutoMutex _lock(&mLock); + + if (threshold < 1000) // Min threshold is 1mSec + return BAD_VALUE; + + mPanicThresholdUsec = threshold; + return OK; +} + +status_t CommonTimeServer::getAutoDisable(bool *autoDisable) { + AutoMutex _lock(&mLock); + *autoDisable = mAutoDisable; + return OK; +} + +status_t CommonTimeServer::setAutoDisable(bool autoDisable) { + AutoMutex _lock(&mLock); + mAutoDisable = autoDisable; + wakeupThread_l(); + return OK; +} + +status_t CommonTimeServer::forceNetworklessMasterMode() { + AutoMutex _lock(&mLock); + + // Can't force networkless master mode if we are currently bound to a + // network. + if (mSocket >= 0) + return INVALID_OPERATION; + + becomeMaster("force networkless"); + + return OK; +} + +void CommonTimeServer::reevaluateAutoDisableState(bool commonClockHasClients) { + AutoMutex _lock(&mLock); + bool needWakeup = (mAutoDisable && mMasterEPValid && + (commonClockHasClients != mCommonClockHasClients)); + + mCommonClockHasClients = commonClockHasClients; + + if (needWakeup) { + ALOGI("Waking up service, auto-disable is engaged and service now has%s" + " clients", mCommonClockHasClients ? "" : " no"); + wakeupThread_l(); + } +} + +#define dump_printf(a, b...) do { \ + int res; \ + res = snprintf(buffer, sizeof(buffer), a, b); \ + buffer[sizeof(buffer) - 1] = 0; \ + if (res > 0) \ + write(fd, buffer, res); \ +} while (0) +#define checked_percentage(a, b) ((0 == b) ? 0.0f : ((100.0f * a) / b)) + +status_t CommonTimeServer::dumpClockInterface(int fd, + const Vector<String16>& args, + size_t activeClients) { + AutoMutex _lock(&mLock); + const size_t SIZE = 256; + char buffer[SIZE]; + + if (checkCallingPermission(String16("android.permission.DUMP")) == false) { + snprintf(buffer, SIZE, "Permission Denial: " + "can't dump CommonClockService from pid=%d, uid=%d\n", + IPCThreadState::self()->getCallingPid(), + IPCThreadState::self()->getCallingUid()); + write(fd, buffer, strlen(buffer)); + } else { + int64_t commonTime; + int64_t localTime; + bool synced; + char maStr[64]; + + localTime = mLocalClock.getLocalTime(); + synced = (OK == mCommonClock.localToCommon(localTime, &commonTime)); + sockaddrToString(mMasterEP, mMasterEPValid, maStr, sizeof(maStr)); + + dump_printf("Common Clock Service Status\nLocal time : %lld\n", + localTime); + + if (synced) + dump_printf("Common time : %lld\n", commonTime); + else + dump_printf("Common time : %s\n", "not synced"); + + dump_printf("Timeline ID : %016llx\n", mTimelineID); + dump_printf("State : %s\n", stateToString(mState)); + dump_printf("Master Addr : %s\n", maStr); + + + if (synced) { + int32_t est = (ICommonClock::STATE_MASTER != mState) + ? mClockRecovery.getLastErrorEstimate() + : 0; + dump_printf("Error Est. : %.3f msec\n", + static_cast<float>(est) / 1000.0); + } else { + dump_printf("Error Est. : %s\n", "unknown"); + } + + dump_printf("Syncs TXes : %u\n", mClient_SyncsSentToCurMaster); + dump_printf("Syncs RXes : %u (%.2f%%)\n", + mClient_SyncRespsRXedFromCurMaster, + checked_percentage( + mClient_SyncRespsRXedFromCurMaster, + mClient_SyncsSentToCurMaster)); + dump_printf("RXs Expired : %u (%.2f%%)\n", + mClient_ExpiredSyncRespsRXedFromCurMaster, + checked_percentage( + mClient_ExpiredSyncRespsRXedFromCurMaster, + mClient_SyncsSentToCurMaster)); + + if (!mClient_LastGoodSyncRX) { + dump_printf("Last Good RX : %s\n", "unknown"); + } else { + int64_t localDelta, usecDelta; + localDelta = localTime - mClient_LastGoodSyncRX; + usecDelta = mCommonClock.localDurationToCommonDuration(localDelta); + dump_printf("Last Good RX : %lld uSec ago\n", usecDelta); + } + + dump_printf("Active Clients : %u\n", activeClients); + mClient_PacketRTTLog.dumpLog(fd, mCommonClock); + } + + return NO_ERROR; +} + +status_t CommonTimeServer::dumpConfigInterface(int fd, + const Vector<String16>& args) { + AutoMutex _lock(&mLock); + const size_t SIZE = 256; + char buffer[SIZE]; + + if (checkCallingPermission(String16("android.permission.DUMP")) == false) { + snprintf(buffer, SIZE, "Permission Denial: " + "can't dump CommonTimeConfigService from pid=%d, uid=%d\n", + IPCThreadState::self()->getCallingPid(), + IPCThreadState::self()->getCallingUid()); + write(fd, buffer, strlen(buffer)); + } else { + char meStr[64]; + + sockaddrToString(mMasterElectionEP, true, meStr, sizeof(meStr)); + + dump_printf("Common Time Config Service Status\n" + "Bound Interface : %s\n", + mBindIfaceValid ? mBindIface.string() : "<unbound>"); + dump_printf("Master Election Endpoint : %s\n", meStr); + dump_printf("Master Election Group ID : %016llx\n", mSyncGroupID); + dump_printf("Master Announce Interval : %d mSec\n", + mMasterAnnounceIntervalMs); + dump_printf("Client Sync Interval : %d mSec\n", + mSyncRequestIntervalMs); + dump_printf("Panic Threshold : %d uSec\n", + mPanicThresholdUsec); + dump_printf("Base ME Prio : 0x%02x\n", + static_cast<uint32_t>(mMasterPriority)); + dump_printf("Effective ME Prio : 0x%02x\n", + static_cast<uint32_t>(effectivePriority())); + dump_printf("Auto Disable Allowed : %s\n", + mAutoDisable ? "yes" : "no"); + dump_printf("Auto Disable Engaged : %s\n", + shouldAutoDisable() ? "yes" : "no"); + } + + return NO_ERROR; +} + +void CommonTimeServer::PacketRTTLog::dumpLog(int fd, const CommonClock& cclk) { + const size_t SIZE = 256; + char buffer[SIZE]; + uint32_t avail = !logFull ? wrPtr : RTT_LOG_SIZE; + + if (!avail) + return; + + dump_printf("\nPacket Log (%d entries)\n", avail); + + uint32_t ndx = 0; + uint32_t i = logFull ? wrPtr : 0; + do { + if (rxTimes[i]) { + int64_t delta = rxTimes[i] - txTimes[i]; + int64_t deltaUsec = cclk.localDurationToCommonDuration(delta); + dump_printf("pkt[%2d] : localTX %12lld localRX %12lld " + "(%.3f msec RTT)\n", + ndx, txTimes[i], rxTimes[i], + static_cast<float>(deltaUsec) / 1000.0); + } else { + dump_printf("pkt[%2d] : localTX %12lld localRX never\n", + ndx, txTimes[i]); + } + i = (i + 1) % RTT_LOG_SIZE; + ndx++; + } while (i != wrPtr); +} + +#undef dump_printf +#undef checked_percentage + +} // namespace android diff --git a/services/common_time/common_time_server_packets.cpp b/services/common_time/common_time_server_packets.cpp new file mode 100644 index 000000000000..9833c37f2519 --- /dev/null +++ b/services/common_time/common_time_server_packets.cpp @@ -0,0 +1,293 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * A service that exchanges time synchronization information between + * a master that defines a timeline and clients that follow the timeline. + */ + +#define LOG_TAG "common_time" +#include <utils/Log.h> + +#include <arpa/inet.h> +#include <stdint.h> + +#include "common_time_server_packets.h" + +namespace android { + +const uint32_t TimeServicePacketHeader::kMagic = + (static_cast<uint32_t>('c') << 24) | + (static_cast<uint32_t>('c') << 16) | + (static_cast<uint32_t>('l') << 8) | + static_cast<uint32_t>('k'); + +const uint16_t TimeServicePacketHeader::kCurVersion = 1; + +#define SERIALIZE_FIELD(field_name, type, converter) \ + do { \ + if ((offset + sizeof(field_name)) > length) \ + return -1; \ + *((type*)(data + offset)) = converter(field_name); \ + offset += sizeof(field_name); \ + } while (0) +#define SERIALIZE_INT16(field_name) SERIALIZE_FIELD(field_name, int16_t, htons) +#define SERIALIZE_INT32(field_name) SERIALIZE_FIELD(field_name, int32_t, htonl) +#define SERIALIZE_INT64(field_name) SERIALIZE_FIELD(field_name, int64_t, htonq) + +#define DESERIALIZE_FIELD(field_name, type, converter) \ + do { \ + if ((offset + sizeof(field_name)) > length) \ + return -1; \ + field_name = converter(*((type*)(data + offset))); \ + offset += sizeof(field_name); \ + } while (0) +#define DESERIALIZE_INT16(field_name) DESERIALIZE_FIELD(field_name, int16_t, ntohs) +#define DESERIALIZE_INT32(field_name) DESERIALIZE_FIELD(field_name, int32_t, ntohl) +#define DESERIALIZE_INT64(field_name) DESERIALIZE_FIELD(field_name, int64_t, ntohq) + +#define kDevicePriorityShift 56 +#define kDeviceIDMask ((static_cast<uint64_t>(1) << kDevicePriorityShift) - 1) + +inline uint64_t packDeviceID(uint64_t devID, uint8_t prio) { + return (devID & kDeviceIDMask) | + (static_cast<uint64_t>(prio) << kDevicePriorityShift); +} + +inline uint64_t unpackDeviceID(uint64_t packed) { + return (packed & kDeviceIDMask); +} + +inline uint8_t unpackDevicePriority(uint64_t packed) { + return static_cast<uint8_t>(packed >> kDevicePriorityShift); +} + +ssize_t TimeServicePacketHeader::serializeHeader(uint8_t* data, + uint32_t length) { + ssize_t offset = 0; + int16_t pktType = static_cast<int16_t>(packetType); + SERIALIZE_INT32(magic); + SERIALIZE_INT16(version); + SERIALIZE_INT16(pktType); + SERIALIZE_INT64(timelineID); + SERIALIZE_INT64(syncGroupID); + return offset; +} + +ssize_t TimeServicePacketHeader::deserializeHeader(const uint8_t* data, + uint32_t length) { + ssize_t offset = 0; + int16_t tmp; + DESERIALIZE_INT32(magic); + DESERIALIZE_INT16(version); + DESERIALIZE_INT16(tmp); + DESERIALIZE_INT64(timelineID); + DESERIALIZE_INT64(syncGroupID); + packetType = static_cast<TimeServicePacketType>(tmp); + return offset; +} + +ssize_t TimeServicePacketHeader::serializePacket(uint8_t* data, + uint32_t length) { + ssize_t ret, tmp; + + ret = serializeHeader(data, length); + if (ret < 0) + return ret; + + data += ret; + length -= ret; + + switch (packetType) { + case TIME_PACKET_WHO_IS_MASTER_REQUEST: + tmp =((WhoIsMasterRequestPacket*)(this))->serializePacket(data, + length); + break; + case TIME_PACKET_WHO_IS_MASTER_RESPONSE: + tmp =((WhoIsMasterResponsePacket*)(this))->serializePacket(data, + length); + break; + case TIME_PACKET_SYNC_REQUEST: + tmp =((SyncRequestPacket*)(this))->serializePacket(data, length); + break; + case TIME_PACKET_SYNC_RESPONSE: + tmp =((SyncResponsePacket*)(this))->serializePacket(data, length); + break; + case TIME_PACKET_MASTER_ANNOUNCEMENT: + tmp =((MasterAnnouncementPacket*)(this))->serializePacket(data, + length); + break; + default: + return -1; + } + + if (tmp < 0) + return tmp; + + return ret + tmp; +} + +ssize_t UniversalTimeServicePacket::deserializePacket( + const uint8_t* data, + uint32_t length, + uint64_t expectedSyncGroupID) { + ssize_t ret; + TimeServicePacketHeader* header; + if (length < 8) + return -1; + + packetType = ntohs(*((uint16_t*)(data + 6))); + switch (packetType) { + case TIME_PACKET_WHO_IS_MASTER_REQUEST: + ret = p.who_is_master_request.deserializePacket(data, length); + header = &p.who_is_master_request; + break; + case TIME_PACKET_WHO_IS_MASTER_RESPONSE: + ret = p.who_is_master_response.deserializePacket(data, length); + header = &p.who_is_master_response; + break; + case TIME_PACKET_SYNC_REQUEST: + ret = p.sync_request.deserializePacket(data, length); + header = &p.sync_request; + break; + case TIME_PACKET_SYNC_RESPONSE: + ret = p.sync_response.deserializePacket(data, length); + header = &p.sync_response; + break; + case TIME_PACKET_MASTER_ANNOUNCEMENT: + ret = p.master_announcement.deserializePacket(data, length); + header = &p.master_announcement; + break; + default: + return -1; + } + + if ((ret >= 0) && !header->checkPacket(expectedSyncGroupID)) + ret = -1; + + return ret; +} + +ssize_t WhoIsMasterRequestPacket::serializePacket(uint8_t* data, + uint32_t length) { + ssize_t offset = serializeHeader(data, length); + if (offset > 0) { + uint64_t packed = packDeviceID(senderDeviceID, senderDevicePriority); + SERIALIZE_INT64(packed); + } + return offset; +} + +ssize_t WhoIsMasterRequestPacket::deserializePacket(const uint8_t* data, + uint32_t length) { + ssize_t offset = deserializeHeader(data, length); + if (offset > 0) { + uint64_t packed; + DESERIALIZE_INT64(packed); + senderDeviceID = unpackDeviceID(packed); + senderDevicePriority = unpackDevicePriority(packed); + } + return offset; +} + +ssize_t WhoIsMasterResponsePacket::serializePacket(uint8_t* data, + uint32_t length) { + ssize_t offset = serializeHeader(data, length); + if (offset > 0) { + uint64_t packed = packDeviceID(deviceID, devicePriority); + SERIALIZE_INT64(packed); + } + return offset; +} + +ssize_t WhoIsMasterResponsePacket::deserializePacket(const uint8_t* data, + uint32_t length) { + ssize_t offset = deserializeHeader(data, length); + if (offset > 0) { + uint64_t packed; + DESERIALIZE_INT64(packed); + deviceID = unpackDeviceID(packed); + devicePriority = unpackDevicePriority(packed); + } + return offset; +} + +ssize_t SyncRequestPacket::serializePacket(uint8_t* data, + uint32_t length) { + ssize_t offset = serializeHeader(data, length); + if (offset > 0) { + SERIALIZE_INT64(clientTxLocalTime); + } + return offset; +} + +ssize_t SyncRequestPacket::deserializePacket(const uint8_t* data, + uint32_t length) { + ssize_t offset = deserializeHeader(data, length); + if (offset > 0) { + DESERIALIZE_INT64(clientTxLocalTime); + } + return offset; +} + +ssize_t SyncResponsePacket::serializePacket(uint8_t* data, + uint32_t length) { + ssize_t offset = serializeHeader(data, length); + if (offset > 0) { + SERIALIZE_INT64(clientTxLocalTime); + SERIALIZE_INT64(masterRxCommonTime); + SERIALIZE_INT64(masterTxCommonTime); + SERIALIZE_INT32(nak); + } + return offset; +} + +ssize_t SyncResponsePacket::deserializePacket(const uint8_t* data, + uint32_t length) { + ssize_t offset = deserializeHeader(data, length); + if (offset > 0) { + DESERIALIZE_INT64(clientTxLocalTime); + DESERIALIZE_INT64(masterRxCommonTime); + DESERIALIZE_INT64(masterTxCommonTime); + DESERIALIZE_INT32(nak); + } + return offset; +} + +ssize_t MasterAnnouncementPacket::serializePacket(uint8_t* data, + uint32_t length) { + ssize_t offset = serializeHeader(data, length); + if (offset > 0) { + uint64_t packed = packDeviceID(deviceID, devicePriority); + SERIALIZE_INT64(packed); + } + return offset; +} + +ssize_t MasterAnnouncementPacket::deserializePacket(const uint8_t* data, + uint32_t length) { + ssize_t offset = deserializeHeader(data, length); + if (offset > 0) { + uint64_t packed; + DESERIALIZE_INT64(packed); + deviceID = unpackDeviceID(packed); + devicePriority = unpackDevicePriority(packed); + } + return offset; +} + +} // namespace android + diff --git a/services/common_time/common_time_server_packets.h b/services/common_time/common_time_server_packets.h new file mode 100644 index 000000000000..57ba8a256308 --- /dev/null +++ b/services/common_time/common_time_server_packets.h @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_COMMON_TIME_SERVER_PACKETS_H +#define ANDROID_COMMON_TIME_SERVER_PACKETS_H + +#include <stdint.h> +#include <common_time/ICommonClock.h> + +namespace android { + +/***** time sync protocol packets *****/ + +enum TimeServicePacketType { + TIME_PACKET_WHO_IS_MASTER_REQUEST = 1, + TIME_PACKET_WHO_IS_MASTER_RESPONSE, + TIME_PACKET_SYNC_REQUEST, + TIME_PACKET_SYNC_RESPONSE, + TIME_PACKET_MASTER_ANNOUNCEMENT, +}; + +class TimeServicePacketHeader { + public: + friend class UniversalTimeServicePacket; + // magic number identifying the protocol + uint32_t magic; + + // protocol version of the packet + uint16_t version; + + // type of the packet + TimeServicePacketType packetType; + + // the timeline ID + uint64_t timelineID; + + // synchronization group this packet belongs to (used to operate multiple + // synchronization domains which all use the same master election endpoint) + uint64_t syncGroupID; + + ssize_t serializePacket(uint8_t* data, uint32_t length); + + protected: + void initHeader(TimeServicePacketType type, + const uint64_t tlID, + const uint64_t groupID) { + magic = kMagic; + version = kCurVersion; + packetType = type; + timelineID = tlID; + syncGroupID = groupID; + } + + bool checkPacket(uint64_t expectedSyncGroupID) const { + return ((magic == kMagic) && + (version == kCurVersion) && + (!expectedSyncGroupID || (syncGroupID == expectedSyncGroupID))); + } + + ssize_t serializeHeader(uint8_t* data, uint32_t length); + ssize_t deserializeHeader(const uint8_t* data, uint32_t length); + + private: + static const uint32_t kMagic; + static const uint16_t kCurVersion; +}; + +// packet querying for a suitable master +class WhoIsMasterRequestPacket : public TimeServicePacketHeader { + public: + uint64_t senderDeviceID; + uint8_t senderDevicePriority; + + void initHeader(const uint64_t groupID) { + TimeServicePacketHeader::initHeader(TIME_PACKET_WHO_IS_MASTER_REQUEST, + ICommonClock::kInvalidTimelineID, + groupID); + } + + ssize_t serializePacket(uint8_t* data, uint32_t length); + ssize_t deserializePacket(const uint8_t* data, uint32_t length); +}; + +// response to a WhoIsMaster request +class WhoIsMasterResponsePacket : public TimeServicePacketHeader { + public: + uint64_t deviceID; + uint8_t devicePriority; + + void initHeader(const uint64_t tlID, const uint64_t groupID) { + TimeServicePacketHeader::initHeader(TIME_PACKET_WHO_IS_MASTER_RESPONSE, + tlID, groupID); + } + + ssize_t serializePacket(uint8_t* data, uint32_t length); + ssize_t deserializePacket(const uint8_t* data, uint32_t length); +}; + +// packet sent by a client requesting correspondence between local +// and common time +class SyncRequestPacket : public TimeServicePacketHeader { + public: + // local time when this request was transmitted + int64_t clientTxLocalTime; + + void initHeader(const uint64_t tlID, const uint64_t groupID) { + TimeServicePacketHeader::initHeader(TIME_PACKET_SYNC_REQUEST, + tlID, groupID); + } + + ssize_t serializePacket(uint8_t* data, uint32_t length); + ssize_t deserializePacket(const uint8_t* data, uint32_t length); +}; + +// response to a sync request sent by the master +class SyncResponsePacket : public TimeServicePacketHeader { + public: + // local time when this request was transmitted by the client + int64_t clientTxLocalTime; + + // common time when the master received the request + int64_t masterRxCommonTime; + + // common time when the master transmitted the response + int64_t masterTxCommonTime; + + // flag that is set if the recipient of the sync request is not acting + // as a master for the requested timeline + uint32_t nak; + + void initHeader(const uint64_t tlID, const uint64_t groupID) { + TimeServicePacketHeader::initHeader(TIME_PACKET_SYNC_RESPONSE, + tlID, groupID); + } + + ssize_t serializePacket(uint8_t* data, uint32_t length); + ssize_t deserializePacket(const uint8_t* data, uint32_t length); +}; + +// announcement of the master's presence +class MasterAnnouncementPacket : public TimeServicePacketHeader { + public: + // the master's device ID + uint64_t deviceID; + uint8_t devicePriority; + + void initHeader(const uint64_t tlID, const uint64_t groupID) { + TimeServicePacketHeader::initHeader(TIME_PACKET_MASTER_ANNOUNCEMENT, + tlID, groupID); + } + + ssize_t serializePacket(uint8_t* data, uint32_t length); + ssize_t deserializePacket(const uint8_t* data, uint32_t length); +}; + +class UniversalTimeServicePacket { + public: + uint16_t packetType; + union { + WhoIsMasterRequestPacket who_is_master_request; + WhoIsMasterResponsePacket who_is_master_response; + SyncRequestPacket sync_request; + SyncResponsePacket sync_response; + MasterAnnouncementPacket master_announcement; + } p; + + ssize_t deserializePacket(const uint8_t* data, + uint32_t length, + uint64_t expectedSyncGroupID); +}; + +}; // namespace android + +#endif // ANDROID_COMMON_TIME_SERVER_PACKETS_H + + diff --git a/services/common_time/diag_thread.cpp b/services/common_time/diag_thread.cpp new file mode 100644 index 000000000000..4cb955131099 --- /dev/null +++ b/services/common_time/diag_thread.cpp @@ -0,0 +1,323 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "common_time" +#include <utils/Log.h> + +#include <fcntl.h> +#include <linux/in.h> +#include <linux/tcp.h> +#include <poll.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <unistd.h> +#include <utils/Errors.h> +#include <utils/misc.h> + +#include <common_time/local_clock.h> + +#include "common_clock.h" +#include "diag_thread.h" + +#define kMaxEvents 16 +#define kListenPort 9876 + +static bool setNonblocking(int fd) { + int flags = fcntl(fd, F_GETFL); + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) { + ALOGE("Failed to set socket (%d) to non-blocking mode (errno %d)", + fd, errno); + return false; + } + + return true; +} + +static bool setNodelay(int fd) { + int tmp = 1; + if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &tmp, sizeof(tmp)) < 0) { + ALOGE("Failed to set socket (%d) to no-delay mode (errno %d)", + fd, errno); + return false; + } + + return true; +} + +namespace android { + +DiagThread::DiagThread(CommonClock* common_clock, LocalClock* local_clock) { + common_clock_ = common_clock; + local_clock_ = local_clock; + listen_fd_ = -1; + data_fd_ = -1; + kernel_logID_basis_known_ = false; + discipline_log_ID_ = 0; +} + +DiagThread::~DiagThread() { +} + +status_t DiagThread::startWorkThread() { + status_t res; + stopWorkThread(); + res = run("Diag"); + + if (res != OK) + ALOGE("Failed to start work thread (res = %d)", res); + + return res; +} + +void DiagThread::stopWorkThread() { + status_t res; + res = requestExitAndWait(); // block until thread exit. + if (res != OK) + ALOGE("Failed to stop work thread (res = %d)", res); +} + +bool DiagThread::openListenSocket() { + bool ret = false; + int flags; + cleanupListenSocket(); + + if ((listen_fd_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { + ALOGE("Socket failed."); + goto bailout; + } + + // Set non-blocking operation + if (!setNonblocking(listen_fd_)) + goto bailout; + + struct sockaddr_in addr; + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + addr.sin_port = htons(kListenPort); + + if (bind(listen_fd_, (struct sockaddr*)&addr, sizeof(addr)) < 0) { + ALOGE("Bind failed."); + goto bailout; + } + + if (listen(listen_fd_, 1) < 0) { + ALOGE("Listen failed."); + goto bailout; + } + + ret = true; +bailout: + if (!ret) + cleanupListenSocket(); + + return ret; +} + +void DiagThread::cleanupListenSocket() { + if (listen_fd_ >= 0) { + int res; + + struct linger l; + l.l_onoff = 1; + l.l_linger = 0; + + setsockopt(listen_fd_, SOL_SOCKET, SO_LINGER, &l, sizeof(l)); + shutdown(listen_fd_, SHUT_RDWR); + close(listen_fd_); + listen_fd_ = -1; + } +} + +void DiagThread::cleanupDataSocket() { + if (data_fd_ >= 0) { + int res; + + struct linger l; + l.l_onoff = 1; + l.l_linger = 0; + + setsockopt(data_fd_, SOL_SOCKET, SO_LINGER, &l, sizeof(l)); + shutdown(data_fd_, SHUT_RDWR); + close(data_fd_); + data_fd_ = -1; + } +} + +void DiagThread::resetLogIDs() { + // Drain and discard all of the events from the kernel + struct local_time_debug_event events[kMaxEvents]; + while(local_clock_->getDebugLog(events, kMaxEvents) > 0) + ; + + { + Mutex::Autolock lock(&discipline_log_lock_); + discipline_log_.clear(); + discipline_log_ID_ = 0; + } + + kernel_logID_basis_known_ = false; +} + +void DiagThread::pushDisciplineEvent(int64_t observed_local_time, + int64_t observed_common_time, + int64_t nominal_common_time, + int32_t total_correction, + int32_t rtt) { + Mutex::Autolock lock(&discipline_log_lock_); + + DisciplineEventRecord evt; + + evt.event_id = discipline_log_ID_++; + + evt.action_local_time = local_clock_->getLocalTime(); + common_clock_->localToCommon(evt.action_local_time, + &evt.action_common_time); + + evt.observed_local_time = observed_local_time; + evt.observed_common_time = observed_common_time; + evt.nominal_common_time = nominal_common_time; + evt.total_correction = total_correction; + evt.rtt = rtt; + + discipline_log_.push_back(evt); + while (discipline_log_.size() > kMaxDisciplineLogSize) + discipline_log_.erase(discipline_log_.begin()); +} + +bool DiagThread::threadLoop() { + struct pollfd poll_fds[1]; + + if (!openListenSocket()) { + ALOGE("Failed to open listen socket"); + goto bailout; + } + + while (!exitPending()) { + memset(&poll_fds, 0, sizeof(poll_fds)); + + if (data_fd_ < 0) { + poll_fds[0].fd = listen_fd_; + poll_fds[0].events = POLLIN; + } else { + poll_fds[0].fd = data_fd_; + poll_fds[0].events = POLLRDHUP | POLLIN; + } + + int poll_res = poll(poll_fds, NELEM(poll_fds), 50); + if (poll_res < 0) { + ALOGE("Fatal error (%d,%d) while waiting on events", + poll_res, errno); + goto bailout; + } + + if (exitPending()) + break; + + if (poll_fds[0].revents) { + if (poll_fds[0].fd == listen_fd_) { + data_fd_ = accept(listen_fd_, NULL, NULL); + + if (data_fd_ < 0) { + ALOGW("Failed accept on socket %d with err %d", + listen_fd_, errno); + } else { + if (!setNonblocking(data_fd_)) + cleanupDataSocket(); + if (!setNodelay(data_fd_)) + cleanupDataSocket(); + } + } else + if (poll_fds[0].fd == data_fd_) { + if (poll_fds[0].revents & POLLRDHUP) { + // Connection hung up; time to clean up. + cleanupDataSocket(); + } else + if (poll_fds[0].revents & POLLIN) { + uint8_t cmd; + if (read(data_fd_, &cmd, sizeof(cmd)) > 0) { + switch(cmd) { + case 'r': + case 'R': + resetLogIDs(); + break; + } + } + } + } + } + + struct local_time_debug_event events[kMaxEvents]; + int amt = local_clock_->getDebugLog(events, kMaxEvents); + + if (amt > 0) { + for (int i = 0; i < amt; i++) { + struct local_time_debug_event& e = events[i]; + + if (!kernel_logID_basis_known_) { + kernel_logID_basis_ = e.local_timesync_event_id; + kernel_logID_basis_known_ = true; + } + + char buf[1024]; + int64_t common_time; + status_t res = common_clock_->localToCommon(e.local_time, + &common_time); + snprintf(buf, sizeof(buf), "E,%lld,%lld,%lld,%d\n", + e.local_timesync_event_id - kernel_logID_basis_, + e.local_time, + common_time, + (OK == res) ? 1 : 0); + buf[sizeof(buf) - 1] = 0; + + if (data_fd_ >= 0) + write(data_fd_, buf, strlen(buf)); + } + } + + { // scope for autolock pattern + Mutex::Autolock lock(&discipline_log_lock_); + + while (discipline_log_.size() > 0) { + char buf[1024]; + DisciplineEventRecord& e = *discipline_log_.begin(); + snprintf(buf, sizeof(buf), + "D,%lld,%lld,%lld,%lld,%lld,%lld,%d,%d\n", + e.event_id, + e.action_local_time, + e.action_common_time, + e.observed_local_time, + e.observed_common_time, + e.nominal_common_time, + e.total_correction, + e.rtt); + buf[sizeof(buf) - 1] = 0; + + if (data_fd_ >= 0) + write(data_fd_, buf, strlen(buf)); + + discipline_log_.erase(discipline_log_.begin()); + } + } + } + +bailout: + cleanupDataSocket(); + cleanupListenSocket(); + return false; +} + +} // namespace android diff --git a/services/common_time/diag_thread.h b/services/common_time/diag_thread.h new file mode 100644 index 000000000000..c630e0d9b525 --- /dev/null +++ b/services/common_time/diag_thread.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __DIAG_THREAD_H__ +#define __DIAG_THREAD_H__ + +#include <utils/List.h> +#include <utils/threads.h> + +namespace android { + +class CommonClock; +class LocalClock; + +class DiagThread : public Thread { + public: + DiagThread(CommonClock* common_clock, LocalClock* local_clock); + ~DiagThread(); + + status_t startWorkThread(); + void stopWorkThread(); + virtual bool threadLoop(); + + void pushDisciplineEvent(int64_t observed_local_time, + int64_t observed_common_time, + int64_t nominal_common_time, + int32_t total_correction, + int32_t rtt); + + private: + typedef struct { + int64_t event_id; + int64_t action_local_time; + int64_t action_common_time; + int64_t observed_local_time; + int64_t observed_common_time; + int64_t nominal_common_time; + int32_t total_correction; + int32_t rtt; + } DisciplineEventRecord; + + bool openListenSocket(); + void cleanupListenSocket(); + void cleanupDataSocket(); + void resetLogIDs(); + + CommonClock* common_clock_; + LocalClock* local_clock_; + int listen_fd_; + int data_fd_; + + int64_t kernel_logID_basis_; + bool kernel_logID_basis_known_; + + static const size_t kMaxDisciplineLogSize = 16; + Mutex discipline_log_lock_; + List<DisciplineEventRecord> discipline_log_; + int64_t discipline_log_ID_; +}; + +} // namespace android + +#endif //__ DIAG_THREAD_H__ diff --git a/services/common_time/main.cpp b/services/common_time/main.cpp new file mode 100644 index 000000000000..49eb30abab66 --- /dev/null +++ b/services/common_time/main.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * A service that exchanges time synchronization information between + * a master that defines a timeline and clients that follow the timeline. + */ + +#define LOG_TAG "common_time" +#include <utils/Log.h> + +#include <binder/IPCThreadState.h> +#include <binder/ProcessState.h> + +#include "common_time_server.h" + +int main(int argc, char *argv[]) { + using namespace android; + + sp<CommonTimeServer> service = new CommonTimeServer(); + if (service == NULL) + return 1; + + ProcessState::self()->startThreadPool(); + service->run("CommonTimeServer", ANDROID_PRIORITY_NORMAL); + + IPCThreadState::self()->joinThreadPool(); + return 0; +} + diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp index 296c95ec937e..1b74aa6340f4 100644 --- a/services/input/EventHub.cpp +++ b/services/input/EventHub.cpp @@ -36,9 +36,9 @@ #include <errno.h> #include <assert.h> -#include <ui/KeyLayoutMap.h> -#include <ui/KeyCharacterMap.h> -#include <ui/VirtualKeyMap.h> +#include <androidfw/KeyLayoutMap.h> +#include <androidfw/KeyCharacterMap.h> +#include <androidfw/VirtualKeyMap.h> #include <string.h> #include <stdint.h> diff --git a/services/input/EventHub.h b/services/input/EventHub.h index 8a2afd32fcf0..4eb47c65dbe1 100644 --- a/services/input/EventHub.h +++ b/services/input/EventHub.h @@ -18,11 +18,11 @@ #ifndef _RUNTIME_EVENT_HUB_H #define _RUNTIME_EVENT_HUB_H -#include <ui/Input.h> -#include <ui/Keyboard.h> -#include <ui/KeyLayoutMap.h> -#include <ui/KeyCharacterMap.h> -#include <ui/VirtualKeyMap.h> +#include <androidfw/Input.h> +#include <androidfw/Keyboard.h> +#include <androidfw/KeyLayoutMap.h> +#include <androidfw/KeyCharacterMap.h> +#include <androidfw/VirtualKeyMap.h> #include <utils/String8.h> #include <utils/threads.h> #include <utils/Log.h> diff --git a/services/input/InputApplication.h b/services/input/InputApplication.h index 67ae94b70573..c04a93590326 100644 --- a/services/input/InputApplication.h +++ b/services/input/InputApplication.h @@ -17,7 +17,7 @@ #ifndef _UI_INPUT_APPLICATION_H #define _UI_INPUT_APPLICATION_H -#include <ui/Input.h> +#include <androidfw/Input.h> #include <utils/RefBase.h> #include <utils/Timers.h> diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp index d4e59d1b46c8..149c0d37d76b 100644 --- a/services/input/InputDispatcher.cpp +++ b/services/input/InputDispatcher.cpp @@ -45,7 +45,7 @@ #include "InputDispatcher.h" #include <cutils/log.h> -#include <ui/PowerManager.h> +#include <androidfw/PowerManager.h> #include <stddef.h> #include <unistd.h> @@ -3105,7 +3105,7 @@ status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChan sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor); - int32_t fd = inputChannel->getFd(); + int fd = inputChannel->getFd(); mConnectionsByFd.add(fd, connection); if (monitor) { diff --git a/services/input/InputDispatcher.h b/services/input/InputDispatcher.h index 5c517f5163c2..4b36480a27dd 100644 --- a/services/input/InputDispatcher.h +++ b/services/input/InputDispatcher.h @@ -17,8 +17,8 @@ #ifndef _UI_INPUT_DISPATCHER_H #define _UI_INPUT_DISPATCHER_H -#include <ui/Input.h> -#include <ui/InputTransport.h> +#include <androidfw/Input.h> +#include <androidfw/InputTransport.h> #include <utils/KeyedVector.h> #include <utils/Vector.h> #include <utils/threads.h> diff --git a/services/input/InputListener.h b/services/input/InputListener.h index f920cd1f6b78..b1dc0b888445 100644 --- a/services/input/InputListener.h +++ b/services/input/InputListener.h @@ -17,7 +17,7 @@ #ifndef _UI_INPUT_LISTENER_H #define _UI_INPUT_LISTENER_H -#include <ui/Input.h> +#include <androidfw/Input.h> #include <utils/RefBase.h> #include <utils/Vector.h> diff --git a/services/input/InputManager.h b/services/input/InputManager.h index df4d299ed3b3..29584c91da66 100644 --- a/services/input/InputManager.h +++ b/services/input/InputManager.h @@ -25,8 +25,8 @@ #include "InputReader.h" #include "InputDispatcher.h" -#include <ui/Input.h> -#include <ui/InputTransport.h> +#include <androidfw/Input.h> +#include <androidfw/InputTransport.h> #include <utils/Errors.h> #include <utils/Vector.h> #include <utils/Timers.h> diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp index 4be06e43d112..eccce292056d 100644 --- a/services/input/InputReader.cpp +++ b/services/input/InputReader.cpp @@ -39,8 +39,8 @@ #include "InputReader.h" #include <cutils/log.h> -#include <ui/Keyboard.h> -#include <ui/VirtualKeyMap.h> +#include <androidfw/Keyboard.h> +#include <androidfw/VirtualKeyMap.h> #include <stddef.h> #include <stdlib.h> diff --git a/services/input/InputReader.h b/services/input/InputReader.h index ad89a222293e..9bbe49ceca81 100644 --- a/services/input/InputReader.h +++ b/services/input/InputReader.h @@ -21,7 +21,7 @@ #include "PointerController.h" #include "InputListener.h" -#include <ui/Input.h> +#include <androidfw/Input.h> #include <ui/DisplayInfo.h> #include <utils/KeyedVector.h> #include <utils/threads.h> diff --git a/services/input/InputWindow.h b/services/input/InputWindow.h index 38968f91cf58..824a64b05b85 100644 --- a/services/input/InputWindow.h +++ b/services/input/InputWindow.h @@ -17,8 +17,8 @@ #ifndef _UI_INPUT_WINDOW_H #define _UI_INPUT_WINDOW_H -#include <ui/Input.h> -#include <ui/InputTransport.h> +#include <androidfw/Input.h> +#include <androidfw/InputTransport.h> #include <utils/RefBase.h> #include <utils/Timers.h> #include <utils/String8.h> diff --git a/services/input/PointerController.h b/services/input/PointerController.h index 700ef7295fe7..39dbf6b9e9bf 100644 --- a/services/input/PointerController.h +++ b/services/input/PointerController.h @@ -20,7 +20,7 @@ #include "SpriteController.h" #include <ui/DisplayInfo.h> -#include <ui/Input.h> +#include <androidfw/Input.h> #include <utils/RefBase.h> #include <utils/Looper.h> #include <utils/String8.h> diff --git a/services/java/com/android/server/AppWidgetServiceImpl.java b/services/java/com/android/server/AppWidgetServiceImpl.java index 41ede2e4b608..9c408c40826b 100644 --- a/services/java/com/android/server/AppWidgetServiceImpl.java +++ b/services/java/com/android/server/AppWidgetServiceImpl.java @@ -463,7 +463,7 @@ class AppWidgetServiceImpl { Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DELETED); intent.setComponent(p.info.provider); intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, id.appWidgetId); - mContext.sendBroadcast(intent); + mContext.sendBroadcast(intent, mUserId); if (p.instances.size() == 0) { // cancel the future updates cancelBroadcasts(p); @@ -471,7 +471,7 @@ class AppWidgetServiceImpl { // send the broacast saying that the provider is not in use any more intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DISABLED); intent.setComponent(p.info.provider); - mContext.sendBroadcast(intent); + mContext.sendBroadcast(intent, mUserId); } } } @@ -515,8 +515,6 @@ class AppWidgetServiceImpl { + " safe mode: " + provider); } - Binder.restoreCallingIdentity(ident); - id.provider = p; p.instances.add(id); int instancesSize = p.instances.size(); @@ -1066,7 +1064,7 @@ class AppWidgetServiceImpl { void sendEnableIntentLocked(Provider p) { Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_ENABLED); intent.setComponent(p.info.provider); - mContext.sendBroadcast(intent); + mContext.sendBroadcast(intent, mUserId); } void sendUpdateIntentLocked(Provider p, int[] appWidgetIds) { @@ -1074,7 +1072,7 @@ class AppWidgetServiceImpl { Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds); intent.setComponent(p.info.provider); - mContext.sendBroadcast(intent); + mContext.sendBroadcast(intent, mUserId); } } @@ -1477,12 +1475,11 @@ class AppWidgetServiceImpl { } AtomicFile savedStateFile() { - int userId = UserId.getCallingUserId(); - File dir = new File("/data/system/users/" + userId); + File dir = new File("/data/system/users/" + mUserId); File settingsFile = new File(dir, SETTINGS_FILENAME); if (!dir.exists()) { dir.mkdirs(); - if (userId == 0) { + if (mUserId == 0) { // Migrate old data File oldFile = new File("/data/system/" + SETTINGS_FILENAME); // Method doesn't throw an exception on failure. Ignore any errors diff --git a/services/java/com/android/server/CommonTimeManagementService.java b/services/java/com/android/server/CommonTimeManagementService.java new file mode 100644 index 000000000000..9a25d2ea5f39 --- /dev/null +++ b/services/java/com/android/server/CommonTimeManagementService.java @@ -0,0 +1,377 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.net.InetAddress; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.net.ConnectivityManager; +import android.net.IConnectivityManager; +import android.net.INetworkManagementEventObserver; +import android.net.InterfaceConfiguration; +import android.net.NetworkInfo; +import android.os.Binder; +import android.os.CommonTimeConfig; +import android.os.Handler; +import android.os.IBinder; +import android.os.INetworkManagementService; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.os.SystemProperties; +import android.util.Log; + +/** + * @hide + * <p>CommonTimeManagementService manages the configuration of the native Common Time service, + * reconfiguring the native service as appropriate in response to changes in network configuration. + */ +class CommonTimeManagementService extends Binder { + /* + * Constants and globals. + */ + private static final String TAG = CommonTimeManagementService.class.getSimpleName(); + private static final int NATIVE_SERVICE_RECONNECT_TIMEOUT = 5000; + private static final String AUTO_DISABLE_PROP = "ro.common_time.auto_disable"; + private static final String ALLOW_WIFI_PROP = "ro.common_time.allow_wifi"; + private static final String SERVER_PRIO_PROP = "ro.common_time.server_prio"; + private static final String NO_INTERFACE_TIMEOUT_PROP = "ro.common_time.no_iface_timeout"; + private static final boolean AUTO_DISABLE; + private static final boolean ALLOW_WIFI; + private static final byte BASE_SERVER_PRIO; + private static final int NO_INTERFACE_TIMEOUT; + private static final InterfaceScoreRule[] IFACE_SCORE_RULES; + + static { + int tmp; + AUTO_DISABLE = (0 != SystemProperties.getInt(AUTO_DISABLE_PROP, 1)); + ALLOW_WIFI = (0 != SystemProperties.getInt(ALLOW_WIFI_PROP, 0)); + tmp = SystemProperties.getInt(SERVER_PRIO_PROP, 1); + NO_INTERFACE_TIMEOUT = SystemProperties.getInt(NO_INTERFACE_TIMEOUT_PROP, 60000); + + if (tmp < 1) + BASE_SERVER_PRIO = 1; + else + if (tmp > 30) + BASE_SERVER_PRIO = 30; + else + BASE_SERVER_PRIO = (byte)tmp; + + if (ALLOW_WIFI) { + IFACE_SCORE_RULES = new InterfaceScoreRule[] { + new InterfaceScoreRule("wlan", (byte)1), + new InterfaceScoreRule("eth", (byte)2), + }; + } else { + IFACE_SCORE_RULES = new InterfaceScoreRule[] { + new InterfaceScoreRule("eth", (byte)2), + }; + } + }; + + /* + * Internal state + */ + private final Context mContext; + private INetworkManagementService mNetMgr; + private CommonTimeConfig mCTConfig; + private String mCurIface; + private Handler mReconnectHandler = new Handler(); + private Handler mNoInterfaceHandler = new Handler(); + private Object mLock = new Object(); + private boolean mDetectedAtStartup = false; + private byte mEffectivePrio = BASE_SERVER_PRIO; + + /* + * Callback handler implementations. + */ + private INetworkManagementEventObserver mIfaceObserver = + new INetworkManagementEventObserver.Stub() { + + public void interfaceStatusChanged(String iface, boolean up) { + reevaluateServiceState(); + } + public void interfaceLinkStateChanged(String iface, boolean up) { + reevaluateServiceState(); + } + public void interfaceAdded(String iface) { + reevaluateServiceState(); + } + public void interfaceRemoved(String iface) { + reevaluateServiceState(); + } + public void limitReached(String limitName, String iface) { } + }; + + private BroadcastReceiver mConnectivityMangerObserver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + reevaluateServiceState(); + } + }; + + private CommonTimeConfig.OnServerDiedListener mCTServerDiedListener = + new CommonTimeConfig.OnServerDiedListener() { + public void onServerDied() { + scheduleTimeConfigReconnect(); + } + }; + + private Runnable mReconnectRunnable = new Runnable() { + public void run() { connectToTimeConfig(); } + }; + + private Runnable mNoInterfaceRunnable = new Runnable() { + public void run() { handleNoInterfaceTimeout(); } + }; + + /* + * Public interface (constructor, systemReady and dump) + */ + public CommonTimeManagementService(Context context) { + mContext = context; + } + + void systemReady() { + if (ServiceManager.checkService(CommonTimeConfig.SERVICE_NAME) == null) { + Log.i(TAG, "No common time service detected on this platform. " + + "Common time services will be unavailable."); + return; + } + + mDetectedAtStartup = true; + + IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); + mNetMgr = INetworkManagementService.Stub.asInterface(b); + + // Network manager is running along-side us, so we should never receiver a remote exception + // while trying to register this observer. + try { + mNetMgr.registerObserver(mIfaceObserver); + } + catch (RemoteException e) { } + + // Register with the connectivity manager for connectivity changed intents. + IntentFilter filter = new IntentFilter(); + filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); + mContext.registerReceiver(mConnectivityMangerObserver, filter); + + // Connect to the common time config service and apply the initial configuration. + connectToTimeConfig(); + } + + @Override + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) + != PackageManager.PERMISSION_GRANTED) { + pw.println(String.format( + "Permission Denial: can't dump CommonTimeManagement service from from " + + "pid=%d, uid=%d", Binder.getCallingPid(), Binder.getCallingUid())); + return; + } + + if (!mDetectedAtStartup) { + pw.println("Native Common Time service was not detected at startup. " + + "Service is unavailable"); + return; + } + + synchronized (mLock) { + pw.println("Current Common Time Management Service Config:"); + pw.println(String.format(" Native service : %s", + (null == mCTConfig) ? "reconnecting" + : "alive")); + pw.println(String.format(" Bound interface : %s", + (null == mCurIface ? "unbound" : mCurIface))); + pw.println(String.format(" Allow WiFi : %s", ALLOW_WIFI ? "yes" : "no")); + pw.println(String.format(" Allow Auto Disable : %s", AUTO_DISABLE ? "yes" : "no")); + pw.println(String.format(" Server Priority : %d", mEffectivePrio)); + pw.println(String.format(" No iface timeout : %d", NO_INTERFACE_TIMEOUT)); + } + } + + /* + * Inner helper classes + */ + private static class InterfaceScoreRule { + public final String mPrefix; + public final byte mScore; + public InterfaceScoreRule(String prefix, byte score) { + mPrefix = prefix; + mScore = score; + } + }; + + /* + * Internal implementation + */ + private void cleanupTimeConfig() { + mReconnectHandler.removeCallbacks(mReconnectRunnable); + mNoInterfaceHandler.removeCallbacks(mNoInterfaceRunnable); + if (null != mCTConfig) { + mCTConfig.release(); + mCTConfig = null; + } + } + + private void connectToTimeConfig() { + // Get access to the common time service configuration interface. If we catch a remote + // exception in the process (service crashed or no running for w/e reason), schedule an + // attempt to reconnect in the future. + cleanupTimeConfig(); + try { + synchronized (mLock) { + mCTConfig = new CommonTimeConfig(); + mCTConfig.setServerDiedListener(mCTServerDiedListener); + mCurIface = mCTConfig.getInterfaceBinding(); + mCTConfig.setAutoDisable(AUTO_DISABLE); + mCTConfig.setMasterElectionPriority(mEffectivePrio); + } + + if (NO_INTERFACE_TIMEOUT >= 0) + mNoInterfaceHandler.postDelayed(mNoInterfaceRunnable, NO_INTERFACE_TIMEOUT); + + reevaluateServiceState(); + } + catch (RemoteException e) { + scheduleTimeConfigReconnect(); + } + } + + private void scheduleTimeConfigReconnect() { + cleanupTimeConfig(); + Log.w(TAG, String.format("Native service died, will reconnect in %d mSec", + NATIVE_SERVICE_RECONNECT_TIMEOUT)); + mReconnectHandler.postDelayed(mReconnectRunnable, + NATIVE_SERVICE_RECONNECT_TIMEOUT); + } + + private void handleNoInterfaceTimeout() { + if (null != mCTConfig) { + Log.i(TAG, "Timeout waiting for interface to come up. " + + "Forcing networkless master mode."); + if (CommonTimeConfig.ERROR_DEAD_OBJECT == mCTConfig.forceNetworklessMasterMode()) + scheduleTimeConfigReconnect(); + } + } + + private void reevaluateServiceState() { + String bindIface = null; + byte bestScore = -1; + try { + // Check to see if this interface is suitable to use for time synchronization. + // + // TODO : This selection algorithm needs to be enhanced for use with mobile devices. In + // particular, the choice of whether to a wireless interface or not should not be an all + // or nothing thing controlled by properties. It would probably be better if the + // platform had some concept of public wireless networks vs. home or friendly wireless + // networks (something a user would configure in settings or when a new interface is + // added). Then this algorithm could pick only wireless interfaces which were flagged + // as friendly, and be dormant when on public wireless networks. + // + // Another issue which needs to be dealt with is the use of driver supplied interface + // name to determine the network type. The fact that the wireless interface on a device + // is named "wlan0" is just a matter of convention; its not a 100% rule. For example, + // there are devices out there where the wireless is name "tiwlan0", not "wlan0". The + // internal network management interfaces in Android have all of the information needed + // to make a proper classification, there is just no way (currently) to fetch an + // interface's type (available from the ConnectionManager) as well as its address + // (available from either the java.net interfaces or from the NetworkManagment service). + // Both can enumerate interfaces, but that is no way to correlate their results (no + // common shared key; although using the interface name in the connection manager would + // be a good start). Until this gets resolved, we resort to substring searching for + // tags like wlan and eth. + // + String ifaceList[] = mNetMgr.listInterfaces(); + if (null != ifaceList) { + for (String iface : ifaceList) { + + byte thisScore = -1; + for (InterfaceScoreRule r : IFACE_SCORE_RULES) { + if (iface.contains(r.mPrefix)) { + thisScore = r.mScore; + break; + } + } + + if (thisScore <= bestScore) + continue; + + InterfaceConfiguration config = mNetMgr.getInterfaceConfig(iface); + if (null == config) + continue; + + if (config.isActive()) { + bindIface = iface; + bestScore = thisScore; + } + } + } + } + catch (RemoteException e) { + // Bad news; we should not be getting remote exceptions from the connectivity manager + // since it is running in SystemServer along side of us. It probably does not matter + // what we do here, but go ahead and unbind the common time service in this case, just + // so we have some defined behavior. + bindIface = null; + } + + boolean doRebind = true; + synchronized (mLock) { + if ((null != bindIface) && (null == mCurIface)) { + Log.e(TAG, String.format("Binding common time service to %s.", bindIface)); + mCurIface = bindIface; + } else + if ((null == bindIface) && (null != mCurIface)) { + Log.e(TAG, "Unbinding common time service."); + mCurIface = null; + } else + if ((null != bindIface) && (null != mCurIface) && !bindIface.equals(mCurIface)) { + Log.e(TAG, String.format("Switching common time service binding from %s to %s.", + mCurIface, bindIface)); + mCurIface = bindIface; + } else { + doRebind = false; + } + } + + if (doRebind && (null != mCTConfig)) { + byte newPrio = (bestScore > 0) + ? (byte)(bestScore * BASE_SERVER_PRIO) + : BASE_SERVER_PRIO; + if (newPrio != mEffectivePrio) { + mEffectivePrio = newPrio; + mCTConfig.setMasterElectionPriority(mEffectivePrio); + } + + int res = mCTConfig.setNetworkBinding(mCurIface); + if (res != CommonTimeConfig.SUCCESS) + scheduleTimeConfigReconnect(); + + else if (NO_INTERFACE_TIMEOUT >= 0) { + mNoInterfaceHandler.removeCallbacks(mNoInterfaceRunnable); + if (null == mCurIface) + mNoInterfaceHandler.postDelayed(mNoInterfaceRunnable, NO_INTERFACE_TIMEOUT); + } + } + } +} diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java index 34a8a027673e..b3eceb10864c 100755 --- a/services/java/com/android/server/NotificationManagerService.java +++ b/services/java/com/android/server/NotificationManagerService.java @@ -768,7 +768,9 @@ public class NotificationManagerService extends INotificationManager.Stub long identity = Binder.clearCallingIdentity(); try { r.statusBarKey = mStatusBar.addNotification(n); - mAttentionLight.pulse(); + if ((n.notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0) { + mAttentionLight.pulse(); + } } finally { Binder.restoreCallingIdentity(identity); diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java index e953355723b4..7b4372fec8da 100644 --- a/services/java/com/android/server/PowerManagerService.java +++ b/services/java/com/android/server/PowerManagerService.java @@ -583,6 +583,7 @@ public class PowerManagerService extends IPowerManager.Stub } nativeInit(); + Power.powerInitNative(); synchronized (mLocks) { updateNativePowerStateLocked(); // We make sure to start out with the screen on due to user activity. diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 0dbc7c367b46..c9b59975c32f 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -132,6 +132,7 @@ class ServerThread extends Thread { RecognitionManagerService recognition = null; ThrottleService throttle = null; NetworkTimeUpdateService networkTimeUpdater = null; + CommonTimeManagementService commonTimeMgmtService = null; // Critical services... try { @@ -575,6 +576,14 @@ class ServerThread extends Thread { } catch (Throwable e) { reportWtf("starting NetworkTimeUpdate service", e); } + + try { + Slog.i(TAG, "CommonTimeManagementService"); + commonTimeMgmtService = new CommonTimeManagementService(context); + ServiceManager.addService("commontime_management", commonTimeMgmtService); + } catch (Throwable e) { + reportWtf("starting CommonTimeManagementService service", e); + } } // Before things start rolling, be sure we have decided whether @@ -653,6 +662,7 @@ class ServerThread extends Thread { final LocationManagerService locationF = location; final CountryDetectorService countryDetectorF = countryDetector; final NetworkTimeUpdateService networkTimeUpdaterF = networkTimeUpdater; + final CommonTimeManagementService commonTimeMgmtServiceF = commonTimeMgmtService; final TextServicesManagerService textServiceManagerServiceF = tsms; final StatusBarManagerService statusBarF = statusBar; @@ -752,6 +762,11 @@ class ServerThread extends Thread { reportWtf("making Network Time Service ready", e); } try { + if (commonTimeMgmtServiceF != null) commonTimeMgmtServiceF.systemReady(); + } catch (Throwable e) { + reportWtf("making Common time management service ready", e); + } + try { if (textServiceManagerServiceF != null) textServiceManagerServiceF.systemReady(); } catch (Throwable e) { reportWtf("making Text Services Manager Service ready", e); diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index ac311b8130c9..8a5e7fc84a7b 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -138,7 +138,6 @@ import java.io.StringWriter; import java.lang.IllegalStateException; import java.lang.ref.WeakReference; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; @@ -2752,7 +2751,13 @@ public final class ActivityManagerService extends ActivityManagerNative } // Just in case... - mMainStack.appDiedLocked(app); + if (mMainStack.mPausingActivity != null && mMainStack.mPausingActivity.app == app) { + if (DEBUG_PAUSE) Slog.v(TAG, "App died while pausing: " +mMainStack.mPausingActivity); + mMainStack.mPausingActivity = null; + } + if (mMainStack.mLastPausedActivity != null && mMainStack.mLastPausedActivity.app == app) { + mMainStack.mLastPausedActivity = null; + } // Remove this application's activities from active lists. mMainStack.removeHistoryRecordsForAppLocked(app); @@ -5754,7 +5759,7 @@ public final class ActivityManagerService extends ActivityManagerNative ComponentName comp = new ComponentName(cpi.packageName, cpi.name); ContentProviderRecord cpr = mProviderMap.getProviderByClass(comp, userId); if (cpr == null) { - cpr = new ContentProviderRecord(cpi, app.info, comp); + cpr = new ContentProviderRecord(this, cpi, app.info, comp); mProviderMap.putProviderByClass(comp, cpr); } if (DEBUG_MU) @@ -5826,7 +5831,8 @@ public final class ActivityManagerService extends ActivityManagerNative return msg; } - boolean incProviderCount(ProcessRecord r, ContentProviderRecord cpr) { + boolean incProviderCount(ProcessRecord r, final ContentProviderRecord cpr, + IBinder externalProcessToken) { if (r != null) { Integer cnt = r.conProviders.get(cpr); if (DEBUG_PROVIDER) Slog.v(TAG, @@ -5842,12 +5848,13 @@ public final class ActivityManagerService extends ActivityManagerNative r.conProviders.put(cpr, new Integer(cnt.intValue()+1)); } } else { - cpr.externals++; + cpr.addExternalProcessHandleLocked(externalProcessToken); } return false; } - boolean decProviderCount(ProcessRecord r, ContentProviderRecord cpr) { + boolean decProviderCount(ProcessRecord r, final ContentProviderRecord cpr, + IBinder externalProcessToken) { if (r != null) { Integer cnt = r.conProviders.get(cpr); if (DEBUG_PROVIDER) Slog.v(TAG, @@ -5863,13 +5870,13 @@ public final class ActivityManagerService extends ActivityManagerNative r.conProviders.put(cpr, new Integer(cnt.intValue()-1)); } } else { - cpr.externals++; + cpr.removeExternalProcessHandleLocked(externalProcessToken); } return false; } private final ContentProviderHolder getContentProviderImpl(IApplicationThread caller, - String name) { + String name, IBinder token) { ContentProviderRecord cpr; ProviderInfo cpi = null; @@ -5913,7 +5920,7 @@ public final class ActivityManagerService extends ActivityManagerNative // In this case the provider instance already exists, so we can // return it right away. - final boolean countChanged = incProviderCount(r, cpr); + final boolean countChanged = incProviderCount(r, cpr, token); if (countChanged) { if (cpr.proc != null && r.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) { // If this is a perceptible app accessing the provider, @@ -5947,7 +5954,7 @@ public final class ActivityManagerService extends ActivityManagerNative Slog.i(TAG, "Existing provider " + cpr.name.flattenToShortString() + " is crashing; detaching " + r); - boolean lastRef = decProviderCount(r, cpr); + boolean lastRef = decProviderCount(r, cpr, token); appDiedLocked(cpr.proc, cpr.proc.pid, cpr.proc.thread); if (!lastRef) { // This wasn't the last ref our process had on @@ -6005,7 +6012,7 @@ public final class ActivityManagerService extends ActivityManagerNative return null; } ai = getAppInfoForUser(ai, Binder.getOrigCallingUser()); - cpr = new ContentProviderRecord(cpi, ai, comp); + cpr = new ContentProviderRecord(this, cpi, ai, comp); } catch (RemoteException ex) { // pm is in same process, this will never happen. } @@ -6075,8 +6082,9 @@ public final class ActivityManagerService extends ActivityManagerNative if (firstClass) { mProviderMap.putProviderByClass(comp, cpr); } + mProviderMap.putProviderByName(name, cpr); - incProviderCount(r, cpr); + incProviderCount(r, cpr, token); } } @@ -6116,12 +6124,17 @@ public final class ActivityManagerService extends ActivityManagerNative throw new SecurityException(msg); } - ContentProviderHolder contentProvider = getContentProviderImpl(caller, name); - return contentProvider; + return getContentProviderImpl(caller, name, null); } - private ContentProviderHolder getContentProviderExternal(String name) { - return getContentProviderImpl(null, name); + public ContentProviderHolder getContentProviderExternal(String name, IBinder token) { + enforceCallingPermission(android.Manifest.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY, + "Do not have permission in call getContentProviderExternal()"); + return getContentProviderExternalUnchecked(name, token); + } + + private ContentProviderHolder getContentProviderExternalUnchecked(String name,IBinder token) { + return getContentProviderImpl(null, name, token); } /** @@ -6157,14 +6170,20 @@ public final class ActivityManagerService extends ActivityManagerNative + cpr.info.name + " in process " + r.processName); return; } else { - if (decProviderCount(r, localCpr)) { + if (decProviderCount(r, localCpr, null)) { updateOomAdjLocked(); } } } } - private void removeContentProviderExternal(String name) { + public void removeContentProviderExternal(String name, IBinder token) { + enforceCallingPermission(android.Manifest.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY, + "Do not have permission in call removeContentProviderExternal()"); + removeContentProviderExternalUnchecked(name, token); + } + + private void removeContentProviderExternalUnchecked(String name, IBinder token) { synchronized (this) { ContentProviderRecord cpr = mProviderMap.getProviderByName(name, Binder.getOrigCallingUser()); @@ -6178,11 +6197,18 @@ public final class ActivityManagerService extends ActivityManagerNative ComponentName comp = new ComponentName(cpr.info.packageName, cpr.info.name); ContentProviderRecord localCpr = mProviderMap.getProviderByClass(comp, Binder.getOrigCallingUser()); - localCpr.externals--; - if (localCpr.externals < 0) { - Slog.e(TAG, "Externals < 0 for content provider " + localCpr); + if (localCpr.hasExternalProcessHandles()) { + if (localCpr.removeExternalProcessHandleLocked(token)) { + updateOomAdjLocked(); + } else { + Slog.e(TAG, "Attmpt to remove content provider " + localCpr + + " with no external reference for token: " + + token + "."); + } + } else { + Slog.e(TAG, "Attmpt to remove content provider: " + localCpr + + " with no external references."); } - updateOomAdjLocked(); } } @@ -6286,7 +6312,7 @@ public final class ActivityManagerService extends ActivityManagerNative ContentProviderHolder holder = null; try { - holder = getContentProviderExternal(name); + holder = getContentProviderExternalUnchecked(name, null); if (holder != null) { return holder.provider.getType(uri); } @@ -6295,7 +6321,7 @@ public final class ActivityManagerService extends ActivityManagerNative return null; } finally { if (holder != null) { - removeContentProviderExternal(name); + removeContentProviderExternalUnchecked(name, null); } Binder.restoreCallingIdentity(ident); } @@ -6400,7 +6426,7 @@ public final class ActivityManagerService extends ActivityManagerNative public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException { enforceNotIsolatedCaller("openContentUri"); String name = uri.getAuthority(); - ContentProviderHolder cph = getContentProviderExternal(name); + ContentProviderHolder cph = getContentProviderExternalUnchecked(name, null); ParcelFileDescriptor pfd = null; if (cph != null) { // We record the binder invoker's uid in thread-local storage before @@ -6422,7 +6448,7 @@ public final class ActivityManagerService extends ActivityManagerNative } // We've got the fd now, so we're done with the provider. - removeContentProviderExternal(name); + removeContentProviderExternalUnchecked(name, null); } else { Slog.d(TAG, "Failed to get provider for authority '" + name + "'"); } @@ -6467,7 +6493,7 @@ public final class ActivityManagerService extends ActivityManagerNative mMainStack.stopIfSleepingLocked(); final long endTime = System.currentTimeMillis() + timeout; while (mMainStack.mResumedActivity != null - || mMainStack.mPausingActivities.size() > 0) { + || mMainStack.mPausingActivity != null) { long delay = endTime - System.currentTimeMillis(); if (delay <= 0) { Slog.w(TAG, "Activity manager shutdown timed out"); @@ -6995,7 +7021,7 @@ public final class ActivityManagerService extends ActivityManagerNative /* TODO: Send this to all users */ broadcastIntentLocked(null, null, intent, null, finisher, 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID, - Process.SYSTEM_UID); + 0 /* UserId zero */); if (finisher != null) { mWaitingUpdate = true; } @@ -8274,13 +8300,8 @@ public final class ActivityManagerService extends ActivityManagerNative } pw.println(" "); - if (mMainStack.mPausingActivities.size() > 0) { - pw.println(" mPausingActivities: " + Arrays.toString( - mMainStack.mPausingActivities.toArray())); - } - if (mMainStack.mInputPausedActivities.size() > 0) { - pw.println(" mInputPausedActivities: " + Arrays.toString( - mMainStack.mInputPausedActivities.toArray())); + if (mMainStack.mPausingActivity != null) { + pw.println(" mPausingActivity: " + mMainStack.mPausingActivity); } pw.println(" mResumedActivity: " + mMainStack.mResumedActivity); pw.println(" mFocusedActivity: " + mFocusedActivity); @@ -10253,7 +10274,7 @@ public final class ActivityManagerService extends ActivityManagerNative for (int i=0; i<NL; i++) { ContentProviderRecord cpr = (ContentProviderRecord) mLaunchingProviders.get(i); - if (cpr.clients.size() <= 0 && cpr.externals <= 0) { + if (cpr.clients.size() <= 0 && !cpr.hasExternalProcessHandles()) { synchronized (cpr) { cpr.launchingApp = null; cpr.notifyAll(); @@ -13455,7 +13476,7 @@ public final class ActivityManagerService extends ActivityManagerNative // If the provider has external (non-framework) process // dependencies, ensure that its adjustment is at least // FOREGROUND_APP_ADJ. - if (cpr.externals != 0) { + if (cpr.hasExternalProcessHandles()) { if (adj > ProcessList.FOREGROUND_APP_ADJ) { adj = ProcessList.FOREGROUND_APP_ADJ; schedGroup = Process.THREAD_GROUP_DEFAULT; @@ -13855,13 +13876,7 @@ public final class ActivityManagerService extends ActivityManagerNative private final ActivityRecord resumedAppLocked() { ActivityRecord resumedActivity = mMainStack.mResumedActivity; if (resumedActivity == null || resumedActivity.app == null) { - for (int i=mMainStack.mPausingActivities.size()-1; i>=0; i--) { - ActivityRecord r = mMainStack.mPausingActivities.get(i); - if (r.app != null) { - resumedActivity = r; - break; - } - } + resumedActivity = mMainStack.mPausingActivity; if (resumedActivity == null || resumedActivity.app == null) { resumedActivity = mMainStack.topRunningActivityLocked(null); } diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java index 977ee8479709..cdab6c6f67b3 100644 --- a/services/java/com/android/server/am/ActivityRecord.java +++ b/services/java/com/android/server/am/ActivityRecord.java @@ -602,7 +602,6 @@ final class ActivityRecord { public void windowsDrawn() { synchronized(service) { - stack.reportActivityDrawnLocked(this); if (launchTime != 0) { final long curTime = SystemClock.uptimeMillis(); final long thisTime = curTime - launchTime; @@ -691,9 +690,7 @@ final class ActivityRecord { // Hmmm, who might we be waiting for? r = stack.mResumedActivity; if (r == null) { - if (stack.mPausingActivities.size() > 0) { - r = stack.mPausingActivities.get(stack.mPausingActivities.size()-1); - } + r = stack.mPausingActivity; } // Both of those null? Fall back to 'this' again if (r == null) { diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java index e8c8275f554a..7b8bc26e6e13 100644 --- a/services/java/com/android/server/am/ActivityStack.java +++ b/services/java/com/android/server/am/ActivityStack.java @@ -227,13 +227,7 @@ final class ActivityStack { * When we are in the process of pausing an activity, before starting the * next one, this variable holds the activity that is currently being paused. */ - final ArrayList<ActivityRecord> mPausingActivities = new ArrayList<ActivityRecord>(); - - /** - * These activities currently have their input paused, as they want for - * the next top activity to have its windows visible. - */ - final ArrayList<ActivityRecord> mInputPausedActivities = new ArrayList<ActivityRecord>(); + ActivityRecord mPausingActivity = null; /** * This is the last activity that we put into the paused state. This is @@ -813,9 +807,9 @@ final class ActivityStack { startPausingLocked(false, true); return; } - if (mPausingActivities.size() > 0) { + if (mPausingActivity != null) { // Still waiting for something to pause; can't sleep yet. - if (DEBUG_PAUSE) Slog.v(TAG, "Sleep still waiting to pause " + mPausingActivities); + if (DEBUG_PAUSE) Slog.v(TAG, "Sleep still waiting to pause " + mPausingActivity); return; } @@ -878,6 +872,11 @@ final class ActivityStack { } private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) { + if (mPausingActivity != null) { + RuntimeException e = new RuntimeException(); + Slog.e(TAG, "Trying to pause when pause is already pending for " + + mPausingActivity, e); + } ActivityRecord prev = mResumedActivity; if (prev == null) { RuntimeException e = new RuntimeException(); @@ -885,25 +884,19 @@ final class ActivityStack { resumeTopActivityLocked(null); return; } - if (mPausingActivities.contains(prev)) { - RuntimeException e = new RuntimeException(); - Slog.e(TAG, "Trying to pause when pause when already pausing " + prev, e); - } if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSING: " + prev); else if (DEBUG_PAUSE) Slog.v(TAG, "Start pausing: " + prev); mResumedActivity = null; - mPausingActivities.add(prev); + mPausingActivity = prev; mLastPausedActivity = prev; prev.state = ActivityState.PAUSING; prev.task.touchActiveTime(); prev.updateThumbnail(screenshotActivities(prev), null); mService.updateCpuStats(); - ActivityRecord pausing; if (prev.app != null && prev.app.thread != null) { if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending pause: " + prev); - pausing = prev; try { EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY, System.identityHashCode(prev), @@ -916,14 +909,12 @@ final class ActivityStack { } catch (Exception e) { // Ignore exception, if process died other code will cleanup. Slog.w(TAG, "Exception thrown during pause", e); - mPausingActivities.remove(prev); + mPausingActivity = null; mLastPausedActivity = null; - pausing = null; } } else { - mPausingActivities.remove(prev); + mPausingActivity = null; mLastPausedActivity = null; - pausing = null; } // If we are not going to sleep, we want to ensure the device is @@ -937,28 +928,18 @@ final class ActivityStack { } } - if (pausing != null) { + + if (mPausingActivity != null) { // Have the window manager pause its key dispatching until the new // activity has started. If we're pausing the activity just because // the screen is being turned off and the UI is sleeping, don't interrupt // key dispatch; the same activity will pick it up again on wakeup. if (!uiSleeping) { - pausing.pauseKeyDispatchingLocked(); - mInputPausedActivities.add(prev); + prev.pauseKeyDispatchingLocked(); } else { if (DEBUG_PAUSE) Slog.v(TAG, "Key dispatch not paused for screen off"); } - if (pausing.configDestroy) { - // The previous is being paused because the configuration - // is changing, which means it is actually stopping... - // To juggle the fact that we are also starting a new - // instance right now, we need to first completely stop - // the current instance before starting the new one. - if (DEBUG_PAUSE) Slog.v(TAG, "Destroying at pause: " + prev); - destroyActivityLocked(pausing, true, false, "pause-config"); - } - // Schedule a pause timeout in case the app doesn't respond. // We don't give it much time because this directly impacts the // responsiveness seen by the user. @@ -970,10 +951,7 @@ final class ActivityStack { // This activity failed to schedule the // pause, so just treat it as being paused now. if (DEBUG_PAUSE) Slog.v(TAG, "Activity not running, resuming next."); - } - - if (!mService.isSleeping()) { - resumeTopActivityLocked(pausing); + resumeTopActivityLocked(null); } } @@ -988,17 +966,16 @@ final class ActivityStack { if (index >= 0) { r = mHistory.get(index); mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r); - if (mPausingActivities.contains(r)) { + if (mPausingActivity == r) { if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSED: " + r + (timeout ? " (due to timeout)" : " (pause complete)")); r.state = ActivityState.PAUSED; - completePauseLocked(r); + completePauseLocked(); } else { - ActivityRecord old = mPausingActivities.size() > 0 - ? mPausingActivities.get(0) : null; EventLog.writeEvent(EventLogTags.AM_FAILED_TO_PAUSE, System.identityHashCode(r), r.shortComponentName, - old != null ? old.shortComponentName : "(none)"); + mPausingActivity != null + ? mPausingActivity.shortComponentName : "(none)"); } } } @@ -1024,14 +1001,8 @@ final class ActivityStack { ProcessRecord fgApp = null; if (mResumedActivity != null) { fgApp = mResumedActivity.app; - } else { - for (int i=mPausingActivities.size()-1; i>=0; i--) { - ActivityRecord pausing = mPausingActivities.get(i); - if (pausing.app == r.app) { - fgApp = pausing.app; - break; - } - } + } else if (mPausingActivity != null) { + fgApp = mPausingActivity.app; } if (r.app != null && fgApp != null && r.app != fgApp && r.lastVisibleTime > mService.mPreviousProcessVisibleTime @@ -1043,49 +1014,58 @@ final class ActivityStack { } } - private final void completePauseLocked(ActivityRecord prev) { + private final void completePauseLocked() { + ActivityRecord prev = mPausingActivity; if (DEBUG_PAUSE) Slog.v(TAG, "Complete pause: " + prev); - if (prev.finishing) { - if (DEBUG_PAUSE) Slog.v(TAG, "Executing finish of activity: " + prev); - prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE); - } else if (prev.app != null) { - if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending stop: " + prev); - if (prev.waitingVisible) { - prev.waitingVisible = false; - mWaitingVisibleActivities.remove(prev); - if (DEBUG_SWITCH || DEBUG_PAUSE) Slog.v( - TAG, "Complete pause, no longer waiting: " + prev); - } - if (prev.configDestroy) { - // The previous is being paused because the configuration - // is changing, which means it is actually stopping... - // To juggle the fact that we are also starting a new - // instance right now, we need to first completely stop - // the current instance before starting the new one. - if (DEBUG_PAUSE) Slog.v(TAG, "Destroying after pause: " + prev); - destroyActivityLocked(prev, true, false, "pause-config"); - } else { - mStoppingActivities.add(prev); - if (mStoppingActivities.size() > 3) { - // If we already have a few activities waiting to stop, - // then give up on things going idle and start clearing - // them out. - if (DEBUG_PAUSE) Slog.v(TAG, "To many pending stops, forcing idle"); - scheduleIdleLocked(); + if (prev != null) { + if (prev.finishing) { + if (DEBUG_PAUSE) Slog.v(TAG, "Executing finish of activity: " + prev); + prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE); + } else if (prev.app != null) { + if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending stop: " + prev); + if (prev.waitingVisible) { + prev.waitingVisible = false; + mWaitingVisibleActivities.remove(prev); + if (DEBUG_SWITCH || DEBUG_PAUSE) Slog.v( + TAG, "Complete pause, no longer waiting: " + prev); + } + if (prev.configDestroy) { + // The previous is being paused because the configuration + // is changing, which means it is actually stopping... + // To juggle the fact that we are also starting a new + // instance right now, we need to first completely stop + // the current instance before starting the new one. + if (DEBUG_PAUSE) Slog.v(TAG, "Destroying after pause: " + prev); + destroyActivityLocked(prev, true, false, "pause-config"); } else { - checkReadyForSleepLocked(); + mStoppingActivities.add(prev); + if (mStoppingActivities.size() > 3) { + // If we already have a few activities waiting to stop, + // then give up on things going idle and start clearing + // them out. + if (DEBUG_PAUSE) Slog.v(TAG, "To many pending stops, forcing idle"); + scheduleIdleLocked(); + } else { + checkReadyForSleepLocked(); + } } + } else { + if (DEBUG_PAUSE) Slog.v(TAG, "App died during pause, not stopping: " + prev); + prev = null; } - } else { - if (DEBUG_PAUSE) Slog.v(TAG, "App died during pause, not stopping: " + prev); - prev = null; + mPausingActivity = null; } - mPausingActivities.remove(prev); - if (mService.isSleeping()) { + if (!mService.isSleeping()) { + resumeTopActivityLocked(prev); + } else { checkReadyForSleepLocked(); } + + if (prev != null) { + prev.resumeKeyDispatchingLocked(); + } if (prev.app != null && prev.cpuTimeAtResume > 0 && mService.mBatteryStatsService.isOnBattery()) { @@ -1142,9 +1122,7 @@ final class ActivityStack { if (mMainStack) { mService.setFocusedActivityLocked(next); } - if (mInputPausedActivities.remove(next)) { - next.resumeKeyDispatchingLocked(); - } + next.resumeKeyDispatchingLocked(); ensureActivitiesVisibleLocked(null, 0); mService.mWindowManager.executeAppTransition(); mNoAnimActivities.clear(); @@ -1374,6 +1352,13 @@ final class ActivityStack { if (DEBUG_SWITCH) Slog.v(TAG, "Resuming " + next); + // If we are currently pausing an activity, then don't do anything + // until that is done. + if (mPausingActivity != null) { + if (DEBUG_SWITCH) Slog.v(TAG, "Skip resume: pausing=" + mPausingActivity); + return false; + } + // Okay we are now going to start a switch, to 'next'. We may first // have to pause the current activity, but this is an important point // where we have decided to go to 'next' so keep track of that. @@ -2455,7 +2440,7 @@ final class ActivityStack { err = startActivityUncheckedLocked(r, sourceRecord, grantedUriPermissions, grantedMode, onlyIfNeeded, true); - if (mDismissKeyguardOnNextActivity && mPausingActivities.size() == 0) { + if (mDismissKeyguardOnNextActivity && mPausingActivity == null) { // Someone asked to have the keyguard dismissed on the next // activity start, but we are not actually doing an activity // switch... just dismiss the keyguard now, because we @@ -3126,18 +3111,7 @@ final class ActivityStack { } mService.notifyAll(); } - - void reportActivityDrawnLocked(ActivityRecord r) { - if (mResumedActivity == r) { - // Once the resumed activity has been drawn, we can stop - // pausing input on all other activities. - for (int i=mInputPausedActivities.size()-1; i>=0; i--) { - mInputPausedActivities.get(i).resumeKeyDispatchingLocked(); - } - mInputPausedActivities.clear(); - } - } - + void reportActivityVisibleLocked(ActivityRecord r) { for (int i=mWaitingActivityVisible.size()-1; i>=0; i--) { WaitResult w = mWaitingActivityVisible.get(i); @@ -3196,9 +3170,7 @@ final class ActivityStack { mService.setFocusedActivityLocked(topRunningActivityLocked(null)); } } - if (mInputPausedActivities.remove(r)) { - r.resumeKeyDispatchingLocked(); - } + r.resumeKeyDispatchingLocked(); try { r.stopped = false; if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPING: " + r @@ -3524,7 +3496,7 @@ final class ActivityStack { // Tell window manager to prepare for this one to be removed. mService.mWindowManager.setAppVisibility(r.appToken, false); - if (!mPausingActivities.contains(r)) { + if (mPausingActivity == null) { if (DEBUG_PAUSE) Slog.v(TAG, "Finish needs to pause: " + r); if (DEBUG_USER_LEAVING) Slog.v(TAG, "finish() => pause with userLeaving=false"); startPausingLocked(false, false); @@ -3608,20 +3580,6 @@ final class ActivityStack { return r; } - final void appDiedLocked(ProcessRecord app) { - for (int i=mPausingActivities.size()-1; i>=0; i--) { - ActivityRecord r = mPausingActivities.get(i); - if (r.app == app) { - if (DEBUG_PAUSE) Slog.v(TAG, "App died while pausing: " + r); - mPausingActivities.remove(i); - mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r); - } - } - if (mLastPausedActivity != null && mLastPausedActivity.app == app) { - mLastPausedActivity = null; - } - } - /** * Perform the common clean-up of an activity record. This is called both * as part of destroyActivityLocked() (when destroying the client-side diff --git a/services/java/com/android/server/am/ContentProviderRecord.java b/services/java/com/android/server/am/ContentProviderRecord.java index 38355537e1c6..f338cfcb7737 100644 --- a/services/java/com/android/server/am/ContentProviderRecord.java +++ b/services/java/com/android/server/am/ContentProviderRecord.java @@ -20,24 +20,35 @@ import android.app.IActivityManager.ContentProviderHolder; import android.content.ComponentName; import android.content.pm.ApplicationInfo; import android.content.pm.ProviderInfo; +import android.os.IBinder; +import android.os.IBinder.DeathRecipient; import android.os.Process; +import android.os.RemoteException; +import android.util.Slog; import java.io.PrintWriter; +import java.util.HashMap; import java.util.HashSet; class ContentProviderRecord extends ContentProviderHolder { // All attached clients final HashSet<ProcessRecord> clients = new HashSet<ProcessRecord>(); + // Handles for non-framework processes supported by this provider + HashMap<IBinder, ExternalProcessHandle> externalProcessTokenToHandle; + // Count for external process for which we have no handles. + int externalProcessNoHandleCount; + final ActivityManagerService service; final int uid; final ApplicationInfo appInfo; final ComponentName name; - int externals; // number of non-framework processes supported by this provider ProcessRecord proc; // if non-null, hosting process. ProcessRecord launchingApp; // if non-null, waiting for this app to be launched. String stringName; - - public ContentProviderRecord(ProviderInfo _info, ApplicationInfo ai, ComponentName _name) { + + public ContentProviderRecord(ActivityManagerService _service, ProviderInfo _info, + ApplicationInfo ai, ComponentName _name) { super(_info); + service = _service; uid = ai.uid; appInfo = ai; name = _name; @@ -50,6 +61,7 @@ class ContentProviderRecord extends ContentProviderHolder { appInfo = cpr.appInfo; name = cpr.name; noReleaseNeeded = cpr.noReleaseNeeded; + service = cpr.service; } public boolean canRunHere(ProcessRecord app) { @@ -57,6 +69,57 @@ class ContentProviderRecord extends ContentProviderHolder { && (uid == Process.SYSTEM_UID || uid == app.info.uid); } + public void addExternalProcessHandleLocked(IBinder token) { + if (token == null) { + externalProcessNoHandleCount++; + } else { + if (externalProcessTokenToHandle == null) { + externalProcessTokenToHandle = new HashMap<IBinder, ExternalProcessHandle>(); + } + ExternalProcessHandle handle = externalProcessTokenToHandle.get(token); + if (handle == null) { + handle = new ExternalProcessHandle(token); + externalProcessTokenToHandle.put(token, handle); + } + handle.mAcquisitionCount++; + } + } + + public boolean removeExternalProcessHandleLocked(IBinder token) { + if (hasExternalProcessHandles()) { + boolean hasHandle = false; + if (externalProcessTokenToHandle != null) { + ExternalProcessHandle handle = externalProcessTokenToHandle.get(token); + if (handle != null) { + hasHandle = true; + handle.mAcquisitionCount--; + if (handle.mAcquisitionCount == 0) { + removeExternalProcessHandleInternalLocked(token); + return true; + } + } + } + if (!hasHandle) { + externalProcessNoHandleCount--; + return true; + } + } + return false; + } + + private void removeExternalProcessHandleInternalLocked(IBinder token) { + ExternalProcessHandle handle = externalProcessTokenToHandle.get(token); + handle.unlinkFromOwnDeathLocked(); + externalProcessTokenToHandle.remove(token); + if (externalProcessTokenToHandle.size() == 0) { + externalProcessTokenToHandle = null; + } + } + + public boolean hasExternalProcessHandles() { + return (externalProcessTokenToHandle != null || externalProcessNoHandleCount > 0); + } + void dump(PrintWriter pw, String prefix) { pw.print(prefix); pw.print("package="); pw.print(info.applicationInfo.packageName); @@ -73,8 +136,9 @@ class ContentProviderRecord extends ContentProviderHolder { pw.print("multiprocess="); pw.print(info.multiprocess); pw.print(" initOrder="); pw.println(info.initOrder); } - if (externals != 0) { - pw.print(prefix); pw.print("externals="); pw.println(externals); + if (hasExternalProcessHandles()) { + pw.print(prefix); pw.print("externals="); + pw.println(externalProcessTokenToHandle.size()); } if (clients.size() > 0) { pw.print(prefix); pw.println("Clients:"); @@ -84,6 +148,7 @@ class ContentProviderRecord extends ContentProviderHolder { } } + @Override public String toString() { if (stringName != null) { return stringName; @@ -96,4 +161,35 @@ class ContentProviderRecord extends ContentProviderHolder { sb.append('}'); return stringName = sb.toString(); } + + // This class represents a handle from an external process to a provider. + private class ExternalProcessHandle implements DeathRecipient { + private static final String LOG_TAG = "ExternalProcessHanldle"; + + private final IBinder mToken; + private int mAcquisitionCount; + + public ExternalProcessHandle(IBinder token) { + mToken = token; + try { + token.linkToDeath(this, 0); + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Couldn't register for death for token: " + mToken, re); + } + } + + public void unlinkFromOwnDeathLocked() { + mToken.unlinkToDeath(this, 0); + } + + @Override + public void binderDied() { + synchronized (service) { + if (hasExternalProcessHandles() && + externalProcessTokenToHandle.get(mToken) != null) { + removeExternalProcessHandleInternalLocked(mToken); + } + } + } + } } diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index bdbaab498b97..80ef0e602200 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -142,8 +142,7 @@ import java.util.List; /** {@hide} */ public class WindowManagerService extends IWindowManager.Stub - implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs, - Choreographer.OnAnimateListener { + implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs { static final String TAG = "WindowManager"; static final boolean DEBUG = false; static final boolean DEBUG_ADD_REMOVE = false; @@ -603,6 +602,18 @@ public class WindowManagerService extends IWindowManager.Stub } private LayoutAndSurfaceFields mInnerFields = new LayoutAndSurfaceFields(); + private final class AnimationRunnable implements Runnable { + @Override + public void run() { + synchronized(mWindowMap) { + mAnimationScheduled = false; + performLayoutAndPlaceSurfacesLocked(); + } + } + } + final AnimationRunnable mAnimationRunnable = new AnimationRunnable(); + boolean mAnimationScheduled; + final class DragInputEventReceiver extends InputEventReceiver { public DragInputEventReceiver(InputChannel inputChannel, Looper looper) { super(inputChannel, looper); @@ -724,7 +735,6 @@ public class WindowManagerService extends IWindowManager.Stub Looper.prepare(); WindowManagerService s = new WindowManagerService(mContext, mPM, mHaveInputMethods, mAllowBootMessages); - s.mChoreographer.addOnAnimateListener(s); android.os.Process.setThreadPriority( android.os.Process.THREAD_PRIORITY_DISPLAY); android.os.Process.setCanSelfBackground(false); @@ -5441,7 +5451,7 @@ public class WindowManagerService extends IWindowManager.Stub if (mScreenRotationAnimation.setRotation(rotation, mFxSession, MAX_ANIMATION_DURATION, mTransitionAnimationScale, mCurDisplayWidth, mCurDisplayHeight)) { - mChoreographer.scheduleAnimation(); + scheduleAnimationLocked(); } } Surface.setOrientation(0, rotation); @@ -6367,7 +6377,7 @@ public class WindowManagerService extends IWindowManager.Stub INJECTION_TIMEOUT_MILLIS); Binder.restoreCallingIdentity(ident); - return reportInjectionResult(result); + return reportInjectionResult(result, pid); } /** @@ -6397,7 +6407,7 @@ public class WindowManagerService extends IWindowManager.Stub INJECTION_TIMEOUT_MILLIS); Binder.restoreCallingIdentity(ident); - return reportInjectionResult(result); + return reportInjectionResult(result, pid); } /** @@ -6427,7 +6437,7 @@ public class WindowManagerService extends IWindowManager.Stub INJECTION_TIMEOUT_MILLIS); Binder.restoreCallingIdentity(ident); - return reportInjectionResult(result); + return reportInjectionResult(result, pid); } /** @@ -6448,24 +6458,23 @@ public class WindowManagerService extends IWindowManager.Stub INJECTION_TIMEOUT_MILLIS); Binder.restoreCallingIdentity(ident); - return reportInjectionResult(result); + return reportInjectionResult(result, pid); } - private boolean reportInjectionResult(int result) { + private boolean reportInjectionResult(int result, int pid) { switch (result) { case InputManager.INPUT_EVENT_INJECTION_PERMISSION_DENIED: - Slog.w(TAG, "Input event injection permission denied."); + Slog.w(TAG, "Input event injection from pid " + pid + " permission denied."); throw new SecurityException( "Injecting to another application requires INJECT_EVENTS permission"); case InputManager.INPUT_EVENT_INJECTION_SUCCEEDED: - //Slog.v(TAG, "Input event injection succeeded."); return true; case InputManager.INPUT_EVENT_INJECTION_TIMED_OUT: - Slog.w(TAG, "Input event injection timed out."); + Slog.w(TAG, "Input event injection from pid " + pid + " timed out."); return false; case InputManager.INPUT_EVENT_INJECTION_FAILED: default: - Slog.w(TAG, "Input event injection failed."); + Slog.w(TAG, "Input event injection from pid " + pid + " failed."); return false; } } @@ -6882,7 +6891,7 @@ public class WindowManagerService extends IWindowManager.Stub case FORCE_GC: { synchronized(mWindowMap) { - if (mChoreographer.isAnimationScheduled()) { + if (mAnimationScheduled) { // If we are animating, don't do the gc now but // delay a bit so we don't interrupt the animation. mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC), @@ -8980,7 +8989,7 @@ public class WindowManagerService extends IWindowManager.Stub if (needRelayout) { requestTraversalLocked(); } else if (mInnerFields.mAnimating) { - mChoreographer.scheduleAnimation(); + scheduleAnimationLocked(); } // Finally update all input windows now that the window changes have stabilized. @@ -9100,10 +9109,10 @@ public class WindowManagerService extends IWindowManager.Stub } } - @Override - public void onAnimate() { - synchronized(mWindowMap) { - performLayoutAndPlaceSurfacesLocked(); + void scheduleAnimationLocked() { + if (!mAnimationScheduled) { + mChoreographer.postAnimationCallback(mAnimationRunnable); + mAnimationScheduled = true; } } @@ -9423,7 +9432,7 @@ public class WindowManagerService extends IWindowManager.Stub if (DEBUG_ORIENTATION) Slog.i(TAG, "**** Dismissing screen rotation animation"); if (mScreenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION, mTransitionAnimationScale, mCurDisplayWidth, mCurDisplayHeight)) { - mChoreographer.scheduleAnimation(); + scheduleAnimationLocked(); } else { mScreenRotationAnimation = null; updateRotation = true; diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java index 6868cf6b82ea..b013d2799520 100644 --- a/services/java/com/android/server/wm/WindowState.java +++ b/services/java/com/android/server/wm/WindowState.java @@ -1593,7 +1593,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { mService.applyAnimationLocked(this, WindowManagerPolicy.TRANSIT_ENTER, true); } if (requestAnim) { - mService.mChoreographer.scheduleAnimation(); + mService.scheduleAnimationLocked(); } return true; } @@ -1634,7 +1634,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { } } if (requestAnim) { - mService.mChoreographer.scheduleAnimation(); + mService.scheduleAnimationLocked(); } return true; } diff --git a/services/jni/com_android_server_PowerManagerService.h b/services/jni/com_android_server_PowerManagerService.h index af107113ecf4..cc3b5ef54016 100644 --- a/services/jni/com_android_server_PowerManagerService.h +++ b/services/jni/com_android_server_PowerManagerService.h @@ -20,7 +20,7 @@ #include "JNIHelp.h" #include "jni.h" -#include <ui/PowerManager.h> +#include <androidfw/PowerManager.h> namespace android { diff --git a/services/surfaceflinger/LayerScreenshot.cpp b/services/surfaceflinger/LayerScreenshot.cpp index c127fa621fe1..c7cf46e53a41 100644 --- a/services/surfaceflinger/LayerScreenshot.cpp +++ b/services/surfaceflinger/LayerScreenshot.cpp @@ -70,6 +70,8 @@ void LayerScreenshot::initTexture(GLfloat u, GLfloat v) { glBindTexture(GL_TEXTURE_2D, mTextureName); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); mTexCoords[0] = 0; mTexCoords[1] = v; mTexCoords[2] = 0; mTexCoords[3] = 0; mTexCoords[4] = u; mTexCoords[5] = 0; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 40717f4e95db..9e3f54839574 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1922,6 +1922,8 @@ status_t SurfaceFlinger::electronBeamOffAnimationImplLocked() glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexCoordPointer(2, GL_FLOAT, 0, texCoords); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glVertexPointer(2, GL_FLOAT, 0, vtx); @@ -2094,6 +2096,8 @@ status_t SurfaceFlinger::electronBeamOnAnimationImplLocked() glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexCoordPointer(2, GL_FLOAT, 0, texCoords); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glVertexPointer(2, GL_FLOAT, 0, vtx); diff --git a/services/surfaceflinger/tests/resize/resize.cpp b/services/surfaceflinger/tests/resize/resize.cpp index 56b2a8f1cb03..7f3f0644c73a 100644 --- a/services/surfaceflinger/tests/resize/resize.cpp +++ b/services/surfaceflinger/tests/resize/resize.cpp @@ -39,7 +39,7 @@ int main(int argc, char** argv) // create a client to surfaceflinger sp<SurfaceComposerClient> client = new SurfaceComposerClient(); - sp<Surface> surface = client->createSurface(getpid(), 0, 160, 240, + sp<Surface> surface = client->createSurface(0, 160, 240, PIXEL_FORMAT_RGB_565); diff --git a/services/surfaceflinger/tests/surface/surface.cpp b/services/surfaceflinger/tests/surface/surface.cpp index 8e1c3fe322b4..9c15f9bb751a 100644 --- a/services/surfaceflinger/tests/surface/surface.cpp +++ b/services/surfaceflinger/tests/surface/surface.cpp @@ -38,7 +38,7 @@ int main(int argc, char** argv) sp<SurfaceComposerClient> client = new SurfaceComposerClient(); sp<SurfaceControl> surfaceControl = client->createSurface( - getpid(), 0, 160, 240, PIXEL_FORMAT_RGB_565); + 0, 160, 240, PIXEL_FORMAT_RGB_565); SurfaceComposerClient::openGlobalTransaction(); surfaceControl->setLayer(100000); SurfaceComposerClient::closeGlobalTransaction(); diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java index 24a4876ee4ef..8cfdb794c03d 100644 --- a/telephony/java/android/telephony/PhoneNumberUtils.java +++ b/telephony/java/android/telephony/PhoneNumberUtils.java @@ -292,6 +292,20 @@ public class PhoneNumberUtils } /** + * Translates keypad letters to actual digits (e.g. 1-800-GOOG-411 will + * become 1-800-4664-411), and then strips all separators (e.g. 1-800-4664-411 will become + * 18004664411). + * + * @see #convertKeypadLettersToDigits(String) + * @see #stripSeparators(String) + * + * @hide + */ + public static String convertAndStrip(String phoneNumber) { + return stripSeparators(convertKeypadLettersToDigits(phoneNumber)); + } + + /** * Converts pause and tonewait pause characters * to Android representation. * RFC 3601 says pause is 'p' and tonewait is 'w'. diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java index 5d764844406d..2b9fb913241c 100644 --- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java @@ -1040,7 +1040,8 @@ public abstract class DataConnectionTracker extends Handler { } } if (didDisable) { - if (enabledCount == 0) { + if ((enabledCount == 0) || (apnId == APN_DUN_ID)) { + mRequestedApnType = Phone.APN_TYPE_DEFAULT; onCleanUpConnection(true, apnId, Phone.REASON_DATA_DISABLED); } diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java index 3fe57aeb20b5..6e4dd58d6ff3 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java @@ -95,6 +95,9 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { Phone.APN_TYPE_MMS, Phone.APN_TYPE_HIPRI }; + private String[] mDunApnTypes = { + Phone.APN_TYPE_DUN }; + private static final int mDefaultApnId = DataConnectionTracker.APN_DEFAULT_ID; /* Constructor */ @@ -121,11 +124,26 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { createAllDataConnectionList(); broadcastMessenger(); + + Context c = mCdmaPhone.getContext(); + String[] t = c.getResources().getStringArray( + com.android.internal.R.array.config_cdma_dun_supported_types); + if (t != null && t.length > 0) { + ArrayList<String> temp = new ArrayList<String>(); + for(int i=0; i< t.length; i++) { + if (!Phone.APN_TYPE_DUN.equalsIgnoreCase(t[i])) { + temp.add(t[i]); + } + } + temp.add(0, Phone.APN_TYPE_DUN); + mDunApnTypes = temp.toArray(t); + } + } @Override public void dispose() { - cleanUpConnection(false, null); + cleanUpConnection(false, null, false); super.dispose(); @@ -282,7 +300,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { * @param tearDown true if the underlying DataConnection should be disconnected. * @param reason for the clean up. */ - private void cleanUpConnection(boolean tearDown, String reason) { + private void cleanUpConnection(boolean tearDown, String reason, boolean doAll) { if (DBG) log("cleanUpConnection: reason: " + reason); // Clear the reconnect alarm, if set. @@ -302,9 +320,15 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { DataConnectionAc dcac = mDataConnectionAsyncChannels.get(conn.getDataConnectionId()); if (tearDown) { - if (DBG) log("cleanUpConnection: teardown, call conn.disconnect"); - conn.tearDown(reason, obtainMessage(EVENT_DISCONNECT_DONE, - conn.getDataConnectionId(), 0, reason)); + if (doAll) { + if (DBG) log("cleanUpConnection: teardown, conn.tearDownAll"); + conn.tearDownAll(reason, obtainMessage(EVENT_DISCONNECT_DONE, + conn.getDataConnectionId(), 0, reason)); + } else { + if (DBG) log("cleanUpConnection: teardown, conn.tearDown"); + conn.tearDown(reason, obtainMessage(EVENT_DISCONNECT_DONE, + conn.getDataConnectionId(), 0, reason)); + } notificationDeferred = true; } else { if (DBG) log("cleanUpConnection: !tearDown, call conn.resetSynchronously"); @@ -348,8 +372,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { String[] types; int apnId; if (mRequestedApnType.equals(Phone.APN_TYPE_DUN)) { - types = new String[1]; - types[0] = Phone.APN_TYPE_DUN; + types = mDunApnTypes; apnId = DataConnectionTracker.APN_DUN_ID; } else { types = mDefaultApnTypes; @@ -587,7 +610,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { @Override protected void onEnableNewApn() { // No mRequestedApnType check; only one connection is supported - cleanUpConnection(true, Phone.REASON_APN_SWITCHED); + cleanUpConnection(true, Phone.REASON_APN_SWITCHED, false); } /** @@ -769,13 +792,13 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { @Override protected void onCleanUpConnection(boolean tearDown, int apnId, String reason) { // No apnId check; only one connection is supported - cleanUpConnection(tearDown, reason); + cleanUpConnection(tearDown, reason, (apnId == APN_DUN_ID)); } @Override protected void onCleanUpAllConnections(String cause) { // Only one CDMA connection is supported - cleanUpConnection(true, cause); + cleanUpConnection(true, cause, false); } private void createAllDataConnectionList() { @@ -821,7 +844,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { notifyDataConnection(Phone.REASON_CDMA_DATA_DETACHED); } else { if (mState == State.FAILED) { - cleanUpConnection(false, Phone.REASON_CDMA_DATA_DETACHED); + cleanUpConnection(false, Phone.REASON_CDMA_DATA_DETACHED, false); mDataConnections.get(0).resetRetryCount(); CdmaCellLocation loc = (CdmaCellLocation)(mPhone.getCellLocation()); @@ -900,7 +923,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker { log("onDataStateChanged: No active connection" + "state is CONNECTED, disconnecting/cleanup"); writeEventLogCdmaDataDrop(); - cleanUpConnection(true, null); + cleanUpConnection(true, null, false); return; } diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java index 9d9680d4a43f..db670f8919de 100644 --- a/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java +++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java @@ -623,4 +623,35 @@ public class PhoneNumberUtilsTest extends AndroidTestCase { // Brazil. assertFalse(PhoneNumberUtils.isPotentialEmergencyNumber("91112345", "BR")); } + + @SmallTest + public void testStripSeparators() { + // Smoke tests which should never fail. + assertEquals("1234567890", PhoneNumberUtils.stripSeparators("1234567890")); + assertEquals("911", PhoneNumberUtils.stripSeparators("911")); + assertEquals("112", PhoneNumberUtils.stripSeparators("112")); + + // Separators should be removed, while '+' or any other digits should not. + assertEquals("+16502910000", PhoneNumberUtils.stripSeparators("+1 (650) 291-0000")); + + // WAIT, PAUSE should *not* be stripped + assertEquals("+16502910000,300;", + PhoneNumberUtils.stripSeparators("+1 (650) 291-0000, 300;")); + } + + @SmallTest + public void testConvertAndStrip() { + // Smoke tests which should never fail. + assertEquals("1234567890", PhoneNumberUtils.convertAndStrip("1234567890")); + assertEquals("911", PhoneNumberUtils.convertAndStrip("911")); + assertEquals("112", PhoneNumberUtils.convertAndStrip("112")); + + // It should convert keypad characters into digits, and strip separators + assertEquals("22233344455566677778889999", + PhoneNumberUtils.convertAndStrip("ABC DEF GHI JKL MNO PQR STUV WXYZ")); + + // Test real cases. + assertEquals("18004664411", PhoneNumberUtils.convertAndStrip("1-800-GOOG-411")); + assertEquals("8002223334", PhoneNumberUtils.convertAndStrip("(800) ABC-DEFG")); + } } diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java index 674c0b700b5a..5fab2bb2d65d 100644 --- a/test-runner/src/android/test/mock/MockContext.java +++ b/test-runner/src/android/test/mock/MockContext.java @@ -267,6 +267,12 @@ public class MockContext extends Context { throw new UnsupportedOperationException(); } + /** @hide */ + @Override + public void sendBroadcast(Intent intent, int userId) { + throw new UnsupportedOperationException(); + } + @Override public void sendBroadcast(Intent intent, String receiverPermission) { throw new UnsupportedOperationException(); diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java index 895963a57fb3..83c9c3d727f6 100644 --- a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java @@ -903,9 +903,6 @@ public class TestShellActivity extends Activity implements LayoutTestController settings.setWorkersEnabled(false); settings.setXSSAuditorEnabled(false); settings.setPageCacheCapacity(0); - // this enables cpu upload path (as opposed to gpu upload path) - // and it's only meant to be a temporary workaround! - settings.setProperty("enable_cpu_upload_path", "true"); settings.setProperty("use_minimal_memory", "false"); } diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/TextActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/TextActivity.java index 4037a6983292..0a868faa7232 100644 --- a/tests/HwAccelerationTest/src/com/android/test/hwui/TextActivity.java +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/TextActivity.java @@ -21,6 +21,7 @@ import android.content.Context; import android.graphics.Canvas; import android.graphics.Paint; import android.os.Bundle; +import android.text.TextPaint; import android.view.View; @SuppressWarnings({"UnusedDeclaration"}) @@ -39,6 +40,7 @@ public class TextActivity extends Activity { private final Paint mScaledPaint; private final Paint mSkewPaint; private final Paint mHugePaint; + private final TextPaint mEventPaint; CustomTextView(Context c) { super(c); @@ -70,6 +72,11 @@ public class TextActivity extends Activity { mHugePaint.setAntiAlias(true); mHugePaint.setColor(0xff000000); mHugePaint.setTextSize(300f); + + mEventPaint = new TextPaint(); + mEventPaint.setFakeBoldText(true); + mEventPaint.setAntiAlias(true); + mEventPaint.setTextSize(14); } @Override @@ -77,6 +84,8 @@ public class TextActivity extends Activity { super.onDraw(canvas); canvas.drawRGB(255, 255, 255); + canvas.drawText("Hello OpenGL renderer!", 300, 20, mEventPaint); + mMediumPaint.setStyle(Paint.Style.FILL_AND_STROKE); mMediumPaint.setStrokeWidth(2.0f); canvas.drawText("Hello OpenGL renderer!", 100, 20, mMediumPaint); diff --git a/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/mandelbrot.rs b/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/mandelbrot.rs index a7987b381298..0ffb0e5a7a37 100644 --- a/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/mandelbrot.rs +++ b/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/mandelbrot.rs @@ -25,13 +25,14 @@ void root(uchar4 *v_out, uint32_t x, uint32_t y) { p.y = -1.f + ((float)y / gDimY) * 2.f; float2 t = 0; + float2 t2 = t * t; int iteration = 0; - while((t.x*t.x + t.y*t.y < 4.f) && (iteration < gMaxIteration)) { - float2 t2 = t * t; + while((t2.x + t2.y < 4.f) && (iteration < gMaxIteration)) { float xtemp = t2.x - t2.y + p.x; t.y = 2 * t.x * t.y + p.y; t.x = xtemp; iteration++; + t2 = t * t; } if(iteration >= gMaxIteration) { diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java index 3615f6057eb2..73682600ec10 100644 --- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java +++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java @@ -283,6 +283,9 @@ public class ImageProcessingActivity extends Activity mRadius = MAX_RADIUS; mScript.set_radius(mRadius); + mScript.invoke_filter(); + mRS.finish(); + long t = java.lang.System.currentTimeMillis(); mScript.invoke_filter(); diff --git a/tests/RenderScriptTests/PerfTest/res/raw/singletexfm.glsl b/tests/RenderScriptTests/PerfTest/res/raw/singletexfm.glsl new file mode 100644 index 000000000000..656961c5b2e5 --- /dev/null +++ b/tests/RenderScriptTests/PerfTest/res/raw/singletexfm.glsl @@ -0,0 +1,8 @@ +varying vec2 varTex0; + +void main() { + lowp vec3 col0 = texture2D(UNI_Tex0, varTex0).rgb; + gl_FragColor.xyz = col0 * UNI_modulate.rgb; + gl_FragColor.w = UNI_modulate.a; +} + diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/FillTest.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/FillTest.java index ba70c7148e89..41f664a0414b 100644 --- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/FillTest.java +++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/FillTest.java @@ -35,18 +35,22 @@ public class FillTest implements RsBenchBaseTest{ // Custom shaders private ProgramFragment mProgFragmentMultitex; private ProgramFragment mProgFragmentSingletex; + private ProgramFragment mProgFragmentSingletexModulate; private final BitmapFactory.Options mOptionsARGB = new BitmapFactory.Options(); int mBenchmarkDimX; int mBenchmarkDimY; private ScriptC_fill_test mFillScript; ScriptField_TestScripts_s.Item[] mTests; + ScriptField_FillTestFragData_s mFragData; private final String[] mNames = { "Fill screen 10x singletexture", "Fill screen 10x 3tex multitexture", "Fill screen 10x blended singletexture", - "Fill screen 10x blended 3tex multitexture" + "Fill screen 10x blended 3tex multitexture", + "Fill screen 3x modulate blended singletexture", + "Fill screen 1x modulate blended singletexture", }; public FillTest() { @@ -88,6 +92,8 @@ public class FillTest implements RsBenchBaseTest{ addTest(index++, 0 /*testId*/, 0 /*blend*/, 10 /*quadCount*/); addTest(index++, 1 /*testId*/, 1 /*blend*/, 10 /*quadCount*/); addTest(index++, 0 /*testId*/, 1 /*blend*/, 10 /*quadCount*/); + addTest(index++, 2 /*testId*/, 1 /*blend*/, 3 /*quadCount*/); + addTest(index++, 2 /*testId*/, 1 /*blend*/, 1 /*quadCount*/); return true; } @@ -112,6 +118,14 @@ public class FillTest implements RsBenchBaseTest{ pfbCustom.setShader(mRes, R.raw.singletexf); pfbCustom.addTexture(Program.TextureType.TEXTURE_2D); mProgFragmentSingletex = pfbCustom.create(); + + pfbCustom = new ProgramFragment.Builder(mRS); + pfbCustom.setShader(mRes, R.raw.singletexfm); + pfbCustom.addTexture(Program.TextureType.TEXTURE_2D); + mFragData = new ScriptField_FillTestFragData_s(mRS, 1); + pfbCustom.addConstant(mFragData.getType()); + mProgFragmentSingletexModulate = pfbCustom.create(); + mProgFragmentSingletexModulate.bindConstants(mFragData.getAllocation(), 0); } private Allocation loadTextureARGB(int id) { @@ -140,6 +154,7 @@ public class FillTest implements RsBenchBaseTest{ mFillScript.set_gProgVertex(progVertex); mFillScript.set_gProgFragmentTexture(mProgFragmentSingletex); + mFillScript.set_gProgFragmentTextureModulate(mProgFragmentSingletexModulate); mFillScript.set_gProgFragmentMultitex(mProgFragmentMultitex); mFillScript.set_gProgStoreBlendNone(ProgramStore.BLEND_NONE_DEPTH_NONE(mRS)); mFillScript.set_gProgStoreBlendAlpha(ProgramStore.BLEND_ALPHA_DEPTH_NONE(mRS)); @@ -150,5 +165,7 @@ public class FillTest implements RsBenchBaseTest{ mFillScript.set_gTexOpaque(loadTextureRGB(R.drawable.data)); mFillScript.set_gTexTransparent(loadTextureARGB(R.drawable.leaf)); mFillScript.set_gTexChecker(loadTextureRGB(R.drawable.checker)); + + mFillScript.bind_gFragData(mFragData); } } diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/fill_test.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/fill_test.rs index 23832d394eda..281f830d328a 100644 --- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/fill_test.rs +++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/fill_test.rs @@ -21,6 +21,7 @@ rs_program_vertex gProgVertex; rs_program_fragment gProgFragmentTexture; +rs_program_fragment gProgFragmentTextureModulate; rs_program_fragment gProgFragmentMultitex; rs_program_store gProgStoreBlendNone; @@ -41,6 +42,11 @@ typedef struct FillTestData_s { } FillTestData; FillTestData *gData; +typedef struct FillTestFragData_s { + float4 modulate; +} FillTestFragData; +FillTestFragData *gFragData; + static float gDt = 0.0f; void init() { @@ -58,7 +64,7 @@ static void bindProgramVertexOrtho() { rsgProgramVertexLoadProjectionMatrix(&proj); } -static void displaySingletexFill(bool blend, int quadCount) { +static void displaySingletexFill(bool blend, int quadCount, bool modulate) { bindProgramVertexOrtho(); rs_matrix4x4 matrix; rsMatrixLoadIdentity(&matrix); @@ -70,9 +76,21 @@ static void displaySingletexFill(bool blend, int quadCount) { } else { rsgBindProgramStore(gProgStoreBlendAlpha); } - rsgBindProgramFragment(gProgFragmentTexture); - rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp); - rsgBindTexture(gProgFragmentTexture, 0, gTexOpaque); + if (modulate) { + rsgBindProgramFragment(gProgFragmentTextureModulate); + rsgBindSampler(gProgFragmentTextureModulate, 0, gLinearClamp); + rsgBindTexture(gProgFragmentTextureModulate, 0, gTexOpaque); + + gFragData->modulate.r = 0.8f; + gFragData->modulate.g = 0.7f; + gFragData->modulate.b = 0.8f; + gFragData->modulate.a = 0.5f; + rsgAllocationSyncAll(rsGetAllocation(gFragData)); + } else { + rsgBindProgramFragment(gProgFragmentTexture); + rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp); + rsgBindTexture(gProgFragmentTexture, 0, gTexOpaque); + } for (int i = 0; i < quadCount; i ++) { float startX = 5 * i, startY = 5 * i; @@ -128,7 +146,10 @@ void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32 displayMultitextureSample(gData->blend == 1 ? true : false, gData->quadCount); break; case 1: - displaySingletexFill(gData->blend == 1 ? true : false, gData->quadCount); + displaySingletexFill(gData->blend == 1 ? true : false, gData->quadCount, false); + break; + case 2: + displaySingletexFill(gData->blend == 1 ? true : false, gData->quadCount, true); break; default: rsDebug("Wrong test number", 0); diff --git a/cmds/keystore/Android.mk b/tests/RenderScriptTests/SceneGraph/Android.mk index 5a9b979c6406..ba4b3c50f3ae 100644 --- a/cmds/keystore/Android.mk +++ b/tests/RenderScriptTests/SceneGraph/Android.mk @@ -1,5 +1,5 @@ # -# Copyright (C) 2009 The Android Open Source Project +# Copyright (C) 2011 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -14,19 +14,13 @@ # limitations under the License. # -LOCAL_PATH:= $(call my-dir) - +LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) -LOCAL_SRC_FILES := keystore.cpp -LOCAL_C_INCLUDES := external/openssl/include -LOCAL_SHARED_LIBRARIES := libcutils libcrypto -LOCAL_MODULE:= keystore -include $(BUILD_EXECUTABLE) -include $(CLEAR_VARS) -LOCAL_SRC_FILES := keystore_cli.cpp -LOCAL_C_INCLUDES := external/openssl/include -LOCAL_SHARED_LIBRARIES := libcutils libcrypto -LOCAL_MODULE:= keystore_cli -LOCAL_MODULE_TAGS := debug -include $(BUILD_EXECUTABLE) +LOCAL_MODULE_TAGS := optional + +LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src) + +LOCAL_PACKAGE_NAME := SceneGraphTest + +include $(BUILD_PACKAGE) diff --git a/tests/RenderScriptTests/SceneGraph/AndroidManifest.xml b/tests/RenderScriptTests/SceneGraph/AndroidManifest.xml new file mode 100644 index 000000000000..e8d1e8e2b080 --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/AndroidManifest.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.testapp"> + <uses-permission + android:name="android.permission.INTERNET" /> + <application android:label="SceneGraphTest"> + <activity android:name="TestApp" + android:label="SceneGraphTest"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + <activity android:name="FileSelector" + android:label="FileSelector" + android:hardwareAccelerated="true"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + </intent-filter> + </activity> + </application> +</manifest> diff --git a/tests/RenderScriptTests/SceneGraph/assets/blue.jpg b/tests/RenderScriptTests/SceneGraph/assets/blue.jpg Binary files differnew file mode 100644 index 000000000000..494e77a199e1 --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/assets/blue.jpg diff --git a/tests/RenderScriptTests/SceneGraph/assets/carbonfiber.jpg b/tests/RenderScriptTests/SceneGraph/assets/carbonfiber.jpg Binary files differnew file mode 100644 index 000000000000..2fcecb0be1f5 --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/assets/carbonfiber.jpg diff --git a/tests/RenderScriptTests/SceneGraph/assets/green.jpg b/tests/RenderScriptTests/SceneGraph/assets/green.jpg Binary files differnew file mode 100644 index 000000000000..a86a754fe2e3 --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/assets/green.jpg diff --git a/tests/RenderScriptTests/SceneGraph/assets/grey.jpg b/tests/RenderScriptTests/SceneGraph/assets/grey.jpg Binary files differnew file mode 100644 index 000000000000..5870b1af055e --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/assets/grey.jpg diff --git a/tests/RenderScriptTests/SceneGraph/assets/orange.jpg b/tests/RenderScriptTests/SceneGraph/assets/orange.jpg Binary files differnew file mode 100644 index 000000000000..7dbe942af1a8 --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/assets/orange.jpg diff --git a/tests/RenderScriptTests/SceneGraph/assets/orientation_test.a3d b/tests/RenderScriptTests/SceneGraph/assets/orientation_test.a3d Binary files differnew file mode 100644 index 000000000000..07318ae11249 --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/assets/orientation_test.a3d diff --git a/tests/RenderScriptTests/SceneGraph/assets/orientation_test.dae b/tests/RenderScriptTests/SceneGraph/assets/orientation_test.dae new file mode 100644 index 000000000000..7eef443fa0e2 --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/assets/orientation_test.dae @@ -0,0 +1,1102 @@ +<?xml version="1.0" ?> +<COLLADA xmlns="http://www.collada.org/2005/11/COLLADASchema" version="1.4.1"> + <asset> + <contributor> + <author>alexst</author> + <authoring_tool>OpenCOLLADA2010</authoring_tool> + <comments>ColladaMaya export options: bakeTransforms=0;relativePaths=0;copyTextures=0;exportTriangles=1;exportCgfxFileReferences=0; isSampling=0;curveConstrainSampling=0;removeStaticCurves=1;exportPolygonMeshes=1;exportLights=1; exportCameras=1;exportJointsAndSkin=1;exportAnimations=0;exportInvisibleNodes=0;exportDefaultCameras=0; exportTexCoords=1;exportNormals=1;exportNormalsPerVertex=1;exportVertexColors=0;exportVertexColorsPerVertex=0; exportTexTangents=0;exportTangents=0;exportReferencedMaterials=1;exportMaterialsOnly=0; exportXRefs=1;dereferenceXRefs=1;exportCameraAsLookat=0;cameraXFov=0;cameraYFov=1;doublePrecision=0</comments> + <source_data>file:///Volumes/Android/art/orientation_test.mb</source_data> + </contributor> + <created>2011-09-30T15:31:38</created> + <modified>2011-09-30T15:31:38</modified> + <unit meter="0.01" name="centimeter" /> + <up_axis>Y_UP</up_axis> + </asset> + <library_cameras> + <camera id="cameraShape1" name="cameraShape1"> + <optics> + <technique_common> + <perspective> + <yfov>37.8493</yfov> + <aspect_ratio>1.5</aspect_ratio> + <znear>1</znear> + <zfar>400</zfar> + </perspective> + </technique_common> + </optics> + <extra> + <technique profile="OpenCOLLADAMaya"> + <film_fit>0</film_fit> + <film_fit_offset>0</film_fit_offset> + <film_offsetX>0</film_offsetX> + <film_offsetY>0</film_offsetY> + <horizontal_aperture>3.599993</horizontal_aperture> + <lens_squeeze>1</lens_squeeze> + <originalMayaNodeId>cameraShape1</originalMayaNodeId> + <vertical_aperture>2.399995</vertical_aperture> + </technique> + </extra> + </camera> + <camera id="CameraDistShape" name="CameraDistShape"> + <optics> + <technique_common> + <perspective> + <yfov>37.8493</yfov> + <aspect_ratio>1.5</aspect_ratio> + <znear>1</znear> + <zfar>1000</zfar> + </perspective> + </technique_common> + </optics> + <extra> + <technique profile="OpenCOLLADAMaya"> + <film_fit>0</film_fit> + <film_fit_offset>0</film_fit_offset> + <film_offsetX>0</film_offsetX> + <film_offsetY>0</film_offsetY> + <horizontal_aperture>3.599993</horizontal_aperture> + <lens_squeeze>1</lens_squeeze> + <originalMayaNodeId>CameraDistShape</originalMayaNodeId> + <vertical_aperture>2.399995</vertical_aperture> + </technique> + </extra> + </camera> + </library_cameras> + <library_materials> + <material id="Paint1" name="Paint1"> + <instance_effect url="#Paint1-fx" /> + </material> + <material id="lambert2" name="lambert2"> + <instance_effect url="#lambert2-fx" /> + </material> + <material id="Plastic" name="Plastic"> + <instance_effect url="#Plastic-fx" /> + </material> + <material id="Metal" name="Metal"> + <instance_effect url="#Metal-fx" /> + </material> + <material id="PlasticCenter" name="PlasticCenter"> + <instance_effect url="#PlasticCenter-fx" /> + </material> + <material id="PlasticRed" name="PlasticRed"> + <instance_effect url="#PlasticRed-fx" /> + </material> + <material id="lambert10" name="lambert10"> + <instance_effect url="#lambert10-fx" /> + </material> + <material id="lambert11" name="lambert11"> + <instance_effect url="#lambert11-fx" /> + </material> + </library_materials> + <library_effects> + <effect id="Metal-fx"> + <profile_COMMON> + <newparam sid="file23-surface"> + <surface type="2D"> + <init_from>file23</init_from> + </surface> + </newparam> + <newparam sid="file23-sampler"> + <sampler2D> + <source>file23-surface</source> + </sampler2D> + </newparam> + <technique sid="common"> + <lambert> + <emission> + <color>0 0 0 1</color> + </emission> + <ambient> + <color>0 0 0 1</color> + </ambient> + <diffuse> + <texture texture="file23-sampler" texcoord="TEX0"> + <extra> + <technique profile="OpenCOLLADAMaya"> + <blend_mode>NONE</blend_mode> + <coverageU>1</coverageU> + <coverageV>1</coverageV> + <fast>0</fast> + <mirrorU>0</mirrorU> + <mirrorV>0</mirrorV> + <noiseU>0</noiseU> + <noiseV>0</noiseV> + <offsetU>0</offsetU> + <offsetV>0</offsetV> + <repeatU>1</repeatU> + <repeatV>1</repeatV> + <rotateFrame>0</rotateFrame> + <rotateUV>0</rotateUV> + <stagger>0</stagger> + <translateFrameU>0</translateFrameU> + <translateFrameV>0</translateFrameV> + <wrapU>1</wrapU> + <wrapV>1</wrapV> + </technique> + </extra> + </texture> + </diffuse> + <transparent opaque="RGB_ZERO"> + <color>0 0 0 1</color> + </transparent> + <transparency> + <float>1</float> + </transparency> + </lambert> + </technique> + </profile_COMMON> + </effect> + <effect id="Paint1-fx"> + <profile_COMMON> + <newparam sid="file25-surface"> + <surface type="2D"> + <init_from>file25</init_from> + </surface> + </newparam> + <newparam sid="file25-sampler"> + <sampler2D> + <source>file25-surface</source> + </sampler2D> + </newparam> + <technique sid="common"> + <lambert> + <emission> + <color>0 0 0 1</color> + </emission> + <ambient> + <color>0 0 0 1</color> + </ambient> + <diffuse> + <texture texture="file25-sampler" texcoord="TEX0"> + <extra> + <technique profile="OpenCOLLADAMaya"> + <blend_mode>NONE</blend_mode> + <coverageU>1</coverageU> + <coverageV>1</coverageV> + <fast>0</fast> + <mirrorU>0</mirrorU> + <mirrorV>0</mirrorV> + <noiseU>0</noiseU> + <noiseV>0</noiseV> + <offsetU>0</offsetU> + <offsetV>0</offsetV> + <repeatU>1</repeatU> + <repeatV>1</repeatV> + <rotateFrame>0</rotateFrame> + <rotateUV>0</rotateUV> + <stagger>0</stagger> + <translateFrameU>0</translateFrameU> + <translateFrameV>0</translateFrameV> + <wrapU>1</wrapU> + <wrapV>1</wrapV> + </technique> + </extra> + </texture> + </diffuse> + <transparent opaque="RGB_ZERO"> + <color>0 0 0 1</color> + </transparent> + <transparency> + <float>1</float> + </transparency> + </lambert> + </technique> + </profile_COMMON> + </effect> + <effect id="Plastic-fx"> + <profile_COMMON> + <newparam sid="file24-surface"> + <surface type="2D"> + <init_from>file24</init_from> + </surface> + </newparam> + <newparam sid="file24-sampler"> + <sampler2D> + <source>file24-surface</source> + </sampler2D> + </newparam> + <technique sid="common"> + <lambert> + <emission> + <color>0 0 0 1</color> + </emission> + <ambient> + <color>0 0 0 1</color> + </ambient> + <diffuse> + <texture texture="file24-sampler" texcoord="TEX0"> + <extra> + <technique profile="OpenCOLLADAMaya"> + <blend_mode>NONE</blend_mode> + <coverageU>1</coverageU> + <coverageV>1</coverageV> + <fast>0</fast> + <mirrorU>0</mirrorU> + <mirrorV>0</mirrorV> + <noiseU>0</noiseU> + <noiseV>0</noiseV> + <offsetU>0</offsetU> + <offsetV>0</offsetV> + <repeatU>1</repeatU> + <repeatV>1</repeatV> + <rotateFrame>0</rotateFrame> + <rotateUV>0</rotateUV> + <stagger>0</stagger> + <translateFrameU>0</translateFrameU> + <translateFrameV>0</translateFrameV> + <wrapU>1</wrapU> + <wrapV>1</wrapV> + </technique> + </extra> + </texture> + </diffuse> + <transparent opaque="RGB_ZERO"> + <color>0 0 0 1</color> + </transparent> + <transparency> + <float>1</float> + </transparency> + </lambert> + </technique> + </profile_COMMON> + </effect> + <effect id="PlasticCenter-fx"> + <profile_COMMON> + <newparam sid="file24-surface"> + <surface type="2D"> + <init_from>file24</init_from> + </surface> + </newparam> + <newparam sid="file24-sampler"> + <sampler2D> + <source>file24-surface</source> + </sampler2D> + </newparam> + <technique sid="common"> + <lambert> + <emission> + <color>0 0 0 1</color> + </emission> + <ambient> + <color>0 0 0 1</color> + </ambient> + <diffuse> + <texture texture="file24-sampler" texcoord="TEX0"> + <extra> + <technique profile="OpenCOLLADAMaya"> + <blend_mode>NONE</blend_mode> + <coverageU>1</coverageU> + <coverageV>1</coverageV> + <fast>0</fast> + <mirrorU>0</mirrorU> + <mirrorV>0</mirrorV> + <noiseU>0</noiseU> + <noiseV>0</noiseV> + <offsetU>0</offsetU> + <offsetV>0</offsetV> + <repeatU>1</repeatU> + <repeatV>1</repeatV> + <rotateFrame>0</rotateFrame> + <rotateUV>0</rotateUV> + <stagger>0</stagger> + <translateFrameU>0</translateFrameU> + <translateFrameV>0</translateFrameV> + <wrapU>1</wrapU> + <wrapV>1</wrapV> + </technique> + </extra> + </texture> + </diffuse> + <transparent opaque="RGB_ZERO"> + <color>0 0 0 1</color> + </transparent> + <transparency> + <float>1</float> + </transparency> + </lambert> + </technique> + </profile_COMMON> + </effect> + <effect id="PlasticRed-fx"> + <profile_COMMON> + <newparam sid="file23-surface"> + <surface type="2D"> + <init_from>file23</init_from> + </surface> + </newparam> + <newparam sid="file23-sampler"> + <sampler2D> + <source>file23-surface</source> + </sampler2D> + </newparam> + <technique sid="common"> + <lambert> + <emission> + <color>0 0 0 1</color> + </emission> + <ambient> + <color>0 0 0 1</color> + </ambient> + <diffuse> + <texture texture="file23-sampler" texcoord="TEX0"> + <extra> + <technique profile="OpenCOLLADAMaya"> + <blend_mode>NONE</blend_mode> + <coverageU>1</coverageU> + <coverageV>1</coverageV> + <fast>0</fast> + <mirrorU>0</mirrorU> + <mirrorV>0</mirrorV> + <noiseU>0</noiseU> + <noiseV>0</noiseV> + <offsetU>0</offsetU> + <offsetV>0</offsetV> + <repeatU>1</repeatU> + <repeatV>1</repeatV> + <rotateFrame>0</rotateFrame> + <rotateUV>0</rotateUV> + <stagger>0</stagger> + <translateFrameU>0</translateFrameU> + <translateFrameV>0</translateFrameV> + <wrapU>1</wrapU> + <wrapV>1</wrapV> + </technique> + </extra> + </texture> + </diffuse> + <transparent opaque="RGB_ZERO"> + <color>0 0 0 1</color> + </transparent> + <transparency> + <float>1</float> + </transparency> + </lambert> + </technique> + </profile_COMMON> + </effect> + <effect id="lambert10-fx"> + <profile_COMMON> + <newparam sid="file28-surface"> + <surface type="2D"> + <init_from>file28</init_from> + </surface> + </newparam> + <newparam sid="file28-sampler"> + <sampler2D> + <source>file28-surface</source> + </sampler2D> + </newparam> + <technique sid="common"> + <lambert> + <emission> + <color>0 0 0 1</color> + </emission> + <ambient> + <color>0 0 0 1</color> + </ambient> + <diffuse> + <texture texture="file28-sampler" texcoord="TEX0"> + <extra> + <technique profile="OpenCOLLADAMaya"> + <blend_mode>NONE</blend_mode> + <coverageU>1</coverageU> + <coverageV>1</coverageV> + <fast>0</fast> + <mirrorU>0</mirrorU> + <mirrorV>0</mirrorV> + <noiseU>0</noiseU> + <noiseV>0</noiseV> + <offsetU>0</offsetU> + <offsetV>0</offsetV> + <repeatU>1</repeatU> + <repeatV>1</repeatV> + <rotateFrame>0</rotateFrame> + <rotateUV>0</rotateUV> + <stagger>0</stagger> + <translateFrameU>0</translateFrameU> + <translateFrameV>0</translateFrameV> + <wrapU>1</wrapU> + <wrapV>1</wrapV> + </technique> + </extra> + </texture> + </diffuse> + <transparent opaque="RGB_ZERO"> + <color>0 0 0 1</color> + </transparent> + <transparency> + <float>1</float> + </transparency> + </lambert> + </technique> + </profile_COMMON> + </effect> + <effect id="lambert11-fx"> + <profile_COMMON> + <newparam sid="file29-surface"> + <surface type="2D"> + <init_from>file29</init_from> + </surface> + </newparam> + <newparam sid="file29-sampler"> + <sampler2D> + <source>file29-surface</source> + </sampler2D> + </newparam> + <technique sid="common"> + <lambert> + <emission> + <color>0 0 0 1</color> + </emission> + <ambient> + <color>0 0 0 1</color> + </ambient> + <diffuse> + <texture texture="file29-sampler" texcoord="TEX0"> + <extra> + <technique profile="OpenCOLLADAMaya"> + <blend_mode>NONE</blend_mode> + <coverageU>1</coverageU> + <coverageV>1</coverageV> + <fast>0</fast> + <mirrorU>0</mirrorU> + <mirrorV>0</mirrorV> + <noiseU>0</noiseU> + <noiseV>0</noiseV> + <offsetU>0</offsetU> + <offsetV>0</offsetV> + <repeatU>1</repeatU> + <repeatV>1</repeatV> + <rotateFrame>0</rotateFrame> + <rotateUV>0</rotateUV> + <stagger>0</stagger> + <translateFrameU>0</translateFrameU> + <translateFrameV>0</translateFrameV> + <wrapU>1</wrapU> + <wrapV>1</wrapV> + </technique> + </extra> + </texture> + </diffuse> + <transparent opaque="RGB_ZERO"> + <color>0 0 0 1</color> + </transparent> + <transparency> + <float>1</float> + </transparency> + </lambert> + </technique> + </profile_COMMON> + </effect> + <effect id="lambert2-fx"> + <profile_COMMON> + <newparam sid="file22-surface"> + <surface type="2D"> + <init_from>file22</init_from> + </surface> + </newparam> + <newparam sid="file22-sampler"> + <sampler2D> + <source>file22-surface</source> + </sampler2D> + </newparam> + <technique sid="common"> + <lambert> + <emission> + <color>0 0 0 1</color> + </emission> + <ambient> + <color>0 0 0 1</color> + </ambient> + <diffuse> + <texture texture="file22-sampler" texcoord="TEX0"> + <extra> + <technique profile="OpenCOLLADAMaya"> + <blend_mode>NONE</blend_mode> + <coverageU>1</coverageU> + <coverageV>1</coverageV> + <fast>0</fast> + <mirrorU>0</mirrorU> + <mirrorV>0</mirrorV> + <noiseU>0</noiseU> + <noiseV>0</noiseV> + <offsetU>0</offsetU> + <offsetV>0</offsetV> + <repeatU>1</repeatU> + <repeatV>1</repeatV> + <rotateFrame>0</rotateFrame> + <rotateUV>0</rotateUV> + <stagger>0</stagger> + <translateFrameU>0</translateFrameU> + <translateFrameV>0</translateFrameV> + <wrapU>1</wrapU> + <wrapV>1</wrapV> + </technique> + </extra> + </texture> + </diffuse> + <transparent opaque="RGB_ZERO"> + <color>0 0 0 1</color> + </transparent> + <transparency> + <float>1</float> + </transparency> + </lambert> + </technique> + </profile_COMMON> + </effect> + </library_effects> + <library_images> + <image id="file29" name="file29" height="0" width="0"> + <init_from>file:///Volumes/Android/Sanity/SceneGraph/assets/blue.jpg</init_from> + <extra> + <technique profile="OpenCOLLADAMaya"> + <dgnode_type>kFile</dgnode_type> + <image_sequence>0</image_sequence> + <originalMayaNodeId>file29</originalMayaNodeId> + </technique> + </extra> + </image> + <image id="file25" name="file25" height="0" width="0"> + <init_from>file:///Volumes/Android/Sanity/SceneGraph/assets/carbonfiber.jpg</init_from> + <extra> + <technique profile="OpenCOLLADAMaya"> + <dgnode_type>kFile</dgnode_type> + <image_sequence>0</image_sequence> + <originalMayaNodeId>file25</originalMayaNodeId> + </technique> + </extra> + </image> + <image id="file28" name="file28" height="0" width="0"> + <init_from>file:///Volumes/Android/Sanity/SceneGraph/assets/green.jpg</init_from> + <extra> + <technique profile="OpenCOLLADAMaya"> + <dgnode_type>kFile</dgnode_type> + <image_sequence>0</image_sequence> + <originalMayaNodeId>file28</originalMayaNodeId> + </technique> + </extra> + </image> + <image id="file22" name="file22" height="0" width="0"> + <init_from>file:///Volumes/Android/Sanity/SceneGraph/assets/grey.jpg</init_from> + <extra> + <technique profile="OpenCOLLADAMaya"> + <dgnode_type>kFile</dgnode_type> + <image_sequence>0</image_sequence> + <originalMayaNodeId>file22</originalMayaNodeId> + </technique> + </extra> + </image> + <image id="file24" name="file24" height="0" width="0"> + <init_from>file:///Volumes/Android/Sanity/SceneGraph/assets/orange.jpg</init_from> + <extra> + <technique profile="OpenCOLLADAMaya"> + <dgnode_type>kFile</dgnode_type> + <image_sequence>0</image_sequence> + <originalMayaNodeId>file24</originalMayaNodeId> + </technique> + </extra> + </image> + <image id="file23" name="file23" height="0" width="0"> + <init_from>file:///Volumes/Android/Sanity/SceneGraph/assets/red.jpg</init_from> + <extra> + <technique profile="OpenCOLLADAMaya"> + <dgnode_type>kFile</dgnode_type> + <image_sequence>0</image_sequence> + <originalMayaNodeId>file23</originalMayaNodeId> + </technique> + </extra> + </image> + </library_images> + <library_visual_scenes> + <visual_scene id="VisualSceneNode" name="orientation_test"> + <node id="camera1" name="camera1"> + <translate sid="translate">24.5791 14.1321 31.4654</translate> + <rotate sid="rotateZ">0 0 1 0</rotate> + <rotate sid="rotateY">0 1 0 42</rotate> + <rotate sid="rotateX">1 0 0 -16.2</rotate> + <scale sid="scale">1 1 1</scale> + <instance_camera url="#cameraShape1" /> + <extra> + <technique profile="OpenCOLLADAMaya"> + <originalMayaNodeId>camera1</originalMayaNodeId> + </technique> + </extra> + </node> + <node id="CameraAim" name="CameraAim"> + <translate sid="translate">0.0209301 3.68542 2.06912</translate> + <rotate sid="rotateY">0 1 0 43.2561</rotate> + <rotate sid="rotateX">1 0 0 -20</rotate> + <scale sid="scale">1 1 1</scale> + <node id="CameraDist" name="CameraDist"> + <translate sid="translate">0 0 45</translate> + <scale sid="scale">1 1 1</scale> + <instance_camera url="#CameraDistShape" /> + <extra> + <technique profile="OpenCOLLADAMaya"> + <originalMayaNodeId>CameraDist</originalMayaNodeId> + </technique> + </extra> + </node> + <extra> + <technique profile="OpenCOLLADAMaya"> + <originalMayaNodeId>CameraAim</originalMayaNodeId> + </technique> + </extra> + </node> + <node id="pSphere4" name="pSphere4"> + <translate sid="translate">-9.69237 0 7.70498</translate> + <scale sid="scale">1 1 1</scale> + <instance_geometry url="#pSphereShape4"> + <bind_material> + <technique_common> + <instance_material symbol="lambert7SG" target="#Paint1"> + <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" /> + </instance_material> + </technique_common> + </bind_material> + </instance_geometry> + <extra> + <technique profile="OpenCOLLADAMaya"> + <originalMayaNodeId>pSphere4</originalMayaNodeId> + </technique> + </extra> + </node> + <node id="pSphere1" name="pSphere1"> + <translate sid="translate">13.0966 0 5.76254</translate> + <scale sid="scale">1 1 1</scale> + <instance_geometry url="#pSphereShape1"> + <bind_material> + <technique_common> + <instance_material symbol="lambert7SG" target="#Paint1"> + <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" /> + </instance_material> + </technique_common> + </bind_material> + </instance_geometry> + <extra> + <technique profile="OpenCOLLADAMaya"> + <originalMayaNodeId>pSphere1</originalMayaNodeId> + </technique> + </extra> + </node> + <node id="pSphere2" name="pSphere2"> + <translate sid="translate">21.7661 0 -13.6375</translate> + <scale sid="scale">1 1 1</scale> + <instance_geometry url="#pSphereShape2"> + <bind_material> + <technique_common> + <instance_material symbol="lambert7SG" target="#Paint1"> + <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" /> + </instance_material> + </technique_common> + </bind_material> + </instance_geometry> + <extra> + <technique profile="OpenCOLLADAMaya"> + <originalMayaNodeId>pSphere2</originalMayaNodeId> + </technique> + </extra> + </node> + <node id="pSphere3" name="pSphere3"> + <translate sid="translate">-13.862 0 -13.6154</translate> + <scale sid="scale">1 1 1</scale> + <instance_geometry url="#pSphereShape3"> + <bind_material> + <technique_common> + <instance_material symbol="lambert7SG" target="#Paint1"> + <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" /> + </instance_material> + </technique_common> + </bind_material> + </instance_geometry> + <extra> + <technique profile="OpenCOLLADAMaya"> + <originalMayaNodeId>pSphere3</originalMayaNodeId> + </technique> + </extra> + </node> + <node id="pSphere5" name="pSphere5"> + <translate sid="translate">31.0862 0 18.5992</translate> + <scale sid="scale">1 1 1</scale> + <instance_geometry url="#pSphereShape5"> + <bind_material> + <technique_common> + <instance_material symbol="lambert7SG" target="#Paint1"> + <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" /> + </instance_material> + </technique_common> + </bind_material> + </instance_geometry> + <extra> + <technique profile="OpenCOLLADAMaya"> + <originalMayaNodeId>pSphere5</originalMayaNodeId> + </technique> + </extra> + </node> + <node id="pCube1" name="pCube1"> + <translate sid="translate">0 0 0</translate> + <scale sid="scale">1 1 1</scale> + <instance_geometry url="#pCubeShape1"> + <bind_material> + <technique_common> + <instance_material symbol="lambert4SG" target="#lambert2"> + <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" /> + </instance_material> + </technique_common> + </bind_material> + </instance_geometry> + <extra> + <technique profile="OpenCOLLADAMaya"> + <originalMayaNodeId>pCube1</originalMayaNodeId> + </technique> + </extra> + </node> + <node id="group1" name="group1"> + <translate sid="translate">0 0 0</translate> + <rotate sid="rotateZ">0 0 1 -162.693</rotate> + <rotate sid="rotateY">0 1 0 21.3345</rotate> + <rotate sid="rotateX">1 0 0 -100.567</rotate> + <scale sid="scale">1 1 1</scale> + <node id="pSphere6" name="pSphere6"> + <translate sid="translate">-13.862 0 -13.6154</translate> + <scale sid="scale">1 1 1</scale> + <instance_geometry url="#pSphereShape6"> + <bind_material> + <technique_common> + <instance_material symbol="lambert6SG" target="#Plastic"> + <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" /> + </instance_material> + </technique_common> + </bind_material> + </instance_geometry> + <extra> + <technique profile="OpenCOLLADAMaya"> + <originalMayaNodeId>pSphere6</originalMayaNodeId> + </technique> + </extra> + </node> + <node id="pSphere7" name="pSphere7"> + <translate sid="translate">-9.69237 0 7.70498</translate> + <scale sid="scale">1 1 1</scale> + <instance_geometry url="#pSphereShape7"> + <bind_material> + <technique_common> + <instance_material symbol="lambert6SG" target="#Plastic"> + <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" /> + </instance_material> + </technique_common> + </bind_material> + </instance_geometry> + <extra> + <technique profile="OpenCOLLADAMaya"> + <originalMayaNodeId>pSphere7</originalMayaNodeId> + </technique> + </extra> + </node> + <node id="pSphere8" name="pSphere8"> + <translate sid="translate">21.7661 0 -13.6375</translate> + <scale sid="scale">1 1 1</scale> + <instance_geometry url="#pSphereShape8"> + <bind_material> + <technique_common> + <instance_material symbol="lambert6SG" target="#Plastic"> + <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" /> + </instance_material> + </technique_common> + </bind_material> + </instance_geometry> + <extra> + <technique profile="OpenCOLLADAMaya"> + <originalMayaNodeId>pSphere8</originalMayaNodeId> + </technique> + </extra> + </node> + <node id="pSphere9" name="pSphere9"> + <translate sid="translate">13.0966 0 5.76254</translate> + <scale sid="scale">1 1 1</scale> + <instance_geometry url="#pSphereShape9"> + <bind_material> + <technique_common> + <instance_material symbol="lambert6SG" target="#Plastic"> + <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" /> + </instance_material> + </technique_common> + </bind_material> + </instance_geometry> + <extra> + <technique profile="OpenCOLLADAMaya"> + <originalMayaNodeId>pSphere9</originalMayaNodeId> + </technique> + </extra> + </node> + <extra> + <technique profile="OpenCOLLADAMaya"> + <originalMayaNodeId>group1</originalMayaNodeId> + </technique> + </extra> + </node> + <node id="group2" name="group2"> + <translate sid="translate">0 0 0</translate> + <rotate sid="rotateZ">0 0 1 45.4017</rotate> + <rotate sid="rotateY">0 1 0 79.393</rotate> + <rotate sid="rotateX">1 0 0 5.10889</rotate> + <scale sid="scale">1 1 1</scale> + <node id="pSphere10" name="pSphere10"> + <translate sid="translate">31.0862 0 18.5992</translate> + <scale sid="scale">1 1 1</scale> + <instance_geometry url="#pSphereShape10"> + <bind_material> + <technique_common> + <instance_material symbol="lambert5SG" target="#Metal"> + <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" /> + </instance_material> + </technique_common> + </bind_material> + </instance_geometry> + <extra> + <technique profile="OpenCOLLADAMaya"> + <originalMayaNodeId>pSphere10</originalMayaNodeId> + </technique> + </extra> + </node> + <node id="pSphere11" name="pSphere11"> + <translate sid="translate">13.0966 0 5.76254</translate> + <scale sid="scale">1 1 1</scale> + <instance_geometry url="#pSphereShape11"> + <bind_material> + <technique_common> + <instance_material symbol="lambert5SG" target="#Metal"> + <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" /> + </instance_material> + </technique_common> + </bind_material> + </instance_geometry> + <extra> + <technique profile="OpenCOLLADAMaya"> + <originalMayaNodeId>pSphere11</originalMayaNodeId> + </technique> + </extra> + </node> + <node id="pSphere12" name="pSphere12"> + <translate sid="translate">7.4784 16.3496 7.36882</translate> + <rotate sid="rotateZ">0 0 1 17.3073</rotate> + <rotate sid="rotateY">0 1 0 158.666</rotate> + <rotate sid="rotateX">1 0 0 79.4335</rotate> + <scale sid="scale">1 1 1</scale> + <instance_geometry url="#pSphereShape12"> + <bind_material> + <technique_common> + <instance_material symbol="lambert5SG" target="#Metal"> + <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" /> + </instance_material> + </technique_common> + </bind_material> + </instance_geometry> + <extra> + <technique profile="OpenCOLLADAMaya"> + <originalMayaNodeId>pSphere12</originalMayaNodeId> + </technique> + </extra> + </node> + <node id="pSphere13" name="pSphere13"> + <translate sid="translate">-9.69237 0 7.70498</translate> + <scale sid="scale">1 1 1</scale> + <instance_geometry url="#pSphereShape13"> + <bind_material> + <technique_common> + <instance_material symbol="lambert5SG" target="#Metal"> + <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" /> + </instance_material> + </technique_common> + </bind_material> + </instance_geometry> + <extra> + <technique profile="OpenCOLLADAMaya"> + <originalMayaNodeId>pSphere13</originalMayaNodeId> + </technique> + </extra> + </node> + <node id="pSphere14" name="pSphere14"> + <translate sid="translate">11.3635 -4.3926 2.21012</translate> + <rotate sid="rotateZ">0 0 1 17.3073</rotate> + <rotate sid="rotateY">0 1 0 158.666</rotate> + <rotate sid="rotateX">1 0 0 79.4335</rotate> + <scale sid="scale">1 1 1</scale> + <instance_geometry url="#pSphereShape14"> + <bind_material> + <technique_common> + <instance_material symbol="lambert5SG" target="#Metal"> + <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" /> + </instance_material> + </technique_common> + </bind_material> + </instance_geometry> + <extra> + <technique profile="OpenCOLLADAMaya"> + <originalMayaNodeId>pSphere14</originalMayaNodeId> + </technique> + </extra> + </node> + <node id="pSphere15" name="pSphere15"> + <translate sid="translate">21.7661 0 -13.6375</translate> + <scale sid="scale">1 1 1</scale> + <instance_geometry url="#pSphereShape15"> + <bind_material> + <technique_common> + <instance_material symbol="lambert5SG" target="#Metal"> + <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" /> + </instance_material> + </technique_common> + </bind_material> + </instance_geometry> + <extra> + <technique profile="OpenCOLLADAMaya"> + <originalMayaNodeId>pSphere15</originalMayaNodeId> + </technique> + </extra> + </node> + <node id="pSphere16" name="pSphere16"> + <translate sid="translate">-9.5945 -8.92317 -5.74901</translate> + <rotate sid="rotateZ">0 0 1 17.3073</rotate> + <rotate sid="rotateY">0 1 0 158.666</rotate> + <rotate sid="rotateX">1 0 0 79.4335</rotate> + <scale sid="scale">1 1 1</scale> + <instance_geometry url="#pSphereShape16"> + <bind_material> + <technique_common> + <instance_material symbol="lambert5SG" target="#Metal"> + <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" /> + </instance_material> + </technique_common> + </bind_material> + </instance_geometry> + <extra> + <technique profile="OpenCOLLADAMaya"> + <originalMayaNodeId>pSphere16</originalMayaNodeId> + </technique> + </extra> + </node> + <node id="pSphere17" name="pSphere17"> + <translate sid="translate">-13.862 0 -13.6154</translate> + <scale sid="scale">1 1 1</scale> + <instance_geometry url="#pSphereShape17"> + <bind_material> + <technique_common> + <instance_material symbol="lambert5SG" target="#Metal"> + <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" /> + </instance_material> + </technique_common> + </bind_material> + </instance_geometry> + <extra> + <technique profile="OpenCOLLADAMaya"> + <originalMayaNodeId>pSphere17</originalMayaNodeId> + </technique> + </extra> + </node> + <node id="pSphere18" name="pSphere18"> + <translate sid="translate">-24.2135 6.497 -5.58935</translate> + <rotate sid="rotateZ">0 0 1 17.3073</rotate> + <rotate sid="rotateY">0 1 0 158.666</rotate> + <rotate sid="rotateX">1 0 0 79.4335</rotate> + <scale sid="scale">1 1 1</scale> + <instance_geometry url="#pSphereShape18"> + <bind_material> + <technique_common> + <instance_material symbol="lambert5SG" target="#Metal"> + <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" /> + </instance_material> + </technique_common> + </bind_material> + </instance_geometry> + <extra> + <technique profile="OpenCOLLADAMaya"> + <originalMayaNodeId>pSphere18</originalMayaNodeId> + </technique> + </extra> + </node> + <extra> + <technique profile="OpenCOLLADAMaya"> + <originalMayaNodeId>group2</originalMayaNodeId> + </technique> + </extra> + </node> + <node id="pCube2" name="pCube2"> + <translate sid="translate">0 0 0</translate> + <scale sid="scale">1 1 1</scale> + <instance_geometry url="#pCubeShape2"> + <bind_material> + <technique_common> + <instance_material symbol="lambert8SG" target="#PlasticCenter"> + <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" /> + </instance_material> + </technique_common> + </bind_material> + </instance_geometry> + <extra> + <technique profile="OpenCOLLADAMaya"> + <originalMayaNodeId>pCube2</originalMayaNodeId> + </technique> + </extra> + </node> + <node id="pCube3" name="pCube3"> + <translate sid="translate">15 0 0</translate> + <scale sid="scale">1 1 1</scale> + <instance_geometry url="#pCubeShape3"> + <bind_material> + <technique_common> + <instance_material symbol="lambert9SG" target="#PlasticRed"> + <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" /> + </instance_material> + </technique_common> + </bind_material> + </instance_geometry> + <extra> + <technique profile="OpenCOLLADAMaya"> + <originalMayaNodeId>pCube3</originalMayaNodeId> + </technique> + </extra> + </node> + <node id="pCube4" name="pCube4"> + <translate sid="translate">0 15 0</translate> + <scale sid="scale">1 1 1</scale> + <instance_geometry url="#pCubeShape4"> + <bind_material> + <technique_common> + <instance_material symbol="lambert10SG" target="#lambert10"> + <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" /> + </instance_material> + </technique_common> + </bind_material> + </instance_geometry> + <extra> + <technique profile="OpenCOLLADAMaya"> + <originalMayaNodeId>pCube4</originalMayaNodeId> + </technique> + </extra> + </node> + <node id="pCube5" name="pCube5"> + <translate sid="translate">0 0 15</translate> + <scale sid="scale">1 1 1</scale> + <instance_geometry url="#pCubeShape5"> + <bind_material> + <technique_common> + <instance_material symbol="lambert11SG" target="#lambert11"> + <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" /> + </instance_material> + </technique_common> + </bind_material> + </instance_geometry> + <extra> + <technique profile="OpenCOLLADAMaya"> + <originalMayaNodeId>pCube5</originalMayaNodeId> + </technique> + </extra> + </node> + </visual_scene> + </library_visual_scenes> + <scene> + <instance_visual_scene url="#VisualSceneNode" /> + </scene> +</COLLADA> diff --git a/tests/RenderScriptTests/SceneGraph/assets/paint.jpg b/tests/RenderScriptTests/SceneGraph/assets/paint.jpg Binary files differnew file mode 100644 index 000000000000..0791045b5c18 --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/assets/paint.jpg diff --git a/tests/RenderScriptTests/SceneGraph/assets/red.jpg b/tests/RenderScriptTests/SceneGraph/assets/red.jpg Binary files differnew file mode 100644 index 000000000000..320a2a6ad187 --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/assets/red.jpg diff --git a/tests/RenderScriptTests/SceneGraph/res/drawable-nodpi/robot.png b/tests/RenderScriptTests/SceneGraph/res/drawable-nodpi/robot.png Binary files differnew file mode 100644 index 000000000000..f7353fd61c5b --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/res/drawable-nodpi/robot.png diff --git a/tests/RenderScriptTests/SceneGraph/res/menu/loader_menu.xml b/tests/RenderScriptTests/SceneGraph/res/menu/loader_menu.xml new file mode 100644 index 000000000000..9ea3010759b6 --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/res/menu/loader_menu.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +* Copyright (C) 2011 The Android Open Source Project +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +--> + +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:id="@+id/load_model" + android:title="@string/load_model" /> + <item android:id="@+id/use_blur" + android:title="@string/use_blur" /> +</menu> diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/blur_h.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/blur_h.glsl new file mode 100644 index 000000000000..fa468cc3620c --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/res/raw/blur_h.glsl @@ -0,0 +1,15 @@ +varying vec2 varTex0; + +void main() { + vec2 blurCoord = varTex0; + blurCoord.x = varTex0.x + UNI_blurOffset0; + vec3 col = texture2D(UNI_Tex0, blurCoord).rgb; + blurCoord.x = varTex0.x + UNI_blurOffset1; + col += texture2D(UNI_Tex0, blurCoord).rgb; + blurCoord.x = varTex0.x + UNI_blurOffset2; + col += texture2D(UNI_Tex0, blurCoord).rgb; + blurCoord.x = varTex0.x + UNI_blurOffset3; + col += texture2D(UNI_Tex0, blurCoord).rgb; + + gl_FragColor = vec4(col * 0.25, 0.0); //texture2D(UNI_Tex0, varTex0); +} diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/blur_v.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/blur_v.glsl new file mode 100644 index 000000000000..a644a3e6b8fb --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/res/raw/blur_v.glsl @@ -0,0 +1,17 @@ +varying vec2 varTex0; + +void main() { + vec2 blurCoord = varTex0; + blurCoord.y = varTex0.y + UNI_blurOffset0; + vec3 col = texture2D(UNI_Tex0, blurCoord).rgb; + blurCoord.y = varTex0.y + UNI_blurOffset1; + col += texture2D(UNI_Tex0, blurCoord).rgb; + blurCoord.y = varTex0.y + UNI_blurOffset2; + col += texture2D(UNI_Tex0, blurCoord).rgb; + blurCoord.y = varTex0.y + UNI_blurOffset3; + col += texture2D(UNI_Tex0, blurCoord).rgb; + + col = col * 0.25; + + gl_FragColor = vec4(col, 0.0); //texture2D(UNI_Tex0, varTex0); +} diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/blur_vertex.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/blur_vertex.glsl new file mode 100644 index 000000000000..bc824b6eb77e --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/res/raw/blur_vertex.glsl @@ -0,0 +1,7 @@ +varying vec2 varTex0; + +void main() { + gl_Position = ATTRIB_position; + varTex0 = ATTRIB_texture0; +} + diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/diffuse.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/diffuse.glsl new file mode 100644 index 000000000000..5d8938bc5a4e --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/res/raw/diffuse.glsl @@ -0,0 +1,19 @@ +varying vec3 varWorldPos; +varying vec3 varWorldNormal; +varying vec2 varTex0; + +void main() { + + vec3 V = normalize(UNI_cameraPos.xyz - varWorldPos.xyz); + vec3 worldNorm = (varWorldNormal); + + vec3 light0Vec = V; + vec3 light0R = reflect(light0Vec, worldNorm); + float light0_Diffuse = dot(worldNorm, light0Vec); + + vec2 t0 = varTex0.xy; + lowp vec4 col = texture2D(UNI_Tex0, t0).rgba; + col.xyz = col.xyz * light0_Diffuse * 1.2; + gl_FragColor = col; //vec4(0.0, 1.0, 0.0, 0.0); +} + diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/metal.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/metal.glsl new file mode 100644 index 000000000000..51f06124d759 --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/res/raw/metal.glsl @@ -0,0 +1,23 @@ +varying vec3 varWorldPos; +varying vec3 varWorldNormal; +varying vec2 varTex0; + +void main() { + + vec3 V = normalize(UNI_cameraPos.xyz - varWorldPos.xyz); + vec3 worldNorm = normalize(varWorldNormal); + + vec3 light0Vec = V; + vec3 light0R = reflect(light0Vec, worldNorm); + float light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.0, 1.0); + float light0Spec = clamp(dot(-light0R, V), 0.001, 1.0); + float light0_Specular = pow(light0Spec, 15.0) * 0.5; + + vec2 t0 = varTex0.xy; + lowp vec4 col = texture2D(UNI_Tex0, t0).rgba; + col.xyz = col.xyz * (textureCube(UNI_Tex1, worldNorm).rgb * 0.5 + vec3(light0_Diffuse)); + col.xyz += light0_Specular * vec3(0.8, 0.8, 1.0); + + gl_FragColor = col; +} + diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/paintf.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/paintf.glsl new file mode 100644 index 000000000000..893d55399003 --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/res/raw/paintf.glsl @@ -0,0 +1,26 @@ +varying vec3 varWorldPos; +varying vec3 varWorldNormal; +varying vec2 varTex0; + +void main() { + + vec3 V = normalize(UNI_cameraPos.xyz - varWorldPos.xyz); + vec3 worldNorm = normalize(varWorldNormal); + + vec3 light0Vec = V; + vec3 light0R = reflect(light0Vec, worldNorm); + float light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.01, 0.99); + float light0Spec = clamp(dot(-light0R, V), 0.001, 1.0); + float light0_Specular = pow(light0Spec, 150.0) * 0.5; + + vec2 t0 = varTex0.xy; + lowp vec4 col = texture2D(UNI_Tex0, t0).rgba; + col.xyz = col.xyz * light0_Diffuse * 1.1; + col.xyz += light0_Specular * vec3(0.8, 0.8, 1.0); + + float fresnel = mix(pow(1.0 - light0_Diffuse, 15.0), 1.0, 0.1); + col.xyz = mix(col.xyz, textureCube(UNI_Tex1, -light0R).rgb * 2.4, fresnel); + col.w = 0.8; + gl_FragColor = col; +} + diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/plastic.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/plastic.glsl new file mode 100644 index 000000000000..ceb53bd232d2 --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/res/raw/plastic.glsl @@ -0,0 +1,22 @@ +varying vec3 varWorldPos; +varying vec3 varWorldNormal; +varying vec2 varTex0; + +void main() { + + vec3 V = normalize(UNI_cameraPos.xyz - varWorldPos.xyz); + vec3 worldNorm = normalize(varWorldNormal); + + vec3 light0Vec = V; + vec3 light0R = reflect(light0Vec, worldNorm); + float light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.0, 1.0); + float light0Spec = clamp(dot(-light0R, V), 0.001, 1.0); + float light0_Specular = pow(light0Spec, 10.0) * 0.5; + + vec2 t0 = varTex0.xy; + lowp vec4 col = texture2D(UNI_Tex0, t0).rgba; + col.xyz = col.xyz * light0_Diffuse * 1.2; + col.xyz += light0_Specular * vec3(0.8, 0.8, 1.0); + gl_FragColor = col; +} + diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/plastic_lights.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/plastic_lights.glsl new file mode 100644 index 000000000000..b2536226afb7 --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/res/raw/plastic_lights.glsl @@ -0,0 +1,29 @@ +varying vec3 varWorldPos; +varying vec3 varWorldNormal; +varying vec2 varTex0; + +void main() { + + vec3 V = normalize(UNI_cameraPos.xyz - varWorldPos.xyz); + vec3 worldNorm = normalize(varWorldNormal); + + vec3 light0Vec = normalize(UNI_lightPos_0.xyz - varWorldPos.xyz); + vec3 light0R = reflect(light0Vec, worldNorm); + float light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.0, 1.0); + float light0Spec = clamp(dot(-light0R, V), 0.001, 1.0); + float light0_Specular = pow(light0Spec, 10.0) * 0.7; + + vec3 light1Vec = normalize(UNI_lightPos_1.xyz - varWorldPos.xyz); + vec3 light1R = reflect(light1Vec, worldNorm); + float light1_Diffuse = clamp(dot(worldNorm, light1Vec), 0.0, 1.0); + float light1Spec = clamp(dot(-light1R, V), 0.001, 1.0); + float light1_Specular = pow(light1Spec, 10.0) * 0.7; + + vec2 t0 = varTex0.xy; + lowp vec4 col = UNI_diffuse; + col.xyz = col.xyz * (light0_Diffuse * UNI_lightColor_0.xyz + + light1_Diffuse * UNI_lightColor_1.xyz); + col.xyz += (light0_Specular + light1_Specular); + gl_FragColor = col; +} + diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/robot.a3d b/tests/RenderScriptTests/SceneGraph/res/raw/robot.a3d Binary files differnew file mode 100644 index 000000000000..f48895cd8451 --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/res/raw/robot.a3d diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/select_color.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/select_color.glsl new file mode 100644 index 000000000000..42b231aa8657 --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/res/raw/select_color.glsl @@ -0,0 +1,13 @@ +varying vec2 varTex0; + +void main() { + vec3 col = texture2D(UNI_Tex0, varTex0).rgb; + + vec3 desat = vec3(0.299, 0.587, 0.114); + float lum = dot(desat, col); + float stepVal = step(lum, 0.8); + col = mix(col, vec3(0.0), stepVal)*0.5; + + gl_FragColor = vec4(col, 0.0); +} + diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/shader2v.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/shader2v.glsl new file mode 100644 index 000000000000..1ea234f0a77b --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/res/raw/shader2v.glsl @@ -0,0 +1,17 @@ +varying vec3 varWorldPos; +varying vec3 varWorldNormal; +varying vec2 varTex0; + +// This is where actual shader code begins +void main() { + vec4 objPos = ATTRIB_position; + vec4 worldPos = UNI_model * objPos; + gl_Position = UNI_viewProj * worldPos; + + mat3 model3 = mat3(UNI_model[0].xyz, UNI_model[1].xyz, UNI_model[2].xyz); + vec3 worldNorm = model3 * ATTRIB_normal; + + varWorldPos = worldPos.xyz; + varWorldNormal = worldNorm; + varTex0 = ATTRIB_texture0; +} diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/texture.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/texture.glsl new file mode 100644 index 000000000000..dd709cf01f9d --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/res/raw/texture.glsl @@ -0,0 +1,7 @@ +varying vec2 varTex0; + +void main() { + lowp vec4 col = texture2D(UNI_Tex0, varTex0).rgba; + gl_FragColor = col; +} + diff --git a/tests/RenderScriptTests/SceneGraph/res/values/strings.xml b/tests/RenderScriptTests/SceneGraph/res/values/strings.xml new file mode 100644 index 000000000000..c916d791c143 --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/res/values/strings.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +* Copyright (C) 2011 The Android Open Source Project +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +--> + +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <skip /> + <string name="load_model">Load Model</string> + <string name="use_blur">Use Blur</string> +</resources> diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Camera.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Camera.java new file mode 100644 index 000000000000..42f2be5e1f59 --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Camera.java @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.scenegraph; + +import java.lang.Math; +import java.util.ArrayList; + +import com.android.scenegraph.SceneManager; + +import android.renderscript.*; +import android.renderscript.Matrix4f; +import android.renderscript.RenderScriptGL; +import android.util.Log; + +/** + * @hide + */ +public class Camera extends SceneGraphBase { + + Transform mTransform; + + ScriptField_Camera_s.Item mData; + ScriptField_Camera_s mField; + + public Camera() { + mData = new ScriptField_Camera_s.Item(); + mData.near = 0.1f; + mData.far = 1000.0f; + mData.horizontalFOV = 60.0f; + mData.aspect = 0; + } + + public void setTransform(Transform t) { + mTransform = t; + if (mField != null) { + mField.set_transformMatrix(0, mTransform.getRSData().getAllocation(), true); + mField.set_isDirty(0, 1, true); + } + } + public void setFOV(float fov) { + mData.horizontalFOV = fov; + if (mField != null) { + mField.set_horizontalFOV(0, fov, true); + mField.set_isDirty(0, 1, true); + } + } + + public void setNear(float n) { + mData.near = n; + if (mField != null) { + mField.set_near(0, n, true); + mField.set_isDirty(0, 1, true); + } + } + + public void setFar(float f) { + mData.far = f; + if (mField != null) { + mField.set_far(0, f, true); + mField.set_isDirty(0, 1, true); + } + } + + public void setName(String n) { + super.setName(n); + if (mField != null) { + RenderScriptGL rs = SceneManager.getRS(); + mData.name = getNameAlloc(rs); + mField.set_name(0, mData.name, true); + mField.set_isDirty(0, 1, true); + } + } + + ScriptField_Camera_s getRSData() { + if (mField != null) { + return mField; + } + + RenderScriptGL rs = SceneManager.getRS(); + if (rs == null) { + return null; + } + + if (mTransform == null) { + throw new RuntimeException("Cameras without transforms are invalid"); + } + + mField = new ScriptField_Camera_s(rs, 1); + + mData.transformMatrix = mTransform.getRSData().getAllocation(); + mData.transformTimestamp = 1; + mData.timestamp = 1; + mData.isDirty = 1; + mData.name = getNameAlloc(rs); + mField.set(mData, 0, true); + + return mField; + } +} + + + + + diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaParser.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaParser.java new file mode 100644 index 000000000000..d954313da12d --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaParser.java @@ -0,0 +1,563 @@ +/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.scenegraph;
+import com.android.scenegraph.CompoundTransform.TranslateComponent;
+import com.android.scenegraph.CompoundTransform.RotateComponent;
+import com.android.scenegraph.CompoundTransform.ScaleComponent;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.StringTokenizer;
+import java.util.HashMap;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+import android.renderscript.*;
+import android.util.Log;
+
+public class ColladaParser {
+ static final String TAG = "ColladaParser";
+ Document mDom;
+
+ HashMap<String, LightBase> mLights;
+ HashMap<String, Camera> mCameras;
+ HashMap<String, ArrayList<ShaderParam> > mEffectsParams;
+ HashMap<String, Texture2D> mImages;
+ HashMap<String, Texture2D> mSamplerImageMap;
+ HashMap<String, String> mMeshIdNameMap;
+ Scene mScene;
+
+ String mRootDir;
+
+ String toString(Float3 v) {
+ String valueStr = v.x + " " + v.y + " " + v.z;
+ return valueStr;
+ }
+
+ String toString(Float4 v) {
+ String valueStr = v.x + " " + v.y + " " + v.z + " " + v.w;
+ return valueStr;
+ }
+
+ public ColladaParser(){
+ mLights = new HashMap<String, LightBase>();
+ mCameras = new HashMap<String, Camera>();
+ mEffectsParams = new HashMap<String, ArrayList<ShaderParam> >();
+ mImages = new HashMap<String, Texture2D>();
+ mMeshIdNameMap = new HashMap<String, String>();
+ }
+
+ public void init(InputStream is, String rootDir) {
+ mLights.clear();
+ mCameras.clear();
+ mEffectsParams.clear();
+
+ mRootDir = rootDir;
+
+ long start = System.currentTimeMillis();
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ try {
+ DocumentBuilder db = dbf.newDocumentBuilder();
+ mDom = db.parse(is);
+ } catch(ParserConfigurationException e) {
+ e.printStackTrace();
+ } catch(SAXException e) {
+ e.printStackTrace();
+ } catch(IOException e) {
+ e.printStackTrace();
+ }
+ long end = System.currentTimeMillis();
+ Log.v("TIMER", " Parse time: " + (end - start));
+ exportSceneData();
+ }
+
+ Scene getScene() {
+ return mScene;
+ }
+
+ private void exportSceneData(){
+ mScene = new Scene();
+
+ Element docEle = mDom.getDocumentElement();
+ NodeList nl = docEle.getElementsByTagName("light");
+ if (nl != null) {
+ for(int i = 0; i < nl.getLength(); i++) {
+ Element l = (Element)nl.item(i);
+ convertLight(l);
+ }
+ }
+
+ nl = docEle.getElementsByTagName("camera");
+ if (nl != null) {
+ for(int i = 0; i < nl.getLength(); i++) {
+ Element c = (Element)nl.item(i);
+ convertCamera(c);
+ }
+ }
+
+ nl = docEle.getElementsByTagName("image");
+ if (nl != null) {
+ for(int i = 0; i < nl.getLength(); i++) {
+ Element img = (Element)nl.item(i);
+ convertImage(img);
+ }
+ }
+
+ nl = docEle.getElementsByTagName("effect");
+ if (nl != null) {
+ for(int i = 0; i < nl.getLength(); i++) {
+ Element e = (Element)nl.item(i);
+ convertEffects(e);
+ }
+ }
+
+ // Material is just a link to the effect
+ nl = docEle.getElementsByTagName("material");
+ if (nl != null) {
+ for(int i = 0; i < nl.getLength(); i++) {
+ Element m = (Element)nl.item(i);
+ convertMaterials(m);
+ }
+ }
+
+ // Look through the geometry list and build up a correlation between id's and names
+ nl = docEle.getElementsByTagName("geometry");
+ if (nl != null) {
+ for(int i = 0; i < nl.getLength(); i++) {
+ Element m = (Element)nl.item(i);
+ convertGeometries(m);
+ }
+ }
+
+
+ nl = docEle.getElementsByTagName("visual_scene");
+ if (nl != null) {
+ for(int i = 0; i < nl.getLength(); i++) {
+ Element s = (Element)nl.item(i);
+ getScene(s);
+ }
+ }
+ }
+
+ private void getRenderable(Element shape, Transform t) {
+ String geoURL = shape.getAttribute("url").substring(1);
+ String geoName = mMeshIdNameMap.get(geoURL);
+ if (geoName != null) {
+ geoURL = geoName;
+ }
+ //RenderableGroup group = new RenderableGroup();
+ //group.setName(geoURL.substring(1));
+ //mScene.appendRenderable(group);
+ NodeList nl = shape.getElementsByTagName("instance_material");
+ if (nl != null) {
+ for(int i = 0; i < nl.getLength(); i++) {
+ Element materialRef = (Element)nl.item(i);
+ String meshIndexName = materialRef.getAttribute("symbol");
+ String materialName = materialRef.getAttribute("target");
+
+ Renderable d = new Renderable();
+ d.setMesh(geoURL, meshIndexName);
+ d.setMaterialName(materialName.substring(1));
+ d.setName(geoURL);
+
+ //Log.v(TAG, "Created drawable geo " + geoURL + " index " + meshIndexName + " material " + materialName);
+
+ d.setTransform(t);
+ //Log.v(TAG, "Set source param " + t.getName());
+
+ // Now find all the parameters that exist on the material
+ ArrayList<ShaderParam> materialParams;
+ materialParams = mEffectsParams.get(materialName.substring(1));
+ for (int pI = 0; pI < materialParams.size(); pI ++) {
+ d.appendSourceParams(materialParams.get(pI));
+ //Log.v(TAG, "Set source param i: " + pI + " name " + materialParams.get(pI).getParamName());
+ }
+ mScene.appendRenderable(d);
+ //group.appendChildren(d);
+ }
+ }
+ }
+
+ private void updateLight(Element shape, Transform t) {
+ String lightURL = shape.getAttribute("url");
+ // collada uses a uri structure to link things,
+ // but we ignore it for now and do a simple search
+ LightBase light = mLights.get(lightURL.substring(1));
+ if (light != null) {
+ light.setTransform(t);
+ //Log.v(TAG, "Set Light " + light.getName() + " " + t.getName());
+ }
+ }
+
+ private void updateCamera(Element shape, Transform t) {
+ String camURL = shape.getAttribute("url");
+ // collada uses a uri structure to link things,
+ // but we ignore it for now and do a simple search
+ Camera cam = mCameras.get(camURL.substring(1));
+ if (cam != null) {
+ cam.setTransform(t);
+ //Log.v(TAG, "Set Camera " + cam.getName() + " " + t.getName());
+ }
+ }
+
+ private void getNode(Element node, Transform parent, String indent) {
+ String name = node.getAttribute("name");
+ String id = node.getAttribute("id");
+ CompoundTransform current = new CompoundTransform();
+ current.setName(name);
+ if (parent != null) {
+ parent.appendChild(current);
+ } else {
+ mScene.appendTransform(current);
+ }
+
+ mScene.addToTransformMap(current);
+
+ //Log.v(TAG, indent + "|");
+ //Log.v(TAG, indent + "[" + name + "]");
+
+ Node childNode = node.getFirstChild();
+ while (childNode != null) {
+ if (childNode.getNodeType() == Node.ELEMENT_NODE) {
+ Element field = (Element)childNode;
+ String fieldName = field.getTagName();
+ String description = field.getAttribute("sid");
+ if (fieldName.equals("translate")) {
+ Float3 value = getFloat3(field);
+ current.addComponent(new TranslateComponent(description, value));
+ //Log.v(TAG, indent + " translate " + description + toString(value));
+ } else if (fieldName.equals("rotate")) {
+ Float4 value = getFloat4(field);
+ //Log.v(TAG, indent + " rotate " + description + toString(value));
+ Float3 axis = new Float3(value.x, value.y, value.z);
+ current.addComponent(new RotateComponent(description, axis, value.w));
+ } else if (fieldName.equals("scale")) {
+ Float3 value = getFloat3(field);
+ //Log.v(TAG, indent + " scale " + description + toString(value));
+ current.addComponent(new ScaleComponent(description, value));
+ } else if (fieldName.equals("instance_geometry")) {
+ getRenderable(field, current);
+ } else if (fieldName.equals("instance_light")) {
+ updateLight(field, current);
+ } else if (fieldName.equals("instance_camera")) {
+ updateCamera(field, current);
+ } else if (fieldName.equals("node")) {
+ getNode(field, current, indent + " ");
+ }
+ }
+ childNode = childNode.getNextSibling();
+ }
+ }
+
+ // This will find the actual texture node, which is sometimes hidden behind a sampler
+ // and sometimes referenced directly
+ Texture2D getTexture(String samplerName) {
+ String texName = samplerName;
+
+ // Check to see if the image file is hidden by a sampler surface link combo
+ Element sampler = mDom.getElementById(samplerName);
+ if (sampler != null) {
+ NodeList nl = sampler.getElementsByTagName("source");
+ if (nl != null && nl.getLength() == 1) {
+ Element ref = (Element)nl.item(0);
+ String surfaceName = getString(ref);
+ if (surfaceName == null) {
+ return null;
+ }
+
+ Element surface = mDom.getElementById(surfaceName);
+ if (surface == null) {
+ return null;
+ }
+ nl = surface.getElementsByTagName("init_from");
+ if (nl != null && nl.getLength() == 1) {
+ ref = (Element)nl.item(0);
+ texName = getString(ref);
+ }
+ }
+ }
+
+ //Log.v(TAG, "Extracted texture name " + texName);
+ return mImages.get(texName);
+ }
+
+ void extractParams(Element fx, ArrayList<ShaderParam> params) {
+ Node paramNode = fx.getFirstChild();
+ while (paramNode != null) {
+ if (paramNode.getNodeType() == Node.ELEMENT_NODE) {
+ String name = paramNode.getNodeName();
+ // Now find what type it is
+ Node typeNode = paramNode.getFirstChild();
+ while (typeNode != null && typeNode.getNodeType() != Node.ELEMENT_NODE) {
+ typeNode = typeNode.getNextSibling();
+ }
+ String paramType = typeNode.getNodeName();
+ Element typeElem = (Element)typeNode;
+ ShaderParam sceneParam = null;
+ if (paramType.equals("color")) {
+ Float4Param f4p = new Float4Param(name);
+ Float4 value = getFloat4(typeElem);
+ f4p.setValue(value);
+ sceneParam = f4p;
+ //Log.v(TAG, "Extracted " + sceneParam.getParamName() + " value " + toString(value));
+ } else if (paramType.equals("float")) {
+ Float4Param f4p = new Float4Param(name);
+ float value = getFloat(typeElem);
+ f4p.setValue(new Float4(value, value, value, value));
+ sceneParam = f4p;
+ //Log.v(TAG, "Extracted " + sceneParam.getParamName() + " value " + value);
+ } else if (paramType.equals("texture")) {
+ String samplerName = typeElem.getAttribute("texture");
+ Texture2D tex = getTexture(samplerName);
+ TextureParam texP = new TextureParam(name);
+ texP.setTexture(tex);
+ sceneParam = texP;
+ //Log.v(TAG, "Extracted texture " + tex);
+ }
+ if (sceneParam != null) {
+ params.add(sceneParam);
+ }
+ }
+ paramNode = paramNode.getNextSibling();
+ }
+ }
+
+ private void convertMaterials(Element mat) {
+ String id = mat.getAttribute("id");
+ NodeList nl = mat.getElementsByTagName("instance_effect");
+ if (nl != null && nl.getLength() == 1) {
+ Element ref = (Element)nl.item(0);
+ String url = ref.getAttribute("url");
+ ArrayList<ShaderParam> params = mEffectsParams.get(url.substring(1));
+ mEffectsParams.put(id, params);
+ }
+ }
+
+ private void convertGeometries(Element geo) {
+ String id = geo.getAttribute("id");
+ String name = geo.getAttribute("name");
+ if (!id.equals(name)) {
+ mMeshIdNameMap.put(id, name);
+ }
+ }
+
+ private void convertEffects(Element fx) {
+ String id = fx.getAttribute("id");
+ ArrayList<ShaderParam> params = new ArrayList<ShaderParam>();
+
+ NodeList nl = fx.getElementsByTagName("newparam");
+ if (nl != null) {
+ for(int i = 0; i < nl.getLength(); i++) {
+ Element field = (Element)nl.item(i);
+ field.setIdAttribute("sid", true);
+ }
+ }
+
+ nl = fx.getElementsByTagName("blinn");
+ if (nl != null) {
+ for(int i = 0; i < nl.getLength(); i++) {
+ Element field = (Element)nl.item(i);
+ //Log.v(TAG, "blinn");
+ extractParams(field, params);
+ }
+ }
+ nl = fx.getElementsByTagName("lambert");
+ if (nl != null) {
+ for(int i = 0; i < nl.getLength(); i++) {
+ Element field = (Element)nl.item(i);
+ //Log.v(TAG, "lambert");
+ extractParams(field, params);
+ }
+ }
+ nl = fx.getElementsByTagName("phong");
+ if (nl != null) {
+ for(int i = 0; i < nl.getLength(); i++) {
+ Element field = (Element)nl.item(i);
+ //Log.v(TAG, "phong");
+ extractParams(field, params);
+ }
+ }
+ mEffectsParams.put(id, params);
+ }
+
+ private void convertLight(Element light) {
+ String name = light.getAttribute("name");
+ String id = light.getAttribute("id");
+
+ // Determine type
+ String[] knownTypes = { "point", "spot", "directional" };
+ final int POINT_LIGHT = 0;
+ final int SPOT_LIGHT = 1;
+ final int DIR_LIGHT = 2;
+ int type = -1;
+ for (int i = 0; i < knownTypes.length; i ++) {
+ NodeList nl = light.getElementsByTagName(knownTypes[i]);
+ if (nl != null && nl.getLength() != 0) {
+ type = i;
+ break;
+ }
+ }
+
+ //Log.v(TAG, "Found Light Type " + type);
+
+ LightBase sceneLight = null;
+ switch (type) {
+ case POINT_LIGHT:
+ sceneLight = new PointLight();
+ break;
+ case SPOT_LIGHT: // TODO: finish light types
+ break;
+ case DIR_LIGHT: // TODO: finish light types
+ break;
+ }
+
+ if (sceneLight == null) {
+ return;
+ }
+
+ Float3 color = getFloat3(light, "color");
+ sceneLight.setColor(color.x, color.y, color.z);
+ sceneLight.setName(name);
+ mScene.appendLight(sceneLight);
+ mLights.put(id, sceneLight);
+
+ //Log.v(TAG, "Light " + name + " color " + toString(color));
+ }
+
+ private void convertCamera(Element camera) {
+ String name = camera.getAttribute("name");
+ String id = camera.getAttribute("id");
+ float fov = 30.0f;
+ if (getString(camera, "yfov") != null) {
+ fov = getFloat(camera, "yfov");
+ } else if(getString(camera, "xfov") != null) {
+ float aspect = getFloat(camera, "aspect_ratio");
+ fov = getFloat(camera, "xfov") / aspect;
+ }
+
+ float near = getFloat(camera, "znear");
+ float far = getFloat(camera, "zfar");
+
+ Camera sceneCamera = new Camera();
+ sceneCamera.setFOV(fov);
+ sceneCamera.setNear(near);
+ sceneCamera.setFar(far);
+ sceneCamera.setName(name);
+ mScene.appendCamera(sceneCamera);
+ mCameras.put(id, sceneCamera);
+ }
+
+ private void convertImage(Element img) {
+ String name = img.getAttribute("name");
+ String id = img.getAttribute("id");
+ String file = getString(img, "init_from");
+
+ Texture2D tex = new Texture2D();
+ tex.setFileName(file);
+ tex.setFileDir(mRootDir);
+ mScene.appendTextures(tex);
+ mImages.put(id, tex);
+ }
+
+ private void getScene(Element scene) {
+ String name = scene.getAttribute("name");
+ String id = scene.getAttribute("id");
+
+ Node childNode = scene.getFirstChild();
+ while (childNode != null) {
+ if (childNode.getNodeType() == Node.ELEMENT_NODE) {
+ String indent = "";
+ getNode((Element)childNode, null, indent);
+ }
+ childNode = childNode.getNextSibling();
+ }
+ }
+
+ private String getString(Element elem, String name) {
+ String text = null;
+ NodeList nl = elem.getElementsByTagName(name);
+ if (nl != null && nl.getLength() != 0) {
+ text = ((Element)nl.item(0)).getFirstChild().getNodeValue();
+ }
+ return text;
+ }
+
+ private String getString(Element elem) {
+ String text = null;
+ text = elem.getFirstChild().getNodeValue();
+ return text;
+ }
+
+ private int getInt(Element elem, String name) {
+ return Integer.parseInt(getString(elem, name));
+ }
+
+ private float getFloat(Element elem, String name) {
+ return Float.parseFloat(getString(elem, name));
+ }
+
+ private float getFloat(Element elem) {
+ return Float.parseFloat(getString(elem));
+ }
+
+ private Float3 parseFloat3(String valueString) {
+ StringTokenizer st = new StringTokenizer(valueString);
+ float x = Float.parseFloat(st.nextToken());
+ float y = Float.parseFloat(st.nextToken());
+ float z = Float.parseFloat(st.nextToken());
+ return new Float3(x, y, z);
+ }
+
+ private Float4 parseFloat4(String valueString) {
+ StringTokenizer st = new StringTokenizer(valueString);
+ float x = Float.parseFloat(st.nextToken());
+ float y = Float.parseFloat(st.nextToken());
+ float z = Float.parseFloat(st.nextToken());
+ float w = Float.parseFloat(st.nextToken());
+ return new Float4(x, y, z, w);
+ }
+
+ private Float3 getFloat3(Element elem, String name) {
+ String valueString = getString(elem, name);
+ return parseFloat3(valueString);
+ }
+
+ private Float4 getFloat4(Element elem, String name) {
+ String valueString = getString(elem, name);
+ return parseFloat4(valueString);
+ }
+
+ private Float3 getFloat3(Element elem) {
+ String valueString = getString(elem);
+ return parseFloat3(valueString);
+ }
+
+ private Float4 getFloat4(Element elem) {
+ String valueString = getString(elem);
+ return parseFloat4(valueString);
+ }
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaScene.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaScene.java new file mode 100644 index 000000000000..301075e52441 --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaScene.java @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.scenegraph; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.FileInputStream; +import java.io.BufferedInputStream; +import java.io.Writer; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.Vector; + +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.AsyncTask; +import android.renderscript.*; +import android.renderscript.Allocation.MipmapControl; +import android.renderscript.Element.Builder; +import android.renderscript.Font.Style; +import android.renderscript.Program.TextureType; +import android.renderscript.ProgramStore.DepthFunc; +import android.util.Log; +import com.android.scenegraph.SceneManager.SceneLoadedCallback; + + +public class ColladaScene { + + private String modelName; + private static String TAG = "ColladaScene"; + private final int STATE_LAST_FOCUS = 1; + boolean mLoadFromSD = false; + + SceneLoadedCallback mCallback; + + public ColladaScene(String name, SceneLoadedCallback cb) { + modelName = name; + mCallback = cb; + } + + public void init(RenderScriptGL rs, Resources res) { + mRS = rs; + mRes = res; + + mLoadFromSD = SceneManager.isSDCardPath(modelName); + + new ColladaLoaderTask().execute(modelName); + } + + private Resources mRes; + private RenderScriptGL mRS; + Scene mActiveScene; + + private class ColladaLoaderTask extends AsyncTask<String, Void, Boolean> { + ColladaParser sceneSource; + protected Boolean doInBackground(String... names) { + String rootDir = names[0].substring(0, names[0].lastIndexOf('/') + 1); + long start = System.currentTimeMillis(); + sceneSource = new ColladaParser(); + InputStream is = null; + try { + if (!mLoadFromSD) { + is = mRes.getAssets().open(names[0]); + } else { + File f = new File(names[0]); + is = new BufferedInputStream(new FileInputStream(f)); + } + } catch (IOException e) { + Log.e(TAG, "Could not open collada file"); + return new Boolean(false); + } + long end = System.currentTimeMillis(); + Log.v("TIMER", "Stream load time: " + (end - start)); + + start = System.currentTimeMillis(); + sceneSource.init(is, rootDir); + end = System.currentTimeMillis(); + Log.v("TIMER", "Collada parse time: " + (end - start)); + return new Boolean(true); + } + + protected void onPostExecute(Boolean result) { + mActiveScene = sceneSource.getScene(); + if (mCallback != null) { + mCallback.mLoadedScene = mActiveScene; + mCallback.run(); + } + + String shortName = modelName.substring(0, modelName.lastIndexOf('.')); + new A3DLoaderTask().execute(shortName + ".a3d"); + } + } + + private class A3DLoaderTask extends AsyncTask<String, Void, Boolean> { + protected Boolean doInBackground(String... names) { + long start = System.currentTimeMillis(); + FileA3D model; + if (!mLoadFromSD) { + model = FileA3D.createFromAsset(mRS, mRes.getAssets(), names[0]); + } else { + model = FileA3D.createFromFile(mRS, names[0]); + } + int numModels = model.getIndexEntryCount(); + for (int i = 0; i < numModels; i ++) { + FileA3D.IndexEntry entry = model.getIndexEntry(i); + if (entry != null && entry.getEntryType() == FileA3D.EntryType.MESH) { + mActiveScene.meshLoaded(entry.getMesh()); + } + } + long end = System.currentTimeMillis(); + Log.v("TIMER", "A3D load time: " + (end - start)); + return new Boolean(true); + } + + protected void onPostExecute(Boolean result) { + } + } + +} + + + diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/CompoundTransform.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/CompoundTransform.java new file mode 100644 index 000000000000..d995dd00af3a --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/CompoundTransform.java @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.scenegraph; + +import java.lang.Math; +import java.util.ArrayList; + +import com.android.scenegraph.SceneManager; + +import android.renderscript.*; +import android.renderscript.Float3; +import android.renderscript.Matrix4f; +import android.util.Log; + +/** + * @hide + */ +public class CompoundTransform extends Transform { + + public static abstract class Component { + String mName; + CompoundTransform mParent; + int mParentIndex; + protected ScriptField_TransformComponent_s.Item mData; + + Component(int type, String name) { + mData = new ScriptField_TransformComponent_s.Item(); + mData.type = type; + mName = name; + } + + void setNameAlloc() { + RenderScriptGL rs = SceneManager.getRS(); + if (mData.name != null) { + return; + } + mData.name = SceneManager.getCachedAlloc(getName()); + if (mData.name == null) { + mData.name = SceneManager.getStringAsAllocation(rs, getName()); + SceneManager.cacheAlloc(getName(), mData.name); + } + } + + ScriptField_TransformComponent_s.Item getRSData() { + setNameAlloc(); + return mData; + } + + protected void update() { + if (mParent != null) { + mParent.updateRSComponent(this); + } + } + + public String getName() { + return mName; + } + } + + public static class TranslateComponent extends Component { + public TranslateComponent(String name, Float3 translate) { + super(ScriptC_export.const_Transform_TRANSLATE, name); + setValue(translate); + } + public Float3 getValue() { + return new Float3(mData.value.x, mData.value.y, mData.value.z); + } + public void setValue(Float3 val) { + mData.value.x = val.x; + mData.value.y = val.y; + mData.value.z = val.z; + update(); + } + } + + public static class RotateComponent extends Component { + public RotateComponent(String name, Float3 axis, float angle) { + super(ScriptC_export.const_Transform_ROTATE, name); + setAxis(axis); + setAngle(angle); + } + public Float3 getAxis() { + return new Float3(mData.value.x, mData.value.y, mData.value.z); + } + public float getAngle() { + return mData.value.w; + } + public void setAxis(Float3 val) { + mData.value.x = val.x; + mData.value.y = val.y; + mData.value.z = val.z; + update(); + } + public void setAngle(float val) { + mData.value.w = val; + update(); + } + } + + public static class ScaleComponent extends Component { + public ScaleComponent(String name, Float3 scale) { + super(ScriptC_export.const_Transform_SCALE, name); + setValue(scale); + } + public Float3 getValue() { + return new Float3(mData.value.x, mData.value.y, mData.value.z); + } + public void setValue(Float3 val) { + mData.value.x = val.x; + mData.value.y = val.y; + mData.value.z = val.z; + update(); + } + } + + ScriptField_TransformComponent_s mComponentField; + public ArrayList<Component> mTransformComponents; + + public CompoundTransform() { + mTransformComponents = new ArrayList<Component>(); + } + + public void addComponent(Component c) { + if (c.mParent != null) { + throw new IllegalArgumentException("Transform components may not be shared"); + } + c.mParent = this; + c.mParentIndex = mTransformComponents.size(); + mTransformComponents.add(c); + updateRSComponentAllocation(); + } + + public void setComponent(int index, Component c) { + if (c.mParent != null) { + throw new IllegalArgumentException("Transform components may not be shared"); + } + if (index >= mTransformComponents.size()) { + throw new IllegalArgumentException("Invalid component index"); + } + c.mParent = this; + c.mParentIndex = index; + mTransformComponents.set(index, c); + updateRSComponent(c); + } + + void updateRSComponent(Component c) { + if (mField == null || mComponentField == null) { + return; + } + mComponentField.set(c.getRSData(), c.mParentIndex, true); + mField.set_isDirty(0, 1, true); + } + + void updateRSComponentAllocation() { + if (mField == null) { + return; + } + initLocalData(); + + mField.set_components(0, mTransformData.components, false); + mField.set_isDirty(0, 1, true); + } + + void initLocalData() { + RenderScriptGL rs = SceneManager.getRS(); + int numComponenets = mTransformComponents.size(); + if (numComponenets > 0) { + mComponentField = new ScriptField_TransformComponent_s(rs, numComponenets); + for (int i = 0; i < numComponenets; i ++) { + Component ith = mTransformComponents.get(i); + mComponentField.set(ith.getRSData(), i, false); + } + mComponentField.copyAll(); + + mTransformData.components = mComponentField.getAllocation(); + } + } +} + + + + + diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Float4Param.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Float4Param.java new file mode 100644 index 000000000000..15024588cad9 --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Float4Param.java @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.scenegraph; + +import java.lang.Math; +import java.util.ArrayList; + +import com.android.scenegraph.Scene; +import com.android.scenegraph.SceneManager; + +import android.renderscript.Element; +import android.renderscript.Float4; +import android.renderscript.Matrix4f; +import android.renderscript.ProgramFragment; +import android.renderscript.ProgramStore; +import android.renderscript.ProgramVertex; +import android.renderscript.RenderScriptGL; +import android.util.Log; + +/** + * @hide + */ +public class Float4Param extends ShaderParam { + private static String TAG = "Float4Param"; + + LightBase mLight; + + public Float4Param(String name) { + super(name); + } + + public Float4Param(String name, float x) { + super(name); + set(x, 0, 0, 0); + } + + public Float4Param(String name, float x, float y) { + super(name); + set(x, y, 0, 0); + } + + public Float4Param(String name, float x, float y, float z) { + super(name); + set(x, y, z, 0); + } + + public Float4Param(String name, float x, float y, float z, float w) { + super(name); + set(x, y, z, w); + } + + void set(float x, float y, float z, float w) { + mData.float_value.x = x; + mData.float_value.y = y; + mData.float_value.z = z; + mData.float_value.w = w; + if (mField != null) { + mField.set_float_value(0, mData.float_value, true); + } + incTimestamp(); + } + + public void setValue(Float4 v) { + set(v.x, v.y, v.z, v.w); + } + + public Float4 getValue() { + return mData.float_value; + } + + public void setLight(LightBase l) { + mLight = l; + if (mField != null) { + mData.light = mLight.getRSData().getAllocation(); + mField.set_light(0, mData.light, true); + } + incTimestamp(); + } + + boolean findLight(String property) { + String indexStr = mParamName.substring(property.length() + 1); + if (indexStr == null) { + Log.e(TAG, "Invalid light index."); + return false; + } + int index = Integer.parseInt(indexStr); + if (index == -1) { + return false; + } + Scene parentScene = SceneManager.getInstance().getActiveScene(); + ArrayList<LightBase> allLights = parentScene.getLights(); + if (index >= allLights.size()) { + return false; + } + mLight = allLights.get(index); + if (mLight == null) { + return false; + } + return true; + } + + int getTypeFromName() { + int paramType = ScriptC_export.const_ShaderParam_FLOAT4_DATA; + if (mParamName.equalsIgnoreCase(cameraPos)) { + paramType = ScriptC_export.const_ShaderParam_FLOAT4_CAMERA_POS; + } else if(mParamName.equalsIgnoreCase(cameraDir)) { + paramType = ScriptC_export.const_ShaderParam_FLOAT4_CAMERA_DIR; + } else if(mParamName.startsWith(lightColor) && findLight(lightColor)) { + paramType = ScriptC_export.const_ShaderParam_FLOAT4_LIGHT_COLOR; + } else if(mParamName.startsWith(lightPos) && findLight(lightPos)) { + paramType = ScriptC_export.const_ShaderParam_FLOAT4_LIGHT_POS; + } else if(mParamName.startsWith(lightDir) && findLight(lightDir)) { + paramType = ScriptC_export.const_ShaderParam_FLOAT4_LIGHT_DIR; + } + return paramType; + } + + void initLocalData() { + mData.type = getTypeFromName(); + if (mCamera != null) { + mData.camera = mCamera.getRSData().getAllocation(); + } + if (mLight != null) { + mData.light = mLight.getRSData().getAllocation(); + } + } +} + + + + + diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/FragmentShader.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/FragmentShader.java new file mode 100644 index 000000000000..c8cc3ac5d890 --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/FragmentShader.java @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.scenegraph; + +import java.lang.Math; +import java.util.ArrayList; + +import com.android.scenegraph.TextureBase; + +import android.content.res.Resources; +import android.renderscript.*; +import android.renderscript.ProgramFragment.Builder; +import android.util.Log; + +/** + * @hide + */ +public class FragmentShader extends Shader { + ProgramFragment mProgram; + ScriptField_FragmentShader_s mField; + + public static class Builder { + + FragmentShader mShader; + ProgramFragment.Builder mBuilder; + + public Builder(RenderScriptGL rs) { + mShader = new FragmentShader(); + mBuilder = new ProgramFragment.Builder(rs); + } + + public Builder setShader(Resources resources, int resourceID) { + mBuilder.setShader(resources, resourceID); + return this; + } + + public Builder setObjectConst(Type type) { + mShader.mPerObjConstants = type; + return this; + } + + public Builder setShaderConst(Type type) { + mShader.mPerShaderConstants = type; + return this; + } + + public Builder addShaderTexture(Program.TextureType texType, String name) { + mShader.mShaderTextureNames.add(name); + mShader.mShaderTextureTypes.add(texType); + return this; + } + + public Builder addTexture(Program.TextureType texType, String name) { + mShader.mTextureNames.add(name); + mShader.mTextureTypes.add(texType); + return this; + } + + public FragmentShader create() { + if (mShader.mPerShaderConstants != null) { + mBuilder.addConstant(mShader.mPerShaderConstants); + } + if (mShader.mPerObjConstants != null) { + mBuilder.addConstant(mShader.mPerObjConstants); + } + for (int i = 0; i < mShader.mTextureTypes.size(); i ++) { + mBuilder.addTexture(mShader.mTextureTypes.get(i)); + } + for (int i = 0; i < mShader.mShaderTextureTypes.size(); i ++) { + mBuilder.addTexture(mShader.mShaderTextureTypes.get(i)); + } + + mShader.mProgram = mBuilder.create(); + return mShader; + } + } + + public ProgramFragment getProgram() { + return mProgram; + } + + ScriptField_ShaderParam_s getTextureParams() { + RenderScriptGL rs = SceneManager.getRS(); + Resources res = SceneManager.getRes(); + if (rs == null || res == null) { + return null; + } + + ArrayList<ScriptField_ShaderParam_s.Item> paramList; + paramList = new ArrayList<ScriptField_ShaderParam_s.Item>(); + + int shaderTextureStart = mTextureTypes.size(); + for (int i = 0; i < mShaderTextureNames.size(); i ++) { + ShaderParam sp = mSourceParams.get(mShaderTextureNames.get(i)); + if (sp != null && sp instanceof TextureParam) { + TextureParam p = (TextureParam)sp; + ScriptField_ShaderParam_s.Item paramRS = new ScriptField_ShaderParam_s.Item(); + paramRS.bufferOffset = shaderTextureStart + i; + paramRS.transformTimestamp = 0; + paramRS.dataTimestamp = 0; + paramRS.data = p.getRSData().getAllocation(); + paramList.add(paramRS); + } + } + + ScriptField_ShaderParam_s rsParams = null; + int paramCount = paramList.size(); + if (paramCount != 0) { + rsParams = new ScriptField_ShaderParam_s(rs, paramCount); + for (int i = 0; i < paramCount; i++) { + rsParams.set(paramList.get(i), i, false); + } + rsParams.copyAll(); + } + return rsParams; + } + + ScriptField_FragmentShader_s getRSData() { + if (mField != null) { + return mField; + } + + RenderScriptGL rs = SceneManager.getRS(); + Resources res = SceneManager.getRes(); + if (rs == null || res == null) { + return null; + } + + ScriptField_FragmentShader_s.Item item = new ScriptField_FragmentShader_s.Item(); + item.program = mProgram; + + ScriptField_ShaderParam_s texParams = getTextureParams(); + if (texParams != null) { + item.shaderTextureParams = texParams.getAllocation(); + } + + linkConstants(rs); + if (mPerShaderConstants != null) { + item.shaderConst = mConstantBuffer; + item.shaderConstParams = mConstantBufferParams.getAllocation(); + mProgram.bindConstants(item.shaderConst, 0); + } + + item.objectConstIndex = -1; + if (mPerObjConstants != null) { + item.objectConstIndex = mPerShaderConstants != null ? 1 : 0; + } + + mField = new ScriptField_FragmentShader_s(rs, 1); + mField.set(item, 0, true); + return mField; + } +} diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/LightBase.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/LightBase.java new file mode 100644 index 000000000000..8f5e2e78c33f --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/LightBase.java @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.scenegraph; + +import java.lang.Math; +import java.util.ArrayList; + +import android.renderscript.Float3; +import android.renderscript.Float4; +import android.renderscript.Matrix4f; +import android.renderscript.RenderScriptGL; +import android.util.Log; + +/** + * @hide + */ +public abstract class LightBase extends SceneGraphBase { + static final int RS_LIGHT_POINT = 0; + static final int RS_LIGHT_DIRECTIONAL = 1; + + ScriptField_Light_s mField; + ScriptField_Light_s.Item mFieldData; + Transform mTransform; + Float4 mColor; + float mIntensity; + public LightBase() { + mColor = new Float4(0.0f, 0.0f, 0.0f, 0.0f); + mIntensity = 1.0f; + } + + public void setTransform(Transform t) { + mTransform = t; + updateRSData(); + } + + public void setColor(float r, float g, float b) { + mColor.x = r; + mColor.y = g; + mColor.z = b; + updateRSData(); + } + + public void setColor(Float3 c) { + setColor(c.x, c.y, c.z); + } + + public void setIntensity(float i) { + mIntensity = i; + updateRSData(); + } + + public void setName(String n) { + super.setName(n); + updateRSData(); + } + + protected void updateRSData() { + if (mField == null) { + return; + } + RenderScriptGL rs = SceneManager.getRS(); + mFieldData.transformMatrix = mTransform.getRSData().getAllocation(); + mFieldData.name = getNameAlloc(rs); + mFieldData.color = mColor; + mFieldData.intensity = mIntensity; + + initLocalData(); + + mField.set(mFieldData, 0, true); + } + + abstract void initLocalData(); + + ScriptField_Light_s getRSData() { + if (mField != null) { + return mField; + } + + RenderScriptGL rs = SceneManager.getRS(); + if (rs == null) { + return null; + } + if (mField == null) { + mField = new ScriptField_Light_s(rs, 1); + mFieldData = new ScriptField_Light_s.Item(); + } + + updateRSData(); + + return mField; + } +} + + + + + diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/MatrixTransform.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/MatrixTransform.java new file mode 100644 index 000000000000..6d70bc9e4cf4 --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/MatrixTransform.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.scenegraph; + +import java.lang.Math; +import java.util.ArrayList; + +import android.renderscript.Matrix4f; +import android.util.Log; + +/** + * @hide + */ +public class MatrixTransform extends Transform { + + Matrix4f mLocalMatrix; + public MatrixTransform() { + mLocalMatrix = new Matrix4f(); + } + + public void setMatrix(Matrix4f matrix) { + mLocalMatrix = matrix; + updateRSData(); + } + + public Matrix4f getMatrix() { + return new Matrix4f(mLocalMatrix.getArray()); + } + + void initLocalData() { + mTransformData.localMat = mLocalMatrix; + } + + void updateRSData() { + if (mField == null) { + return; + } + mField.set_localMat(0, mLocalMatrix, false); + mField.set_isDirty(0, 1, true); + } +} + + + + + diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/PointLight.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/PointLight.java new file mode 100644 index 000000000000..574bafc4173c --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/PointLight.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.scenegraph; + +import java.lang.Math; +import java.util.ArrayList; + +import android.renderscript.Matrix4f; +import android.renderscript.ProgramFragment; +import android.renderscript.ProgramStore; +import android.renderscript.ProgramVertex; +import android.util.Log; + +/** + * @hide + */ +public class PointLight extends LightBase { + public PointLight() { + } + + void initLocalData() { + mFieldData.type = RS_LIGHT_POINT; + } +} + + + + + diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderPass.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderPass.java new file mode 100644 index 000000000000..02fd69d20078 --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderPass.java @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.scenegraph; + +import java.lang.Math; +import java.util.ArrayList; + +import android.util.Log; + +import android.renderscript.*; +import android.content.res.Resources; + +/** + * @hide + */ +public class RenderPass extends SceneGraphBase { + + TextureRenderTarget mColorTarget; + Float4 mClearColor; + boolean mShouldClearColor; + + TextureRenderTarget mDepthTarget; + float mClearDepth; + boolean mShouldClearDepth; + + ArrayList<RenderableBase> mObjectsToDraw; + + Camera mCamera; + + ScriptField_RenderPass_s.Item mRsField; + + public RenderPass() { + mObjectsToDraw = new ArrayList<RenderableBase>(); + mClearColor = new Float4(0.0f, 0.0f, 0.0f, 0.0f); + mShouldClearColor = true; + mClearDepth = 1.0f; + mShouldClearDepth = true; + } + + public void appendRenderable(Renderable d) { + mObjectsToDraw.add(d); + } + + public void setCamera(Camera c) { + mCamera = c; + } + + public void setColorTarget(TextureRenderTarget colorTarget) { + mColorTarget = colorTarget; + } + public void setClearColor(Float4 clearColor) { + mClearColor = clearColor; + } + public void setShouldClearColor(boolean shouldClearColor) { + mShouldClearColor = shouldClearColor; + } + + public void setDepthTarget(TextureRenderTarget depthTarget) { + mDepthTarget = depthTarget; + } + public void setClearDepth(float clearDepth) { + mClearDepth = clearDepth; + } + public void setShouldClearDepth(boolean shouldClearDepth) { + mShouldClearDepth = shouldClearDepth; + } + + public ArrayList<RenderableBase> getRenderables() { + return mObjectsToDraw; + } + + ScriptField_RenderPass_s.Item getRsField(RenderScriptGL rs, Resources res) { + if (mRsField != null) { + return mRsField; + } + + mRsField = new ScriptField_RenderPass_s.Item(); + if (mColorTarget != null) { + mRsField.color_target = mColorTarget.getRsData(true).get_texture(0); + } + if (mColorTarget != null) { + mRsField.depth_target = mDepthTarget.getRsData(true).get_texture(0); + } + mRsField.camera = mCamera != null ? mCamera.getRSData().getAllocation() : null; + + if (mObjectsToDraw.size() != 0) { + Allocation drawableData = Allocation.createSized(rs, + Element.ALLOCATION(rs), + mObjectsToDraw.size()); + Allocation[] drawableAllocs = new Allocation[mObjectsToDraw.size()]; + for (int i = 0; i < mObjectsToDraw.size(); i ++) { + Renderable dI = (Renderable)mObjectsToDraw.get(i); + drawableAllocs[i] = dI.getRsField(rs, res).getAllocation(); + } + drawableData.copyFrom(drawableAllocs); + mRsField.objects = drawableData; + } + + mRsField.clear_color = mClearColor; + mRsField.clear_depth = mClearDepth; + mRsField.should_clear_color = mShouldClearColor; + mRsField.should_clear_depth = mShouldClearDepth; + return mRsField; + } +} + + + + + diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderState.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderState.java new file mode 100644 index 000000000000..c08a72283a9e --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderState.java @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.scenegraph; + +import java.lang.Math; +import java.util.ArrayList; +import android.content.res.Resources; + +import android.renderscript.Allocation; +import android.renderscript.Element; +import android.renderscript.Matrix4f; +import android.renderscript.ProgramFragment; +import android.renderscript.ProgramRaster; +import android.renderscript.ProgramStore; +import android.renderscript.ProgramVertex; +import android.renderscript.RSRuntimeException; +import android.renderscript.RenderScript; +import android.renderscript.RenderScriptGL; +import android.util.Log; + +/** + * @hide + */ +public class RenderState extends SceneGraphBase { + VertexShader mVertex; + FragmentShader mFragment; + ProgramStore mStore; + ProgramRaster mRaster; + + ScriptField_RenderState_s mField; + + public RenderState(VertexShader pv, + FragmentShader pf, + ProgramStore ps, + ProgramRaster pr) { + mVertex = pv; + mFragment = pf; + mStore = ps; + mRaster = pr; + } + + public RenderState(RenderState r) { + mVertex = r.mVertex; + mFragment = r.mFragment; + mStore = r.mStore; + mRaster = r.mRaster; + } + + public void setProgramVertex(VertexShader pv) { + mVertex = pv; + updateRSData(); + } + + public void setProgramFragment(FragmentShader pf) { + mFragment = pf; + updateRSData(); + } + + public void setProgramStore(ProgramStore ps) { + mStore = ps; + updateRSData(); + } + + public void setProgramRaster(ProgramRaster pr) { + mRaster = pr; + updateRSData(); + } + + void updateRSData() { + if (mField == null) { + return; + } + ScriptField_RenderState_s.Item item = new ScriptField_RenderState_s.Item(); + item.pv = mVertex.getRSData().getAllocation(); + item.pf = mFragment.getRSData().getAllocation(); + item.ps = mStore; + item.pr = mRaster; + + mField.set(item, 0, true); + } + + public ScriptField_RenderState_s getRSData() { + if (mField != null) { + return mField; + } + + RenderScriptGL rs = SceneManager.getRS(); + if (rs == null) { + return null; + } + + mField = new ScriptField_RenderState_s(rs, 1); + updateRSData(); + + return mField; + } +} diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Renderable.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Renderable.java new file mode 100644 index 000000000000..9f7ab411c00d --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Renderable.java @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.scenegraph; + +import java.lang.Math; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; + +import com.android.scenegraph.Float4Param; +import com.android.scenegraph.SceneManager; +import com.android.scenegraph.ShaderParam; +import com.android.scenegraph.TransformParam; + +import android.content.res.Resources; +import android.renderscript.Allocation; +import android.renderscript.Element; +import android.renderscript.Element.DataType; +import android.renderscript.Matrix4f; +import android.renderscript.Mesh; +import android.renderscript.ProgramFragment; +import android.renderscript.ProgramStore; +import android.renderscript.ProgramVertex; +import android.renderscript.RenderScriptGL; +import android.util.Log; + +/** + * @hide + */ +public class Renderable extends RenderableBase { + HashMap<String, ShaderParam> mSourceParams; + + RenderState mRenderState; + Transform mTransform; + + String mMeshName; + String mMeshIndexName; + + public String mMaterialName; + + ScriptField_Renderable_s mField; + ScriptField_Renderable_s.Item mData; + + public Renderable() { + mSourceParams = new HashMap<String, ShaderParam>(); + mData = new ScriptField_Renderable_s.Item(); + } + + public void setCullType(int cull) { + mData.cullType = cull; + } + + public void setRenderState(RenderState renderState) { + mRenderState = renderState; + if (mField != null) { + RenderScriptGL rs = SceneManager.getRS(); + updateFieldItem(rs); + mField.set(mData, 0, true); + } + } + + public void setMesh(Mesh mesh) { + mData.mesh = mesh; + if (mField != null) { + mField.set_mesh(0, mData.mesh, true); + } + } + + public void setMesh(String mesh, String indexName) { + mMeshName = mesh; + mMeshIndexName = indexName; + } + + public void setMaterialName(String name) { + mMaterialName = name; + } + + public void setTransform(Transform t) { + mTransform = t; + if (mField != null) { + RenderScriptGL rs = SceneManager.getRS(); + updateFieldItem(rs); + mField.set(mData, 0, true); + } + } + + public void appendSourceParams(ShaderParam p) { + mSourceParams.put(p.getParamName(), p); + // Possibly lift this restriction later + if (mField != null) { + throw new RuntimeException("Can't add source params to objects that are rendering"); + } + } + + public void resolveMeshData(Mesh mesh) { + mData.mesh = mesh; + if (mData.mesh == null) { + Log.v("DRAWABLE: ", "*** NO MESH *** " + mMeshName); + return; + } + int subIndexCount = mData.mesh.getPrimitiveCount(); + if (subIndexCount == 1 || mMeshIndexName == null) { + mData.meshIndex = 0; + } else { + for (int i = 0; i < subIndexCount; i ++) { + if (mData.mesh.getIndexSetAllocation(i).getName().equals(mMeshIndexName)) { + mData.meshIndex = i; + break; + } + } + } + if (mField != null) { + mField.set(mData, 0, true); + } + } + + void updateTextures(RenderScriptGL rs) { + Iterator<ShaderParam> allParamsIter = mSourceParams.values().iterator(); + int paramIndex = 0; + while (allParamsIter.hasNext()) { + ShaderParam sp = allParamsIter.next(); + if (sp instanceof TextureParam) { + TextureParam p = (TextureParam)sp; + TextureBase tex = p.getTexture(); + if (tex != null) { + mData.pf_textures[paramIndex++] = tex.getRsData(false).getAllocation(); + } + } + } + ProgramFragment pf = mRenderState.mFragment.mProgram; + mData.pf_num_textures = pf != null ? Math.min(pf.getTextureCount(), paramIndex) : 0; + if (mField != null) { + mField.set_pf_textures(0, mData.pf_textures, true); + mField.set_pf_num_textures(0, mData.pf_num_textures, true); + } + } + + public void setVisible(boolean vis) { + mData.cullType = vis ? 0 : 2; + if (mField != null) { + mField.set_cullType(0, mData.cullType, true); + } + } + + ScriptField_Renderable_s getRsField(RenderScriptGL rs, Resources res) { + if (mField != null) { + return mField; + } + updateFieldItem(rs); + updateTextures(rs); + + mField = new ScriptField_Renderable_s(rs, 1); + mField.set(mData, 0, true); + + return mField; + } + + void updateVertexConstants(RenderScriptGL rs) { + Allocation pvParams = null, vertexConstants = null; + VertexShader pv = mRenderState.mVertex; + if (pv != null && pv.getObjectConstants() != null) { + vertexConstants = Allocation.createTyped(rs, pv.getObjectConstants()); + Element vertexConst = vertexConstants.getType().getElement(); + pvParams = ShaderParam.fillInParams(vertexConst, mSourceParams, + mTransform).getAllocation(); + } + mData.pv_const = vertexConstants; + mData.pv_constParams = pvParams; + } + + void updateFragmentConstants(RenderScriptGL rs) { + Allocation pfParams = null, fragmentConstants = null; + FragmentShader pf = mRenderState.mFragment; + if (pf != null && pf.getObjectConstants() != null) { + fragmentConstants = Allocation.createTyped(rs, pf.getObjectConstants()); + Element fragmentConst = fragmentConstants.getType().getElement(); + pfParams = ShaderParam.fillInParams(fragmentConst, mSourceParams, + mTransform).getAllocation(); + } + mData.pf_const = fragmentConstants; + mData.pf_constParams = pfParams; + } + + void updateFieldItem(RenderScriptGL rs) { + updateVertexConstants(rs); + updateFragmentConstants(rs); + + if (mTransform != null) { + mData.transformMatrix = mTransform.getRSData().getAllocation(); + } + mData.name = getNameAlloc(rs); + mData.render_state = mRenderState.getRSData().getAllocation(); + mData.bVolInitialized = 0; + } +} + + + + + diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderableBase.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderableBase.java new file mode 100644 index 000000000000..74535dd94987 --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderableBase.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.scenegraph; + +import java.lang.Math; +import java.util.ArrayList; + +import android.renderscript.Matrix4f; +import android.renderscript.ProgramFragment; +import android.renderscript.ProgramStore; +import android.renderscript.ProgramVertex; +import android.util.Log; + +/** + * @hide + */ +public class RenderableBase extends SceneGraphBase { + public RenderableBase() { + } +} + + + + + diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderableGroup.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderableGroup.java new file mode 100644 index 000000000000..590bbab9c5f8 --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderableGroup.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.scenegraph; + +import java.lang.Math; +import java.util.ArrayList; + +import android.renderscript.Matrix4f; +import android.renderscript.ProgramFragment; +import android.renderscript.ProgramStore; +import android.renderscript.ProgramVertex; +import android.util.Log; + +/** + * @hide + */ +public class RenderableGroup extends RenderableBase { + + ArrayList<RenderableBase> mChildren; + + public RenderableGroup() { + mChildren = new ArrayList<RenderableBase>(); + } + + public void appendChildren(RenderableBase d) { + mChildren.add(d); + } +} + + + + + diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Scene.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Scene.java new file mode 100644 index 000000000000..8c09860c8b9e --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Scene.java @@ -0,0 +1,308 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.scenegraph; + +import java.lang.Math; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.android.scenegraph.SceneManager; +import com.android.scenegraph.TextureBase; + +import android.content.res.Resources; +import android.os.AsyncTask; +import android.renderscript.*; +import android.renderscript.Mesh; +import android.renderscript.RenderScriptGL; +import android.util.Log; + +/** + * @hide + */ +public class Scene extends SceneGraphBase { + private static String TIMER_TAG = "TIMER"; + + CompoundTransform mRootTransforms; + HashMap<String, Transform> mTransformMap; + ArrayList<RenderPass> mRenderPasses; + ArrayList<LightBase> mLights; + ArrayList<Camera> mCameras; + ArrayList<FragmentShader> mFragmentShaders; + ArrayList<VertexShader> mVertexShaders; + ArrayList<RenderableBase> mRenderables; + HashMap<String, RenderableBase> mRenderableMap; + ArrayList<Texture2D> mTextures; + + HashMap<String, ArrayList<Renderable> > mRenderableMeshMap; + + // RS Specific stuff + ScriptField_SgTransform mTransformRSData; + + RenderScriptGL mRS; + Resources mRes; + + ScriptField_RenderPass_s mRenderPassAlloc; + + public Scene() { + mRenderPasses = new ArrayList<RenderPass>(); + mLights = new ArrayList<LightBase>(); + mCameras = new ArrayList<Camera>(); + mFragmentShaders = new ArrayList<FragmentShader>(); + mVertexShaders = new ArrayList<VertexShader>(); + mRenderables = new ArrayList<RenderableBase>(); + mRenderableMap = new HashMap<String, RenderableBase>(); + mRenderableMeshMap = new HashMap<String, ArrayList<Renderable> >(); + mTextures = new ArrayList<Texture2D>(); + mRootTransforms = new CompoundTransform(); + mRootTransforms.setName("_scene_root_"); + mTransformMap = new HashMap<String, Transform>(); + } + + public void appendTransform(Transform t) { + mRootTransforms.appendChild(t); + } + + // temporary + public void addToTransformMap(Transform t) { + mTransformMap.put(t.getName(), t); + } + + public Transform getTransformByName(String name) { + return mTransformMap.get(name); + } + + public void appendRenderPass(RenderPass p) { + mRenderPasses.add(p); + } + + public void clearRenderPasses() { + mRenderPasses.clear(); + } + + public void appendLight(LightBase l) { + mLights.add(l); + } + + public void appendCamera(Camera c) { + mCameras.add(c); + } + + public void appendShader(FragmentShader f) { + mFragmentShaders.add(f); + } + + public void appendShader(VertexShader v) { + mVertexShaders.add(v); + } + + public ArrayList<Camera> getCameras() { + return mCameras; + } + + public ArrayList<LightBase> getLights() { + return mLights; + } + + public void appendRenderable(RenderableBase d) { + mRenderables.add(d); + mRenderableMap.put(d.getName(), d); + } + + public ArrayList<RenderableBase> getRenderables() { + return mRenderables; + } + + public RenderableBase getRenderableByName(String name) { + return mRenderableMap.get(name); + } + + public void appendTextures(Texture2D tex) { + mTextures.add(tex); + } + + public void assignRenderStateToMaterial(RenderState renderState, String regex) { + Pattern pattern = Pattern.compile(regex); + int numRenderables = mRenderables.size(); + for (int i = 0; i < numRenderables; i ++) { + Renderable shape = (Renderable)mRenderables.get(i); + Matcher m = pattern.matcher(shape.mMaterialName); + if (m.find()) { + shape.setRenderState(renderState); + } + } + } + + public void assignRenderState(RenderState renderState) { + int numRenderables = mRenderables.size(); + for (int i = 0; i < numRenderables; i ++) { + Renderable shape = (Renderable)mRenderables.get(i); + shape.setRenderState(renderState); + } + } + + public void meshLoaded(Mesh m) { + ArrayList<Renderable> entries = mRenderableMeshMap.get(m.getName()); + int numEntries = entries.size(); + for (int i = 0; i < numEntries; i++) { + Renderable d = entries.get(i); + d.resolveMeshData(m); + } + } + + void addToMeshMap(Renderable d) { + ArrayList<Renderable> entries = mRenderableMeshMap.get(d.mMeshName); + if (entries == null) { + entries = new ArrayList<Renderable>(); + mRenderableMeshMap.put(d.mMeshName, entries); + } + entries.add(d); + } + + public void destroyRS() { + SceneManager sceneManager = SceneManager.getInstance(); + mTransformRSData = null; + sceneManager.mRenderLoop.bind_gRootNode(mTransformRSData); + sceneManager.mRenderLoop.set_gRenderableObjects(null); + mRenderPassAlloc = null; + sceneManager.mRenderLoop.set_gRenderPasses(null); + sceneManager.mRenderLoop.bind_gFrontToBack(null); + sceneManager.mRenderLoop.bind_gBackToFront(null); + sceneManager.mRenderLoop.set_gCameras(null); + + mTransformMap = null; + mRenderPasses = null; + mLights = null; + mCameras = null; + mRenderables = null; + mRenderableMap = null; + mTextures = null; + mRenderableMeshMap = null; + mRootTransforms = null; + } + + public void initRenderPassRS(RenderScriptGL rs, SceneManager sceneManager) { + if (mRenderPasses.size() != 0) { + mRenderPassAlloc = new ScriptField_RenderPass_s(mRS, mRenderPasses.size()); + for (int i = 0; i < mRenderPasses.size(); i ++) { + mRenderPassAlloc.set(mRenderPasses.get(i).getRsField(mRS, mRes), i, false); + } + mRenderPassAlloc.copyAll(); + sceneManager.mRenderLoop.set_gRenderPasses(mRenderPassAlloc.getAllocation()); + } + } + + private void addDrawables(RenderScriptGL rs, Resources res, SceneManager sceneManager) { + Allocation drawableData = Allocation.createSized(rs, + Element.ALLOCATION(rs), + mRenderables.size()); + Allocation[] drawableAllocs = new Allocation[mRenderables.size()]; + for (int i = 0; i < mRenderables.size(); i ++) { + Renderable dI = (Renderable)mRenderables.get(i); + addToMeshMap(dI); + drawableAllocs[i] = dI.getRsField(rs, res).getAllocation(); + } + drawableData.copyFrom(drawableAllocs); + sceneManager.mRenderLoop.set_gRenderableObjects(drawableData); + + initRenderPassRS(rs, sceneManager); + } + + private void addShaders(RenderScriptGL rs, Resources res, SceneManager sceneManager) { + Allocation shaderData = Allocation.createSized(rs, Element.ALLOCATION(rs), + mVertexShaders.size()); + Allocation[] shaderAllocs = new Allocation[mVertexShaders.size()]; + for (int i = 0; i < mVertexShaders.size(); i ++) { + VertexShader sI = mVertexShaders.get(i); + shaderAllocs[i] = sI.getRSData().getAllocation(); + } + shaderData.copyFrom(shaderAllocs); + sceneManager.mRenderLoop.set_gVertexShaders(shaderData); + + shaderData = Allocation.createSized(rs, Element.ALLOCATION(rs), mFragmentShaders.size()); + shaderAllocs = new Allocation[mFragmentShaders.size()]; + for (int i = 0; i < mFragmentShaders.size(); i ++) { + FragmentShader sI = mFragmentShaders.get(i); + shaderAllocs[i] = sI.getRSData().getAllocation(); + } + shaderData.copyFrom(shaderAllocs); + sceneManager.mRenderLoop.set_gFragmentShaders(shaderData); + } + + public void initRS() { + SceneManager sceneManager = SceneManager.getInstance(); + mRS = SceneManager.getRS(); + mRes = SceneManager.getRes(); + long start = System.currentTimeMillis(); + mTransformRSData = mRootTransforms.getRSData(); + long end = System.currentTimeMillis(); + Log.v(TIMER_TAG, "Transform init time: " + (end - start)); + + start = System.currentTimeMillis(); + + sceneManager.mRenderLoop.bind_gRootNode(mTransformRSData); + end = System.currentTimeMillis(); + Log.v(TIMER_TAG, "Script init time: " + (end - start)); + + start = System.currentTimeMillis(); + addDrawables(mRS, mRes, sceneManager); + end = System.currentTimeMillis(); + Log.v(TIMER_TAG, "Renderable init time: " + (end - start)); + + addShaders(mRS, mRes, sceneManager); + + Allocation opaqueBuffer = null; + if (mRenderables.size() > 0) { + opaqueBuffer = Allocation.createSized(mRS, Element.U32(mRS), mRenderables.size()); + } + Allocation transparentBuffer = null; + if (mRenderables.size() > 0) { + transparentBuffer = Allocation.createSized(mRS, Element.U32(mRS), mRenderables.size()); + } + + sceneManager.mRenderLoop.bind_gFrontToBack(opaqueBuffer); + sceneManager.mRenderLoop.bind_gBackToFront(transparentBuffer); + + if (mCameras.size() > 0) { + Allocation cameraData; + cameraData = Allocation.createSized(mRS, Element.ALLOCATION(mRS), mCameras.size()); + Allocation[] cameraAllocs = new Allocation[mCameras.size()]; + for (int i = 0; i < mCameras.size(); i ++) { + cameraAllocs[i] = mCameras.get(i).getRSData().getAllocation(); + } + cameraData.copyFrom(cameraAllocs); + sceneManager.mRenderLoop.set_gCameras(cameraData); + } + + if (mLights.size() > 0) { + Allocation lightData = Allocation.createSized(mRS, + Element.ALLOCATION(mRS), + mLights.size()); + Allocation[] lightAllocs = new Allocation[mLights.size()]; + for (int i = 0; i < mLights.size(); i ++) { + lightAllocs[i] = mLights.get(i).getRSData().getAllocation(); + } + lightData.copyFrom(lightAllocs); + sceneManager.mRenderLoop.set_gLights(lightData); + } + } +} + + + + diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneGraphBase.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneGraphBase.java new file mode 100644 index 000000000000..412ffbf77900 --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneGraphBase.java @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.scenegraph; + +import java.lang.Math; +import java.util.ArrayList; + +import com.android.scenegraph.SceneManager; + +import android.renderscript.Allocation; +import android.renderscript.Element; +import android.renderscript.Matrix4f; +import android.renderscript.ProgramFragment; +import android.renderscript.ProgramStore; +import android.renderscript.ProgramVertex; +import android.renderscript.RSRuntimeException; +import android.renderscript.RenderScript; +import android.renderscript.RenderScriptGL; +import android.util.Log; + +/** + * @hide + */ +public abstract class SceneGraphBase { + String mName; + Allocation mNameAlloc; + public void setName(String n) { + mName = n; + mNameAlloc = null; + } + + public String getName() { + return mName; + } + + Allocation getNameAlloc(RenderScriptGL rs) { + if (mNameAlloc == null) { + mNameAlloc = SceneManager.getStringAsAllocation(rs, getName()); + } + return mNameAlloc; + } +} + + + + + diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneManager.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneManager.java new file mode 100644 index 000000000000..535905ab1eee --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneManager.java @@ -0,0 +1,353 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.scenegraph; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.Writer; +import java.lang.Math; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.android.scenegraph.Camera; +import com.android.scenegraph.MatrixTransform; +import com.android.scenegraph.Scene; +import com.android.testapp.R; + +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.AsyncTask; +import android.renderscript.*; +import android.renderscript.Allocation.MipmapControl; +import android.renderscript.Mesh; +import android.renderscript.RenderScriptGL; +import android.renderscript.Type.Builder; +import android.util.Log; +import android.view.SurfaceHolder; + +/** + * @hide + */ +public class SceneManager extends SceneGraphBase { + + HashMap<String, Allocation> mAllocationMap; + + ScriptC_render mRenderLoop; + ScriptC mCameraScript; + ScriptC mLightScript; + ScriptC mObjectParamsScript; + ScriptC mFragmentParamsScript; + ScriptC mVertexParamsScript; + ScriptC mCullScript; + ScriptC_transform mTransformScript; + ScriptC_export mExportScript; + + RenderScriptGL mRS; + Resources mRes; + Mesh mQuad; + int mWidth; + int mHeight; + + Scene mActiveScene; + private static SceneManager sSceneManager; + + private Allocation mDefault2D; + private Allocation mDefaultCube; + + private static Allocation getDefault(boolean isCube) { + final int dimension = 4; + final int bytesPerPixel = 4; + int arraySize = dimension * dimension * bytesPerPixel; + + RenderScriptGL rs = sSceneManager.mRS; + Type.Builder b = new Type.Builder(rs, Element.RGBA_8888(rs)); + b.setX(dimension).setY(dimension); + if (isCube) { + b.setFaces(true); + arraySize *= 6; + } + Type bitmapType = b.create(); + + Allocation.MipmapControl mip = Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE; + int usage = Allocation.USAGE_GRAPHICS_TEXTURE; + Allocation defaultImage = Allocation.createTyped(rs, bitmapType, mip, usage); + + byte imageData[] = new byte[arraySize]; + defaultImage.copyFrom(imageData); + return defaultImage; + } + + static Allocation getDefaultTex2D() { + if (sSceneManager == null) { + return null; + } + return sSceneManager.mDefault2D; + } + + static Allocation getDefaultTexCube() { + if (sSceneManager == null) { + return null; + } + return sSceneManager.mDefaultCube; + } + + public static boolean isSDCardPath(String path) { + int sdCardIndex = path.indexOf("sdcard/"); + // We are looking for /sdcard/ or sdcard/ + if (sdCardIndex == 0 || sdCardIndex == 1) { + return true; + } + sdCardIndex = path.indexOf("mnt/sdcard/"); + if (sdCardIndex == 0 || sdCardIndex == 1) { + return true; + } + return false; + } + + static Bitmap loadBitmap(String name, Resources res) { + InputStream is = null; + boolean loadFromSD = isSDCardPath(name); + try { + if (!loadFromSD) { + is = res.getAssets().open(name); + } else { + File f = new File(name); + is = new BufferedInputStream(new FileInputStream(f)); + } + } catch (IOException e) { + Log.e("ImageLoaderTask", " Message: " + e.getMessage()); + return null; + } + + Bitmap b = BitmapFactory.decodeStream(is); + try { + is.close(); + } catch (IOException e) { + Log.e("ImageLoaderTask", " Message: " + e.getMessage()); + } + return b; + } + + public static Allocation loadCubemap(String name, RenderScriptGL rs, Resources res) { + Bitmap b = loadBitmap(name, res); + if (b == null) { + return null; + } + return Allocation.createCubemapFromBitmap(rs, b, + MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE, + Allocation.USAGE_GRAPHICS_TEXTURE); + } + + public static Allocation loadTexture2D(String name, RenderScriptGL rs, Resources res) { + Bitmap b = loadBitmap(name, res); + if (b == null) { + return null; + } + return Allocation.createFromBitmap(rs, b, + Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE, + Allocation.USAGE_GRAPHICS_TEXTURE); + } + + public static ProgramStore BLEND_ADD_DEPTH_NONE(RenderScript rs) { + ProgramStore.Builder builder = new ProgramStore.Builder(rs); + builder.setDepthFunc(ProgramStore.DepthFunc.ALWAYS); + builder.setBlendFunc(ProgramStore.BlendSrcFunc.ONE, ProgramStore.BlendDstFunc.ONE); + builder.setDitherEnabled(false); + builder.setDepthMaskEnabled(false); + return builder.create(); + } + + static Allocation getStringAsAllocation(RenderScript rs, String str) { + if (str == null) { + return null; + } + if (str.length() == 0) { + return null; + } + byte[] allocArray = null; + byte[] nullChar = new byte[1]; + nullChar[0] = 0; + try { + allocArray = str.getBytes("UTF-8"); + Allocation alloc = Allocation.createSized(rs, Element.U8(rs), + allocArray.length + 1, + Allocation.USAGE_SCRIPT); + alloc.copy1DRangeFrom(0, allocArray.length, allocArray); + alloc.copy1DRangeFrom(allocArray.length, 1, nullChar); + return alloc; + } + catch (Exception e) { + throw new RSRuntimeException("Could not convert string to utf-8."); + } + } + + static Allocation getCachedAlloc(String str) { + if (sSceneManager == null) { + throw new RuntimeException("Scene manager not initialized"); + } + return sSceneManager.mAllocationMap.get(str); + } + + static void cacheAlloc(String str, Allocation alloc) { + if (sSceneManager == null) { + throw new RuntimeException("Scene manager not initialized"); + } + sSceneManager.mAllocationMap.put(str, alloc); + } + + public static class SceneLoadedCallback implements Runnable { + public Scene mLoadedScene; + public String mName; + public void run() { + } + } + + public Scene getActiveScene() { + return mActiveScene; + } + + public void setActiveScene(Scene s) { + mActiveScene = s; + + // Do some sanity checking + if (mActiveScene.getCameras().size() == 0) { + Matrix4f camPos = new Matrix4f(); + camPos.translate(0, 0, 10); + MatrixTransform cameraTransform = new MatrixTransform(); + cameraTransform.setName("_DefaultCameraTransform"); + cameraTransform.setMatrix(camPos); + mActiveScene.appendTransform(cameraTransform); + Camera cam = new Camera(); + cam.setName("_DefaultCamera"); + cam.setTransform(cameraTransform); + mActiveScene.appendCamera(cam); + } + } + + static RenderScriptGL getRS() { + if (sSceneManager == null) { + return null; + } + return sSceneManager.mRS; + } + + static Resources getRes() { + if (sSceneManager == null) { + return null; + } + return sSceneManager.mRes; + } + + public static SceneManager getInstance() { + if (sSceneManager == null) { + sSceneManager = new SceneManager(); + } + return sSceneManager; + } + + protected SceneManager() { + } + + public void loadModel(String name, SceneLoadedCallback cb) { + ColladaScene scene = new ColladaScene(name, cb); + scene.init(mRS, mRes); + } + + public Mesh getScreenAlignedQuad() { + if (mQuad != null) { + return mQuad; + } + + Mesh.TriangleMeshBuilder tmb = new Mesh.TriangleMeshBuilder(mRS, + 3, Mesh.TriangleMeshBuilder.TEXTURE_0); + + tmb.setTexture(0.0f, 1.0f); + tmb.addVertex(-1.0f, 1.0f, 1.0f); + + tmb.setTexture(0.0f, 0.0f); + tmb.addVertex(-1.0f, -1.0f, 1.0f); + + tmb.setTexture(1.0f, 0.0f); + tmb.addVertex(1.0f, -1.0f, 1.0f); + + tmb.setTexture(1.0f, 1.0f); + tmb.addVertex(1.0f, 1.0f, 1.0f); + + tmb.addTriangle(0, 1, 2); + tmb.addTriangle(2, 3, 0); + + mQuad = tmb.create(true); + return mQuad; + } + + public Renderable getRenderableQuad(String name, RenderState state) { + Renderable quad = new Renderable(); + quad.setTransform(new MatrixTransform()); + quad.setMesh(getScreenAlignedQuad()); + quad.setName(name); + quad.setRenderState(state); + quad.setCullType(1); + return quad; + } + + public void initRS(RenderScriptGL rs, Resources res, int w, int h) { + mRS = rs; + mRes = res; + mAllocationMap = new HashMap<String, Allocation>(); + + mQuad = null; + mDefault2D = getDefault(false); + mDefaultCube = getDefault(true); + + mExportScript = new ScriptC_export(rs, res, R.raw.export); + + mTransformScript = new ScriptC_transform(rs, res, R.raw.transform); + mTransformScript.set_gTransformScript(mTransformScript); + + mCameraScript = new ScriptC_camera(rs, res, R.raw.camera); + mLightScript = new ScriptC_light(rs, res, R.raw.light); + mObjectParamsScript = new ScriptC_object_params(rs, res, R.raw.object_params); + mFragmentParamsScript = new ScriptC_object_params(rs, res, R.raw.fragment_params); + mVertexParamsScript = new ScriptC_object_params(rs, res, R.raw.vertex_params); + mCullScript = new ScriptC_cull(rs, res, R.raw.cull); + + mRenderLoop = new ScriptC_render(rs, res, R.raw.render); + mRenderLoop.set_gTransformScript(mTransformScript); + mRenderLoop.set_gCameraScript(mCameraScript); + mRenderLoop.set_gLightScript(mLightScript); + mRenderLoop.set_gObjectParamsScript(mObjectParamsScript); + mRenderLoop.set_gFragmentParamsScript(mFragmentParamsScript); + mRenderLoop.set_gVertexParamsScript(mVertexParamsScript); + mRenderLoop.set_gCullScript(mCullScript); + + mRenderLoop.set_gPFSBackground(ProgramStore.BLEND_NONE_DEPTH_TEST(mRS)); + } + + public ScriptC getRenderLoop() { + return mRenderLoop; + } +} + + + + diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Shader.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Shader.java new file mode 100644 index 000000000000..497511437115 --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Shader.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.scenegraph; + +import java.lang.Math; +import java.util.ArrayList; +import java.util.HashMap; + +import com.android.scenegraph.SceneGraphBase; +import com.android.scenegraph.ShaderParam; + +import android.renderscript.*; +import android.renderscript.ProgramFragment.Builder; +import android.util.Log; + +/** + * @hide + */ +public abstract class Shader extends SceneGraphBase { + protected Type mPerObjConstants; + protected Type mPerShaderConstants; + + protected HashMap<String, ShaderParam> mSourceParams; + protected ArrayList<String> mShaderTextureNames; + protected ArrayList<Program.TextureType > mShaderTextureTypes; + protected ArrayList<String> mTextureNames; + protected ArrayList<Program.TextureType > mTextureTypes; + + protected Allocation mConstantBuffer; + protected ScriptField_ShaderParam_s mConstantBufferParams; + + public Shader() { + mSourceParams = new HashMap<String, ShaderParam>(); + mShaderTextureNames = new ArrayList<String>(); + mShaderTextureTypes = new ArrayList<Program.TextureType>(); + mTextureNames = new ArrayList<String>(); + mTextureTypes = new ArrayList<Program.TextureType>(); + } + + public void appendSourceParams(ShaderParam p) { + mSourceParams.put(p.getParamName(), p); + } + + public Type getObjectConstants() { + return mPerObjConstants; + } + + public Type getShaderConstants() { + return mPerObjConstants; + } + + void linkConstants(RenderScriptGL rs) { + if (mPerShaderConstants == null) { + return; + } + + Element constElem = mPerShaderConstants.getElement(); + mConstantBufferParams = ShaderParam.fillInParams(constElem, mSourceParams, null); + + mConstantBuffer = Allocation.createTyped(rs, mPerShaderConstants); + } +} diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ShaderParam.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ShaderParam.java new file mode 100644 index 000000000000..8dea53574a45 --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ShaderParam.java @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.scenegraph; + +import java.lang.Math; +import java.util.ArrayList; +import java.util.HashMap; + +import com.android.scenegraph.SceneManager; +import com.android.scenegraph.Transform; + +import android.renderscript.Element; +import android.renderscript.Matrix4f; +import android.renderscript.ProgramFragment; +import android.renderscript.ProgramStore; +import android.renderscript.ProgramVertex; +import android.renderscript.RenderScriptGL; +import android.util.Log; + +/** + * @hide + */ +public abstract class ShaderParam extends SceneGraphBase { + + static final String cameraPos = "cameraPos"; + static final String cameraDir = "cameraDir"; + + static final String lightColor = "lightColor"; + static final String lightPos = "lightPos"; + static final String lightDir = "lightDir"; + + static final String view = "view"; + static final String proj = "proj"; + static final String viewProj = "viewProj"; + static final String model = "model"; + static final String modelView = "modelView"; + static final String modelViewProj = "modelViewProj"; + + static final long sMaxTimeStamp = 0xffffffffL; + + ScriptField_ShaderParamData_s.Item mData; + ScriptField_ShaderParamData_s mField; + + String mParamName; + Camera mCamera; + + static ScriptField_ShaderParam_s fillInParams(Element constantElem, + HashMap<String, ShaderParam> sourceParams, + Transform transform) { + RenderScriptGL rs = SceneManager.getRS(); + ArrayList<ScriptField_ShaderParam_s.Item> paramList; + paramList = new ArrayList<ScriptField_ShaderParam_s.Item>(); + + int subElemCount = constantElem.getSubElementCount(); + for (int i = 0; i < subElemCount; i ++) { + String inputName = constantElem.getSubElementName(i); + int offset = constantElem.getSubElementOffsetBytes(i); + + ShaderParam matchingParam = sourceParams.get(inputName); + Element subElem = constantElem.getSubElement(i); + // Make one if it's not there + if (matchingParam == null) { + if (subElem.getDataType() == Element.DataType.FLOAT_32) { + matchingParam = new Float4Param(inputName); + } else if (subElem.getDataType() == Element.DataType.MATRIX_4X4) { + TransformParam trParam = new TransformParam(inputName); + trParam.setTransform(transform); + matchingParam = trParam; + } + } + ScriptField_ShaderParam_s.Item paramRS = new ScriptField_ShaderParam_s.Item(); + paramRS.bufferOffset = offset; + paramRS.transformTimestamp = 0; + paramRS.dataTimestamp = 0; + paramRS.data = matchingParam.getRSData().getAllocation(); + if (subElem.getDataType() == Element.DataType.FLOAT_32) { + paramRS.float_vecSize = subElem.getVectorSize(); + } + + paramList.add(paramRS); + } + + ScriptField_ShaderParam_s rsParams = null; + int paramCount = paramList.size(); + if (paramCount != 0) { + rsParams = new ScriptField_ShaderParam_s(rs, paramCount); + for (int i = 0; i < paramCount; i++) { + rsParams.set(paramList.get(i), i, false); + } + rsParams.copyAll(); + } + return rsParams; + } + + public ShaderParam(String name) { + mParamName = name; + mData = new ScriptField_ShaderParamData_s.Item(); + } + + public String getParamName() { + return mParamName; + } + + public void setCamera(Camera c) { + mCamera = c; + if (mField != null) { + mData.camera = mCamera.getRSData().getAllocation(); + mField.set_camera(0, mData.camera, true); + } + } + + protected void incTimestamp() { + if (mField != null) { + mData.timestamp ++; + mData.timestamp %= sMaxTimeStamp; + mField.set_timestamp(0, mData.timestamp, true); + } + } + + abstract void initLocalData(); + + public ScriptField_ShaderParamData_s getRSData() { + if (mField != null) { + return mField; + } + + RenderScriptGL rs = SceneManager.getRS(); + mField = new ScriptField_ShaderParamData_s(rs, 1); + + if (mParamName != null) { + mData.paramName = SceneManager.getCachedAlloc(mParamName); + if (mData.paramName == null) { + mData.paramName = SceneManager.getStringAsAllocation(rs, mParamName); + SceneManager.cacheAlloc(mParamName, mData.paramName); + } + } + initLocalData(); + mData.timestamp = 1; + + mField.set(mData, 0, true); + return mField; + } +} + + + + + diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Texture2D.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Texture2D.java new file mode 100644 index 000000000000..8fae9d931700 --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Texture2D.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.scenegraph; + +import java.lang.Math; + +import com.android.scenegraph.SceneManager; + +import android.content.res.Resources; +import android.renderscript.*; +import android.util.Log; + +/** + * @hide + */ +public class Texture2D extends TextureBase { + String mFileName; + String mFileDir; + + public Texture2D() { + super(ScriptC_export.const_TextureType_TEXTURE_2D); + } + + public Texture2D(Allocation tex) { + super(ScriptC_export.const_TextureType_TEXTURE_2D); + setTexture(tex); + } + + public void setFileDir(String dir) { + mFileDir = dir; + } + + public void setFileName(String file) { + mFileName = file; + } + + public String getFileName() { + return mFileName; + } + + public void setTexture(Allocation tex) { + mData.texture = tex != null ? tex : SceneManager.getDefaultTex2D(); + if (mField != null) { + mField.set_texture(0, mData.texture, true); + } + } + + void load() { + RenderScriptGL rs = SceneManager.getRS(); + Resources res = SceneManager.getRes(); + String shortName = mFileName.substring(mFileName.lastIndexOf('/') + 1); + setTexture(SceneManager.loadTexture2D(mFileDir + shortName, rs, res)); + } + + ScriptField_Texture_s getRsData(boolean loadNow) { + if (mField != null) { + return mField; + } + + RenderScriptGL rs = SceneManager.getRS(); + Resources res = SceneManager.getRes(); + if (rs == null || res == null) { + return null; + } + + mField = new ScriptField_Texture_s(rs, 1); + + if (loadNow) { + load(); + } else { + mData.texture = SceneManager.getDefaultTex2D(); + new SingleImageLoaderTask().execute(this); + } + + mField.set(mData, 0, true); + return mField; + } +} + + + + + diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureBase.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureBase.java new file mode 100644 index 000000000000..ba49d4e2cc0e --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureBase.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.scenegraph; + +import java.lang.Math; + +import com.android.scenegraph.SceneManager; +import android.os.AsyncTask; +import android.content.res.Resources; +import android.renderscript.*; +import android.util.Log; + +/** + * @hide + */ +public abstract class TextureBase extends SceneGraphBase { + + class SingleImageLoaderTask extends AsyncTask<TextureBase, Void, Boolean> { + protected Boolean doInBackground(TextureBase... objects) { + TextureBase tex = objects[0]; + tex.load(); + return new Boolean(true); + } + protected void onPostExecute(Boolean result) { + } + } + + ScriptField_Texture_s.Item mData; + ScriptField_Texture_s mField; + TextureBase(int type) { + mData = new ScriptField_Texture_s.Item(); + mData.type = type; + } + + protected Allocation mRsTexture; + abstract ScriptField_Texture_s getRsData(boolean loadNow); + abstract void load(); +} + + + + + diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureCube.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureCube.java new file mode 100644 index 000000000000..12c81c20dd11 --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureCube.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.scenegraph; + +import java.lang.Math; + +import com.android.scenegraph.SceneManager; +import com.android.scenegraph.TextureBase; + +import android.content.res.Resources; +import android.renderscript.*; +import android.util.Log; + +/** + * @hide + */ +public class TextureCube extends TextureBase { + String mFileName; + String mFileDir; + + public TextureCube() { + super(ScriptC_export.const_TextureType_TEXTURE_CUBE); + } + + public TextureCube(Allocation tex) { + super(ScriptC_export.const_TextureType_TEXTURE_CUBE); + setTexture(tex); + } + + public TextureCube(String dir, String file) { + super(ScriptC_export.const_TextureType_TEXTURE_CUBE); + setFileDir(dir); + setFileName(file); + } + + public void setFileDir(String dir) { + mFileDir = dir; + } + + public void setFileName(String file) { + mFileName = file; + } + + public String getFileName() { + return mFileName; + } + + public void setTexture(Allocation tex) { + mData.texture = tex != null ? tex : SceneManager.getDefaultTexCube(); + if (mField != null) { + mField.set_texture(0, mData.texture, true); + } + } + + void load() { + RenderScriptGL rs = SceneManager.getRS(); + Resources res = SceneManager.getRes(); + String shortName = mFileName.substring(mFileName.lastIndexOf('/') + 1); + setTexture(SceneManager.loadCubemap(mFileDir + shortName, rs, res)); + } + + ScriptField_Texture_s getRsData(boolean loadNow) { + if (mField != null) { + return mField; + } + + RenderScriptGL rs = SceneManager.getRS(); + Resources res = SceneManager.getRes(); + if (rs == null || res == null) { + return null; + } + + mField = new ScriptField_Texture_s(rs, 1); + + if (loadNow) { + load(); + } else { + mData.texture = SceneManager.getDefaultTexCube(); + new SingleImageLoaderTask().execute(this); + } + + mField.set(mData, 0, true); + return mField; + } +} + + + + + diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureParam.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureParam.java new file mode 100644 index 000000000000..e656ed264409 --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureParam.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.scenegraph; + +import java.lang.Math; +import java.util.ArrayList; + +import android.graphics.Camera; +import android.renderscript.RenderScriptGL; +import android.renderscript.Float4; +import android.renderscript.Matrix4f; +import android.renderscript.ProgramFragment; +import android.renderscript.ProgramStore; +import android.renderscript.ProgramVertex; +import android.renderscript.Element; +import android.util.Log; + +/** + * @hide + */ +public class TextureParam extends ShaderParam { + + TextureBase mTexture; + + public TextureParam(String name) { + super(name); + } + + public TextureParam(String name, TextureBase t) { + super(name); + setTexture(t); + } + + public void setTexture(TextureBase t) { + mTexture = t; + } + + public TextureBase getTexture() { + return mTexture; + } + + void initLocalData() { + mData.type = ScriptC_export.const_ShaderParam_TEXTURE; + if (mTexture != null) { + mData.texture = mTexture.getRsData(false).getAllocation(); + } + } +} + + + + + diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureRenderTarget.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureRenderTarget.java new file mode 100644 index 000000000000..6aa29a53ecc4 --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureRenderTarget.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.scenegraph; + +import java.lang.Math; + +import com.android.scenegraph.SceneManager; + +import android.content.res.Resources; +import android.renderscript.*; +import android.util.Log; + +/** + * @hide + */ +public class TextureRenderTarget extends TextureBase { + public TextureRenderTarget() { + super(ScriptC_export.const_TextureType_TEXTURE_RENDER_TARGET); + } + + public TextureRenderTarget(Allocation tex) { + super(ScriptC_export.const_TextureType_TEXTURE_RENDER_TARGET); + setTexture(tex); + } + + public void setTexture(Allocation tex) { + mData.texture = tex; + if (mField != null) { + mField.set_texture(0, mData.texture, true); + } + } + + void load() { + } + + ScriptField_Texture_s getRsData(boolean loadNow) { + if (mField != null) { + return mField; + } + + RenderScriptGL rs = SceneManager.getRS(); + if (rs == null) { + return null; + } + + mField = new ScriptField_Texture_s(rs, 1); + mField.set(mData, 0, true); + return mField; + } +} + + + + + diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Transform.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Transform.java new file mode 100644 index 000000000000..8180bd071636 --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Transform.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.scenegraph; + +import java.lang.Math; +import java.util.ArrayList; + +import android.renderscript.*; +import android.renderscript.Matrix4f; +import android.util.Log; + +/** + * @hide + */ +public abstract class Transform extends SceneGraphBase { + Transform mParent; + ArrayList<Transform> mChildren; + + ScriptField_SgTransform mField; + ScriptField_SgTransform.Item mTransformData; + + public Transform() { + mChildren = new ArrayList<Transform>(); + mParent = null; + } + + public void appendChild(Transform t) { + mChildren.add(t); + t.mParent = this; + updateRSChildData(true); + } + + abstract void initLocalData(); + + void updateRSChildData(boolean copyData) { + if (mField == null) { + return; + } + RenderScriptGL rs = SceneManager.getRS(); + if (mChildren.size() != 0) { + Allocation childRSData = Allocation.createSized(rs, Element.ALLOCATION(rs), + mChildren.size()); + mTransformData.children = childRSData; + + Allocation[] childrenAllocs = new Allocation[mChildren.size()]; + for (int i = 0; i < mChildren.size(); i ++) { + Transform child = mChildren.get(i); + childrenAllocs[i] = child.getRSData().getAllocation(); + } + childRSData.copyFrom(childrenAllocs); + } + if (copyData) { + mField.set(mTransformData, 0, true); + } + } + + ScriptField_SgTransform getRSData() { + if (mField != null) { + return mField; + } + + RenderScriptGL rs = SceneManager.getRS(); + if (rs == null) { + return null; + } + mField = new ScriptField_SgTransform(rs, 1); + + mTransformData = new ScriptField_SgTransform.Item(); + mTransformData.name = getNameAlloc(rs); + mTransformData.isDirty = 1; + mTransformData.timestamp = 1; + + initLocalData(); + updateRSChildData(false); + + mField.set(mTransformData, 0, true); + return mField; + } +} + + + + + diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TransformParam.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TransformParam.java new file mode 100644 index 000000000000..d120d5d9b97d --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TransformParam.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.scenegraph; + +import java.lang.Math; +import java.util.ArrayList; + +import android.renderscript.RenderScriptGL; +import android.renderscript.Matrix4f; +import android.renderscript.ProgramFragment; +import android.renderscript.ProgramStore; +import android.renderscript.ProgramVertex; +import android.renderscript.Element; +import android.util.Log; + +/** + * @hide + */ +public class TransformParam extends ShaderParam { + + Transform mTransform; + LightBase mLight; + + public TransformParam(String name) { + super(name); + } + + public void setTransform(Transform t) { + mTransform = t; + if (mField != null && mTransform != null) { + mData.transform = mTransform.getRSData().getAllocation(); + } + incTimestamp(); + } + + int getTypeFromName() { + int paramType = ScriptC_export.const_ShaderParam_TRANSFORM_DATA; + if (mParamName.equalsIgnoreCase(view)) { + paramType = ScriptC_export.const_ShaderParam_TRANSFORM_VIEW; + } else if(mParamName.equalsIgnoreCase(proj)) { + paramType = ScriptC_export.const_ShaderParam_TRANSFORM_PROJ; + } else if(mParamName.equalsIgnoreCase(viewProj)) { + paramType = ScriptC_export.const_ShaderParam_TRANSFORM_VIEW_PROJ; + } else if(mParamName.equalsIgnoreCase(model)) { + paramType = ScriptC_export.const_ShaderParam_TRANSFORM_MODEL; + } else if(mParamName.equalsIgnoreCase(modelView)) { + paramType = ScriptC_export.const_ShaderParam_TRANSFORM_MODEL_VIEW; + } else if(mParamName.equalsIgnoreCase(modelViewProj)) { + paramType = ScriptC_export.const_ShaderParam_TRANSFORM_MODEL_VIEW_PROJ; + } + return paramType; + } + + void initLocalData() { + mData.type = getTypeFromName(); + if (mTransform != null) { + mData.transform = mTransform.getRSData().getAllocation(); + } + if (mCamera != null) { + mData.camera = mCamera.getRSData().getAllocation(); + } + if (mLight != null) { + mData.light = mLight.getRSData().getAllocation(); + } + } +} + + + + + diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/VertexShader.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/VertexShader.java new file mode 100644 index 000000000000..f7d0e6d8a48a --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/VertexShader.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.scenegraph; + +import java.lang.Math; +import java.util.ArrayList; + +import android.content.res.Resources; +import android.renderscript.*; +import android.util.Log; + +/** + * @hide + */ +public class VertexShader extends Shader { + ProgramVertex mProgram; + ScriptField_VertexShader_s mField; + + public static class Builder { + VertexShader mShader; + ProgramVertex.Builder mBuilder; + + public Builder(RenderScriptGL rs) { + mShader = new VertexShader(); + mBuilder = new ProgramVertex.Builder(rs); + } + + public Builder setShader(Resources resources, int resourceID) { + mBuilder.setShader(resources, resourceID); + return this; + } + + public Builder setObjectConst(Type type) { + mShader.mPerObjConstants = type; + return this; + } + + public Builder setShaderConst(Type type) { + mShader.mPerShaderConstants = type; + return this; + } + + public Builder addInput(Element e) { + mBuilder.addInput(e); + return this; + } + + public VertexShader create() { + if (mShader.mPerShaderConstants != null) { + mBuilder.addConstant(mShader.mPerShaderConstants); + } + if (mShader.mPerObjConstants != null) { + mBuilder.addConstant(mShader.mPerObjConstants); + } + mShader.mProgram = mBuilder.create(); + return mShader; + } + } + + public ProgramVertex getProgram() { + return mProgram; + } + + ScriptField_VertexShader_s getRSData() { + if (mField != null) { + return mField; + } + + RenderScriptGL rs = SceneManager.getRS(); + Resources res = SceneManager.getRes(); + if (rs == null || res == null) { + return null; + } + + ScriptField_VertexShader_s.Item item = new ScriptField_VertexShader_s.Item(); + item.program = mProgram; + + linkConstants(rs); + if (mPerShaderConstants != null) { + item.shaderConst = mConstantBuffer; + item.shaderConstParams = mConstantBufferParams.getAllocation(); + mProgram.bindConstants(item.shaderConst, 0); + } + + item.objectConstIndex = -1; + if (mPerObjConstants != null) { + item.objectConstIndex = mPerShaderConstants != null ? 1 : 0; + } + + mField = new ScriptField_VertexShader_s(rs, 1); + mField.set(item, 0, true); + return mField; + } +} diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/camera.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/camera.rs new file mode 100644 index 000000000000..dc0a885a685d --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/camera.rs @@ -0,0 +1,66 @@ +// Copyright (C) 2011 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma version(1) + +#pragma rs java_package_name(com.android.scenegraph) + +//#define DEBUG_CAMERA +#include "scenegraph_objects.rsh" + +void root(const rs_allocation *v_in, rs_allocation *v_out, const float *usrData) { + + SgCamera *cam = (SgCamera *)rsGetElementAt(*v_in, 0); + float aspect = *usrData; + if (cam->aspect != aspect) { + cam->isDirty = 1; + cam->aspect = aspect; + } + if (cam->isDirty) { + rsMatrixLoadPerspective(&cam->proj, cam->horizontalFOV, cam->aspect, cam->near, cam->far); + } + + const SgTransform *camTransform = (const SgTransform *)rsGetElementAt(cam->transformMatrix, 0); + //rsDebug("Camera stamp", cam->transformTimestamp); + //rsDebug("Transform stamp", camTransform->timestamp); + if (camTransform->timestamp != cam->transformTimestamp || cam->isDirty) { + cam->isDirty = 1; + rs_matrix4x4 camPosMatrix; + rsMatrixLoad(&camPosMatrix, &camTransform->globalMat); + float4 zero = {0.0f, 0.0f, 0.0f, 1.0f}; + cam->position = rsMatrixMultiply(&camPosMatrix, zero); + + rsMatrixInverse(&camPosMatrix); + rsMatrixLoad(&cam->view, &camPosMatrix); + + rsMatrixLoad(&cam->viewProj, &cam->proj); + rsMatrixMultiply(&cam->viewProj, &cam->view); + + rsExtractFrustumPlanes(&cam->viewProj, + &cam->frustumPlanes[0], &cam->frustumPlanes[1], + &cam->frustumPlanes[2], &cam->frustumPlanes[3], + &cam->frustumPlanes[3], &cam->frustumPlanes[4]); + } + + if (cam->isDirty) { + cam->timestamp ++; + } + + cam->isDirty = 0; + cam->transformTimestamp = camTransform->timestamp; + +#ifdef DEBUG_CAMERA + printCameraInfo(cam); +#endif //DEBUG_CAMERA +} diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/cull.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/cull.rs new file mode 100644 index 000000000000..024e026b69df --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/cull.rs @@ -0,0 +1,86 @@ +// Copyright (C) 2012 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma version(1) + +#pragma rs java_package_name(com.android.scenegraph) + +#include "scenegraph_objects.rsh" + +static void getTransformedSphere(SgRenderable *obj) { + obj->worldBoundingSphere = obj->boundingSphere; + obj->worldBoundingSphere.w = 1.0f; + const SgTransform *objTransform = (const SgTransform *)rsGetElementAt(obj->transformMatrix, 0); + obj->worldBoundingSphere = rsMatrixMultiply(&objTransform->globalMat, obj->worldBoundingSphere); + + const float4 unitVec = {0.57735f, 0.57735f, 0.57735f, 0.0f}; + float4 scaledVec = rsMatrixMultiply(&objTransform->globalMat, unitVec); + scaledVec.w = 0.0f; + obj->worldBoundingSphere.w = obj->boundingSphere.w * length(scaledVec); +} + +static bool frustumCulled(SgRenderable *obj, SgCamera *cam) { + if (!obj->bVolInitialized) { + float minX, minY, minZ, maxX, maxY, maxZ; + rsgMeshComputeBoundingBox(obj->mesh, + &minX, &minY, &minZ, + &maxX, &maxY, &maxZ); + //rsDebug("min", minX, minY, minZ); + //rsDebug("max", maxX, maxY, maxZ); + float4 sphere; + sphere.x = (maxX + minX) * 0.5f; + sphere.y = (maxY + minY) * 0.5f; + sphere.z = (maxZ + minZ) * 0.5f; + float3 radius; + radius.x = (maxX - sphere.x); + radius.y = (maxY - sphere.y); + radius.z = (maxZ - sphere.z); + + sphere.w = length(radius); + obj->boundingSphere = sphere; + obj->bVolInitialized = 1; + //rsDebug("Sphere", sphere); + } + + getTransformedSphere(obj); + + return !rsIsSphereInFrustum(&obj->worldBoundingSphere, + &cam->frustumPlanes[0], &cam->frustumPlanes[1], + &cam->frustumPlanes[2], &cam->frustumPlanes[3], + &cam->frustumPlanes[4], &cam->frustumPlanes[5]); +} + + +void root(rs_allocation *v_out, const void *usrData) { + + SgRenderable *drawable = (SgRenderable *)rsGetElementAt(*v_out, 0); + const SgCamera *camera = (const SgCamera*)usrData; + + drawable->isVisible = 0; + // Not loaded yet + if (!rsIsObject(drawable->mesh) || drawable->cullType == CULL_ALWAYS) { + return; + } + + // check to see if we are culling this object and if it's + // outside the frustum + if (drawable->cullType == CULL_FRUSTUM && frustumCulled(drawable, (SgCamera*)camera)) { +#ifdef DEBUG_RENDERABLES + rsDebug("Culled", drawable); + printName(drawable->name); +#endif // DEBUG_RENDERABLES + return; + } + drawable->isVisible = 1; +} diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/export.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/export.rs new file mode 100644 index 000000000000..b438a43abaab --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/export.rs @@ -0,0 +1,61 @@ +// Copyright (C) 2011 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma version(1) + +#pragma rs java_package_name(com.android.scenegraph) + +// The sole purpose of this script is to have various structs exposed +// so that java reflected classes are generated +#include "scenegraph_objects.rsh" + +// Export our native constants to java so that we don't have parallel definitions +const int ShaderParam_FLOAT4_DATA = SHADER_PARAM_FLOAT4_DATA; +const int ShaderParam_TRANSFORM_DATA = SHADER_PARAM_TRANSFORM_DATA; +const int ShaderParam_TRANSFORM_MODEL = SHADER_PARAM_TRANSFORM_MODEL; + +const int ShaderParam_FLOAT4_CAMERA_POS = SHADER_PARAM_FLOAT4_CAMERA_POS; +const int ShaderParam_FLOAT4_CAMERA_DIR = SHADER_PARAM_FLOAT4_CAMERA_DIR; +const int ShaderParam_TRANSFORM_VIEW = SHADER_PARAM_TRANSFORM_VIEW; +const int ShaderParam_TRANSFORM_PROJ = SHADER_PARAM_TRANSFORM_PROJ; +const int ShaderParam_TRANSFORM_VIEW_PROJ = SHADER_PARAM_TRANSFORM_VIEW_PROJ; +const int ShaderParam_TRANSFORM_MODEL_VIEW = SHADER_PARAM_TRANSFORM_MODEL_VIEW; +const int ShaderParam_TRANSFORM_MODEL_VIEW_PROJ = SHADER_PARAM_TRANSFORM_MODEL_VIEW_PROJ; + +const int ShaderParam_FLOAT4_LIGHT_COLOR = SHADER_PARAM_FLOAT4_LIGHT_COLOR; +const int ShaderParam_FLOAT4_LIGHT_POS = SHADER_PARAM_FLOAT4_LIGHT_POS; +const int ShaderParam_FLOAT4_LIGHT_DIR = SHADER_PARAM_FLOAT4_LIGHT_DIR; + +const int ShaderParam_TEXTURE = SHADER_PARAM_TEXTURE; + +const int Transform_TRANSLATE = TRANSFORM_TRANSLATE; +const int Transform_ROTATE = TRANSFORM_ROTATE; +const int Transform_SCALE = TRANSFORM_SCALE; + +const int TextureType_TEXTURE_2D = TEXTURE_2D; +const int TextureType_TEXTURE_CUBE = TEXTURE_CUBE; +const int TextureType_TEXTURE_RENDER_TARGET = TEXTURE_RENDER_TARGET; + +SgTransform *exportPtr; +SgTransformComponent *componentPtr; +SgRenderState *sExport; +SgRenderable *drExport; +SgRenderPass *pExport; +SgCamera *exportPtrCam; +SgLight *exportPtrLight; +SgShaderParam *spExport; +SgShaderParamData *spDataExport; +SgVertexShader *pvExport; +SgFragmentShader *pfExport; +SgTexture *texExport; diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/fragment_params.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/fragment_params.rs new file mode 100644 index 000000000000..7202285c247e --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/fragment_params.rs @@ -0,0 +1,30 @@ +// Copyright (C) 2012 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma version(1) + +#pragma rs java_package_name(com.android.scenegraph) + +#include "scenegraph_objects.rsh" + +//#define DEBUG_PARAMS + +#include "params.rsh" + +void root(rs_allocation *v_out, const void *usrData) { + SgFragmentShader *shader = (SgFragmentShader *)rsGetElementAt(*v_out, 0); + const SgCamera *camera = (const SgCamera*)usrData; + processAllParams(shader->shaderConst, shader->shaderConstParams, camera); + processTextureParams(shader); +} diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/light.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/light.rs new file mode 100644 index 000000000000..e11979f27ff8 --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/light.rs @@ -0,0 +1,33 @@ +// Copyright (C) 2011 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma version(1) + +#pragma rs java_package_name(com.android.scenegraph) + +//#define DEBUG_LIGHT +#include "scenegraph_objects.rsh" + +void root(const rs_allocation *v_in, rs_allocation *v_out) { + + SgLight *light = (SgLight *)rsGetElementAt(*v_in, 0); + const SgTransform *lTransform = (const SgTransform *)rsGetElementAt(light->transformMatrix, 0); + + float4 zero = {0.0f, 0.0f, 0.0f, 1.0f}; + light->position = rsMatrixMultiply(&lTransform->globalMat, zero); + +#ifdef DEBUG_LIGHT + printLightInfo(light); +#endif //DEBUG_LIGHT +} diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/object_params.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/object_params.rs new file mode 100644 index 000000000000..0d524a663150 --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/object_params.rs @@ -0,0 +1,36 @@ +// Copyright (C) 2012 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma version(1) + +#pragma rs java_package_name(com.android.scenegraph) + +#include "scenegraph_objects.rsh" + +//#define DEBUG_PARAMS + +#include "params.rsh" + +void root(rs_allocation *v_out, const void *usrData) { + + SgRenderable *drawable = (SgRenderable *)rsGetElementAt(*v_out, 0); + // Visibility flag was set earlier in the cull stage + if (!drawable->isVisible) { + return; + } + + const SgCamera *camera = (const SgCamera*)usrData; + processAllParams(drawable->pf_const, drawable->pf_constParams, camera); + processAllParams(drawable->pv_const, drawable->pv_constParams, camera); +} diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/params.rsh b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/params.rsh new file mode 100644 index 000000000000..575794bff452 --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/params.rsh @@ -0,0 +1,193 @@ +// Copyright (C) 2012 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma version(1) + +#pragma rs java_package_name(com.android.scenegraph) + +#include "scenegraph_objects.rsh" + +//#define DEBUG_PARAMS +static void debugParam(SgShaderParam *p, SgShaderParamData *pData) { + rsDebug("____________ Param ____________", p); + printName(pData->paramName); + rsDebug("bufferOffset", p->bufferOffset); + rsDebug("type ", pData->type); + rsDebug("data timestamp ", pData->timestamp); + rsDebug("param timestamp", p->dataTimestamp); + + const SgTransform *pTransform = NULL; + if (rsIsObject(pData->transform)) { + pTransform = (const SgTransform *)rsGetElementAt(pData->transform, 0); + + rsDebug("transform", pTransform); + printName(pTransform->name); + rsDebug("timestamp", pTransform->timestamp); + rsDebug("param timestamp", p->transformTimestamp); + } + + const SgLight *pLight = NULL; + if (rsIsObject(pData->light)) { + pLight = (const SgLight *)rsGetElementAt(pData->light, 0); + printLightInfo(pLight); + } +} + + +static void writeFloatData(float *ptr, const float4 *input, uint32_t vecSize) { +#ifdef DEBUG_PARAMS + rsDebug("Writing value ", *input); + rsDebug("Writing vec size ", vecSize); +#endif // DEBUG_PARAMS + + switch (vecSize) { + case 1: + *ptr = input->x; + break; + case 2: + *((float2*)ptr) = (*input).xy; + break; + case 3: + *((float3*)ptr) = (*input).xyz; + break; + case 4: + *((float4*)ptr) = *input; + break; + } +} + +static bool processParam(SgShaderParam *p, SgShaderParamData *pData, + uint8_t *constantBuffer, + const SgCamera *currentCam, + SgFragmentShader *shader) { + bool isDataOnly = (pData->type > SHADER_PARAM_DATA_ONLY); + const SgTransform *pTransform = NULL; + if (rsIsObject(pData->transform)) { + pTransform = (const SgTransform *)rsGetElementAt(pData->transform, 0); + } + + if (isDataOnly) { + // If we are a transform param and our transform is unchanged, nothing to do + if (pTransform) { + if (p->transformTimestamp == pTransform->timestamp) { + return false; + } + p->transformTimestamp = pTransform->timestamp; + } else { + if (p->dataTimestamp == pData->timestamp) { + return false; + } + p->dataTimestamp = pData->timestamp; + } + } + + const SgLight *pLight = NULL; + if (rsIsObject(pData->light)) { + pLight = (const SgLight *)rsGetElementAt(pData->light, 0); + } + + uint8_t *dataPtr = NULL; + const SgTexture *tex = NULL; + if (pData->type == SHADER_PARAM_TEXTURE) { + tex = rsGetElementAt(pData->texture, 0); + } else { + dataPtr = constantBuffer + p->bufferOffset; + } + + switch (pData->type) { + case SHADER_PARAM_TEXTURE: + rsgBindTexture(shader->program, p->bufferOffset, tex->texture); + break; + case SHADER_PARAM_FLOAT4_DATA: + writeFloatData((float*)dataPtr, &pData->float_value, p->float_vecSize); + break; + case SHADER_PARAM_FLOAT4_CAMERA_POS: + writeFloatData((float*)dataPtr, ¤tCam->position, p->float_vecSize); + break; + case SHADER_PARAM_FLOAT4_CAMERA_DIR: break; + case SHADER_PARAM_FLOAT4_LIGHT_COLOR: + writeFloatData((float*)dataPtr, &pLight->color, p->float_vecSize); + break; + case SHADER_PARAM_FLOAT4_LIGHT_POS: + writeFloatData((float*)dataPtr, &pLight->position, p->float_vecSize); + break; + case SHADER_PARAM_FLOAT4_LIGHT_DIR: break; + + case SHADER_PARAM_TRANSFORM_DATA: + rsMatrixLoad((rs_matrix4x4*)dataPtr, &pTransform->globalMat); + break; + case SHADER_PARAM_TRANSFORM_VIEW: + rsMatrixLoad((rs_matrix4x4*)dataPtr, ¤tCam->view); + break; + case SHADER_PARAM_TRANSFORM_PROJ: + rsMatrixLoad((rs_matrix4x4*)dataPtr, ¤tCam->proj); + break; + case SHADER_PARAM_TRANSFORM_VIEW_PROJ: + rsMatrixLoad((rs_matrix4x4*)dataPtr, ¤tCam->viewProj); + break; + case SHADER_PARAM_TRANSFORM_MODEL: + rsMatrixLoad((rs_matrix4x4*)dataPtr, &pTransform->globalMat); + break; + case SHADER_PARAM_TRANSFORM_MODEL_VIEW: + rsMatrixLoad((rs_matrix4x4*)dataPtr, ¤tCam->view); + rsMatrixLoadMultiply((rs_matrix4x4*)dataPtr, + (rs_matrix4x4*)dataPtr, + &pTransform->globalMat); + break; + case SHADER_PARAM_TRANSFORM_MODEL_VIEW_PROJ: + rsMatrixLoad((rs_matrix4x4*)dataPtr, ¤tCam->viewProj); + rsMatrixLoadMultiply((rs_matrix4x4*)dataPtr, + (rs_matrix4x4*)dataPtr, + &pTransform->globalMat); + break; + } + return true; +} + +static void processAllParams(rs_allocation shaderConst, + rs_allocation allParams, + const SgCamera *camera) { + if (rsIsObject(shaderConst)) { + uint8_t *constantBuffer = (uint8_t*)rsGetElementAt(shaderConst, 0); + + int numParams = 0; + if (rsIsObject(allParams)) { + numParams = rsAllocationGetDimX(allParams); + } + bool updated = false; + for (int i = 0; i < numParams; i ++) { + SgShaderParam *current = (SgShaderParam*)rsGetElementAt(allParams, i); + SgShaderParamData *currentData = (SgShaderParamData*)rsGetElementAt(current->data, 0); +#ifdef DEBUG_PARAMS + debugParam(current, currentData); +#endif // DEBUG_PARAMS + updated = processParam(current, currentData, constantBuffer, camera, NULL) || updated; + } + } +} + +static void processTextureParams(SgFragmentShader *shader) { + int numParams = 0; + if (rsIsObject(shader->shaderTextureParams)) { + numParams = rsAllocationGetDimX(shader->shaderTextureParams); + } + for (int i = 0; i < numParams; i ++) { + SgShaderParam *current = (SgShaderParam*)rsGetElementAt(shader->shaderTextureParams, i); + SgShaderParamData *currentData = (SgShaderParamData*)rsGetElementAt(current->data, 0); +#ifdef DEBUG_PARAMS + debugParam(current, currentData); +#endif // DEBUG_PARAMS + processParam(current, currentData, NULL, NULL, shader); + } +} diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/render.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/render.rs new file mode 100644 index 000000000000..d8d48b3da25c --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/render.rs @@ -0,0 +1,240 @@ +// Copyright (C) 2011-2012 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma version(1) + +#pragma rs java_package_name(com.android.scenegraph) + +#include "rs_graphics.rsh" +#include "scenegraph_objects.rsh" + +rs_script gTransformScript; +rs_script gCameraScript; +rs_script gLightScript; +rs_script gObjectParamsScript; +rs_script gFragmentParamsScript; +rs_script gVertexParamsScript; +rs_script gCullScript; + +SgTransform *gRootNode; +rs_allocation gCameras; +rs_allocation gLights; +rs_allocation gFragmentShaders; +rs_allocation gVertexShaders; +rs_allocation gRenderableObjects; + +rs_allocation gRenderPasses; + +// Temporary shaders +rs_program_store gPFSBackground; + +uint32_t *gFrontToBack; +static uint32_t gFrontToBackCount = 0; +uint32_t *gBackToFront; +static uint32_t gBackToFrontCount = 0; + +static SgCamera *gActiveCamera = NULL; + +static rs_allocation nullAlloc; + +// #define DEBUG_RENDERABLES +static void draw(SgRenderable *obj) { +#ifdef DEBUG_RENDERABLES + const SgTransform *objTransform = (const SgTransform *)rsGetElementAt(obj->transformMatrix, 0); + rsDebug("**** Drawing object with transform", obj); + printName(objTransform->name); + rsDebug("Model matrix: ", &objTransform->globalMat); + printName(obj->name); +#endif //DEBUG_RENDERABLES + + const SgRenderState *renderState = (const SgRenderState *)rsGetElementAt(obj->render_state, 0); + const SgVertexShader *pv = (const SgVertexShader *)rsGetElementAt(renderState->pv, 0); + const SgFragmentShader *pf = (const SgFragmentShader *)rsGetElementAt(renderState->pf, 0); + + if (pv->objectConstIndex != -1) { + rsgBindConstant(pv->program, pv->objectConstIndex, obj->pv_const); + } + if (pf->objectConstIndex != -1) { + rsgBindConstant(pf->program, pf->objectConstIndex, obj->pf_const); + } + + if (rsIsObject(renderState->ps)) { + rsgBindProgramStore(renderState->ps); + } else { + rsgBindProgramStore(gPFSBackground); + } + + if (rsIsObject(renderState->pr)) { + rsgBindProgramRaster(renderState->pr); + } else { + rs_program_raster pr; + rsgBindProgramRaster(pr); + } + + rsgBindProgramVertex(pv->program); + rsgBindProgramFragment(pf->program); + + for (uint32_t i = 0; i < obj->pf_num_textures; i ++) { + const SgTexture *tex = rsGetElementAt(obj->pf_textures[i], 0); + rsgBindTexture(pf->program, i, tex->texture); + } + + rsgDrawMesh(obj->mesh, obj->meshIndex); +} + +static void sortToBucket(SgRenderable *obj) { + const SgRenderState *renderState = (const SgRenderState *)rsGetElementAt(obj->render_state, 0); + if (rsIsObject(renderState->ps)) { + bool isOpaque = false; + if (isOpaque) { + gFrontToBack[gFrontToBackCount++] = (uint32_t)obj; + } else { + gBackToFront[gBackToFrontCount++] = (uint32_t)obj; + } + } else { + gFrontToBack[gFrontToBackCount++] = (uint32_t)obj; + } +} + +static void updateActiveCamera(rs_allocation cam) { + gActiveCamera = (SgCamera *)rsGetElementAt(cam, 0); +} + +static void prepareCameras() { + // now compute all the camera matrices + if (rsIsObject(gCameras)) { + float aspect = (float)rsgGetWidth() / (float)rsgGetHeight(); + rsForEach(gCameraScript, gCameras, nullAlloc, &aspect, sizeof(aspect)); + } +} + +static void prepareLights() { + if (rsIsObject(gLights)) { + rsForEach(gLightScript, gLights, nullAlloc); + } +} + +static void drawSorted() { + for (int i = 0; i < gFrontToBackCount; i ++) { + SgRenderable *current = (SgRenderable*)gFrontToBack[i]; + draw(current); + } + + for (int i = 0; i < gBackToFrontCount; i ++) { + SgRenderable *current = (SgRenderable*)gBackToFront[i]; + draw(current); + } +} + +static void drawAllObjects(rs_allocation allObj) { + if (!rsIsObject(allObj)) { + return; + } + + rsForEach(gVertexParamsScript, nullAlloc, gVertexShaders, + gActiveCamera, sizeof(gActiveCamera)); + rsForEach(gFragmentParamsScript, nullAlloc, gFragmentShaders, + gActiveCamera, sizeof(gActiveCamera)); + + // Run the params and cull script + rsForEach(gCullScript, nullAlloc, allObj, gActiveCamera, sizeof(gActiveCamera)); + rsForEach(gObjectParamsScript, nullAlloc, allObj, gActiveCamera, sizeof(gActiveCamera)); + + int numRenderables = rsAllocationGetDimX(allObj); + for (int i = 0; i < numRenderables; i ++) { + rs_allocation *drawAlloc = (rs_allocation*)rsGetElementAt(allObj, i); + SgRenderable *current = (SgRenderable*)rsGetElementAt(*drawAlloc, 0); + if (current->isVisible) { + sortToBucket(current); + } + } + drawSorted(); +} + +int root(void) { +#ifdef DEBUG_RENDERABLES + rsDebug("=============================================================================", 0); +#endif // DEBUG_RENDERABLES + + // first step is to update the transform hierachy + if (gRootNode && rsIsObject(gRootNode->children)) { + rsForEach(gTransformScript, gRootNode->children, nullAlloc, 0, 0); + } + + prepareCameras(); + prepareLights(); + + if (rsIsObject(gRenderPasses)) { + rsgClearDepth(1.0f); + int numPasses = rsAllocationGetDimX(gRenderPasses); + for (uint i = 0; i < numPasses; i ++) { + gFrontToBackCount = 0; + gBackToFrontCount = 0; + SgRenderPass *pass = (SgRenderPass*)rsGetElementAt(gRenderPasses, i); + if (rsIsObject(pass->color_target)) { + rsgBindColorTarget(pass->color_target, 0); + } + if (rsIsObject(pass->depth_target)) { + rsgBindDepthTarget(pass->depth_target); + } + if (!rsIsObject(pass->color_target) && + !rsIsObject(pass->depth_target)) { + rsgClearAllRenderTargets(); + } + updateActiveCamera(pass->camera); + if (pass->should_clear_color) { + rsgClearColor(pass->clear_color.x, pass->clear_color.y, + pass->clear_color.z, pass->clear_color.w); + } + if (pass->should_clear_depth) { + rsgClearDepth(pass->clear_depth); + } + drawAllObjects(pass->objects); + } + } else { + gFrontToBackCount = 0; + gBackToFrontCount = 0; + rsgClearColor(1.0f, 1.0f, 1.0f, 1.0f); + rsgClearDepth(1.0f); + + if (rsIsObject(gCameras)) { + rs_allocation *camAlloc = (rs_allocation*)rsGetElementAt(gCameras, 0); + updateActiveCamera(*camAlloc); + } + drawAllObjects(gRenderableObjects); + } + return 10; +} + +// Search through sorted and culled objects +void pick(int screenX, int screenY) { + float3 pnt, vec; + getCameraRay(gActiveCamera, screenX, screenY, &pnt, &vec); + + for (int i = 0; i < gFrontToBackCount; i ++) { + SgRenderable *current = (SgRenderable*)gFrontToBack[i]; + bool isPicked = intersect(current, pnt, vec); + if (isPicked) { + current->cullType = CULL_ALWAYS; + } + } + + for (int i = 0; i < gBackToFrontCount; i ++) { + SgRenderable *current = (SgRenderable*)gBackToFront[i]; + bool isPicked = intersect(current, pnt, vec); + if (isPicked) { + current->cullType = CULL_ALWAYS; + } + } +} diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/scenegraph_objects.rsh b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/scenegraph_objects.rsh new file mode 100644 index 000000000000..bdca3ab1995b --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/scenegraph_objects.rsh @@ -0,0 +1,323 @@ +// Copyright (C) 2011-2012 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma version(1) + +#pragma rs java_package_name(com.android.scenegraph) + +#ifndef _TRANSFORM_DEF_ +#define _TRANSFORM_DEF_ + +#include "rs_graphics.rsh" + +#define TRANSFORM_NONE 0 +#define TRANSFORM_TRANSLATE 1 +#define TRANSFORM_ROTATE 2 +#define TRANSFORM_SCALE 3 + +#define CULL_FRUSTUM 0 +#define CULL_ALWAYS 2 + +#define LIGHT_POINT 0 +#define LIGHT_DIRECTIONAL 1 + +// Shader params that involve only data +#define SHADER_PARAM_DATA_ONLY 10000 +#define SHADER_PARAM_FLOAT4_DATA 10001 +#define SHADER_PARAM_TRANSFORM_DATA 10002 +#define SHADER_PARAM_TRANSFORM_MODEL 10003 + +// Shader params that involve camera +#define SHADER_PARAM_CAMERA 1000 +#define SHADER_PARAM_FLOAT4_CAMERA_POS 1001 +#define SHADER_PARAM_FLOAT4_CAMERA_DIR 1002 +#define SHADER_PARAM_TRANSFORM_VIEW 1003 +#define SHADER_PARAM_TRANSFORM_PROJ 1004 +#define SHADER_PARAM_TRANSFORM_VIEW_PROJ 1005 +#define SHADER_PARAM_TRANSFORM_MODEL_VIEW 1006 +#define SHADER_PARAM_TRANSFORM_MODEL_VIEW_PROJ 1007 + +// Shader Params that only involve lights +#define SHADER_PARAM_LIGHT 100 +#define SHADER_PARAM_FLOAT4_LIGHT_COLOR 103 +#define SHADER_PARAM_FLOAT4_LIGHT_POS 104 +#define SHADER_PARAM_FLOAT4_LIGHT_DIR 105 + +#define SHADER_PARAM_TEXTURE 10 + +#define TEXTURE_NONE 0 +#define TEXTURE_2D 1 +#define TEXTURE_CUBE 2 +#define TEXTURE_RENDER_TARGET 3 + +typedef struct TransformComponent_s { + float4 value; + int type; + rs_allocation name; +} SgTransformComponent; + +typedef struct __attribute__((packed, aligned(4))) SgTransform { + rs_matrix4x4 globalMat; + rs_matrix4x4 localMat; + + rs_allocation components; + int isDirty; + + rs_allocation children; + rs_allocation name; + + // Used to check whether transform params need to be updated + uint32_t timestamp; +} SgTransform; + +typedef struct VertexShader_s { + rs_program_vertex program; + // Buffer with vertex constant data + rs_allocation shaderConst; + // ShaderParam's that populate data + rs_allocation shaderConstParams; + // location of the per object constants on the buffer + int objectConstIndex; +} SgVertexShader; + +typedef struct FragmentShader_s { + rs_program_fragment program; + // Buffer with vertex constant data + rs_allocation shaderConst; + // ShaderParam's that populate data + rs_allocation shaderConstParams; + // ShaderParam's that set textures + rs_allocation shaderTextureParams; + // location of the per object constants on the buffer + int objectConstIndex; +} SgFragmentShader; + +typedef struct RenderState_s { + rs_allocation pv; // VertexShader struct + rs_allocation pf; // FragmentShader struct + rs_program_store ps; + rs_program_raster pr; +} SgRenderState; + +typedef struct Renderable_s { + rs_allocation render_state; + // Buffer with vertex constant data + rs_allocation pv_const; + // ShaderParam's that populate data + rs_allocation pv_constParams; + // Buffer with fragment constant data + rs_allocation pf_const; + // ShaderParam's that populate data + rs_allocation pf_constParams; + rs_allocation pf_textures[8]; + int pf_num_textures; + rs_mesh mesh; + int meshIndex; + rs_allocation transformMatrix; + rs_allocation name; + float4 boundingSphere; + float4 worldBoundingSphere; + int bVolInitialized; + int cullType; // specifies whether to frustum cull + int isVisible; +} SgRenderable; + +typedef struct RenderPass_s { + rs_allocation color_target; + rs_allocation depth_target; + rs_allocation camera; + rs_allocation objects; + + float4 clear_color; + float clear_depth; + bool should_clear_color; + bool should_clear_depth; +} SgRenderPass; + +typedef struct Camera_s { + rs_matrix4x4 proj; + rs_matrix4x4 view; + rs_matrix4x4 viewProj; + float4 position; + float near; + float far; + float horizontalFOV; + float aspect; + rs_allocation name; + rs_allocation transformMatrix; + float4 frustumPlanes[6]; + + int isDirty; + // Timestamp of the camera itself to signal params if anything changes + uint32_t timestamp; + // Timestamp of our transform + uint32_t transformTimestamp; +} SgCamera; + +typedef struct Light_s { + float4 position; + float4 color; + float intensity; + int type; + rs_allocation name; + rs_allocation transformMatrix; +} SgLight; + +// This represents the shader parameter data needed to set a float or transform data +typedef struct ShaderParamData_s { + int type; + float4 float_value; + uint32_t timestamp; + rs_allocation paramName; + rs_allocation camera; + rs_allocation light; + rs_allocation transform; + rs_allocation texture; +} SgShaderParamData; + +// This represents a shader parameter that knows how to update itself for a given +// renderable or shader and contains a timestamp for the last time this buffer was updated +typedef struct ShaderParam_s { + // Used to check whether transform params need to be updated + uint32_t transformTimestamp; + // Used to check whether data params need to be updated + // These are used when somebody set the matrix of float value directly in java + uint32_t dataTimestamp; + // Specifies where in the constant buffer data gets written to + int bufferOffset; + // An instance of SgShaderParamData that could be shared by multiple objects + rs_allocation data; + // How many components of the vector we need to write + int float_vecSize; +} SgShaderParam; + +// This represents a texture object +typedef struct Texture_s { + uint32_t type; + rs_allocation texture; +} SgTexture; + +static void printName(rs_allocation name) { + if (!rsIsObject(name)) { + rsDebug("no name", 0); + return; + } + + rsDebug((const char*)rsGetElementAt(name, 0), 0); +} + +static void printCameraInfo(const SgCamera *cam) { + rsDebug("***** Camera information. ptr:", cam); + printName(cam->name); + const SgTransform *camTransform = (const SgTransform *)rsGetElementAt(cam->transformMatrix, 0); + rsDebug("Transform name:", camTransform); + printName(camTransform->name); + + rsDebug("Aspect: ", cam->aspect); + rsDebug("Near: ", cam->near); + rsDebug("Far: ", cam->far); + rsDebug("Fov: ", cam->horizontalFOV); + rsDebug("Position: ", cam->position); + rsDebug("Proj: ", &cam->proj); + rsDebug("View: ", &cam->view); +} + +static void printLightInfo(const SgLight *light) { + rsDebug("***** Light information. ptr:", light); + printName(light->name); + const SgTransform *lTransform = (const SgTransform *)rsGetElementAt(light->transformMatrix, 0); + rsDebug("Transform name:", lTransform); + printName(lTransform->name); + + rsDebug("Position: ", light->position); + rsDebug("Color : ", light->color); + rsDebug("Intensity: ", light->intensity); + rsDebug("Type: ", light->type); +} + +static void getCameraRay(const SgCamera *cam, int screenX, int screenY, float3 *pnt, float3 *vec) { + rsDebug("=================================", screenX); + rsDebug("Point X", screenX); + rsDebug("Point Y", screenY); + + rs_matrix4x4 mvpInv; + rsMatrixLoad(&mvpInv, &cam->viewProj); + rsMatrixInverse(&mvpInv); + + float width = (float)rsgGetWidth(); + float height = (float)rsgGetHeight(); + + float4 pos = {(float)screenX, height - (float)screenY, 0.0f, 1.0f}; + + pos.x /= width; + pos.y /= height; + + rsDebug("Pre Norm X", pos.x); + rsDebug("Pre Norm Y", pos.y); + + pos.xy = pos.xy * 2.0f - 1.0f; + + rsDebug("Norm X", pos.x); + rsDebug("Norm Y", pos.y); + + pos = rsMatrixMultiply(&mvpInv, pos); + float oneOverW = 1.0f / pos.w; + pos.xyz *= oneOverW; + + rsDebug("World X", pos.x); + rsDebug("World Y", pos.y); + rsDebug("World Z", pos.z); + + rsDebug("Cam X", cam->position.x); + rsDebug("Cam Y", cam->position.y); + rsDebug("Cam Z", cam->position.z); + + *vec = normalize(pos.xyz - cam->position.xyz); + rsDebug("Vec X", vec->x); + rsDebug("Vec Y", vec->y); + rsDebug("Vec Z", vec->z); + *pnt = cam->position.xyz; +} + +static bool intersect(const SgRenderable *obj, float3 pnt, float3 vec) { + // Solving for t^2 + Bt + C = 0 + float3 originMinusCenter = pnt - obj->worldBoundingSphere.xyz; + float B = dot(originMinusCenter, vec) * 2.0f; + float C = dot(originMinusCenter, originMinusCenter) - + obj->worldBoundingSphere.w * obj->worldBoundingSphere.w; + + float discriminant = B * B - 4.0f * C; + if (discriminant < 0.0f) { + return false; + } + discriminant = sqrt(discriminant); + + float t0 = (-B - discriminant) * 0.5f; + float t1 = (-B + discriminant) * 0.5f; + + if (t0 > t1) { + float temp = t0; + t0 = t1; + t1 = temp; + } + + // The sphere is behind us + if (t1 < 0.0f) { + return false; + } + return true; +} + + +#endif // _TRANSFORM_DEF_ diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/transform.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/transform.rs new file mode 100644 index 000000000000..941b5a8c292a --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/transform.rs @@ -0,0 +1,127 @@ +// Copyright (C) 2011 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma version(1) + +#pragma rs java_package_name(com.android.modelviewer) + +#include "scenegraph_objects.rsh" + +rs_script gTransformScript; + +typedef struct { + int changed; + rs_matrix4x4 *mat; +} ParentData; + +//#define DEBUG_TRANSFORMS +static void debugTransform(SgTransform *data, const ParentData *parent) { + rsDebug("****** <Transform> ******", (int)data); + printName(data->name); + rsDebug("isDirty", data->isDirty); + rsDebug("parent", (int)parent); + rsDebug("child ", rsIsObject(data->children)); + + // Refresh matrices if dirty + if (data->isDirty && rsIsObject(data->components)) { + uint32_t numComponenets = rsAllocationGetDimX(data->components); + for (int i = 0; i < numComponenets; i ++) { + const SgTransformComponent *comp = NULL; + comp = (const SgTransformComponent *)rsGetElementAt(data->components, i); + + if (rsIsObject(comp->name)) { + rsDebug((const char*)rsGetElementAt(comp->name, 0), comp->value); + rsDebug("Type", comp->type); + } else { + rsDebug("no name", comp->value); + rsDebug("Type", comp->type); + } + } + } + + rsDebug("timestamp", data->timestamp); + rsDebug("****** </Transform> ******", (int)data); +} + +static void appendTransformation(int type, float4 data, rs_matrix4x4 *mat) { + rs_matrix4x4 temp; + + switch (type) { + case TRANSFORM_TRANSLATE: + rsMatrixLoadTranslate(&temp, data.x, data.y, data.z); + break; + case TRANSFORM_ROTATE: + rsMatrixLoadRotate(&temp, data.w, data.x, data.y, data.z); + break; + case TRANSFORM_SCALE: + rsMatrixLoadScale(&temp, data.x, data.y, data.z); + break; + } + rsMatrixMultiply(mat, &temp); +} + +void root(const rs_allocation *v_in, rs_allocation *v_out, const void *usrData) { + + SgTransform *data = (SgTransform *)rsGetElementAt(*v_in, 0); + const ParentData *parent = (const ParentData *)usrData; + +#ifdef DEBUG_TRANSFORMS + debugTransform(data, parent); +#endif //DEBUG_TRANSFORMS + + rs_matrix4x4 *localMat = &data->localMat; + rs_matrix4x4 *globalMat = &data->globalMat; + + // Refresh matrices if dirty + if (data->isDirty && rsIsObject(data->components)) { + bool resetLocal = false; + uint32_t numComponenets = rsAllocationGetDimX(data->components); + for (int i = 0; i < numComponenets; i ++) { + if (!resetLocal) { + // Reset our local matrix only for component transforms + rsMatrixLoadIdentity(localMat); + resetLocal = true; + } + const SgTransformComponent *comp = NULL; + comp = (const SgTransformComponent *)rsGetElementAt(data->components, i); + appendTransformation(comp->type, comp->value, localMat); + } + } + + if (parent) { + data->isDirty = (parent->changed || data->isDirty) ? 1 : 0; + if (data->isDirty) { + rsMatrixLoad(globalMat, parent->mat); + rsMatrixMultiply(globalMat, localMat); + } + } else if (data->isDirty) { + rsMatrixLoad(globalMat, localMat); + } + + ParentData toChild; + toChild.changed = 0; + toChild.mat = globalMat; + + if (data->isDirty) { + toChild.changed = 1; + data->timestamp ++; + } + + if (rsIsObject(data->children)) { + rs_allocation nullAlloc; + rsForEach(gTransformScript, data->children, nullAlloc, &toChild, sizeof(toChild)); + } + + data->isDirty = 0; +} diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/vertex_params.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/vertex_params.rs new file mode 100644 index 000000000000..88955a88ffdd --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/vertex_params.rs @@ -0,0 +1,29 @@ +// Copyright (C) 2012 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma version(1) + +#pragma rs java_package_name(com.android.scenegraph) + +#include "scenegraph_objects.rsh" + +//#define DEBUG_PARAMS + +#include "params.rsh" + +void root(rs_allocation *v_out, const void *usrData) { + SgVertexShader *shader = (SgVertexShader *)rsGetElementAt(*v_out, 0); + const SgCamera *camera = (const SgCamera*)usrData; + processAllParams(shader->shaderConst, shader->shaderConstParams, camera); +} diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/FileSelector.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/FileSelector.java new file mode 100644 index 000000000000..420e1330d88a --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/FileSelector.java @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.testapp; + +import java.io.File; +import java.io.FileFilter; +import java.util.ArrayList; +import java.util.List; + +import android.app.ListActivity; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.view.View; +import android.widget.ArrayAdapter; +import android.widget.ListView; + +/** + * A list view where the last item the user clicked is placed in + * the "activated" state, causing its background to highlight. + */ +public class FileSelector extends ListActivity { + + File[] mCurrentSubList; + File mCurrentFile; + + class DAEFilter implements FileFilter { + public boolean accept(File file) { + if (file.isDirectory()) { + return true; + } + return file.getName().endsWith(".dae"); + } + } + + private void populateList(File file) { + + mCurrentFile = file; + setTitle(mCurrentFile.getAbsolutePath() + "/*.dae"); + List<String> names = new ArrayList<String>(); + names.add(".."); + + mCurrentSubList = mCurrentFile.listFiles(new DAEFilter()); + + if (mCurrentSubList != null) { + for (int i = 0; i < mCurrentSubList.length; i ++) { + String fileName = mCurrentSubList[i].getName(); + if (mCurrentSubList[i].isDirectory()) { + fileName = "/" + fileName; + } + names.add(fileName); + } + } + + // Use the built-in layout for showing a list item with a single + // line of text whose background is changes when activated. + setListAdapter(new ArrayAdapter<String>(this, + android.R.layout.simple_list_item_activated_1, names)); + getListView().setTextFilterEnabled(true); + + // Tell the list view to show one checked/activated item at a time. + getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE); + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + populateList(new File("/sdcard/")); + } + + @Override + protected void onListItemClick(ListView l, View v, int position, long id) { + if (position == 0) { + File parent = mCurrentFile.getParentFile(); + if (parent == null) { + return; + } + populateList(parent); + return; + } + + // the first thing in list is parent directory + File selectedFile = mCurrentSubList[position - 1]; + if (selectedFile.isDirectory()) { + populateList(selectedFile); + return; + } + + Intent resultIntent = new Intent(); + resultIntent.setData(Uri.fromFile(selectedFile)); + setResult(RESULT_OK, resultIntent); + finish(); + } + +} diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/FullscreenBlur.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/FullscreenBlur.java new file mode 100644 index 000000000000..28f916c864c7 --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/FullscreenBlur.java @@ -0,0 +1,192 @@ +/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package com.android.testapp;
+
+import java.util.ArrayList;
+
+import com.android.scenegraph.*;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.AsyncTask;
+import android.renderscript.*;
+import android.renderscript.Allocation.MipmapControl;
+import android.renderscript.Element.Builder;
+import android.renderscript.Font.Style;
+import android.renderscript.Program.TextureType;
+import android.renderscript.ProgramStore.DepthFunc;
+import android.util.Log;
+
+class FullscreenBlur {
+
+ static TextureRenderTarget sRenderTargetBlur0Color;
+ static TextureRenderTarget sRenderTargetBlur0Depth;
+ static TextureRenderTarget sRenderTargetBlur1Color;
+ static TextureRenderTarget sRenderTargetBlur1Depth;
+ static TextureRenderTarget sRenderTargetBlur2Color;
+ static TextureRenderTarget sRenderTargetBlur2Depth;
+
+ static FragmentShader mPF_BlurH;
+ static FragmentShader mPF_BlurV;
+ static FragmentShader mPF_SelectColor;
+ static FragmentShader mPF_Texture;
+ static VertexShader mPV_Paint;
+ static VertexShader mPV_Blur;
+
+ static int targetWidth;
+ static int targetHeight;
+
+ // This is only used when full screen blur is enabled
+ // Basically, it's the offscreen render targets
+ static void createRenderTargets(RenderScriptGL rs, int w, int h) {
+ targetWidth = w/8;
+ targetHeight = h/8;
+ Type.Builder b = new Type.Builder(rs, Element.RGBA_8888(rs));
+ Type renderType = b.setX(targetWidth).setY(targetHeight).create();
+ int usage = Allocation.USAGE_GRAPHICS_TEXTURE | Allocation.USAGE_GRAPHICS_RENDER_TARGET;
+ sRenderTargetBlur0Color = new TextureRenderTarget(Allocation.createTyped(rs, renderType, usage));
+ sRenderTargetBlur1Color = new TextureRenderTarget(Allocation.createTyped(rs, renderType, usage));
+ sRenderTargetBlur2Color = new TextureRenderTarget(Allocation.createTyped(rs, renderType, usage));
+
+ b = new Type.Builder(rs, Element.createPixel(rs, Element.DataType.UNSIGNED_16,
+ Element.DataKind.PIXEL_DEPTH));
+ renderType = b.setX(targetWidth).setY(targetHeight).create();
+ usage = Allocation.USAGE_GRAPHICS_RENDER_TARGET;
+ sRenderTargetBlur0Depth = new TextureRenderTarget(Allocation.createTyped(rs, renderType, usage));
+ sRenderTargetBlur1Depth = new TextureRenderTarget(Allocation.createTyped(rs, renderType, usage));
+ sRenderTargetBlur2Depth = new TextureRenderTarget(Allocation.createTyped(rs, renderType, usage));
+ }
+
+ static void addOffsets(Renderable quad, float advance) {
+ quad.appendSourceParams(new Float4Param("blurOffset0", - advance * 2.5f));
+ quad.appendSourceParams(new Float4Param("blurOffset1", - advance * 0.5f));
+ quad.appendSourceParams(new Float4Param("blurOffset2", advance * 1.5f));
+ quad.appendSourceParams(new Float4Param("blurOffset3", advance * 3.5f));
+ }
+
+ static RenderPass addPass(Scene scene, Camera cam, TextureRenderTarget color, TextureRenderTarget depth) {
+ RenderPass pass = new RenderPass();
+ pass.setColorTarget(color);
+ pass.setDepthTarget(depth);
+ pass.setShouldClearColor(false);
+ pass.setShouldClearDepth(false);
+ pass.setCamera(cam);
+ scene.appendRenderPass(pass);
+ return pass;
+ }
+
+ static void addBlurPasses(Scene scene, RenderScriptGL rs, Camera cam) {
+ SceneManager sceneManager = SceneManager.getInstance();
+ ArrayList<RenderableBase> allDraw = scene.getRenderables();
+ int numDraw = allDraw.size();
+
+ ProgramRaster cullNone = ProgramRaster.CULL_NONE(rs);
+ ProgramStore blendAdd = SceneManager.BLEND_ADD_DEPTH_NONE(rs);
+ ProgramStore blendNone = ProgramStore.BLEND_NONE_DEPTH_NONE(rs);
+
+ RenderState drawTex = new RenderState(mPV_Blur, mPF_Texture, blendAdd, cullNone);
+ RenderState selectCol = new RenderState(mPV_Blur, mPF_SelectColor, blendNone, cullNone);
+ RenderState hBlur = new RenderState(mPV_Blur, mPF_BlurH, blendNone, cullNone);
+ RenderState vBlur = new RenderState(mPV_Blur, mPF_BlurV, blendNone, cullNone);
+
+ // Renders the scene off screen
+ RenderPass blurSourcePass = addPass(scene, cam,
+ sRenderTargetBlur0Color,
+ sRenderTargetBlur0Depth);
+ blurSourcePass.setClearColor(new Float4(1.0f, 1.0f, 1.0f, 1.0f));
+ blurSourcePass.setShouldClearColor(true);
+ blurSourcePass.setClearDepth(1.0f);
+ blurSourcePass.setShouldClearDepth(true);
+ for (int i = 0; i < numDraw; i ++) {
+ blurSourcePass.appendRenderable((Renderable)allDraw.get(i));
+ }
+
+ // Pass for selecting bright colors
+ RenderPass selectColorPass = addPass(scene, cam,
+ sRenderTargetBlur2Color,
+ sRenderTargetBlur2Depth);
+ Renderable quad = sceneManager.getRenderableQuad("ScreenAlignedQuadS", selectCol);
+ quad.appendSourceParams(new TextureParam("color", sRenderTargetBlur0Color));
+ selectColorPass.appendRenderable(quad);
+
+ // Horizontal blur
+ RenderPass horizontalBlurPass = addPass(scene, cam,
+ sRenderTargetBlur1Color,
+ sRenderTargetBlur1Depth);
+ quad = sceneManager.getRenderableQuad("ScreenAlignedQuadH", hBlur);
+ quad.appendSourceParams(new TextureParam("color", sRenderTargetBlur2Color));
+ addOffsets(quad, 1.0f / (float)targetWidth);
+ horizontalBlurPass.appendRenderable(quad);
+
+ // Vertical Blur
+ RenderPass verticalBlurPass = addPass(scene, cam,
+ sRenderTargetBlur2Color,
+ sRenderTargetBlur2Depth);
+ quad = sceneManager.getRenderableQuad("ScreenAlignedQuadV", vBlur);
+ quad.appendSourceParams(new TextureParam("color", sRenderTargetBlur1Color));
+ addOffsets(quad, 1.0f / (float)targetHeight);
+ verticalBlurPass.appendRenderable(quad);
+ }
+
+ // Additively renders the blurred colors on top of the scene
+ static void addCompositePass(Scene scene, RenderScriptGL rs, Camera cam) {
+ SceneManager sceneManager = SceneManager.getInstance();
+ RenderState drawTex = new RenderState(mPV_Blur, mPF_Texture,
+ SceneManager.BLEND_ADD_DEPTH_NONE(rs),
+ ProgramRaster.CULL_NONE(rs));
+
+ RenderPass compositePass = addPass(scene, cam, null, null);
+ Renderable quad = sceneManager.getRenderableQuad("ScreenAlignedQuadComposite", drawTex);
+ quad.appendSourceParams(new TextureParam("color", sRenderTargetBlur2Color));
+ compositePass.appendRenderable(quad);
+ }
+
+ static private FragmentShader getShader(Resources res, RenderScriptGL rs,
+ int resID, Type constants) {
+ FragmentShader.Builder fb = new FragmentShader.Builder(rs);
+ fb.setShader(res, resID);
+ fb.addTexture(TextureType.TEXTURE_2D, "color");
+ if (constants != null) {
+ fb.setObjectConst(constants);
+ }
+ FragmentShader prog = fb.create();
+ prog.getProgram().bindSampler(Sampler.CLAMP_LINEAR(rs), 0);
+ return prog;
+ }
+
+ static void initShaders(Resources res, RenderScriptGL rs) {
+ ScriptField_BlurOffsets blurConst = new ScriptField_BlurOffsets(rs, 1);
+ VertexShader.Builder vb = new VertexShader.Builder(rs);
+ vb.addInput(ScriptField_VertexShaderInputs.createElement(rs));
+ vb.setShader(res, R.raw.blur_vertex);
+ mPV_Blur = vb.create();
+
+ mPF_Texture = getShader(res, rs, R.raw.texture, null);
+ mPF_Texture.getProgram().bindSampler(Sampler.WRAP_LINEAR_MIP_LINEAR(rs), 0);
+ mPF_BlurH = getShader(res, rs, R.raw.blur_h, blurConst.getAllocation().getType());
+ mPF_BlurV = getShader(res, rs, R.raw.blur_v, blurConst.getAllocation().getType());
+ mPF_SelectColor = getShader(res, rs, R.raw.select_color, null);
+ }
+
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestApp.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestApp.java new file mode 100644 index 000000000000..385a7ab37d11 --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestApp.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.testapp; + +import android.renderscript.RSSurfaceView; +import android.renderscript.RenderScript; + +import android.app.Activity; +import android.content.res.Configuration; +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.provider.Settings.System; +import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.Window; +import android.widget.Button; +import android.widget.ListView; +import android.view.MenuInflater; +import android.view.Window; +import android.net.Uri; + +import java.lang.Runtime; + +public class TestApp extends Activity { + + private TestAppView mView; + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + + // Create our Preview view and set it as the content of our + // Activity + mView = new TestAppView(this); + setContentView(mView); + } + + @Override + protected void onResume() { + // Ideally a game should implement onResume() and onPause() + // to take appropriate action when the activity looses focus + super.onResume(); + mView.resume(); + } + + @Override + protected void onPause() { + // Ideally a game should implement onResume() and onPause() + // to take appropriate action when the activity looses focus + super.onPause(); + mView.pause(); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.loader_menu, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + // Handle item selection + switch (item.getItemId()) { + case R.id.load_model: + loadModel(); + return true; + case R.id.use_blur: + mView.mRender.toggleBlur(); + return true; + default: + return super.onOptionsItemSelected(item); + } + } + + private static final int FIND_DAE_MODEL = 10; + public void onActivityResult(int requestCode, int resultCode, Intent data) { + if (resultCode == RESULT_OK) { + if (requestCode == FIND_DAE_MODEL) { + Uri selectedImageUri = data.getData(); + Log.e("Selected Path: ", selectedImageUri.getPath()); + mView.mRender.loadModel(selectedImageUri.getPath()); + } + } + } + + public void loadModel() { + Intent intent = new Intent(); + intent.setAction(Intent.ACTION_PICK); + intent.setClassName("com.android.testapp", + "com.android.testapp.FileSelector"); + startActivityForResult(intent, FIND_DAE_MODEL); + } + +} + diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppLoadingScreen.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppLoadingScreen.java new file mode 100644 index 000000000000..5bd8f0bccf16 --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppLoadingScreen.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.testapp; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.Vector; + +import com.android.scenegraph.SceneManager; + +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.AsyncTask; +import android.renderscript.*; +import android.renderscript.Allocation.MipmapControl; +import android.renderscript.Element.Builder; +import android.renderscript.Font.Style; +import android.renderscript.Program.TextureType; +import android.renderscript.ProgramStore.DepthFunc; +import android.util.Log; + +// This is where the scenegraph and the rendered objects are initialized and used +public class TestAppLoadingScreen { + + private static String TAG = "TestAppLoadingScreen"; + + private Resources mRes; + private RenderScriptGL mRS; + private ScriptC_test_app mScript; + + public TestAppLoadingScreen(RenderScriptGL rs, Resources res) { + mRS = rs; + mRes = res; + // Shows the loading screen with some text + renderLoading(); + // Adds a little 3D bugdroid model to the laoding screen asynchronously. + new LoadingScreenLoaderTask().execute(); + } + + public void showLoadingScreen(boolean show) { + if (show) { + mRS.bindRootScript(mScript); + } else { + mRS.bindRootScript(SceneManager.getInstance().getRenderLoop()); + } + } + + // The loading screen has some elements that shouldn't be loaded on the UI thread + private class LoadingScreenLoaderTask extends AsyncTask<String, Void, Boolean> { + Allocation robotTex; + Mesh robotMesh; + protected Boolean doInBackground(String... names) { + long start = System.currentTimeMillis(); + robotTex = Allocation.createFromBitmapResource(mRS, mRes, R.drawable.robot, + MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE, + Allocation.USAGE_GRAPHICS_TEXTURE); + + FileA3D model = FileA3D.createFromResource(mRS, mRes, R.raw.robot); + FileA3D.IndexEntry entry = model.getIndexEntry(0); + if (entry != null && entry.getEntryType() == FileA3D.EntryType.MESH) { + robotMesh = entry.getMesh(); + } + + mScript.set_gPFSBackground(ProgramStore.BLEND_NONE_DEPTH_TEST(mRS)); + + ProgramFragmentFixedFunction.Builder b = new ProgramFragmentFixedFunction.Builder(mRS); + b.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE, + ProgramFragmentFixedFunction.Builder.Format.RGBA, 0); + ProgramFragment pfDefault = b.create(); + pfDefault.bindSampler(Sampler.CLAMP_LINEAR(mRS), 0); + mScript.set_gPFBackground(pfDefault); + + ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS); + ProgramVertexFixedFunction pvDefault = pvb.create(); + ProgramVertexFixedFunction.Constants va = new ProgramVertexFixedFunction.Constants(mRS); + ((ProgramVertexFixedFunction)pvDefault).bindConstants(va); + mScript.set_gPVBackground(pvDefault); + + long end = System.currentTimeMillis(); + Log.v("TIMER", "Loading load time: " + (end - start)); + return new Boolean(true); + } + + protected void onPostExecute(Boolean result) { + mScript.set_gRobotTex(robotTex); + mScript.set_gRobotMesh(robotMesh); + } + } + + // Creates a simple script to show a loding screen until everything is initialized + // Could also be used to do some custom renderscript work before handing things over + // to the scenegraph + void renderLoading() { + mScript = new ScriptC_test_app(mRS, mRes, R.raw.test_app); + mRS.bindRootScript(mScript); + } +} diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppRS.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppRS.java new file mode 100644 index 000000000000..7bf781287f73 --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppRS.java @@ -0,0 +1,265 @@ +/* + * Copyright (C) 2011-2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.testapp; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.Vector; + +import com.android.scenegraph.*; +import com.android.scenegraph.SceneManager.SceneLoadedCallback; + +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.AsyncTask; +import android.renderscript.*; +import android.renderscript.Program.TextureType; +import android.util.Log; + +// This is where the scenegraph and the rendered objects are initialized and used +public class TestAppRS { + + private static String modelName = "orientation_test.dae"; + private static String TAG = "TestAppRS"; + private static String mFilePath = ""; + + int mWidth; + int mHeight; + + boolean mUseBlur; + + TestAppLoadingScreen mLoadingScreen; + + // Used to asynchronously load scene elements like meshes and transform hierarchies + SceneLoadedCallback mLoadedCallback = new SceneLoadedCallback() { + public void run() { + prepareToRender(mLoadedScene); + } + }; + + // Top level class that initializes all the elements needed to use the scene graph + SceneManager mSceneManager; + + // Used to move the camera around in the 3D world + TouchHandler mTouchHandler; + + private Resources mRes; + private RenderScriptGL mRS; + + // Shaders + private FragmentShader mPaintF; + private FragmentShader mLightsF; + private FragmentShader mAluminumF; + private FragmentShader mPlasticF; + private FragmentShader mDiffuseF; + private FragmentShader mTextureF; + private VertexShader mGenericV; + + Scene mActiveScene; + + // This is a part of the test app, it's used to tests multiple render passes and is toggled + // on and off in the menu, off by default + void toggleBlur() { + mUseBlur = !mUseBlur; + + mActiveScene.clearRenderPasses(); + initRenderPasses(); + mActiveScene.initRenderPassRS(mRS, mSceneManager); + + // This is just a hardcoded object in the scene that gets turned on and off for the demo + // to make things look a bit better. This could be deleted in the cleanup + Renderable plane = (Renderable)mActiveScene.getRenderableByName("pPlaneShape1"); + if (plane != null) { + plane.setVisible(!mUseBlur); + } + } + + public void init(RenderScriptGL rs, Resources res, int width, int height) { + mUseBlur = false; + mRS = rs; + mRes = res; + mWidth = width; + mHeight = height; + + mTouchHandler = new TouchHandler(); + + mSceneManager = SceneManager.getInstance(); + // Initializes all the RS specific scenegraph elements + mSceneManager.initRS(mRS, mRes, mWidth, mHeight); + + mLoadingScreen = new TestAppLoadingScreen(mRS, mRes); + + // Initi renderscript stuff specific to the app. This will need to be abstracted out later. + FullscreenBlur.createRenderTargets(mRS, mWidth, mHeight); + initPaintShaders(); + + // Load a scene to render + mSceneManager.loadModel(mFilePath + modelName, mLoadedCallback); + } + + // When a new model file is selected from the UI, this function gets called to init everything + void loadModel(String path) { + mLoadingScreen.showLoadingScreen(true); + mActiveScene.destroyRS(); + mSceneManager.loadModel(path, mLoadedCallback); + } + + public void onActionDown(float x, float y) { + mTouchHandler.onActionDown(x, y); + } + + public void onActionScale(float scale) { + mTouchHandler.onActionScale(scale); + } + + public void onActionMove(float x, float y) { + mTouchHandler.onActionMove(x, y); + } + + FragmentShader createFromResource(int id, boolean addCubemap, Type constType) { + FragmentShader.Builder fb = new FragmentShader.Builder(mRS); + fb.setShaderConst(constType); + fb.setShader(mRes, id); + fb.addTexture(TextureType.TEXTURE_2D, "diffuse"); + if (addCubemap) { + fb.addShaderTexture(TextureType.TEXTURE_CUBE, "reflection"); + } + FragmentShader pf = fb.create(); + pf.getProgram().bindSampler(Sampler.WRAP_LINEAR_MIP_LINEAR(mRS), 0); + if (addCubemap) { + pf.getProgram().bindSampler(Sampler.CLAMP_LINEAR_MIP_LINEAR(mRS), 1); + } + return pf; + } + + private void initPaintShaders() { + ScriptField_ModelParams objConst = new ScriptField_ModelParams(mRS, 1); + ScriptField_ViewProjParams shaderConst = new ScriptField_ViewProjParams(mRS, 1); + + VertexShader.Builder vb = new VertexShader.Builder(mRS); + vb.addInput(ScriptField_VertexShaderInputs.createElement(mRS)); + vb.setShader(mRes, R.raw.shader2v); + vb.setObjectConst(objConst.getAllocation().getType()); + vb.setShaderConst(shaderConst.getAllocation().getType()); + mGenericV = vb.create(); + + ScriptField_CameraParams fsConst = new ScriptField_CameraParams(mRS, 1); + ScriptField_LightParams fsConst2 = new ScriptField_LightParams(mRS, 1); + + mPaintF = createFromResource(R.raw.paintf, true, fsConst.getAllocation().getType()); + // Assign a reflection map + TextureCube envCube = new TextureCube("sdcard/scenegraph/", "cube_env.png"); + mPaintF.appendSourceParams(new TextureParam("reflection", envCube)); + + mAluminumF = createFromResource(R.raw.metal, true, fsConst.getAllocation().getType()); + TextureCube diffCube = new TextureCube("sdcard/scenegraph/", "cube_spec.png"); + mAluminumF.appendSourceParams(new TextureParam("reflection", diffCube)); + + mPlasticF = createFromResource(R.raw.plastic, false, fsConst.getAllocation().getType()); + mDiffuseF = createFromResource(R.raw.diffuse, false, fsConst.getAllocation().getType()); + mTextureF = createFromResource(R.raw.texture, false, fsConst.getAllocation().getType()); + + FragmentShader.Builder fb = new FragmentShader.Builder(mRS); + fb.setObjectConst(fsConst2.getAllocation().getType()); + fb.setShader(mRes, R.raw.plastic_lights); + mLightsF = fb.create(); + + FullscreenBlur.initShaders(mRes, mRS); + } + + void initRenderPasses() { + ArrayList<RenderableBase> allDraw = mActiveScene.getRenderables(); + int numDraw = allDraw.size(); + + if (mUseBlur) { + FullscreenBlur.addBlurPasses(mActiveScene, mRS, mTouchHandler.getCamera()); + } + + RenderPass mainPass = new RenderPass(); + mainPass.setClearColor(new Float4(1.0f, 1.0f, 1.0f, 1.0f)); + mainPass.setShouldClearColor(true); + mainPass.setClearDepth(1.0f); + mainPass.setShouldClearDepth(true); + mainPass.setCamera(mTouchHandler.getCamera()); + for (int i = 0; i < numDraw; i ++) { + mainPass.appendRenderable((Renderable)allDraw.get(i)); + } + mActiveScene.appendRenderPass(mainPass); + + if (mUseBlur) { + FullscreenBlur.addCompositePass(mActiveScene, mRS, mTouchHandler.getCamera()); + } + } + + private void addShadersToScene() { + mActiveScene.appendShader(mPaintF); + mActiveScene.appendShader(mLightsF); + mActiveScene.appendShader(mAluminumF); + mActiveScene.appendShader(mPlasticF); + mActiveScene.appendShader(mDiffuseF); + mActiveScene.appendShader(mTextureF); + mActiveScene.appendShader(mGenericV); + } + + public void prepareToRender(Scene s) { + mSceneManager.setActiveScene(s); + mActiveScene = s; + mTouchHandler.init(mActiveScene); + addShadersToScene(); + RenderState plastic = new RenderState(mGenericV, mPlasticF, null, null); + RenderState diffuse = new RenderState(mGenericV, mDiffuseF, null, null); + RenderState paint = new RenderState(mGenericV, mPaintF, null, null); + RenderState aluminum = new RenderState(mGenericV, mAluminumF, null, null); + RenderState lights = new RenderState(mGenericV, mLightsF, null, null); + RenderState glassTransp = new RenderState(mGenericV, mPaintF, + ProgramStore.BLEND_ALPHA_DEPTH_TEST(mRS), null); + + initRenderPasses(); + + mActiveScene.assignRenderState(plastic); + + mActiveScene.assignRenderStateToMaterial(diffuse, "lambert2$"); + + mActiveScene.assignRenderStateToMaterial(paint, "^Paint"); + mActiveScene.assignRenderStateToMaterial(paint, "^Carbon"); + mActiveScene.assignRenderStateToMaterial(paint, "^Glass"); + mActiveScene.assignRenderStateToMaterial(paint, "^MainGlass"); + + mActiveScene.assignRenderStateToMaterial(aluminum, "^Metal"); + mActiveScene.assignRenderStateToMaterial(aluminum, "^Brake"); + + mActiveScene.assignRenderStateToMaterial(glassTransp, "^GlassLight"); + + mActiveScene.assignRenderStateToMaterial(lights, "^LightBlinn"); + + Renderable plane = (Renderable)mActiveScene.getRenderableByName("pPlaneShape1"); + if (plane != null) { + RenderState texState = new RenderState(mGenericV, mTextureF, null, null); + plane.setRenderState(texState); + plane.setVisible(!mUseBlur); + } + + long start = System.currentTimeMillis(); + mActiveScene.initRS(); + long end = System.currentTimeMillis(); + Log.v("TIMER", "Scene init time: " + (end - start)); + + mLoadingScreen.showLoadingScreen(false); + } +} diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppView.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppView.java new file mode 100644 index 000000000000..687f35b3ec7d --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppView.java @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.testapp; + +import java.io.Writer; +import java.util.ArrayList; +import java.util.concurrent.Semaphore; + +import android.renderscript.RSSurfaceView; +import android.renderscript.RenderScript; +import android.renderscript.RenderScriptGL; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.os.Handler; +import android.os.Message; +import android.util.AttributeSet; +import android.util.Log; +import android.view.Surface; +import android.view.SurfaceHolder; +import android.view.SurfaceView; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.ScaleGestureDetector; + +public class TestAppView extends RSSurfaceView { + + public TestAppView(Context context) { + super(context); + mScaleDetector = new ScaleGestureDetector(context, new ScaleListener()); + } + + private RenderScriptGL mRS; + TestAppRS mRender; + + private ScaleGestureDetector mScaleDetector; + private static final int INVALID_POINTER_ID = -1; + private int mActivePointerId = INVALID_POINTER_ID; + + public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { + super.surfaceChanged(holder, format, w, h); + if (mRS == null) { + RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig(); + sc.setDepth(16, 24); + mRS = createRenderScriptGL(sc); + mRS.setSurface(holder, w, h); + mRender = new TestAppRS(); + mRender.init(mRS, getResources(), w, h); + } + } + + @Override + protected void onDetachedFromWindow() { + if (mRS != null) { + mRender = null; + mRS = null; + destroyRenderScriptGL(); + } + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) + { + // break point at here + // this method doesn't work when 'extends View' include 'extends ScrollView'. + return super.onKeyDown(keyCode, event); + } + + + @Override + public boolean onTouchEvent(MotionEvent ev) { + mScaleDetector.onTouchEvent(ev); + + boolean ret = false; + float x = ev.getX(); + float y = ev.getY(); + + final int action = ev.getAction(); + + switch (action & MotionEvent.ACTION_MASK) { + case MotionEvent.ACTION_DOWN: { + mRender.onActionDown(x, y); + mActivePointerId = ev.getPointerId(0); + ret = true; + break; + } + case MotionEvent.ACTION_MOVE: { + if (!mScaleDetector.isInProgress()) { + mRender.onActionMove(x, y); + } + mRender.onActionDown(x, y); + ret = true; + break; + } + + case MotionEvent.ACTION_UP: { + mActivePointerId = INVALID_POINTER_ID; + break; + } + + case MotionEvent.ACTION_CANCEL: { + mActivePointerId = INVALID_POINTER_ID; + break; + } + + case MotionEvent.ACTION_POINTER_UP: { + final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) + >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; + final int pointerId = ev.getPointerId(pointerIndex); + if (pointerId == mActivePointerId) { + // This was our active pointer going up. Choose a new + // active pointer and adjust accordingly. + final int newPointerIndex = pointerIndex == 0 ? 1 : 0; + x = ev.getX(newPointerIndex); + y = ev.getY(newPointerIndex); + mRender.onActionDown(x, y); + mActivePointerId = ev.getPointerId(newPointerIndex); + } + break; + } + } + + return ret; + } + + private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { + @Override + public boolean onScale(ScaleGestureDetector detector) { + mRender.onActionScale(detector.getScaleFactor()); + return true; + } + } +} + + diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TouchHandler.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TouchHandler.java new file mode 100644 index 000000000000..d8e48e80161a --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TouchHandler.java @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.testapp; + +import android.util.Log; +import android.renderscript.Float3; +import com.android.scenegraph.*; +import com.android.scenegraph.CompoundTransform.RotateComponent; +import com.android.scenegraph.CompoundTransform.TranslateComponent; + +public class TouchHandler { + private static String TAG = "TouchHandler"; + + float mLastX; + float mLastY; + + float mRotateXValue; + float mRotateYValue; + Float3 mDistValue; + Float3 mPosValue; + + CompoundTransform mCameraRig; + RotateComponent mRotateX; + RotateComponent mRotateY; + TranslateComponent mDist; + TranslateComponent mPosition; + Camera mCamera; + + public void init(Scene scene) { + // Some initial values for camera position + mRotateXValue = -20; + mRotateYValue = 45; + mDistValue = new Float3(0, 0, 45); + mPosValue = new Float3(0, 4, 0); + + mRotateX = new RotateComponent("RotateX", new Float3(1, 0, 0), mRotateXValue); + mRotateY = new RotateComponent("RotateY", new Float3(0, 1, 0), mRotateYValue); + mDist = new TranslateComponent("Distance", mDistValue); + mPosition = new TranslateComponent("Distance", mPosValue); + + // Make a camera transform we can manipulate + mCameraRig = new CompoundTransform(); + mCameraRig.setName("CameraRig"); + mCameraRig.addComponent(mPosition); + mCameraRig.addComponent(mRotateY); + mCameraRig.addComponent(mRotateX); + mCameraRig.addComponent(mDist); + scene.appendTransform(mCameraRig); + mCamera = new Camera(); + mCamera.setTransform(mCameraRig); + scene.appendCamera(mCamera); + } + + public Camera getCamera() { + return mCamera; + } + + public void onActionDown(float x, float y) { + mLastX = x; + mLastY = y; + } + + public void onActionScale(float scale) { + if (mDist == null) { + return; + } + mDistValue.z *= 1.0f / scale; + mDistValue.z = Math.max(10.0f, Math.min(mDistValue.z, 150.0f)); + mDist.setValue(mDistValue); + } + + public void onActionMove(float x, float y) { + if (mRotateX == null) { + return; + } + + float dx = mLastX - x; + float dy = mLastY - y; + + if (Math.abs(dy) <= 2.0f) { + dy = 0.0f; + } + if (Math.abs(dx) <= 2.0f) { + dx = 0.0f; + } + + mRotateYValue += dx * 0.25f; + mRotateYValue %= 360.0f; + + mRotateXValue += dy * 0.25f; + mRotateXValue = Math.max(mRotateXValue , -80.0f); + mRotateXValue = Math.min(mRotateXValue , 0.0f); + + mRotateX.setAngle(mRotateXValue); + mRotateY.setAngle(mRotateYValue); + + mLastX = x; + mLastY = y; + } +} diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rs new file mode 100644 index 000000000000..997a1a748628 --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rs @@ -0,0 +1,86 @@ +// Copyright (C) 2011 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma version(1) + +#pragma rs java_package_name(com.android.testapp) + +#include "rs_graphics.rsh" +#include "test_app.rsh" + +// Making sure these get reflected +FBlurOffsets *blurExport; +VShaderInputs *iExport; +FShaderParams *fConst; +FShaderLightParams *fConts2; +VSParams *vConst2; +VObjectParams *vConst3; + +rs_program_vertex gPVBackground; +rs_program_fragment gPFBackground; + +rs_allocation gRobotTex; +rs_mesh gRobotMesh; + +rs_program_store gPFSBackground; + +float gRotate; + +void init() { + gRotate = 0.0f; +} + +static int pos = 50; +static float gRotateY = 120.0f; +static float3 gLookAt = 0; +static float gZoom = 50.0f; +static void displayLoading() { + if (rsIsObject(gRobotTex) && rsIsObject(gRobotMesh)) { + rsgBindProgramVertex(gPVBackground); + rs_matrix4x4 proj; + float aspect = (float)rsgGetWidth() / (float)rsgGetHeight(); + rsMatrixLoadPerspective(&proj, 30.0f, aspect, 1.0f, 100.0f); + rsgProgramVertexLoadProjectionMatrix(&proj); + + rsgBindProgramFragment(gPFBackground); + rsgBindProgramStore(gPFSBackground); + rsgBindTexture(gPFBackground, 0, gRobotTex); + + rs_matrix4x4 matrix; + rsMatrixLoadIdentity(&matrix); + // Position our models on the screen + gRotateY += rsGetDt()*100; + rsMatrixTranslate(&matrix, 0, 0, -gZoom); + rsMatrixRotate(&matrix, 20.0f, 1.0f, 0.0f, 0.0f); + rsMatrixRotate(&matrix, gRotateY, 0.0f, 1.0f, 0.0f); + rsMatrixScale(&matrix, 0.2f, 0.2f, 0.2f); + rsgProgramVertexLoadModelMatrix(&matrix); + rsgDrawMesh(gRobotMesh); + } + + uint width = rsgGetWidth(); + uint height = rsgGetHeight(); + int left = 0, right = 0, top = 0, bottom = 0; + const char* text = "Initializing..."; + rsgMeasureText(text, &left, &right, &top, &bottom); + int centeredPos = width / 2 - (right - left) / 2; + rsgDrawText(text, centeredPos, height / 2 + height / 10); +} + +int root(void) { + rsgClearColor(1.0f, 1.0f, 1.0f, 1.0f); + rsgClearDepth(1.0f); + displayLoading(); + return 30; +} diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rsh b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rsh new file mode 100644 index 000000000000..5fbcbb2ebb69 --- /dev/null +++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rsh @@ -0,0 +1,52 @@ +// Copyright (C) 2012 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma version(1) + +#pragma rs java_package_name(com.android.testapp) + +// Helpers +typedef struct ViewProjParams { + rs_matrix4x4 viewProj; +} VSParams; + +typedef struct ModelParams { + rs_matrix4x4 model; +} VObjectParams; + +typedef struct CameraParams { + float4 cameraPos; +} FShaderParams; + +typedef struct LightParams { + float4 lightPos_0; + float4 lightColor_0; + float4 lightPos_1; + float4 lightColor_1; + float4 cameraPos; + float4 diffuse; +} FShaderLightParams; + +typedef struct BlurOffsets { + float blurOffset0; + float blurOffset1; + float blurOffset2; + float blurOffset3; +} FBlurOffsets; + +typedef struct VertexShaderInputs { + float4 position; + float3 normal; + float2 texture0; +} VShaderInputs; diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java index eaada5ff6968..c7bd80994603 100644 --- a/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java +++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java @@ -64,6 +64,11 @@ public class RSTestCore { unitTests = new ArrayList<UnitTest>(); + unitTests.add(new UT_mesh(this, mRes, mCtx)); + unitTests.add(new UT_element(this, mRes, mCtx)); + unitTests.add(new UT_sampler(this, mRes, mCtx)); + unitTests.add(new UT_program_store(this, mRes, mCtx)); + unitTests.add(new UT_program_raster(this, mRes, mCtx)); unitTests.add(new UT_primitives(this, mRes, mCtx)); unitTests.add(new UT_constant(this, mRes, mCtx)); unitTests.add(new UT_vector(this, mRes, mCtx)); diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_element.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_element.java new file mode 100644 index 000000000000..3e2a2ca2195e --- /dev/null +++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_element.java @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.rs.test; + +import android.content.Context; +import android.content.res.Resources; +import android.renderscript.*; +import android.renderscript.Element.*; +import android.renderscript.Element.DataKind.*; +import android.renderscript.Element.DataType.*; + +public class UT_element extends UnitTest { + private Resources mRes; + + Element simpleElem; + Element complexElem; + + final String subElemNames[] = { + "subElem0", + "subElem1", + "subElem2", + "arrayElem0", + "arrayElem1", + "subElem3", + "subElem4", + "subElem5", + "subElem6", + "subElem_7", + }; + + final int subElemArraySizes[] = { + 1, + 1, + 1, + 2, + 5, + 1, + 1, + 1, + 1, + 1, + }; + + final int subElemOffsets[] = { + 0, + 4, + 8, + 12, + 20, + 40, + 44, + 48, + 64, + 80, + }; + + protected UT_element(RSTestCore rstc, Resources res, Context ctx) { + super(rstc, "Element", ctx); + mRes = res; + } + + private void initializeGlobals(RenderScript RS, ScriptC_element s) { + simpleElem = Element.F32_3(RS); + complexElem = ScriptField_ComplexStruct.createElement(RS); + s.set_simpleElem(simpleElem); + s.set_complexElem(complexElem); + + ScriptField_ComplexStruct data = new ScriptField_ComplexStruct(RS, 1); + s.bind_complexStruct(data); + } + + private void testScriptSide(RenderScript pRS) { + ScriptC_element s = new ScriptC_element(pRS, mRes, R.raw.element); + pRS.setMessageHandler(mRsMessage); + initializeGlobals(pRS, s); + s.invoke_element_test(); + pRS.finish(); + waitForMessage(); + } + + private void testJavaSide(RenderScript RS) { + + int subElemCount = simpleElem.getSubElementCount(); + _RS_ASSERT("subElemCount == 0", subElemCount == 0); + _RS_ASSERT("simpleElem.getDataKind() == USER", + simpleElem.getDataKind() == DataKind.USER); + _RS_ASSERT("simpleElem.getDataType() == FLOAT_32", + simpleElem.getDataType() == DataType.FLOAT_32); + + subElemCount = complexElem.getSubElementCount(); + _RS_ASSERT("subElemCount == 10", subElemCount == 10); + _RS_ASSERT("complexElem.getDataKind() == USER", + complexElem.getDataKind() == DataKind.USER); + _RS_ASSERT("complexElemsimpleElem.getDataType() == NONE", + complexElem.getDataType() == DataType.NONE); + _RS_ASSERT("complexElem.getSizeBytes() == ScriptField_ComplexStruct.Item.sizeof", + complexElem.getSizeBytes() == ScriptField_ComplexStruct.Item.sizeof); + + for (int i = 0; i < subElemCount; i ++) { + _RS_ASSERT("complexElem.getSubElement(i) != null", + complexElem.getSubElement(i) != null); + _RS_ASSERT("complexElem.getSubElementName(i).equals(subElemNames[i])", + complexElem.getSubElementName(i).equals(subElemNames[i])); + _RS_ASSERT("complexElem.getSubElementArraySize(i) == subElemArraySizes[i]", + complexElem.getSubElementArraySize(i) == subElemArraySizes[i]); + _RS_ASSERT("complexElem.getSubElementOffsetBytes(i) == subElemOffsets[i]", + complexElem.getSubElementOffsetBytes(i) == subElemOffsets[i]); + } + } + + public void run() { + RenderScript pRS = RenderScript.create(mCtx); + testScriptSide(pRS); + testJavaSide(pRS); + passTest(); + pRS.destroy(); + } +} diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_mesh.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_mesh.java new file mode 100644 index 000000000000..0c93702e0b07 --- /dev/null +++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_mesh.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.rs.test; + +import android.content.Context; +import android.content.res.Resources; +import android.renderscript.*; +import android.renderscript.Mesh.*; + +public class UT_mesh extends UnitTest { + private Resources mRes; + + Mesh mesh; + + protected UT_mesh(RSTestCore rstc, Resources res, Context ctx) { + super(rstc, "Mesh", ctx); + mRes = res; + } + + private void initializeGlobals(RenderScript RS, ScriptC_mesh s) { + Allocation vAlloc0 = Allocation.createSized(RS, Element.F32(RS), 10); + Allocation vAlloc1 = Allocation.createSized(RS, Element.F32_2(RS), 10); + + Allocation iAlloc0 = Allocation.createSized(RS, Element.I16(RS), 10); + Allocation iAlloc2 = Allocation.createSized(RS, Element.I16(RS), 10); + + Mesh.AllocationBuilder mBuilder = new Mesh.AllocationBuilder(RS); + mBuilder.addVertexAllocation(vAlloc0); + mBuilder.addVertexAllocation(vAlloc1); + + mBuilder.addIndexSetAllocation(iAlloc0, Primitive.POINT); + mBuilder.addIndexSetType(Primitive.LINE); + mBuilder.addIndexSetAllocation(iAlloc2, Primitive.TRIANGLE); + + s.set_mesh(mBuilder.create()); + s.set_vertexAlloc0(vAlloc0); + s.set_vertexAlloc1(vAlloc1); + s.set_indexAlloc0(iAlloc0); + s.set_indexAlloc2(iAlloc2); + } + + private void testScriptSide(RenderScript pRS) { + ScriptC_mesh s = new ScriptC_mesh(pRS, mRes, R.raw.mesh); + pRS.setMessageHandler(mRsMessage); + initializeGlobals(pRS, s); + s.invoke_mesh_test(); + pRS.finish(); + waitForMessage(); + } + + private void testJavaSide(RenderScript RS) { + } + + public void run() { + RenderScript pRS = RenderScript.create(mCtx); + testScriptSide(pRS); + testJavaSide(pRS); + passTest(); + pRS.destroy(); + } +} diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_raster.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_raster.java new file mode 100644 index 000000000000..1de4d717f582 --- /dev/null +++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_raster.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.rs.test; + +import android.content.Context; +import android.content.res.Resources; +import android.renderscript.*; +import android.renderscript.ProgramRaster; +import android.renderscript.ProgramRaster.CullMode; + +public class UT_program_raster extends UnitTest { + private Resources mRes; + + ProgramRaster pointSpriteEnabled; + ProgramRaster cullMode; + + protected UT_program_raster(RSTestCore rstc, Resources res, Context ctx) { + super(rstc, "ProgramRaster", ctx); + mRes = res; + } + + private ProgramRaster.Builder getDefaultBuilder(RenderScript RS) { + ProgramRaster.Builder b = new ProgramRaster.Builder(RS); + b.setCullMode(CullMode.BACK); + b.setPointSpriteEnabled(false); + return b; + } + + private void initializeGlobals(RenderScript RS, ScriptC_program_raster s) { + ProgramRaster.Builder b = getDefaultBuilder(RS); + pointSpriteEnabled = b.setPointSpriteEnabled(true).create(); + b = getDefaultBuilder(RS); + cullMode = b.setCullMode(CullMode.FRONT).create(); + + s.set_pointSpriteEnabled(pointSpriteEnabled); + s.set_cullMode(cullMode); + } + + private void testScriptSide(RenderScript pRS) { + ScriptC_program_raster s = new ScriptC_program_raster(pRS, mRes, R.raw.program_raster); + pRS.setMessageHandler(mRsMessage); + initializeGlobals(pRS, s); + s.invoke_program_raster_test(); + pRS.finish(); + waitForMessage(); + } + + private void testJavaSide(RenderScript RS) { + _RS_ASSERT("pointSpriteEnabled.getPointSpriteEnabled() == true", + pointSpriteEnabled.getPointSpriteEnabled() == true); + _RS_ASSERT("pointSpriteEnabled.getCullMode() == ProgramRaster.CullMode.BACK", + pointSpriteEnabled.getCullMode() == ProgramRaster.CullMode.BACK); + + _RS_ASSERT("cullMode.getPointSpriteEnabled() == false", + cullMode.getPointSpriteEnabled() == false); + _RS_ASSERT("cullMode.getCullMode() == ProgramRaster.CullMode.FRONT", + cullMode.getCullMode() == ProgramRaster.CullMode.FRONT); + } + + public void run() { + RenderScript pRS = RenderScript.create(mCtx); + testScriptSide(pRS); + testJavaSide(pRS); + passTest(); + pRS.destroy(); + } +} diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_store.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_store.java new file mode 100644 index 000000000000..72a401dfd249 --- /dev/null +++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_store.java @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.rs.test; + +import android.content.Context; +import android.content.res.Resources; +import android.renderscript.*; +import android.renderscript.ProgramStore.BlendDstFunc; +import android.renderscript.ProgramStore.BlendSrcFunc; +import android.renderscript.ProgramStore.Builder; +import android.renderscript.ProgramStore.DepthFunc; + +public class UT_program_store extends UnitTest { + private Resources mRes; + + ProgramStore ditherEnable; + ProgramStore colorRWriteEnable; + ProgramStore colorGWriteEnable; + ProgramStore colorBWriteEnable; + ProgramStore colorAWriteEnable; + ProgramStore blendSrc; + ProgramStore blendDst; + ProgramStore depthWriteEnable; + ProgramStore depthFunc; + + protected UT_program_store(RSTestCore rstc, Resources res, Context ctx) { + super(rstc, "ProgramStore", ctx); + mRes = res; + } + + private ProgramStore.Builder getDefaultBuilder(RenderScript RS) { + ProgramStore.Builder b = new ProgramStore.Builder(RS); + b.setBlendFunc(ProgramStore.BlendSrcFunc.ZERO, ProgramStore.BlendDstFunc.ZERO); + b.setColorMaskEnabled(false, false, false, false); + b.setDepthFunc(ProgramStore.DepthFunc.ALWAYS); + b.setDepthMaskEnabled(false); + b.setDitherEnabled(false); + return b; + } + + private void initializeGlobals(RenderScript RS, ScriptC_program_store s) { + ProgramStore.Builder b = getDefaultBuilder(RS); + ditherEnable = b.setDitherEnabled(true).create(); + + b = getDefaultBuilder(RS); + colorRWriteEnable = b.setColorMaskEnabled(true, false, false, false).create(); + + b = getDefaultBuilder(RS); + colorGWriteEnable = b.setColorMaskEnabled(false, true, false, false).create(); + + b = getDefaultBuilder(RS); + colorBWriteEnable = b.setColorMaskEnabled(false, false, true, false).create(); + + b = getDefaultBuilder(RS); + colorAWriteEnable = b.setColorMaskEnabled(false, false, false, true).create(); + + b = getDefaultBuilder(RS); + blendSrc = b.setBlendFunc(ProgramStore.BlendSrcFunc.DST_COLOR, + ProgramStore.BlendDstFunc.ZERO).create(); + + b = getDefaultBuilder(RS); + blendDst = b.setBlendFunc(ProgramStore.BlendSrcFunc.ZERO, + ProgramStore.BlendDstFunc.DST_ALPHA).create(); + + b = getDefaultBuilder(RS); + depthWriteEnable = b.setDepthMaskEnabled(true).create(); + + b = getDefaultBuilder(RS); + depthFunc = b.setDepthFunc(ProgramStore.DepthFunc.GREATER).create(); + + s.set_ditherEnable(ditherEnable); + s.set_colorRWriteEnable(colorRWriteEnable); + s.set_colorGWriteEnable(colorGWriteEnable); + s.set_colorBWriteEnable(colorBWriteEnable); + s.set_colorAWriteEnable(colorAWriteEnable); + s.set_blendSrc(blendSrc); + s.set_blendDst(blendDst); + s.set_depthWriteEnable(depthWriteEnable); + s.set_depthFunc(depthFunc); + } + + private void testScriptSide(RenderScript pRS) { + ScriptC_program_store s = new ScriptC_program_store(pRS, mRes, R.raw.program_store); + pRS.setMessageHandler(mRsMessage); + initializeGlobals(pRS, s); + s.invoke_program_store_test(); + pRS.finish(); + waitForMessage(); + } + + void checkObject(ProgramStore ps, + boolean depthMask, + DepthFunc df, + BlendSrcFunc bsf, + BlendDstFunc bdf, + boolean R, + boolean G, + boolean B, + boolean A, + boolean dither) { + _RS_ASSERT("ps.getDepthMaskEnabled() == depthMask", ps.getDepthMaskEnabled() == depthMask); + _RS_ASSERT("ps.getDepthFunc() == df", ps.getDepthFunc() == df); + _RS_ASSERT("ps.getBlendSrcFunc() == bsf", ps.getBlendSrcFunc() == bsf); + _RS_ASSERT("ps.getBlendDstFunc() == bdf", ps.getBlendDstFunc() == bdf); + _RS_ASSERT("ps.getColorMaskREnabled() == R", ps.getColorMaskREnabled() == R); + _RS_ASSERT("ps.getColorMaskGEnabled() == G", ps.getColorMaskGEnabled() == G); + _RS_ASSERT("ps.getColorMaskBEnabled() == B", ps.getColorMaskBEnabled() == B); + _RS_ASSERT("ps.getColorMaskAEnabled() == A", ps.getColorMaskAEnabled() == A); + _RS_ASSERT("ps.getDitherEnabled() == dither", ps.getDitherEnabled() == dither); + } + + void varyBuilderColorAndDither(ProgramStore.Builder pb, + boolean depthMask, + DepthFunc df, + BlendSrcFunc bsf, + BlendDstFunc bdf) { + for (int r = 0; r <= 1; r++) { + boolean isR = (r == 1); + for (int g = 0; g <= 1; g++) { + boolean isG = (g == 1); + for (int b = 0; b <= 1; b++) { + boolean isB = (b == 1); + for (int a = 0; a <= 1; a++) { + boolean isA = (a == 1); + for (int dither = 0; dither <= 1; dither++) { + boolean isDither = (dither == 1); + pb.setDitherEnabled(isDither); + pb.setColorMaskEnabled(isR, isG, isB, isA); + ProgramStore ps = pb.create(); + checkObject(ps, depthMask, df, bsf, bdf, isR, isG, isB, isA, isDither); + } + } + } + } + } + } + + public void testJavaSide(RenderScript RS) { + for (int depth = 0; depth <= 1; depth++) { + boolean depthMask = (depth == 1); + for (DepthFunc df : DepthFunc.values()) { + for (BlendSrcFunc bsf : BlendSrcFunc.values()) { + for (BlendDstFunc bdf : BlendDstFunc.values()) { + ProgramStore.Builder b = new ProgramStore.Builder(RS); + b.setDepthFunc(df); + b.setDepthMaskEnabled(depthMask); + b.setBlendFunc(bsf, bdf); + varyBuilderColorAndDither(b, depthMask, df, bsf, bdf); + } + } + } + } + } + + public void run() { + RenderScript pRS = RenderScript.create(mCtx); + testJavaSide(pRS); + testScriptSide(pRS); + pRS.destroy(); + } +} diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_sampler.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_sampler.java new file mode 100644 index 000000000000..c328cf6a392b --- /dev/null +++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_sampler.java @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.rs.test; + +import android.content.Context; +import android.content.res.Resources; +import android.renderscript.*; +import android.renderscript.Sampler; +import android.renderscript.Sampler.Value; + +public class UT_sampler extends UnitTest { + private Resources mRes; + + Sampler minification; + Sampler magnification; + Sampler wrapS; + Sampler wrapT; + Sampler anisotropy; + + protected UT_sampler(RSTestCore rstc, Resources res, Context ctx) { + super(rstc, "Sampler", ctx); + mRes = res; + } + + private Sampler.Builder getDefaultBuilder(RenderScript RS) { + Sampler.Builder b = new Sampler.Builder(RS); + b.setMinification(Value.NEAREST); + b.setMagnification(Value.NEAREST); + b.setWrapS(Value.CLAMP); + b.setWrapT(Value.CLAMP); + b.setAnisotropy(1.0f); + return b; + } + + private void initializeGlobals(RenderScript RS, ScriptC_sampler s) { + Sampler.Builder b = getDefaultBuilder(RS); + b.setMinification(Value.LINEAR_MIP_LINEAR); + minification = b.create(); + + b = getDefaultBuilder(RS); + b.setMagnification(Value.LINEAR); + magnification = b.create(); + + b = getDefaultBuilder(RS); + b.setWrapS(Value.WRAP); + wrapS = b.create(); + + b = getDefaultBuilder(RS); + b.setWrapT(Value.WRAP); + wrapT = b.create(); + + b = getDefaultBuilder(RS); + b.setAnisotropy(8.0f); + anisotropy = b.create(); + + s.set_minification(minification); + s.set_magnification(magnification); + s.set_wrapS(wrapS); + s.set_wrapT(wrapT); + s.set_anisotropy(anisotropy); + } + + private void testScriptSide(RenderScript pRS) { + ScriptC_sampler s = new ScriptC_sampler(pRS, mRes, R.raw.sampler); + pRS.setMessageHandler(mRsMessage); + initializeGlobals(pRS, s); + s.invoke_sampler_test(); + pRS.finish(); + waitForMessage(); + } + + private void testJavaSide(RenderScript RS) { + _RS_ASSERT("minification.getMagnification() == Sampler.Value.NEAREST", + minification.getMagnification() == Sampler.Value.NEAREST); + _RS_ASSERT("minification.getMinification() == Sampler.Value.LINEAR_MIP_LINEAR", + minification.getMinification() == Sampler.Value.LINEAR_MIP_LINEAR); + _RS_ASSERT("minification.getWrapS() == Sampler.Value.CLAMP", + minification.getWrapS() == Sampler.Value.CLAMP); + _RS_ASSERT("minification.getWrapT() == Sampler.Value.CLAMP", + minification.getWrapT() == Sampler.Value.CLAMP); + _RS_ASSERT("minification.getAnisotropy() == 1.0f", + minification.getAnisotropy() == 1.0f); + + _RS_ASSERT("magnification.getMagnification() == Sampler.Value.LINEAR", + magnification.getMagnification() == Sampler.Value.LINEAR); + _RS_ASSERT("magnification.getMinification() == Sampler.Value.NEAREST", + magnification.getMinification() == Sampler.Value.NEAREST); + _RS_ASSERT("magnification.getWrapS() == Sampler.Value.CLAMP", + magnification.getWrapS() == Sampler.Value.CLAMP); + _RS_ASSERT("magnification.getWrapT() == Sampler.Value.CLAMP", + magnification.getWrapT() == Sampler.Value.CLAMP); + _RS_ASSERT("magnification.getAnisotropy() == 1.0f", + magnification.getAnisotropy() == 1.0f); + + _RS_ASSERT("wrapS.getMagnification() == Sampler.Value.NEAREST", + wrapS.getMagnification() == Sampler.Value.NEAREST); + _RS_ASSERT("wrapS.getMinification() == Sampler.Value.NEAREST", + wrapS.getMinification() == Sampler.Value.NEAREST); + _RS_ASSERT("wrapS.getWrapS() == Sampler.Value.WRAP", + wrapS.getWrapS() == Sampler.Value.WRAP); + _RS_ASSERT("wrapS.getWrapT() == Sampler.Value.CLAMP", + wrapS.getWrapT() == Sampler.Value.CLAMP); + _RS_ASSERT("wrapS.getAnisotropy() == 1.0f", + wrapS.getAnisotropy() == 1.0f); + + _RS_ASSERT("wrapT.getMagnification() == Sampler.Value.NEAREST", + wrapT.getMagnification() == Sampler.Value.NEAREST); + _RS_ASSERT("wrapT.getMinification() == Sampler.Value.NEAREST", + wrapT.getMinification() == Sampler.Value.NEAREST); + _RS_ASSERT("wrapT.getWrapS() == Sampler.Value.CLAMP", + wrapT.getWrapS() == Sampler.Value.CLAMP); + _RS_ASSERT("wrapT.getWrapT() == Sampler.Value.WRAP", + wrapT.getWrapT() == Sampler.Value.WRAP); + _RS_ASSERT("wrapT.getAnisotropy() == 1.0f", + wrapT.getAnisotropy() == 1.0f); + + _RS_ASSERT("anisotropy.getMagnification() == Sampler.Value.NEAREST", + anisotropy.getMagnification() == Sampler.Value.NEAREST); + _RS_ASSERT("anisotropy.getMinification() == Sampler.Value.NEAREST", + anisotropy.getMinification() == Sampler.Value.NEAREST); + _RS_ASSERT("anisotropy.getWrapS() == Sampler.Value.CLAMP", + anisotropy.getWrapS() == Sampler.Value.CLAMP); + _RS_ASSERT("anisotropy.getWrapT() == Sampler.Value.CLAMP", + anisotropy.getWrapT() == Sampler.Value.CLAMP); + _RS_ASSERT("anisotropy.getAnisotropy() == 1.0f", + anisotropy.getAnisotropy() == 8.0f); + } + + public void run() { + RenderScript pRS = RenderScript.create(mCtx); + testScriptSide(pRS); + testJavaSide(pRS); + passTest(); + pRS.destroy(); + } +} diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UnitTest.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UnitTest.java index edff83f2756b..fbac124b896b 100644 --- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UnitTest.java +++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UnitTest.java @@ -58,8 +58,8 @@ public class UnitTest extends Thread { protected void _RS_ASSERT(String message, boolean b) { if(b == false) { - result = -1; Log.e(name, message + " FAILED"); + failTest(); } } diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/element.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/element.rs new file mode 100644 index 000000000000..0c42d84e1481 --- /dev/null +++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/element.rs @@ -0,0 +1,158 @@ +#include "shared.rsh" +#include "rs_graphics.rsh" + +rs_element simpleElem; +rs_element complexElem; +typedef struct ComplexStruct { + float subElem0; + float subElem1; + int subElem2; + float arrayElem0[2]; + int arrayElem1[5]; + char subElem3; + float subElem4; + float2 subElem5; + float3 subElem6; + float4 subElem_7; +} ComplexStruct_t; + +ComplexStruct_t *complexStruct; + +static const char *subElemNames[] = { + "subElem0", + "subElem1", + "subElem2", + "arrayElem0", + "arrayElem1", + "subElem3", + "subElem4", + "subElem5", + "subElem6", + "subElem_7", +}; + +static uint32_t subElemNamesSizes[] = { + 8, + 8, + 8, + 10, + 10, + 8, + 8, + 8, + 8, + 9, +}; + +static uint32_t subElemArraySizes[] = { + 1, + 1, + 1, + 2, + 5, + 1, + 1, + 1, + 1, + 1, +}; + +static void resetStruct() { + uint8_t *bytePtr = (uint8_t*)complexStruct; + uint32_t sizeOfStruct = sizeof(*complexStruct); + for(uint32_t i = 0; i < sizeOfStruct; i ++) { + bytePtr[i] = 0; + } +} + +static bool equals(const char *name0, const char * name1, uint32_t len) { + for (uint32_t i = 0; i < len; i ++) { + if (name0[i] != name1[i]) { + return false; + } + } + return true; +} + +static bool test_element_getters() { + bool failed = false; + + uint32_t subElemOffsets[10]; + uint32_t index = 0; + subElemOffsets[index++] = (uint32_t)&complexStruct->subElem0 - (uint32_t)complexStruct; + subElemOffsets[index++] = (uint32_t)&complexStruct->subElem1 - (uint32_t)complexStruct; + subElemOffsets[index++] = (uint32_t)&complexStruct->subElem2 - (uint32_t)complexStruct; + subElemOffsets[index++] = (uint32_t)&complexStruct->arrayElem0 - (uint32_t)complexStruct; + subElemOffsets[index++] = (uint32_t)&complexStruct->arrayElem1 - (uint32_t)complexStruct; + subElemOffsets[index++] = (uint32_t)&complexStruct->subElem3 - (uint32_t)complexStruct; + subElemOffsets[index++] = (uint32_t)&complexStruct->subElem4 - (uint32_t)complexStruct; + subElemOffsets[index++] = (uint32_t)&complexStruct->subElem5 - (uint32_t)complexStruct; + subElemOffsets[index++] = (uint32_t)&complexStruct->subElem6 - (uint32_t)complexStruct; + subElemOffsets[index++] = (uint32_t)&complexStruct->subElem_7 - (uint32_t)complexStruct; + + uint32_t subElemCount = rsElementGetSubElementCount(simpleElem); + _RS_ASSERT(subElemCount == 0); + _RS_ASSERT(rsElementGetDataKind(simpleElem) == RS_KIND_USER); + _RS_ASSERT(rsElementGetDataType(simpleElem) == RS_TYPE_FLOAT_32); + _RS_ASSERT(rsElementGetVectorSize(simpleElem) == 3); + + subElemCount = rsElementGetSubElementCount(complexElem); + _RS_ASSERT(subElemCount == 10); + _RS_ASSERT(rsElementGetDataKind(complexElem) == RS_KIND_USER); + _RS_ASSERT(rsElementGetDataType(complexElem) == RS_TYPE_NONE); + _RS_ASSERT(rsElementGetVectorSize(complexElem) == 1); + _RS_ASSERT(rsElementGetSizeBytes(complexElem) == sizeof(*complexStruct)); + + char buffer[64]; + for (uint32_t i = 0; i < subElemCount; i ++) { + rs_element subElem = rsElementGetSubElement(complexElem, i); + _RS_ASSERT(rsIsObject(subElem)); + + _RS_ASSERT(rsElementGetSubElementNameLength(complexElem, i) == subElemNamesSizes[i] + 1); + + uint32_t written = rsElementGetSubElementName(complexElem, i, buffer, 64); + _RS_ASSERT(written == subElemNamesSizes[i]); + _RS_ASSERT(equals(buffer, subElemNames[i], written)); + + _RS_ASSERT(rsElementGetSubElementArraySize(complexElem, i) == subElemArraySizes[i]); + _RS_ASSERT(rsElementGetSubElementOffsetBytes(complexElem, i) == subElemOffsets[i]); + } + + // Tests error checking + rs_element subElem = rsElementGetSubElement(complexElem, subElemCount); + _RS_ASSERT(!rsIsObject(subElem)); + + _RS_ASSERT(rsElementGetSubElementNameLength(complexElem, subElemCount) == 0); + + _RS_ASSERT(rsElementGetSubElementName(complexElem, subElemCount, buffer, 64) == 0); + _RS_ASSERT(rsElementGetSubElementName(complexElem, 0, NULL, 64) == 0); + _RS_ASSERT(rsElementGetSubElementName(complexElem, 0, buffer, 0) == 0); + uint32_t written = rsElementGetSubElementName(complexElem, 0, buffer, 5); + _RS_ASSERT(written == 4); + _RS_ASSERT(buffer[4] == '\0'); + + _RS_ASSERT(rsElementGetSubElementArraySize(complexElem, subElemCount) == 0); + _RS_ASSERT(rsElementGetSubElementOffsetBytes(complexElem, subElemCount) == 0); + + if (failed) { + rsDebug("test_element_getters FAILED", 0); + } + else { + rsDebug("test_element_getters PASSED", 0); + } + + return failed; +} + +void element_test() { + bool failed = false; + failed |= test_element_getters(); + + if (failed) { + rsSendToClientBlocking(RS_MSG_TEST_FAILED); + } + else { + rsSendToClientBlocking(RS_MSG_TEST_PASSED); + } +} + diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/mesh.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/mesh.rs new file mode 100644 index 000000000000..627ab9923c72 --- /dev/null +++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/mesh.rs @@ -0,0 +1,64 @@ +#include "shared.rsh" +#include "rs_graphics.rsh" + +rs_mesh mesh; +rs_allocation vertexAlloc0; +rs_allocation vertexAlloc1; + +rs_allocation indexAlloc0; +rs_allocation indexAlloc2; + +static bool test_mesh_getters() { + bool failed = false; + + _RS_ASSERT(rsMeshGetVertexAllocationCount(mesh) == 2); + _RS_ASSERT(rsMeshGetPrimitiveCount(mesh) == 3); + + rs_allocation meshV0 = rsMeshGetVertexAllocation(mesh, 0); + rs_allocation meshV1 = rsMeshGetVertexAllocation(mesh, 1); + rs_allocation meshV2 = rsMeshGetVertexAllocation(mesh, 2); + _RS_ASSERT(meshV0.p == vertexAlloc0.p); + _RS_ASSERT(meshV1.p == vertexAlloc1.p); + _RS_ASSERT(!rsIsObject(meshV2)); + + rs_allocation meshI0 = rsMeshGetIndexAllocation(mesh, 0); + rs_allocation meshI1 = rsMeshGetIndexAllocation(mesh, 1); + rs_allocation meshI2 = rsMeshGetIndexAllocation(mesh, 2); + rs_allocation meshI3 = rsMeshGetIndexAllocation(mesh, 3); + _RS_ASSERT(meshI0.p == indexAlloc0.p); + _RS_ASSERT(!rsIsObject(meshI1)); + _RS_ASSERT(meshI2.p == indexAlloc2.p); + _RS_ASSERT(!rsIsObject(meshI3)); + + rs_primitive p0 = rsMeshGetPrimitive(mesh, 0); + rs_primitive p1 = rsMeshGetPrimitive(mesh, 1); + rs_primitive p2 = rsMeshGetPrimitive(mesh, 2); + rs_primitive p3 = rsMeshGetPrimitive(mesh, 3); + + _RS_ASSERT(p0 == RS_PRIMITIVE_POINT); + _RS_ASSERT(p1 == RS_PRIMITIVE_LINE); + _RS_ASSERT(p2 == RS_PRIMITIVE_TRIANGLE); + _RS_ASSERT(p3 == RS_PRIMITIVE_INVALID); + + if (failed) { + rsDebug("test_mesh_getters FAILED", 0); + } + else { + rsDebug("test_mesh_getters PASSED", 0); + } + + return failed; +} + +void mesh_test() { + bool failed = false; + failed |= test_mesh_getters(); + + if (failed) { + rsSendToClientBlocking(RS_MSG_TEST_FAILED); + } + else { + rsSendToClientBlocking(RS_MSG_TEST_PASSED); + } +} + diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/program_raster.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/program_raster.rs new file mode 100644 index 000000000000..11b8c3060cd4 --- /dev/null +++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/program_raster.rs @@ -0,0 +1,37 @@ +#include "shared.rsh" +#include "rs_graphics.rsh" + +rs_program_raster pointSpriteEnabled; +rs_program_raster cullMode; + +static bool test_program_raster_getters() { + bool failed = false; + + _RS_ASSERT(rsgProgramRasterGetPointSpriteEnabled(pointSpriteEnabled) == true); + _RS_ASSERT(rsgProgramRasterGetCullMode(pointSpriteEnabled) == RS_CULL_BACK); + + _RS_ASSERT(rsgProgramRasterGetPointSpriteEnabled(cullMode) == false); + _RS_ASSERT(rsgProgramRasterGetCullMode(cullMode) == RS_CULL_FRONT); + + if (failed) { + rsDebug("test_program_raster_getters FAILED", 0); + } + else { + rsDebug("test_program_raster_getters PASSED", 0); + } + + return failed; +} + +void program_raster_test() { + bool failed = false; + failed |= test_program_raster_getters(); + + if (failed) { + rsSendToClientBlocking(RS_MSG_TEST_FAILED); + } + else { + rsSendToClientBlocking(RS_MSG_TEST_PASSED); + } +} + diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/program_store.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/program_store.rs new file mode 100644 index 000000000000..3cd8a208ca66 --- /dev/null +++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/program_store.rs @@ -0,0 +1,128 @@ +#include "shared.rsh" +#include "rs_graphics.rsh" + +rs_program_store ditherEnable; +rs_program_store colorRWriteEnable; +rs_program_store colorGWriteEnable; +rs_program_store colorBWriteEnable; +rs_program_store colorAWriteEnable; +rs_program_store blendSrc; +rs_program_store blendDst; +rs_program_store depthWriteEnable; +rs_program_store depthFunc; + +static bool test_program_store_getters() { + bool failed = false; + + _RS_ASSERT(rsgProgramStoreGetDepthFunc(depthFunc) == RS_DEPTH_FUNC_GREATER); + _RS_ASSERT(rsgProgramStoreGetDepthMask(depthFunc) == false); + _RS_ASSERT(rsgProgramStoreGetColorMaskR(depthFunc) == false); + _RS_ASSERT(rsgProgramStoreGetColorMaskG(depthFunc) == false); + _RS_ASSERT(rsgProgramStoreGetColorMaskB(depthFunc) == false); + _RS_ASSERT(rsgProgramStoreGetColorMaskA(depthFunc) == false); + _RS_ASSERT(rsgProgramStoreGetDitherEnabled(depthFunc) == false); + _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(depthFunc) == RS_BLEND_SRC_ZERO); + _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(depthFunc) == RS_BLEND_DST_ZERO); + + _RS_ASSERT(rsgProgramStoreGetDepthFunc(depthWriteEnable) == RS_DEPTH_FUNC_ALWAYS); + _RS_ASSERT(rsgProgramStoreGetDepthMask(depthWriteEnable) == true); + _RS_ASSERT(rsgProgramStoreGetColorMaskR(depthWriteEnable) == false); + _RS_ASSERT(rsgProgramStoreGetColorMaskG(depthWriteEnable) == false); + _RS_ASSERT(rsgProgramStoreGetColorMaskB(depthWriteEnable) == false); + _RS_ASSERT(rsgProgramStoreGetColorMaskA(depthWriteEnable) == false); + _RS_ASSERT(rsgProgramStoreGetDitherEnabled(depthWriteEnable) == false); + _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(depthWriteEnable) == RS_BLEND_SRC_ZERO); + _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(depthWriteEnable) == RS_BLEND_DST_ZERO); + + _RS_ASSERT(rsgProgramStoreGetDepthFunc(colorRWriteEnable) == RS_DEPTH_FUNC_ALWAYS); + _RS_ASSERT(rsgProgramStoreGetDepthMask(colorRWriteEnable) == false); + _RS_ASSERT(rsgProgramStoreGetColorMaskR(colorRWriteEnable) == true); + _RS_ASSERT(rsgProgramStoreGetColorMaskG(colorRWriteEnable) == false); + _RS_ASSERT(rsgProgramStoreGetColorMaskB(colorRWriteEnable) == false); + _RS_ASSERT(rsgProgramStoreGetColorMaskA(colorRWriteEnable) == false); + _RS_ASSERT(rsgProgramStoreGetDitherEnabled(colorRWriteEnable) == false); + _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(colorRWriteEnable) == RS_BLEND_SRC_ZERO); + _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(colorRWriteEnable) == RS_BLEND_DST_ZERO); + + _RS_ASSERT(rsgProgramStoreGetDepthFunc(colorGWriteEnable) == RS_DEPTH_FUNC_ALWAYS); + _RS_ASSERT(rsgProgramStoreGetDepthMask(colorGWriteEnable) == false); + _RS_ASSERT(rsgProgramStoreGetColorMaskR(colorGWriteEnable) == false); + _RS_ASSERT(rsgProgramStoreGetColorMaskG(colorGWriteEnable) == true); + _RS_ASSERT(rsgProgramStoreGetColorMaskB(colorGWriteEnable) == false); + _RS_ASSERT(rsgProgramStoreGetColorMaskA(colorGWriteEnable) == false); + _RS_ASSERT(rsgProgramStoreGetDitherEnabled(colorGWriteEnable) == false); + _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(colorGWriteEnable) == RS_BLEND_SRC_ZERO); + _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(colorGWriteEnable) == RS_BLEND_DST_ZERO); + + _RS_ASSERT(rsgProgramStoreGetDepthFunc(colorBWriteEnable) == RS_DEPTH_FUNC_ALWAYS); + _RS_ASSERT(rsgProgramStoreGetDepthMask(colorBWriteEnable) == false); + _RS_ASSERT(rsgProgramStoreGetColorMaskR(colorBWriteEnable) == false); + _RS_ASSERT(rsgProgramStoreGetColorMaskG(colorBWriteEnable) == false); + _RS_ASSERT(rsgProgramStoreGetColorMaskB(colorBWriteEnable) == true); + _RS_ASSERT(rsgProgramStoreGetColorMaskA(colorBWriteEnable) == false); + _RS_ASSERT(rsgProgramStoreGetDitherEnabled(colorBWriteEnable) == false); + _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(colorBWriteEnable) == RS_BLEND_SRC_ZERO); + _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(colorBWriteEnable) == RS_BLEND_DST_ZERO); + + _RS_ASSERT(rsgProgramStoreGetDepthFunc(colorAWriteEnable) == RS_DEPTH_FUNC_ALWAYS); + _RS_ASSERT(rsgProgramStoreGetDepthMask(colorAWriteEnable) == false); + _RS_ASSERT(rsgProgramStoreGetColorMaskR(colorAWriteEnable) == false); + _RS_ASSERT(rsgProgramStoreGetColorMaskG(colorAWriteEnable) == false); + _RS_ASSERT(rsgProgramStoreGetColorMaskB(colorAWriteEnable) == false); + _RS_ASSERT(rsgProgramStoreGetColorMaskA(colorAWriteEnable) == true); + _RS_ASSERT(rsgProgramStoreGetDitherEnabled(colorAWriteEnable) == false); + _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(colorAWriteEnable) == RS_BLEND_SRC_ZERO); + _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(colorAWriteEnable) == RS_BLEND_DST_ZERO); + + _RS_ASSERT(rsgProgramStoreGetDepthFunc(ditherEnable) == RS_DEPTH_FUNC_ALWAYS); + _RS_ASSERT(rsgProgramStoreGetDepthMask(ditherEnable) == false); + _RS_ASSERT(rsgProgramStoreGetColorMaskR(ditherEnable) == false); + _RS_ASSERT(rsgProgramStoreGetColorMaskG(ditherEnable) == false); + _RS_ASSERT(rsgProgramStoreGetColorMaskB(ditherEnable) == false); + _RS_ASSERT(rsgProgramStoreGetColorMaskA(ditherEnable) == false); + _RS_ASSERT(rsgProgramStoreGetDitherEnabled(ditherEnable) == true); + _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(ditherEnable) == RS_BLEND_SRC_ZERO); + _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(ditherEnable) == RS_BLEND_DST_ZERO); + + _RS_ASSERT(rsgProgramStoreGetDepthFunc(blendSrc) == RS_DEPTH_FUNC_ALWAYS); + _RS_ASSERT(rsgProgramStoreGetDepthMask(blendSrc) == false); + _RS_ASSERT(rsgProgramStoreGetColorMaskR(blendSrc) == false); + _RS_ASSERT(rsgProgramStoreGetColorMaskG(blendSrc) == false); + _RS_ASSERT(rsgProgramStoreGetColorMaskB(blendSrc) == false); + _RS_ASSERT(rsgProgramStoreGetColorMaskA(blendSrc) == false); + _RS_ASSERT(rsgProgramStoreGetDitherEnabled(blendSrc) == false); + _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(blendSrc) == RS_BLEND_SRC_DST_COLOR); + _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(blendSrc) == RS_BLEND_DST_ZERO); + + _RS_ASSERT(rsgProgramStoreGetDepthFunc(blendDst) == RS_DEPTH_FUNC_ALWAYS); + _RS_ASSERT(rsgProgramStoreGetDepthMask(blendDst) == false); + _RS_ASSERT(rsgProgramStoreGetColorMaskR(blendDst) == false); + _RS_ASSERT(rsgProgramStoreGetColorMaskG(blendDst) == false); + _RS_ASSERT(rsgProgramStoreGetColorMaskB(blendDst) == false); + _RS_ASSERT(rsgProgramStoreGetColorMaskA(blendDst) == false); + _RS_ASSERT(rsgProgramStoreGetDitherEnabled(blendDst) == false); + _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(blendDst) == RS_BLEND_SRC_ZERO); + _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(blendDst) == RS_BLEND_DST_DST_ALPHA); + + if (failed) { + rsDebug("test_program_store_getters FAILED", 0); + } + else { + rsDebug("test_program_store_getters PASSED", 0); + } + + return failed; +} + +void program_store_test() { + bool failed = false; + failed |= test_program_store_getters(); + + if (failed) { + rsSendToClientBlocking(RS_MSG_TEST_FAILED); + } + else { + rsSendToClientBlocking(RS_MSG_TEST_PASSED); + } +} + diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/sampler.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/sampler.rs new file mode 100644 index 000000000000..ac9a5496afb2 --- /dev/null +++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/sampler.rs @@ -0,0 +1,63 @@ +#include "shared.rsh" +#include "rs_graphics.rsh" +rs_sampler minification; +rs_sampler magnification; +rs_sampler wrapS; +rs_sampler wrapT; +rs_sampler anisotropy; + +static bool test_sampler_getters() { + bool failed = false; + + _RS_ASSERT(rsgSamplerGetMagnification(minification) == RS_SAMPLER_NEAREST); + _RS_ASSERT(rsgSamplerGetMinification(minification) == RS_SAMPLER_LINEAR_MIP_LINEAR); + _RS_ASSERT(rsgSamplerGetWrapS(minification) == RS_SAMPLER_CLAMP); + _RS_ASSERT(rsgSamplerGetWrapT(minification) == RS_SAMPLER_CLAMP); + _RS_ASSERT(rsgSamplerGetAnisotropy(minification) == 1.0f); + + _RS_ASSERT(rsgSamplerGetMagnification(magnification) == RS_SAMPLER_LINEAR); + _RS_ASSERT(rsgSamplerGetMinification(magnification) == RS_SAMPLER_NEAREST); + _RS_ASSERT(rsgSamplerGetWrapS(magnification) == RS_SAMPLER_CLAMP); + _RS_ASSERT(rsgSamplerGetWrapT(magnification) == RS_SAMPLER_CLAMP); + _RS_ASSERT(rsgSamplerGetAnisotropy(magnification) == 1.0f); + + _RS_ASSERT(rsgSamplerGetMagnification(wrapS) == RS_SAMPLER_NEAREST); + _RS_ASSERT(rsgSamplerGetMinification(wrapS) == RS_SAMPLER_NEAREST); + _RS_ASSERT(rsgSamplerGetWrapS(wrapS) == RS_SAMPLER_WRAP); + _RS_ASSERT(rsgSamplerGetWrapT(wrapS) == RS_SAMPLER_CLAMP); + _RS_ASSERT(rsgSamplerGetAnisotropy(wrapS) == 1.0f); + + _RS_ASSERT(rsgSamplerGetMagnification(wrapT) == RS_SAMPLER_NEAREST); + _RS_ASSERT(rsgSamplerGetMinification(wrapT) == RS_SAMPLER_NEAREST); + _RS_ASSERT(rsgSamplerGetWrapS(wrapT) == RS_SAMPLER_CLAMP); + _RS_ASSERT(rsgSamplerGetWrapT(wrapT) == RS_SAMPLER_WRAP); + _RS_ASSERT(rsgSamplerGetAnisotropy(wrapT) == 1.0f); + + _RS_ASSERT(rsgSamplerGetMagnification(anisotropy) == RS_SAMPLER_NEAREST); + _RS_ASSERT(rsgSamplerGetMinification(anisotropy) == RS_SAMPLER_NEAREST); + _RS_ASSERT(rsgSamplerGetWrapS(anisotropy) == RS_SAMPLER_CLAMP); + _RS_ASSERT(rsgSamplerGetWrapT(anisotropy) == RS_SAMPLER_CLAMP); + _RS_ASSERT(rsgSamplerGetAnisotropy(anisotropy) == 8.0f); + + if (failed) { + rsDebug("test_sampler_getters FAILED", 0); + } + else { + rsDebug("test_sampler_getters PASSED", 0); + } + + return failed; +} + +void sampler_test() { + bool failed = false; + failed |= test_sampler_getters(); + + if (failed) { + rsSendToClientBlocking(RS_MSG_TEST_FAILED); + } + else { + rsSendToClientBlocking(RS_MSG_TEST_PASSED); + } +} + diff --git a/tests/SmokeTest/tests/src/com/android/smoketest/ProcessErrorsTest.java b/tests/SmokeTest/tests/src/com/android/smoketest/ProcessErrorsTest.java index 5f53a9bf4aab..1a2dcb971bb8 100644 --- a/tests/SmokeTest/tests/src/com/android/smoketest/ProcessErrorsTest.java +++ b/tests/SmokeTest/tests/src/com/android/smoketest/ProcessErrorsTest.java @@ -19,12 +19,21 @@ package com.android.smoketest; import com.android.internal.os.RuntimeInit; import android.app.ActivityManager; +import android.app.ActivityManager.ProcessErrorStateInfo; import android.content.Context; +import android.content.ComponentName; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; import android.test.AndroidTestCase; import android.util.Log; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Set; /** * This smoke test is designed to quickly sniff for any error conditions @@ -32,53 +41,125 @@ import java.util.List; */ public class ProcessErrorsTest extends AndroidTestCase { - private final String TAG = "ProcessErrorsTest"; + private static final String TAG = "ProcessErrorsTest"; protected ActivityManager mActivityManager; + protected PackageManager mPackageManager; @Override public void setUp() throws Exception { super.setUp(); - mActivityManager = (ActivityManager) + mActivityManager = (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE); + mPackageManager = getContext().getPackageManager(); } public void testSetUpConditions() throws Exception { assertNotNull(mActivityManager); + assertNotNull(mPackageManager); } public void testNoProcessErrors() throws Exception { - List<ActivityManager.ProcessErrorStateInfo> errList; + final String reportMsg = checkForProcessErrors(); + if (reportMsg != null) { + Log.w(TAG, reportMsg); + } + + // report a non-empty list back to the test framework + assertNull(reportMsg, reportMsg); + } + + private String checkForProcessErrors() throws Exception { + List<ProcessErrorStateInfo> errList; errList = mActivityManager.getProcessesInErrorState(); // note: this contains information about each process that is currently in an error // condition. if the list is empty (null) then "we're good". // if the list is non-empty, then it's useful to report the contents of the list - // we'll put a copy in the log, and we'll report it back to the framework via the assert. final String reportMsg = reportListContents(errList); - if (reportMsg != null) { - Log.w(TAG, reportMsg); + return reportMsg; + } + + /** + * A test that runs all Launcher-launchable activities and verifies that no ANRs or crashes + * happened while doing so. + * <p /> + * FIXME: Doesn't detect multiple crashing apps properly, since the crash dialog for the + * FIXME: first app doesn't go away. + */ + public void testRunAllActivities() throws Exception { + final Intent home = new Intent(Intent.ACTION_MAIN); + home.addCategory(Intent.CATEGORY_HOME); + home.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + + final Intent launchable = new Intent(Intent.ACTION_MAIN); + launchable.addCategory(Intent.CATEGORY_LAUNCHER); + final List<ResolveInfo> activities = mPackageManager.queryIntentActivities(launchable, 0); + final Set<ProcessError> errSet = new HashSet<ProcessError>(); + + for (ResolveInfo info : activities) { + Log.i(TAG, String.format("Got %s/%s", info.activityInfo.packageName, + info.activityInfo.name)); + + // build an Intent to launch the app + final ComponentName component = new ComponentName(info.activityInfo.packageName, + info.activityInfo.name); + final Intent intent = new Intent(Intent.ACTION_MAIN); + intent.setComponent(component); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + + // launch app, and wait 7 seconds for it to start/settle + getContext().startActivity(intent); + try { + Thread.sleep(7000); + } catch (InterruptedException e) { + // ignore + } + + // See if there are any errors + Collection<ProcessErrorStateInfo> procs = mActivityManager.getProcessesInErrorState(); + if (procs != null) { + errSet.addAll(ProcessError.fromCollection(procs)); + } + + // Send the "home" intent and wait 2 seconds for us to get there + getContext().startActivity(home); + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + // ignore + } + } + + if (!errSet.isEmpty()) { + fail(String.format("Got %d errors: %s", errSet.size(), + reportWrappedListContents(errSet))); } - - // report a non-empty list back to the test framework - assertNull(reportMsg, errList); } - + + private String reportWrappedListContents(Collection<ProcessError> errList) { + List<ProcessErrorStateInfo> newList = new ArrayList<ProcessErrorStateInfo>(errList.size()); + for (ProcessError err : errList) { + newList.add(err.info); + } + return reportListContents(newList); + } + /** * This helper function will dump the actual error reports. * * @param errList The error report containing one or more error records. * @return Returns a string containing all of the errors. */ - private String reportListContents(List<ActivityManager.ProcessErrorStateInfo> errList) { + private String reportListContents(Collection<ProcessErrorStateInfo> errList) { if (errList == null) return null; StringBuilder builder = new StringBuilder(); - Iterator<ActivityManager.ProcessErrorStateInfo> iter = errList.iterator(); + Iterator<ProcessErrorStateInfo> iter = errList.iterator(); while (iter.hasNext()) { - ActivityManager.ProcessErrorStateInfo entry = iter.next(); + ProcessErrorStateInfo entry = iter.next(); String condition; switch (entry.condition) { @@ -96,8 +177,77 @@ public class ProcessErrorsTest extends AndroidTestCase { builder.append("Process error ").append(condition).append(" "); builder.append(" ").append(entry.shortMsg); builder.append(" detected in ").append(entry.processName).append(" ").append(entry.tag); + builder.append("\n"); } return builder.toString(); } - + + /** + * A {@link ProcessErrorStateInfo} wrapper class that hashes how we want (so that equivalent + * crashes are considered equal). + */ + private static class ProcessError { + public final ProcessErrorStateInfo info; + + public ProcessError(ProcessErrorStateInfo newInfo) { + info = newInfo; + } + + public static Collection<ProcessError> fromCollection(Collection<ProcessErrorStateInfo> in) + { + List<ProcessError> out = new ArrayList<ProcessError>(in.size()); + for (ProcessErrorStateInfo info : in) { + out.add(new ProcessError(info)); + } + return out; + } + + private boolean strEquals(String a, String b) { + if ((a == null) && (b == null)) { + return true; + } else if ((a == null) || (b == null)) { + return false; + } else { + return a.equals(b); + } + } + + @Override + public boolean equals(Object other) { + if (other == null) return false; + if (!(other instanceof ProcessError)) return false; + ProcessError peOther = (ProcessError) other; + + return (info.condition == peOther.info.condition) + && strEquals(info.longMsg, peOther.info.longMsg) + && (info.pid == peOther.info.pid) + && strEquals(info.processName, peOther.info.processName) + && strEquals(info.shortMsg, peOther.info.shortMsg) + && strEquals(info.stackTrace, peOther.info.stackTrace) + && strEquals(info.tag, peOther.info.tag) + && (info.uid == peOther.info.uid); + } + + private int hash(Object obj) { + if (obj == null) { + return 13; + } else { + return obj.hashCode(); + } + } + + @Override + public int hashCode() { + int code = 17; + code += info.condition; + code *= hash(info.longMsg); + code += info.pid; + code *= hash(info.processName); + code *= hash(info.shortMsg); + code *= hash(info.stackTrace); + code *= hash(info.tag); + code += info.uid; + return code; + } + } } diff --git a/tests/SmokeTestApps/Android.mk b/tests/SmokeTestApps/Android.mk new file mode 100644 index 000000000000..3f5f0118b1ac --- /dev/null +++ b/tests/SmokeTestApps/Android.mk @@ -0,0 +1,12 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests + +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +LOCAL_PACKAGE_NAME := SmokeTestTriggerApps + +include $(BUILD_PACKAGE) + +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/tests/SmokeTestApps/AndroidManifest.xml b/tests/SmokeTestApps/AndroidManifest.xml new file mode 100644 index 000000000000..0f20107f60d1 --- /dev/null +++ b/tests/SmokeTestApps/AndroidManifest.xml @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2012 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.smoketest.triggers"> + + <application android:label="something"> + <activity android:name=".CrashyApp" + android:label="Test Crashy App"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + + <activity android:name=".CrashyApp2" + android:label="Test Crashy App2"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + + <activity android:name=".UnresponsiveApp" + android:label="Test Unresponsive App"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> +</manifest> diff --git a/tests/SmokeTestApps/README b/tests/SmokeTestApps/README new file mode 100644 index 000000000000..04aa366862bd --- /dev/null +++ b/tests/SmokeTestApps/README @@ -0,0 +1,3 @@ +The apps in this folder are intentionally bad-behaving apps that are intended +to trigger the smoke tests to fail. They are otherwise not useful. + diff --git a/tests/SmokeTestApps/src/com/android/smoketest/triggers/CrashyApp.java b/tests/SmokeTestApps/src/com/android/smoketest/triggers/CrashyApp.java new file mode 100644 index 000000000000..c11b0f3acf79 --- /dev/null +++ b/tests/SmokeTestApps/src/com/android/smoketest/triggers/CrashyApp.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.smoketest.triggers; + +import android.app.Activity; +import android.os.Bundle; +import android.widget.TextView; + +public class CrashyApp extends Activity { + /** Called when the activity is first created. */ + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + TextView tv = new TextView(this); + tv.setText("Hello, Crashy Android"); + setContentView(tv); + } + + @Override + public void onResume() { + ((String) null).length(); + } +} diff --git a/tests/SmokeTestApps/src/com/android/smoketest/triggers/CrashyApp2.java b/tests/SmokeTestApps/src/com/android/smoketest/triggers/CrashyApp2.java new file mode 100644 index 000000000000..3ef5b2b93cb9 --- /dev/null +++ b/tests/SmokeTestApps/src/com/android/smoketest/triggers/CrashyApp2.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.smoketest.triggers; + +import android.app.Activity; +import android.os.Bundle; +import android.widget.TextView; + +public class CrashyApp2 extends Activity { + /** Called when the activity is first created. */ + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + TextView tv = new TextView(this); + tv.setText("Hello, Other Crashy Android"); + setContentView(tv); + } + + + @Override + public void onResume() { + throw new RuntimeException("Two drums and a cymbal fall off a cliff..."); + } +} diff --git a/tests/SmokeTestApps/src/com/android/smoketest/triggers/UnresponsiveApp.java b/tests/SmokeTestApps/src/com/android/smoketest/triggers/UnresponsiveApp.java new file mode 100644 index 000000000000..1291897d0998 --- /dev/null +++ b/tests/SmokeTestApps/src/com/android/smoketest/triggers/UnresponsiveApp.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.smoketest.triggers; + +import android.app.Activity; +import android.os.Bundle; +import android.widget.TextView; + +public class UnresponsiveApp extends Activity { + /** Called when the activity is first created. */ + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + TextView tv = new TextView(this); + tv.setText("Hello, Unresponsive Android"); + setContentView(tv); + } + + @Override + public void onResume() { + // Attempt to provoke the ire of the ActivityManager + while (true) { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + // ignore + } + } + } +} diff --git a/tests/backup/backup_helper_test.cpp b/tests/backup/backup_helper_test.cpp index 04358ad46984..b5f6ff57e6d9 100644 --- a/tests/backup/backup_helper_test.cpp +++ b/tests/backup/backup_helper_test.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include <utils/BackupHelpers.h> +#include <androidfw/BackupHelpers.h> #include <stdio.h> #include <string.h> diff --git a/tools/aapt/AaptAssets.h b/tools/aapt/AaptAssets.h index 1c653e1fb77a..59249529fbba 100644 --- a/tools/aapt/AaptAssets.h +++ b/tools/aapt/AaptAssets.h @@ -7,14 +7,14 @@ #define __AAPT_ASSETS_H #include <stdlib.h> -#include <utils/AssetManager.h> +#include <androidfw/AssetManager.h> +#include <androidfw/ResourceTypes.h> #include <utils/KeyedVector.h> -#include <utils/String8.h> -#include <utils/ResourceTypes.h> +#include <utils/RefBase.h> #include <utils/SortedVector.h> #include <utils/String8.h> +#include <utils/String8.h> #include <utils/Vector.h> -#include <utils/RefBase.h> #include "ZipFile.h" #include "Bundle.h" diff --git a/tools/aapt/Images.cpp b/tools/aapt/Images.cpp index ffbe875b72f7..6402e3cb38d8 100644 --- a/tools/aapt/Images.cpp +++ b/tools/aapt/Images.cpp @@ -8,7 +8,7 @@ #include "Images.h" -#include <utils/ResourceTypes.h> +#include <androidfw/ResourceTypes.h> #include <utils/ByteOrder.h> #include <png.h> diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp index 7a0499c476d7..0c0b2ea0765f 100644 --- a/tools/aapt/ResourceTable.cpp +++ b/tools/aapt/ResourceTable.cpp @@ -9,8 +9,8 @@ #include "XMLNode.h" #include "ResourceFilter.h" +#include <androidfw/ResourceTypes.h> #include <utils/ByteOrder.h> -#include <utils/ResourceTypes.h> #include <stdarg.h> #define NOISY(x) //x diff --git a/tools/aapt/StringPool.h b/tools/aapt/StringPool.h index 255bdbfc0a7f..86044ed1ad2b 100644 --- a/tools/aapt/StringPool.h +++ b/tools/aapt/StringPool.h @@ -10,7 +10,7 @@ #include "Main.h" #include "AaptAssets.h" -#include <utils/ResourceTypes.h> +#include <androidfw/ResourceTypes.h> #include <utils/String16.h> #include <utils/TextOutput.h> diff --git a/tools/aapt/ZipFile.cpp b/tools/aapt/ZipFile.cpp index 0705be3380db..8057068dd685 100644 --- a/tools/aapt/ZipFile.cpp +++ b/tools/aapt/ZipFile.cpp @@ -20,7 +20,7 @@ #define LOG_TAG "zip" -#include <utils/ZipUtils.h> +#include <androidfw/ZipUtils.h> #include <utils/Log.h> #include "ZipFile.h" diff --git a/tools/aidl/Type.cpp b/tools/aidl/Type.cpp index 42e12265247d..d572af6d2aab 100755 --- a/tools/aidl/Type.cpp +++ b/tools/aidl/Type.cpp @@ -123,7 +123,7 @@ register_base_types() RPC_DATA_TYPE = new RpcDataType(); NAMES.Add(RPC_DATA_TYPE); - RPC_ERROR_TYPE = new UserDataType("com.android.athome.rpc", "RpcError", + RPC_ERROR_TYPE = new UserDataType("android.support.place.rpc", "RpcError", true, __FILE__, __LINE__); NAMES.Add(RPC_ERROR_TYPE); @@ -1234,7 +1234,7 @@ GenericListType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variabl // ================================================================ RpcDataType::RpcDataType() - :UserDataType("com.android.athome.rpc", "RpcData", true, true, true) + :UserDataType("android.support.place.rpc", "RpcData", true, true, true) { } diff --git a/tools/aidl/generate_java_rpc.cpp b/tools/aidl/generate_java_rpc.cpp index ecff3a1ad3e7..e5fa07605f2a 100644 --- a/tools/aidl/generate_java_rpc.cpp +++ b/tools/aidl/generate_java_rpc.cpp @@ -7,26 +7,26 @@ Type* SERVICE_CONTEXT_TYPE = new Type("android.content", "Context", Type::BUILT_IN, false, false, false); -Type* PRESENTER_BASE_TYPE = new Type("com.android.athome.connector", +Type* PRESENTER_BASE_TYPE = new Type("android.support.place.connector", "EventListener", Type::BUILT_IN, false, false, false); -Type* PRESENTER_LISTENER_BASE_TYPE = new Type("com.android.athome.connector", +Type* PRESENTER_LISTENER_BASE_TYPE = new Type("android.support.place.connector", "EventListener.Listener", Type::BUILT_IN, false, false, false); -Type* RPC_BROKER_TYPE = new Type("com.android.athome.connector", "Broker", +Type* RPC_BROKER_TYPE = new Type("android.support.place.connector", "Broker", Type::BUILT_IN, false, false, false); Type* RPC_CONTAINER_TYPE = new Type("com.android.athome.connector", "ConnectorContainer", Type::BUILT_IN, false, false, false); Type* PLACE_INFO_TYPE = new Type("android.support.place.connector", "PlaceInfo", Type::BUILT_IN, false, false, false); // TODO: Just use Endpoint, so this works for all endpoints. -Type* RPC_CONNECTOR_TYPE = new Type("com.android.athome.connector", "Connector", +Type* RPC_CONNECTOR_TYPE = new Type("android.support.place.connector", "Connector", Type::BUILT_IN, false, false, false); -Type* RPC_ENDPOINT_INFO_TYPE = new UserDataType("com.android.athome.rpc", +Type* RPC_ENDPOINT_INFO_TYPE = new UserDataType("android.support.place.rpc", "EndpointInfo", true, __FILE__, __LINE__); -Type* RPC_RESULT_HANDLER_TYPE = new UserDataType("com.android.athome.rpc", "RpcResultHandler", +Type* RPC_RESULT_HANDLER_TYPE = new UserDataType("android.support.place.rpc", "RpcResultHandler", true, __FILE__, __LINE__); -Type* RPC_ERROR_LISTENER_TYPE = new Type("com.android.athome.rpc", "RpcErrorHandler", +Type* RPC_ERROR_LISTENER_TYPE = new Type("android.support.place.rpc", "RpcErrorHandler", Type::BUILT_IN, false, false, false); -Type* RPC_CONTEXT_TYPE = new UserDataType("com.android.athome.rpc", "RpcContext", true, +Type* RPC_CONTEXT_TYPE = new UserDataType("android.support.place.rpc", "RpcContext", true, __FILE__, __LINE__); static void generate_create_from_data(Type* t, StatementBlock* addTo, const string& key, diff --git a/tools/layoutlib/bridge/src/android/view/AttachInfo_Accessor.java b/tools/layoutlib/bridge/src/android/view/AttachInfo_Accessor.java index 96de51c08793..97d99695386f 100644 --- a/tools/layoutlib/bridge/src/android/view/AttachInfo_Accessor.java +++ b/tools/layoutlib/bridge/src/android/view/AttachInfo_Accessor.java @@ -29,7 +29,7 @@ public class AttachInfo_Accessor { public static void setAttachInfo(View view) { AttachInfo info = new AttachInfo(new BridgeWindowSession(), new BridgeWindow(), - new Handler(), null); + new ViewRootImpl(view.getContext()), new Handler(), null); info.mHasWindowFocus = true; info.mWindowVisibility = View.VISIBLE; info.mInTouchMode = false; // this is so that we can display selections. diff --git a/tools/makekeycodes/makekeycodes.cpp b/tools/makekeycodes/makekeycodes.cpp index 16df774c643e..6ffbfb859ab8 100644 --- a/tools/makekeycodes/makekeycodes.cpp +++ b/tools/makekeycodes/makekeycodes.cpp @@ -1,5 +1,21 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #include <stdio.h> -#include <ui/KeycodeLabels.h> +#include <androidfw/KeycodeLabels.h> int main(int argc, char** argv) diff --git a/tools/obbtool/Main.cpp b/tools/obbtool/Main.cpp index 932dbec7b2e1..b2152e8f8468 100644 --- a/tools/obbtool/Main.cpp +++ b/tools/obbtool/Main.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include <utils/ObbFile.h> +#include <androidfw/ObbFile.h> #include <utils/String8.h> #include <getopt.h> diff --git a/tools/validatekeymaps/Main.cpp b/tools/validatekeymaps/Main.cpp index 8ab9b6ae3de6..3cc2467b7166 100644 --- a/tools/validatekeymaps/Main.cpp +++ b/tools/validatekeymaps/Main.cpp @@ -14,9 +14,9 @@ * limitations under the License. */ -#include <ui/KeyCharacterMap.h> -#include <ui/KeyLayoutMap.h> -#include <ui/VirtualKeyMap.h> +#include <androidfw/KeyCharacterMap.h> +#include <androidfw/KeyLayoutMap.h> +#include <androidfw/VirtualKeyMap.h> #include <utils/PropertyMap.h> #include <utils/String8.h> diff --git a/wifi/java/android/net/wifi/WifiMonitor.java b/wifi/java/android/net/wifi/WifiMonitor.java index bbb74d1a8090..d05e0b8ace89 100644 --- a/wifi/java/android/net/wifi/WifiMonitor.java +++ b/wifi/java/android/net/wifi/WifiMonitor.java @@ -366,17 +366,6 @@ public class WifiMonitor { handleDriverEvent(eventData); } else if (event == TERMINATING) { /** - * If monitor socket is closed, we have already - * stopped the supplicant, simply exit the monitor thread - */ - if (eventData.startsWith(MONITOR_SOCKET_CLOSED_STR)) { - if (false) { - Log.d(TAG, "Monitor socket is closed, exiting thread"); - } - break; - } - - /** * Close the supplicant connection if we see * too many recv errors */ diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java index 48a785c98b28..e3dd3a621fae 100644 --- a/wifi/java/android/net/wifi/WifiNative.java +++ b/wifi/java/android/net/wifi/WifiNative.java @@ -39,6 +39,8 @@ import java.util.List; */ public class WifiNative { + private static final boolean DBG = false; + private final String mTAG; private static final int DEFAULT_GROUP_OWNER_INTENT = 7; static final int BLUETOOTH_COEXISTENCE_MODE_ENABLED = 0; @@ -53,9 +55,7 @@ public class WifiNative { public native static boolean unloadDriver(); - public native static boolean startSupplicant(); - - public native static boolean startP2pSupplicant(); + public native static boolean startSupplicant(boolean p2pSupported); /* Sends a kill signal to supplicant. To be used when we have lost connection or when the supplicant is hung */ @@ -79,6 +79,7 @@ public class WifiNative { public WifiNative(String iface) { mInterface = iface; + mTAG = "WifiNative-" + iface; } public boolean connectToSupplicant() { @@ -94,14 +95,17 @@ public class WifiNative { } private boolean doBooleanCommand(String command) { + if (DBG) Log.d(mTAG, "doBoolean: " + command); return doBooleanCommand(mInterface, command); } private int doIntCommand(String command) { + if (DBG) Log.d(mTAG, "doInt: " + command); return doIntCommand(mInterface, command); } private String doStringCommand(String command) { + if (DBG) Log.d(mTAG, "doString: " + command); return doStringCommand(mInterface, command); } @@ -437,6 +441,10 @@ public class WifiNative { return doBooleanCommand("P2P_FIND " + timeout); } + public boolean p2pStopFind() { + return doBooleanCommand("P2P_STOP_FIND"); + } + public boolean p2pListen() { return doBooleanCommand("P2P_LISTEN"); } diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java index fb9286e90915..1b64f3e3a2f5 100644 --- a/wifi/java/android/net/wifi/WifiStateMachine.java +++ b/wifi/java/android/net/wifi/WifiStateMachine.java @@ -45,6 +45,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.PackageManager; import android.net.ConnectivityManager; import android.net.DhcpInfo; import android.net.DhcpInfoInternal; @@ -118,6 +119,8 @@ public class WifiStateMachine extends StateMachine { private INetworkManagementService mNwService; private ConnectivityManager mCm; + private final boolean mP2pSupported; + /* Scan results handling */ private List<ScanResult> mScanResults; private static final Pattern scanResultPattern = Pattern.compile("\t+"); @@ -361,9 +364,9 @@ public class WifiStateMachine extends StateMachine { /* Reset the WPS state machine */ static final int CMD_RESET_WPS_STATE = BASE + 122; - /* Interaction with WifiP2pService */ - public static final int WIFI_ENABLE_PENDING = BASE + 131; - public static final int P2P_ENABLE_PROCEED = BASE + 132; + /* P2p commands */ + public static final int CMD_ENABLE_P2P = BASE + 131; + public static final int CMD_DISABLE_P2P = BASE + 132; private static final int CONNECT_MODE = 1; private static final int SCAN_ONLY_MODE = 2; @@ -482,9 +485,6 @@ public class WifiStateMachine extends StateMachine { /* Waiting for untether confirmation to stop soft Ap */ private State mSoftApStoppingState = new SoftApStoppingState(); - /* Wait till p2p is disabled */ - private State mWaitForP2pDisableState = new WaitForP2pDisableState(); - private class TetherStateChange { ArrayList<String> available; ArrayList<String> active; @@ -556,6 +556,9 @@ public class WifiStateMachine extends StateMachine { IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); mNwService = INetworkManagementService.Stub.asInterface(b); + mP2pSupported = mContext.getPackageManager().hasSystemFeature( + PackageManager.FEATURE_WIFI_DIRECT); + mWifiNative = new WifiNative(mInterfaceName); mWifiConfigStore = new WifiConfigStore(context, mWifiNative); mWifiMonitor = new WifiMonitor(this, mWifiNative); @@ -639,7 +642,6 @@ public class WifiStateMachine extends StateMachine { addState(mTetheringState, mSoftApStartedState); addState(mTetheredState, mSoftApStartedState); addState(mSoftApStoppingState, mDefaultState); - addState(mWaitForP2pDisableState, mDefaultState); setInitialState(mInitialState); @@ -1752,7 +1754,9 @@ public class WifiStateMachine extends StateMachine { * If we've exceeded the maximum number of retries for DHCP * to a given network, disable the network */ - if (++mReconnectCount > getMaxDhcpRetries()) { + int maxRetries = getMaxDhcpRetries(); + // maxRetries == 0 means keep trying forever + if (maxRetries > 0 && ++mReconnectCount > maxRetries) { loge("Failed " + mReconnectCount + " times, Disabling " + mLastNetworkId); mWifiConfigStore.disableNetwork(mLastNetworkId, @@ -1896,11 +1900,6 @@ public class WifiStateMachine extends StateMachine { mReplyChannel.replyToMessage(message, WifiManager.CMD_WPS_COMPLETED, new WpsResult(Status.FAILURE)); break; - case WifiP2pService.P2P_ENABLE_PENDING: - // turn off wifi and defer to be handled in DriverUnloadedState - setWifiEnabled(false); - deferMessage(message); - break; default: loge("Error! unhandled message" + message); break; @@ -2060,7 +2059,7 @@ public class WifiStateMachine extends StateMachine { loge("Unable to change interface settings: " + ie); } - if(mWifiNative.startSupplicant()) { + if(mWifiNative.startSupplicant(mP2pSupported)) { if (DBG) log("Supplicant start successful"); mWifiMonitor.startMonitoring(); transitionTo(mSupplicantStartingState); @@ -2172,11 +2171,7 @@ public class WifiStateMachine extends StateMachine { if (DBG) log(getName() + message.toString() + "\n"); switch (message.what) { case CMD_LOAD_DRIVER: - mWifiP2pChannel.sendMessage(WIFI_ENABLE_PENDING); - transitionTo(mWaitForP2pDisableState); - break; - case WifiP2pService.P2P_ENABLE_PENDING: - mReplyChannel.replyToMessage(message, P2P_ENABLE_PROCEED); + transitionTo(mDriverLoadingState); break; default: return NOT_HANDLED; @@ -2556,13 +2551,15 @@ public class WifiStateMachine extends StateMachine { mWifiNative.status(); transitionTo(mDisconnectedState); } + + if (mP2pSupported) mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_ENABLE_P2P); } @Override public boolean processMessage(Message message) { if (DBG) log(getName() + message.toString() + "\n"); boolean eventLoggingEnabled = true; switch(message.what) { - case CMD_SET_SCAN_TYPE: + case CMD_SET_SCAN_TYPE: mSetScanActive = (message.arg1 == SCAN_ACTIVE); mWifiNative.setScanMode(mSetScanActive); break; @@ -2675,6 +2672,8 @@ public class WifiStateMachine extends StateMachine { mIsRunning = false; updateBatteryWorkSource(null); mScanResults = null; + + if (mP2pSupported) mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P); } } @@ -3348,7 +3347,6 @@ public class WifiStateMachine extends StateMachine { case CMD_START_PACKET_FILTERING: case CMD_STOP_PACKET_FILTERING: case CMD_TETHER_STATE_CHANGE: - case WifiP2pService.P2P_ENABLE_PENDING: deferMessage(message); break; case WifiStateMachine.CMD_RESPONSE_AP_CONFIG: @@ -3412,55 +3410,6 @@ public class WifiStateMachine extends StateMachine { transitionTo(mTetheringState); } break; - case WifiP2pService.P2P_ENABLE_PENDING: - // turn of soft Ap and defer to be handled in DriverUnloadedState - setWifiApEnabled(null, false); - deferMessage(message); - break; - default: - return NOT_HANDLED; - } - EventLog.writeEvent(EVENTLOG_WIFI_EVENT_HANDLED, message.what); - return HANDLED; - } - } - - class WaitForP2pDisableState extends State { - private int mSavedArg; - @Override - public void enter() { - if (DBG) log(getName() + "\n"); - EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName()); - - //Preserve the argument arg1 that has information used in DriverLoadingState - mSavedArg = getCurrentMessage().arg1; - } - @Override - public boolean processMessage(Message message) { - if (DBG) log(getName() + message.toString() + "\n"); - switch(message.what) { - case WifiP2pService.WIFI_ENABLE_PROCEED: - //restore argument from original message (CMD_LOAD_DRIVER) - message.arg1 = mSavedArg; - transitionTo(mDriverLoadingState); - break; - case CMD_LOAD_DRIVER: - case CMD_UNLOAD_DRIVER: - case CMD_START_SUPPLICANT: - case CMD_STOP_SUPPLICANT: - case CMD_START_AP: - case CMD_STOP_AP: - case CMD_START_DRIVER: - case CMD_STOP_DRIVER: - case CMD_SET_SCAN_MODE: - case CMD_SET_SCAN_TYPE: - case CMD_SET_HIGH_PERF_MODE: - case CMD_SET_COUNTRY_CODE: - case CMD_SET_FREQUENCY_BAND: - case CMD_START_PACKET_FILTERING: - case CMD_STOP_PACKET_FILTERING: - deferMessage(message); - break; default: return NOT_HANDLED; } @@ -3510,7 +3459,6 @@ public class WifiStateMachine extends StateMachine { case CMD_SET_FREQUENCY_BAND: case CMD_START_PACKET_FILTERING: case CMD_STOP_PACKET_FILTERING: - case WifiP2pService.P2P_ENABLE_PENDING: deferMessage(message); break; default: @@ -3606,7 +3554,6 @@ public class WifiStateMachine extends StateMachine { case CMD_SET_FREQUENCY_BAND: case CMD_START_PACKET_FILTERING: case CMD_STOP_PACKET_FILTERING: - case WifiP2pService.P2P_ENABLE_PENDING: deferMessage(message); break; default: diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java index 7471a2d0a28f..b0cde6439e59 100644 --- a/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java +++ b/wifi/java/android/net/wifi/p2p/WifiP2pDevice.java @@ -301,7 +301,8 @@ public class WifiP2pDevice implements Parcelable { private String trimQuotes(String str) { str = str.trim(); if (str.startsWith("'") && str.endsWith("'")) { - return str.substring(1, str.length()-1); + if (str.length() <= 2) return ""; + else return str.substring(1, str.length()-1); } return str; } diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java index 9205300a5d2e..4fd0a575b701 100644 --- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java +++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java @@ -199,68 +199,61 @@ public class WifiP2pManager { private static final int BASE = Protocol.BASE_WIFI_P2P_MANAGER; /** @hide */ - public static final int ENABLE_P2P = BASE + 1; + public static final int DISCOVER_PEERS = BASE + 1; /** @hide */ - public static final int ENABLE_P2P_FAILED = BASE + 2; + public static final int DISCOVER_PEERS_FAILED = BASE + 2; /** @hide */ - public static final int ENABLE_P2P_SUCCEEDED = BASE + 3; + public static final int DISCOVER_PEERS_SUCCEEDED = BASE + 3; /** @hide */ - public static final int DISABLE_P2P = BASE + 4; + public static final int STOP_DISCOVERY = BASE + 4; /** @hide */ - public static final int DISABLE_P2P_FAILED = BASE + 5; + public static final int STOP_DISCOVERY_FAILED = BASE + 5; /** @hide */ - public static final int DISABLE_P2P_SUCCEEDED = BASE + 6; + public static final int STOP_DISCOVERY_SUCCEEDED = BASE + 6; /** @hide */ - public static final int DISCOVER_PEERS = BASE + 7; + public static final int CONNECT = BASE + 7; /** @hide */ - public static final int DISCOVER_PEERS_FAILED = BASE + 8; + public static final int CONNECT_FAILED = BASE + 8; /** @hide */ - public static final int DISCOVER_PEERS_SUCCEEDED = BASE + 9; + public static final int CONNECT_SUCCEEDED = BASE + 9; /** @hide */ - public static final int CONNECT = BASE + 10; + public static final int CANCEL_CONNECT = BASE + 10; /** @hide */ - public static final int CONNECT_FAILED = BASE + 11; + public static final int CANCEL_CONNECT_FAILED = BASE + 11; /** @hide */ - public static final int CONNECT_SUCCEEDED = BASE + 12; + public static final int CANCEL_CONNECT_SUCCEEDED = BASE + 12; /** @hide */ - public static final int CANCEL_CONNECT = BASE + 13; + public static final int CREATE_GROUP = BASE + 13; /** @hide */ - public static final int CANCEL_CONNECT_FAILED = BASE + 14; + public static final int CREATE_GROUP_FAILED = BASE + 14; /** @hide */ - public static final int CANCEL_CONNECT_SUCCEEDED = BASE + 15; + public static final int CREATE_GROUP_SUCCEEDED = BASE + 15; /** @hide */ - public static final int CREATE_GROUP = BASE + 16; + public static final int REMOVE_GROUP = BASE + 16; /** @hide */ - public static final int CREATE_GROUP_FAILED = BASE + 17; + public static final int REMOVE_GROUP_FAILED = BASE + 17; /** @hide */ - public static final int CREATE_GROUP_SUCCEEDED = BASE + 18; + public static final int REMOVE_GROUP_SUCCEEDED = BASE + 18; /** @hide */ - public static final int REMOVE_GROUP = BASE + 19; + public static final int REQUEST_PEERS = BASE + 19; /** @hide */ - public static final int REMOVE_GROUP_FAILED = BASE + 20; - /** @hide */ - public static final int REMOVE_GROUP_SUCCEEDED = BASE + 21; - - /** @hide */ - public static final int REQUEST_PEERS = BASE + 22; - /** @hide */ - public static final int RESPONSE_PEERS = BASE + 23; + public static final int RESPONSE_PEERS = BASE + 20; /** @hide */ - public static final int REQUEST_CONNECTION_INFO = BASE + 24; + public static final int REQUEST_CONNECTION_INFO = BASE + 21; /** @hide */ - public static final int RESPONSE_CONNECTION_INFO = BASE + 25; + public static final int RESPONSE_CONNECTION_INFO = BASE + 22; /** @hide */ - public static final int REQUEST_GROUP_INFO = BASE + 26; + public static final int REQUEST_GROUP_INFO = BASE + 23; /** @hide */ - public static final int RESPONSE_GROUP_INFO = BASE + 27; + public static final int RESPONSE_GROUP_INFO = BASE + 24; /** * Create a new WifiP2pManager instance. Applications use @@ -376,6 +369,7 @@ public class WifiP2pManager { break; /* ActionListeners grouped together */ case WifiP2pManager.DISCOVER_PEERS_FAILED: + case WifiP2pManager.STOP_DISCOVERY_FAILED: case WifiP2pManager.CONNECT_FAILED: case WifiP2pManager.CANCEL_CONNECT_FAILED: case WifiP2pManager.CREATE_GROUP_FAILED: @@ -386,6 +380,7 @@ public class WifiP2pManager { break; /* ActionListeners grouped together */ case WifiP2pManager.DISCOVER_PEERS_SUCCEEDED: + case WifiP2pManager.STOP_DISCOVERY_SUCCEEDED: case WifiP2pManager.CONNECT_SUCCEEDED: case WifiP2pManager.CANCEL_CONNECT_SUCCEEDED: case WifiP2pManager.CREATE_GROUP_SUCCEEDED: @@ -459,26 +454,6 @@ public class WifiP2pManager { } /** - * Sends in a request to the system to enable p2p. This will pop up a dialog - * to the user and upon authorization will enable p2p. - * @hide - */ - public void enableP2p(Channel c) { - if (c == null) return; - c.mAsyncChannel.sendMessage(ENABLE_P2P); - } - - /** - * Sends in a request to the system to disable p2p. This will pop up a dialog - * to the user and upon authorization will enable p2p. - * @hide - */ - public void disableP2p(Channel c) { - if (c == null) return; - c.mAsyncChannel.sendMessage(DISABLE_P2P); - } - - /** * Initiate peer discovery. A discovery process involves scanning for available Wi-Fi peers * for the purpose of establishing a connection. * @@ -503,6 +478,16 @@ public class WifiP2pManager { } /** + * TODO: Add more documentation before opening up + * Cancel peer discovery + * @hide + */ + public void stopPeerDiscovery(Channel c, ActionListener listener) { + if (c == null) return; + c.mAsyncChannel.sendMessage(STOP_DISCOVERY, 0, c.putListener(listener)); + } + + /** * Start a p2p connection to a device with the specified configuration. * * <p> The function call immediately returns after sending a connection request diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java index 69cbb5c35938..5b0e42489490 100644 --- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java +++ b/wifi/java/android/net/wifi/p2p/WifiP2pService.java @@ -49,6 +49,7 @@ import android.os.Handler; import android.os.HandlerThread; import android.os.Message; import android.os.Messenger; +import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemProperties; import android.provider.Settings; @@ -84,7 +85,7 @@ import java.util.Collection; */ public class WifiP2pService extends IWifiP2pManager.Stub { private static final String TAG = "WifiP2pService"; - private static final boolean DBG = true; + private static final boolean DBG = false; private static final String NETWORKTYPE = "WIFI_P2P"; private Context mContext; @@ -94,11 +95,6 @@ public class WifiP2pService extends IWifiP2pManager.Stub { INetworkManagementService mNwService; private DhcpStateMachine mDhcpStateMachine; - //Tracked to notify the user about wifi client/hotspot being shut down - //during p2p bring up - private int mWifiState = WifiManager.WIFI_STATE_DISABLED; - private int mWifiApState = WifiManager.WIFI_AP_STATE_DISABLED; - private P2pStateMachine mP2pStateMachine; private AsyncChannel mReplyChannel = new AsyncChannel(); private AsyncChannel mWifiChannel; @@ -110,6 +106,9 @@ public class WifiP2pService extends IWifiP2pManager.Stub { private static final int GROUP_CREATING_WAIT_TIME_MS = 120 * 1000; private static int mGroupCreatingTimeoutIndex = 0; + /* Set a two minute discover timeout to avoid STA scans from being blocked */ + private static final int DISCOVER_TIMEOUT_S = 120; + /** * Delay between restarts upon failure to setup connection with supplicant */ @@ -124,28 +123,13 @@ public class WifiP2pService extends IWifiP2pManager.Stub { private static final int BASE = Protocol.BASE_WIFI_P2P_SERVICE; - /* Message sent to WifiStateMachine to indicate p2p enable is pending */ - public static final int P2P_ENABLE_PENDING = BASE + 1; - /* Message sent to WifiStateMachine to indicate Wi-Fi client/hotspot operation can proceed */ - public static final int WIFI_ENABLE_PROCEED = BASE + 2; - /* Delayed message to timeout group creation */ - public static final int GROUP_CREATING_TIMED_OUT = BASE + 3; - - /* User accepted to disable Wi-Fi in order to enable p2p */ - private static final int WIFI_DISABLE_USER_ACCEPT = BASE + 4; - /* User rejected to disable Wi-Fi in order to enable p2p */ - private static final int WIFI_DISABLE_USER_REJECT = BASE + 5; + public static final int GROUP_CREATING_TIMED_OUT = BASE + 1; /* User accepted a peer request */ - private static final int PEER_CONNECTION_USER_ACCEPT = BASE + 6; + private static final int PEER_CONNECTION_USER_ACCEPT = BASE + 2; /* User rejected a peer request */ - private static final int PEER_CONNECTION_USER_REJECT = BASE + 7; - - /* Airplane mode changed */ - private static final int AIRPLANE_MODE_CHANGED = BASE + 8; - /* Emergency callback mode */ - private static final int EMERGENCY_CALLBACK_MODE = BASE + 9; + private static final int PEER_CONNECTION_USER_REJECT = BASE + 3; private final boolean mP2pSupported; @@ -166,7 +150,7 @@ public class WifiP2pService extends IWifiP2pManager.Stub { public WifiP2pService(Context context) { mContext = context; - //STOPSHIP: fix this + //STOPSHIP: get this from native side mInterface = "p2p0"; mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI_P2P, 0, NETWORKTYPE, ""); @@ -179,15 +163,6 @@ public class WifiP2pService extends IWifiP2pManager.Stub { mP2pStateMachine = new P2pStateMachine(TAG, mP2pSupported); mP2pStateMachine.start(); - - // broadcasts - IntentFilter filter = new IntentFilter(); - filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION); - filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); - filter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED); - filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION); - mContext.registerReceiver(new WifiStateReceiver(), filter); - } public void connectivityServiceReady() { @@ -195,26 +170,6 @@ public class WifiP2pService extends IWifiP2pManager.Stub { mNwService = INetworkManagementService.Stub.asInterface(b); } - private class WifiStateReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) { - mWifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, - WifiManager.WIFI_STATE_DISABLED); - } else if (action.equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION)) { - mWifiApState = intent.getIntExtra(WifiManager.EXTRA_WIFI_AP_STATE, - WifiManager.WIFI_AP_STATE_DISABLED); - } else if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) { - mP2pStateMachine.sendMessage(AIRPLANE_MODE_CHANGED); - } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) { - if (intent.getBooleanExtra("phoneinECMState", false) == true) { - mP2pStateMachine.sendMessage(EMERGENCY_CALLBACK_MODE); - } - } - } - } - private void enforceAccessPermission() { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE, "WifiP2pService"); @@ -264,8 +219,6 @@ public class WifiP2pService extends IWifiP2pManager.Stub { private P2pNotSupportedState mP2pNotSupportedState = new P2pNotSupportedState(); private P2pDisablingState mP2pDisablingState = new P2pDisablingState(); private P2pDisabledState mP2pDisabledState = new P2pDisabledState(); - private WaitForUserActionState mWaitForUserActionState = new WaitForUserActionState(); - private WaitForWifiDisableState mWaitForWifiDisableState = new WaitForWifiDisableState(); private P2pEnablingState mP2pEnablingState = new P2pEnablingState(); private P2pEnabledState mP2pEnabledState = new P2pEnabledState(); // Inactive is when p2p is enabled with no connectivity @@ -299,8 +252,6 @@ public class WifiP2pService extends IWifiP2pManager.Stub { addState(mP2pNotSupportedState, mDefaultState); addState(mP2pDisablingState, mDefaultState); addState(mP2pDisabledState, mDefaultState); - addState(mWaitForUserActionState, mP2pDisabledState); - addState(mWaitForWifiDisableState, mP2pDisabledState); addState(mP2pEnablingState, mDefaultState); addState(mP2pEnabledState, mDefaultState); addState(mInactiveState, mP2pEnabledState); @@ -346,23 +297,14 @@ public class WifiP2pService extends IWifiP2pManager.Stub { AsyncChannel ac = new AsyncChannel(); ac.connect(mContext, getHandler(), message.replyTo); break; - case WifiStateMachine.WIFI_ENABLE_PENDING: - // Disable p2p operation before we can respond - sendMessage(WifiP2pManager.DISABLE_P2P); - deferMessage(message); - break; - case WifiP2pManager.ENABLE_P2P: - replyToMessage(message, WifiP2pManager.ENABLE_P2P_FAILED, - WifiP2pManager.BUSY); - break; - case WifiP2pManager.DISABLE_P2P: - replyToMessage(message, WifiP2pManager.DISABLE_P2P_FAILED, - WifiP2pManager.BUSY); - break; case WifiP2pManager.DISCOVER_PEERS: replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED, WifiP2pManager.BUSY); break; + case WifiP2pManager.STOP_DISCOVERY: + replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED, + WifiP2pManager.BUSY); + break; case WifiP2pManager.CONNECT: replyToMessage(message, WifiP2pManager.CONNECT_FAILED, WifiP2pManager.BUSY); @@ -388,16 +330,14 @@ public class WifiP2pService extends IWifiP2pManager.Stub { case WifiP2pManager.REQUEST_GROUP_INFO: replyToMessage(message, WifiP2pManager.RESPONSE_GROUP_INFO, mGroup); break; - case AIRPLANE_MODE_CHANGED: - if (isAirplaneModeOn()) sendMessage(WifiP2pManager.DISABLE_P2P); - break; - case EMERGENCY_CALLBACK_MODE: - sendMessage(WifiP2pManager.DISABLE_P2P); - break; // Ignore case WifiMonitor.P2P_INVITATION_RESULT_EVENT: - case WIFI_DISABLE_USER_ACCEPT: - case WIFI_DISABLE_USER_REJECT: + case WifiMonitor.SCAN_RESULTS_EVENT: + case WifiMonitor.SUP_CONNECTION_EVENT: + case WifiMonitor.SUP_DISCONNECTION_EVENT: + case WifiMonitor.NETWORK_CONNECTION_EVENT: + case WifiMonitor.NETWORK_DISCONNECTION_EVENT: + case WifiMonitor.SUPPLICANT_STATE_CHANGE_EVENT: case PEER_CONNECTION_USER_ACCEPT: case PEER_CONNECTION_USER_REJECT: case GROUP_CREATING_TIMED_OUT: @@ -414,20 +354,12 @@ public class WifiP2pService extends IWifiP2pManager.Stub { @Override public boolean processMessage(Message message) { switch (message.what) { - // Allow Wi-Fi to proceed - case WifiStateMachine.WIFI_ENABLE_PENDING: - replyToMessage(message, WIFI_ENABLE_PROCEED); - break; - case WifiP2pManager.ENABLE_P2P: - replyToMessage(message, WifiP2pManager.ENABLE_P2P_FAILED, - WifiP2pManager.P2P_UNSUPPORTED); - break; - case WifiP2pManager.DISABLE_P2P: - replyToMessage(message, WifiP2pManager.DISABLE_P2P_FAILED, + case WifiP2pManager.DISCOVER_PEERS: + replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED, WifiP2pManager.P2P_UNSUPPORTED); break; - case WifiP2pManager.DISCOVER_PEERS: - replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED, + case WifiP2pManager.STOP_DISCOVERY: + replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED, WifiP2pManager.P2P_UNSUPPORTED); break; case WifiP2pManager.CONNECT: @@ -438,7 +370,7 @@ public class WifiP2pService extends IWifiP2pManager.Stub { replyToMessage(message, WifiP2pManager.CANCEL_CONNECT_FAILED, WifiP2pManager.P2P_UNSUPPORTED); break; - case WifiP2pManager.CREATE_GROUP: + case WifiP2pManager.CREATE_GROUP: replyToMessage(message, WifiP2pManager.CREATE_GROUP_FAILED, WifiP2pManager.P2P_UNSUPPORTED); break; @@ -455,26 +387,15 @@ public class WifiP2pService extends IWifiP2pManager.Stub { class P2pDisablingState extends State { @Override - public void enter() { - if (DBG) logd(getName()); - logd("stopping supplicant"); - if (!mWifiNative.stopSupplicant()) { - loge("Failed to stop supplicant, issue kill"); - mWifiNative.killSupplicant(); - } - } - - @Override public boolean processMessage(Message message) { if (DBG) logd(getName() + message.toString()); switch (message.what) { case WifiMonitor.SUP_DISCONNECTION_EVENT: - logd("Supplicant connection lost"); - mWifiNative.closeSupplicantConnection(); + if (DBG) logd("p2p socket connection lost"); transitionTo(mP2pDisabledState); break; - case WifiP2pManager.ENABLE_P2P: - case WifiP2pManager.DISABLE_P2P: + case WifiStateMachine.CMD_ENABLE_P2P: + case WifiStateMachine.CMD_DISABLE_P2P: deferMessage(message); break; default: @@ -484,7 +405,6 @@ public class WifiP2pService extends IWifiP2pManager.Stub { } } - class P2pDisabledState extends State { @Override public void enter() { @@ -495,118 +415,19 @@ public class WifiP2pService extends IWifiP2pManager.Stub { public boolean processMessage(Message message) { if (DBG) logd(getName() + message.toString()); switch (message.what) { - case WifiP2pManager.ENABLE_P2P: - OnClickListener listener = new OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - if (which == DialogInterface.BUTTON_POSITIVE) { - sendMessage(WIFI_DISABLE_USER_ACCEPT); - } else { - sendMessage(WIFI_DISABLE_USER_REJECT); - } - } - }; - - // Show a user request dialog if we know Wi-Fi client/hotspot is in operation - if (mWifiState != WifiManager.WIFI_STATE_DISABLED || - mWifiApState != WifiManager.WIFI_AP_STATE_DISABLED) { - Resources r = Resources.getSystem(); - AlertDialog dialog = new AlertDialog.Builder(mContext) - .setTitle(r.getString(R.string.wifi_p2p_dialog_title)) - .setMessage(r.getString(R.string.wifi_p2p_turnon_message)) - .setPositiveButton(r.getString(R.string.ok), listener) - .setNegativeButton(r.getString(R.string.cancel), listener) - .create(); - dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); - dialog.show(); - transitionTo(mWaitForUserActionState); - } else { - mWifiChannel.sendMessage(P2P_ENABLE_PENDING); - transitionTo(mWaitForWifiDisableState); - } - replyToMessage(message, WifiP2pManager.ENABLE_P2P_SUCCEEDED); - break; - case WifiP2pManager.DISABLE_P2P: - replyToMessage(message, WifiP2pManager.DISABLE_P2P_SUCCEEDED); - break; - case WifiStateMachine.WIFI_ENABLE_PENDING: - replyToMessage(message, WIFI_ENABLE_PROCEED); - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - } - - class WaitForUserActionState extends State { - @Override - public void enter() { - if (DBG) logd(getName()); - } - - @Override - public boolean processMessage(Message message) { - if (DBG) logd(getName() + message.toString()); - switch (message.what) { - case WIFI_DISABLE_USER_ACCEPT: - mWifiChannel.sendMessage(P2P_ENABLE_PENDING); - transitionTo(mWaitForWifiDisableState); - break; - case WIFI_DISABLE_USER_REJECT: - logd("User rejected enabling p2p"); - sendP2pStateChangedBroadcast(false); - transitionTo(mP2pDisabledState); - break; - case WifiP2pManager.ENABLE_P2P: - case WifiP2pManager.DISABLE_P2P: - deferMessage(message); - break; - default: - return NOT_HANDLED; - } - return HANDLED; - } - } - - class WaitForWifiDisableState extends State { - @Override - public void enter() { - if (DBG) logd(getName()); - } - - @Override - public boolean processMessage(Message message) { - if (DBG) logd(getName() + message.toString()); - switch (message.what) { - case WifiStateMachine.P2P_ENABLE_PROCEED: + case WifiStateMachine.CMD_ENABLE_P2P: try { - mNwService.wifiFirmwareReload(mInterface, "P2P"); - } catch (Exception e) { - loge("Failed to reload p2p firmware " + e); - // continue - } - - //A runtime crash can leave the interface up and - //this affects p2p when supplicant starts up. - //Ensure interface is down before a supplicant start. - try { - mNwService.setInterfaceDown(mInterface); - } catch (Exception e) { - if (DBG) Slog.w(TAG, "Unable to bring down wlan interface: " + e); - } - - if (mWifiNative.startP2pSupplicant()) { - mWifiMonitor.startMonitoring(); - transitionTo(mP2pEnablingState); - } else { - notifyP2pEnableFailure(); - transitionTo(mP2pDisabledState); + mNwService.setInterfaceUp(mInterface); + } catch (RemoteException re) { + loge("Unable to change interface settings: " + re); + } catch (IllegalStateException ie) { + loge("Unable to change interface settings: " + ie); } + mWifiMonitor.startMonitoring(); + transitionTo(mP2pEnablingState); break; - case WifiP2pManager.ENABLE_P2P: - case WifiP2pManager.DISABLE_P2P: - deferMessage(message); + case WifiStateMachine.CMD_DISABLE_P2P: + //Nothing to do break; default: return NOT_HANDLED; @@ -626,22 +447,15 @@ public class WifiP2pService extends IWifiP2pManager.Stub { if (DBG) logd(getName() + message.toString()); switch (message.what) { case WifiMonitor.SUP_CONNECTION_EVENT: - logd("P2p start successful"); + if (DBG) logd("P2p socket connection successful"); transitionTo(mInactiveState); break; case WifiMonitor.SUP_DISCONNECTION_EVENT: - if (++mP2pRestartCount <= P2P_RESTART_TRIES) { - loge("Failed to start p2p, retry"); - mWifiNative.killSupplicant(); - sendMessageDelayed(WifiP2pManager.ENABLE_P2P, P2P_RESTART_INTERVAL_MSECS); - } else { - loge("Failed " + mP2pRestartCount + " times to start p2p, quit "); - mP2pRestartCount = 0; - } + loge("P2p socket connection failed"); transitionTo(mP2pDisabledState); break; - case WifiP2pManager.ENABLE_P2P: - case WifiP2pManager.DISABLE_P2P: + case WifiStateMachine.CMD_ENABLE_P2P: + case WifiStateMachine.CMD_DISABLE_P2P: deferMessage(message); break; default: @@ -658,30 +472,36 @@ public class WifiP2pService extends IWifiP2pManager.Stub { sendP2pStateChangedBroadcast(true); mNetworkInfo.setIsAvailable(true); initializeP2pSettings(); - showNotification(); } @Override public boolean processMessage(Message message) { if (DBG) logd(getName() + message.toString()); switch (message.what) { - case WifiP2pManager.ENABLE_P2P: - replyToMessage(message, WifiP2pManager.ENABLE_P2P_SUCCEEDED); + case WifiStateMachine.CMD_ENABLE_P2P: + //Nothing to do break; - case WifiP2pManager.DISABLE_P2P: + case WifiStateMachine.CMD_DISABLE_P2P: if (mPeers.clear()) sendP2pPeersChangedBroadcast(); - replyToMessage(message, WifiP2pManager.DISABLE_P2P_SUCCEEDED); + mWifiNative.closeSupplicantConnection(); transitionTo(mP2pDisablingState); break; case WifiP2pManager.DISCOVER_PEERS: - int timeout = message.arg1; - if (mWifiNative.p2pFind(timeout)) { + if (mWifiNative.p2pFind(DISCOVER_TIMEOUT_S)) { replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_SUCCEEDED); } else { replyToMessage(message, WifiP2pManager.DISCOVER_PEERS_FAILED, WifiP2pManager.ERROR); } break; + case WifiP2pManager.STOP_DISCOVERY: + if (mWifiNative.p2pStopFind()) { + replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_SUCCEEDED); + } else { + replyToMessage(message, WifiP2pManager.STOP_DISCOVERY_FAILED, + WifiP2pManager.ERROR); + } + break; case WifiMonitor.P2P_DEVICE_FOUND_EVENT: WifiP2pDevice device = (WifiP2pDevice) message.obj; if (mThisDevice.deviceAddress.equals(device.deviceAddress)) break; @@ -692,15 +512,7 @@ public class WifiP2pService extends IWifiP2pManager.Stub { device = (WifiP2pDevice) message.obj; if (mPeers.remove(device)) sendP2pPeersChangedBroadcast(); break; - case WifiMonitor.SUP_DISCONNECTION_EVENT: /* Supplicant died */ - loge("Connection lost, restart p2p"); - mWifiNative.killSupplicant(); - mWifiNative.closeSupplicantConnection(); - if (mPeers.clear()) sendP2pPeersChangedBroadcast(); - transitionTo(mP2pDisabledState); - sendMessageDelayed(WifiP2pManager.ENABLE_P2P, P2P_RESTART_INTERVAL_MSECS); - break; - default: + default: return NOT_HANDLED; } return HANDLED; @@ -710,7 +522,6 @@ public class WifiP2pService extends IWifiP2pManager.Stub { public void exit() { sendP2pStateChangedBroadcast(false); mNetworkInfo.setIsAvailable(false); - clearNotification(); } } @@ -719,7 +530,8 @@ public class WifiP2pService extends IWifiP2pManager.Stub { public void enter() { if (DBG) logd(getName()); //Start listening every time we get inactive - mWifiNative.p2pListen(); + //TODO: Fix listen after driver behavior is fixed + //mWifiNative.p2pListen(); } @Override @@ -737,6 +549,8 @@ public class WifiP2pService extends IWifiP2pManager.Stub { //TODO: if failure, remove config and do a regular p2pConnect() mWifiNative.p2pReinvoke(netId, mSavedPeerConfig.deviceAddress); } else { + //Stop discovery before issuing connect + mWifiNative.p2pStopFind(); //If peer is a GO, we do not need to send provisional discovery, //the supplicant takes care of it. if (isGroupOwner(mSavedPeerConfig.deviceAddress)) { @@ -1114,7 +928,7 @@ public class WifiP2pService extends IWifiP2pManager.Stub { } // Do the regular device lost handling return NOT_HANDLED; - case WifiP2pManager.DISABLE_P2P: + case WifiStateMachine.CMD_DISABLE_P2P: sendMessage(WifiP2pManager.REMOVE_GROUP); deferMessage(message); break; @@ -1494,54 +1308,5 @@ public class WifiP2pService extends IWifiP2pManager.Stub { Slog.e(TAG, s); } - private void showNotification() { - NotificationManager notificationManager = - (NotificationManager)mContext.getSystemService(Context.NOTIFICATION_SERVICE); - if (notificationManager == null || mNotification != null) { - return; - } - - Intent intent = new Intent(android.provider.Settings.ACTION_WIRELESS_SETTINGS); - intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); - - PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0); - - Resources r = Resources.getSystem(); - CharSequence title = r.getText(R.string.wifi_p2p_enabled_notification_title); - CharSequence message = r.getText(R.string.wifi_p2p_enabled_notification_message); - - mNotification = new Notification(); - mNotification.when = 0; - //TODO: might change to be a seperate icon - mNotification.icon = R.drawable.stat_sys_tether_wifi; - mNotification.defaults &= ~Notification.DEFAULT_SOUND; - mNotification.flags = Notification.FLAG_ONGOING_EVENT; - mNotification.tickerText = title; - mNotification.setLatestEventInfo(mContext, title, message, pi); - - notificationManager.notify(mNotification.icon, mNotification); - } - - private void clearNotification() { - NotificationManager notificationManager = - (NotificationManager)mContext.getSystemService(Context.NOTIFICATION_SERVICE); - if (notificationManager != null && mNotification != null) { - notificationManager.cancel(mNotification.icon); - mNotification = null; - } - } - - private boolean isAirplaneSensitive() { - String airplaneModeRadios = Settings.System.getString(mContext.getContentResolver(), - Settings.System.AIRPLANE_MODE_RADIOS); - return airplaneModeRadios == null - || airplaneModeRadios.contains(Settings.System.RADIO_WIFI); - } - - private boolean isAirplaneModeOn() { - return isAirplaneSensitive() && Settings.System.getInt(mContext.getContentResolver(), - Settings.System.AIRPLANE_MODE_ON, 0) == 1; - } - } } |